// ============================================================================
// move.gl | Bubble Loader Mixins
// ============================================================================
// Copyright 2025 Scape Agency BV
// Licensed under MIT License
// ============================================================================

////
/// Bubble Loader Mixins
/// ===========================================================================
///
/// This module provides mixins for bubble/ball-based loading animations.
///
/// @group Loaders
/// @author Scape Agency
/// @link https://move.gl
/// @since 0.1.0
/// @access public
////

@use "../../variables" as *;


// ============================================================================
// Keyframes
// ============================================================================

///
/// Scale bubble animation keyframes.
///
@mixin keyframes_bubble_scale {
    @keyframes bubble-scale {
        0%, 100% { transform: scale(0); }
        50% { transform: scale(1); }
    }
}

///
/// Bubble fade animation keyframes.
///
@mixin keyframes_bubble_fade {
    @keyframes bubble-fade {
        0%, 80%, 100% { box-shadow: 0 2.5em 0 -1.3em; }
        40% { box-shadow: 0 2.5em 0 0; }
    }
}

///
/// Bubble flash animation keyframes.
///
@mixin keyframes_bubble_flash {
    @keyframes bubble-flash {
        0% {
            background-color: rgba(255, 255, 255, 0.2);
            box-shadow: 32px 0 rgba(255, 255, 255, 0.2), -32px 0 var(--loader-color, $loader-color);
        }
        50% {
            background-color: var(--loader-color, $loader-color);
            box-shadow: 32px 0 rgba(255, 255, 255, 0.2), -32px 0 rgba(255, 255, 255, 0.2);
        }
        100% {
            background-color: rgba(255, 255, 255, 0.2);
            box-shadow: 32px 0 var(--loader-color, $loader-color), -32px 0 rgba(255, 255, 255, 0.2);
        }
    }
}

///
/// Bubble pulse keyframes.
///
@mixin keyframes_bubble_pulse {
    @keyframes bubble-pulse {
        33% {
            background: var(--loader-color, $loader-color);
            box-shadow: -24px 0 var(--loader-accent, $loader-accent), 24px 0 var(--loader-color, $loader-color);
        }
        66% {
            background: var(--loader-accent, $loader-accent);
            box-shadow: -24px 0 var(--loader-color, $loader-color), 24px 0 var(--loader-color, $loader-color);
        }
        100% {
            background: var(--loader-color, $loader-color);
            box-shadow: -24px 0 var(--loader-color, $loader-color), 24px 0 var(--loader-accent, $loader-accent);
        }
    }
}

///
/// Bubble expand keyframes.
///
@mixin keyframes_bubble_expand {
    @keyframes bubble-expand {
        0% {
            box-shadow: 0 0, 0 0;
            color: rgba(255, 255, 255, 0.2);
        }
        100% {
            box-shadow: -24px 0, 24px 0;
            color: rgba(255, 255, 255, 0.8);
        }
    }
}

///
/// Bubble collision keyframes.
///
@mixin keyframes_bubble_collision {
    @keyframes bubble-collision-left {
        0%, 100% { transform: translate(-15px); }
        50% { transform: translate(15px); }
    }
    @keyframes bubble-collision-right {
        0%, 100% { transform: translate(15px); }
        50% { transform: translate(-15px); }
    }
}


// ============================================================================
// Bubble Loader Mixins
// ============================================================================

///
/// Rotating bubbles loader.
///
/// @param {Length} $size [48px] - Loader size.
/// @param {Color} $color [#FFF] - Primary color.
/// @param {Color} $accent [#FF3D00] - Accent color.
/// @param {Time} $duration [1s] - Animation duration.
///
@mixin loader_bubble_rotate(
    $size: $loader-size,
    $color: $loader-color,
    $accent: $loader-accent,
    $duration: $loader-speed
) {
    width: var(--loader-size, $size);
    height: var(--loader-size, $size);
    display: block;
    position: relative;
    box-sizing: border-box;
    animation: rotation $duration linear infinite;

    &::after,
    &::before {
        content: '';
        box-sizing: border-box;
        position: absolute;
        width: calc(var(--loader-size, $size) / 2);
        height: calc(var(--loader-size, $size) / 2);
        top: 0;
        background-color: var(--loader-color, $color);
        border-radius: 50%;
        animation: bubble-scale $duration infinite ease-in-out;
    }

    &::before {
        top: auto;
        bottom: 0;
        background-color: var(--loader-accent, $accent);
        animation-delay: calc($duration / 2);
    }
}

///
/// Three dots bounce loader.
///
/// @param {Length} $size [7px] - Base font size.
/// @param {Color} $color [#FFF] - Dot color.
/// @param {Time} $duration [1.8s] - Animation duration.
///
@mixin loader_bubble_dots_bounce(
    $size: 7px,
    $color: $loader-color,
    $duration: 1.8s
) {
    &, &::before, &::after {
        border-radius: 50%;
        width: 2.5em;
        height: 2.5em;
        animation-fill-mode: both;
        animation: bubble-fade $duration infinite ease-in-out;
    }

    color: var(--loader-color, $color);
    font-size: $size;
    position: relative;
    text-indent: -9999em;
    transform: translateZ(0);
    animation-delay: -0.16s;

    &::before,
    &::after {
        content: '';
        position: absolute;
        top: 0;
    }

    &::before {
        left: -3.5em;
        animation-delay: -0.32s;
    }

    &::after {
        left: 3.5em;
    }
}

///
/// Three dots flash loader.
///
/// @param {Length} $size [16px] - Dot size.
/// @param {Color} $color [#FFF] - Dot color.
/// @param {Time} $duration [0.5s] - Animation duration.
///
@mixin loader_bubble_dots_flash(
    $size: 16px,
    $color: $loader-color,
    $duration: 0.5s
) {
    width: $size;
    height: $size;
    border-radius: 50%;
    background-color: var(--loader-color, $color);
    box-shadow: calc($size * 2) 0 var(--loader-color, $color), calc($size * -2) 0 var(--loader-color, $color);
    position: relative;
    animation: bubble-flash $duration ease-out infinite alternate;
}

///
/// Three dots pulse loader.
///
/// @param {Length} $size [16px] - Dot size.
/// @param {Color} $color [#FFF] - Primary color.
/// @param {Color} $accent [#FF3D00] - Accent color.
/// @param {Time} $duration [2s] - Animation duration.
///
@mixin loader_bubble_dots_pulse(
    $size: 16px,
    $color: $loader-color,
    $accent: $loader-accent,
    $duration: 2s
) {
    width: $size;
    height: $size;
    border-radius: 50%;
    display: block;
    position: relative;
    background: var(--loader-accent, $accent);
    color: var(--loader-color, $color);
    box-shadow: -24px 0, 24px 0;
    box-sizing: border-box;
    animation: bubble-pulse $duration ease-in-out infinite;
}

///
/// Three dots rotation loader.
///
/// @param {Length} $size [16px] - Dot size.
/// @param {Color} $color [#FF3D00] - Primary color.
/// @param {Color} $accent [#FFF] - Secondary color.
/// @param {Time} $duration [2s] - Animation duration.
///
@mixin loader_bubble_dots_rotate(
    $size: 16px,
    $color: $loader-accent,
    $accent: $loader-color,
    $duration: 2s
) {
    width: $size;
    height: $size;
    border-radius: 50%;
    display: block;
    position: relative;
    background: var(--loader-accent, $color);
    color: var(--loader-color, $accent);
    box-shadow: -24px 0, 24px 0;
    box-sizing: border-box;
    animation: rotation $duration ease-in-out infinite;
}

///
/// Expanding shadow dots loader.
///
/// @param {Length} $size [16px] - Dot size.
/// @param {Color} $color [#FFF] - Dot color.
/// @param {Time} $duration [2s] - Animation duration.
///
@mixin loader_bubble_expand(
    $size: 16px,
    $color: $loader-color,
    $duration: 2s
) {
    width: $size;
    height: $size;
    border-radius: 50%;
    display: block;
    position: relative;
    background: var(--loader-color, $color);
    box-sizing: border-box;
    animation: bubble-expand $duration linear infinite alternate;
}

///
/// Colliding dots loader.
///
/// @param {Length} $size [15px] - Dot size.
/// @param {Color} $color [#FFF] - Primary color.
/// @param {Color} $accent [#FF3D00] - Accent color.
/// @param {Time} $duration [1s] - Animation duration.
///
@mixin loader_bubble_collision(
    $size: 15px,
    $color: $loader-color,
    $accent: $loader-accent,
    $duration: 1s
) {
    position: relative;

    &::before,
    &::after {
        content: '';
        width: $size;
        height: $size;
        display: block;
        position: relative;
        margin: 10px auto;
        border-radius: 50%;
        background: var(--loader-color, $color);
        animation: bubble-collision-left $duration infinite ease-in-out;
    }

    &::after {
        background: var(--loader-accent, $accent);
        animation: bubble-collision-right $duration infinite ease-in-out;
    }
}

///
/// Two balls flip loader.
///
/// @param {Length} $size [48px] - Loader size.
/// @param {Color} $color [#FFF] - Primary color.
/// @param {Color} $accent [#FF3D00] - Accent color.
/// @param {Time} $duration [1s] - Animation duration.
///
@mixin loader_bubble_flip(
    $size: $loader-size,
    $color: $loader-color,
    $accent: $loader-accent,
    $duration: 1s
) {
    box-sizing: border-box;
    position: relative;
    width: var(--loader-size, $size);
    height: var(--loader-size, $size);
    animation: flip $duration linear infinite;

    &::after,
    &::before {
        content: '';
        width: calc(var(--loader-size, $size) / 2);
        height: calc(var(--loader-size, $size) / 2);
        position: absolute;
        border-radius: 50%;
        background: var(--loader-accent, $accent);
        animation: rotation $duration linear infinite;
        transform-origin: calc(var(--loader-size, $size) / 4) 100%;
    }

    &::before {
        transform-origin: 0 50%;
        background: var(--loader-color, $color);
    }
}

///
/// Rotation keyframes (shared).
///
@mixin keyframes_rotation {
    @keyframes rotation {
        0% { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
    }
}

///
/// Flip keyframes.
///
@mixin keyframes_flip {
    @keyframes flip {
        0%, 50% { transform: rotateY(0deg); }
        50%, 100% { transform: rotateY(180deg); }
    }
}
