/* =============================================================================
   Custom AJAX Add to Cart — Button Animation States

   Replaces WooCommerce's default off-centre spinning-gear (loading) and
   permanent checkmark (added) with a clean, centred CSS spinner that
   hides the button text while running, followed by a brief checkmark
   that auto-reverts to the original text (controlled by JS timeout).
   ============================================================================= */

/* --------------------------------------------------------------------------
   1. Kill WooCommerce's own ::after icon-font states entirely.
      WC injects a spinning gear (.loading) and a checkmark (.added) via
      ::after using its own WooCommerce icon font. We replace both.
   -------------------------------------------------------------------------- */
.woocommerce a.button.loading::after,
.woocommerce button.button.loading::after,
.woocommerce .button.loading::after,
.woocommerce a.button.added::after,
.woocommerce button.button.added::after,
.woocommerce .button.added::after,
.woocommerce a.button.failed::after,
.woocommerce button.button.failed::after,
.woocommerce .button.failed::after {
    content: none !important;
}

/* --------------------------------------------------------------------------
   2. During loading / just-added: hide all existing button content without
      changing the button's dimensions (no layout shift).

      - color: transparent  → hides text nodes and icon-font glyphs (<i> etc.)
      - > * visibility:hidden → hides SVG icons, image children, etc.
      - position: relative   → anchor point for the ::before pseudo-element
      - pointer-events: none → disables hover so theme :hover rules (e.g.
        `background: none`) cannot strip the button's background mid-spin
      - transition: none     → prevents a slow colour fade when hover drops off
   -------------------------------------------------------------------------- */
.add_to_cart_button.loading,
.add_to_cart_button.added,
.add_to_cart_button.failed,
.single_add_to_cart_button.loading,
.single_add_to_cart_button.added,
.single_add_to_cart_button.failed {
    color:          transparent !important;
    position:       relative;
    pointer-events: none;
    transition:     none !important;
}

/* Loading: dim the button to signal "working". Overrides WooCommerce's
   .button.loading { opacity: .25 } which is too aggressive. */
.add_to_cart_button.loading,
.single_add_to_cart_button.loading {
    opacity: 0.65 !important;
}

/* Added (checkmark) / Failed (✕): back to full opacity for a clean result state. */
.add_to_cart_button.added,
.add_to_cart_button.failed,
.single_add_to_cart_button.added,
.single_add_to_cart_button.failed {
    opacity: 1 !important;
}

.add_to_cart_button.loading    > *,
.add_to_cart_button.added      > *,
.add_to_cart_button.failed     > *,
.single_add_to_cart_button.loading > *,
.single_add_to_cart_button.added   > *,
.single_add_to_cart_button.failed  > * {
    visibility: hidden; /* preserves child element space, hides visually */
}

/* --------------------------------------------------------------------------
   3. Loading state — centred spinning ring.

      Uses ::before so it naturally overrides any cart-icon that a theme
      may already be injecting via ::before on the button in its normal state.
      The spinner colour defaults to white; override --caac-color on your
      button selector if the button has a light background.
   -------------------------------------------------------------------------- */
.add_to_cart_button.loading::before,
.single_add_to_cart_button.loading::before {
    --caac-color: #fff;

    content:      '';
    box-sizing:   border-box;
    position:     absolute;
    /* Center via inset + auto margins — resolved once at layout time, so
       nothing positional is recalculated each animation frame. Only the
       rotate() is handed to the GPU compositor, which is perfectly stable. */
    top:          0;
    right:        0;
    bottom:       0;
    left:         0;
    margin:       auto;
    /* Fixed even-pixel size so transform-origin: 50% 50% always lands on a
       whole pixel — eliminates wobble caused by odd em-to-px rounding. */
    width:        20px;
    height:       20px;
    border-radius:    50%;
    border:           2px solid rgba(255, 255, 255, 0.3);
    border-top-color: var(--caac-color);
    will-change:      transform;
    animation:        caac-spin 0.65s linear infinite;
}

@keyframes caac-spin {
    to { transform: rotate(360deg); }
}

/* --------------------------------------------------------------------------
   4. Added state — centred CSS-drawn checkmark, pops in, removed by JS after 2 s.

      Draws a ✓ using border-right + border-bottom on an empty box and
      rotating it 45°. Much crisper than a Unicode character at any size.
   -------------------------------------------------------------------------- */
.add_to_cart_button.added::before,
.single_add_to_cart_button.added::before {
    --caac-color: #fff;

    content:        '';
    box-sizing:     border-box;
    position:       absolute;
    top:            50%;
    left:           50%;
    width:          0.5em;
    height:         1em;
    border-right:   0.15em solid var(--caac-color);
    border-bottom:  0.15em solid var(--caac-color);
    /* translate(-50%, -62%) nudges the visual centre of the rotated shape. */
    transform:      translate(-50%, -62%) rotate(45deg);
    animation:      caac-pop-in 0.22s ease-out both;
}

/* The pop-in keyframe must carry the full transform so it isn't reset */
@keyframes caac-pop-in {
    from { transform: translate(-50%, -62%) rotate(45deg) scale(0.3); opacity: 0; }
    to   { transform: translate(-50%, -62%) rotate(45deg) scale(1);   opacity: 1; }
}

/* --------------------------------------------------------------------------
   5. Failed state — centred ✕ + button shake.

      Draws the ✕ with a single ::before using two crossed linear-gradients,
      matching the single-pseudo approach of the checkmark. No ::after needed.
      A subtle horizontal shake on the button itself communicates "error".
      Removed by JS after 2 s, same as the checkmark.
   -------------------------------------------------------------------------- */
.add_to_cart_button.failed,
.single_add_to_cart_button.failed {
    animation: caac-shake 0.4s ease-out;
}

.add_to_cart_button.failed::before,
.single_add_to_cart_button.failed::before {
    --caac-color: #fff;

    content:    '' !important;   /* must beat theme cart-icon ::before */
    box-sizing: border-box;
    position:   absolute;
    top:        50%;
    left:       50%;
    width:      14px;
    height:     14px;
    transform:  translate(-50%, -50%);
    background:
        linear-gradient(  45deg, transparent 0%, transparent 43%, var(--caac-color) 43%, var(--caac-color) 57%, transparent 57% ),
        linear-gradient( -45deg, transparent 0%, transparent 43%, var(--caac-color) 43%, var(--caac-color) 57%, transparent 57% );
    animation:  caac-x-in 0.2s ease-out both;
}

@keyframes caac-x-in {
    from { transform: translate(-50%, -50%) scale(0.3); opacity: 0; }
    to   { transform: translate(-50%, -50%) scale(1);   opacity: 1; }
}

@keyframes caac-shake {
    0%, 100% { transform: translateX(0); }
    15%      { transform: translateX(-4px); }
    30%      { transform: translateX(4px); }
    45%      { transform: translateX(-3px); }
    60%      { transform: translateX(3px); }
    75%      { transform: translateX(-1px); }
    90%      { transform: translateX(1px); }
}

