/* ── Button busy indicator ───────────────────────────────────────────────────────────────────
   A spinner on any control marked data-busy="1" while its work is in flight.

   Keyed off data-busy because this codebase ALREADY uses that attribute as its double-submit
   guard (cart.js Place Order / Pay / Confirm Address, address-flow.js Save, offers.js). Hooking
   the existing convention means those buttons get a spinner with no JavaScript change at all,
   and any future handler that follows the same convention is covered for free.

   NON-BLOCKING by design. Nothing here dims the page, covers it, or traps focus — only the
   pressed control changes. The rest of the page stays scrollable and interactive while a request
   is in flight, which matters most on the cart: a customer who tapped Place Order should still be
   able to read their order while it goes through.

   currentColor and 1em are the two choices that make this work everywhere without per-button
   rules: the spinner takes the button's own text colour (white on the red CTAs, dark on the
   ghost ones) and scales to its font-size, so it fits a 0.75rem APPLY chip and a full-width
   Place Order bar equally. */
@keyframes pt-busy-spin { to { transform: rotate(360deg); } }

/* :not(.is-busy) so the Proceed bar, which has its own arrow-to-spinner treatment in menu.css,
   does not end up with two spinners. */
button[data-busy="1"]:not(.is-busy)::after,
a[data-busy="1"]:not(.is-busy)::after {
    content: '';
    display: inline-block;
    box-sizing: border-box;
    width: 1em;
    height: 1em;
    margin-left: 8px;
    vertical-align: -0.15em;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    animation: pt-busy-spin 0.6s linear infinite;
}

/* progress, not wait: the pointer stays usable elsewhere on the page. */
button[data-busy="1"],
a[data-busy="1"] { cursor: progress; }

/* Most of these handlers also set .disabled, which the browser greys out. Lift the opacity back
   so the label and spinner stay legible — a busy button still needs to be readable. */
button[data-busy="1"]:disabled { opacity: 0.9; }

@media (prefers-reduced-motion: reduce) {
    button[data-busy="1"]:not(.is-busy)::after,
    a[data-busy="1"]:not(.is-busy)::after {
        animation: none;
        /* Static ring rather than a spinning one — still reads as "in progress". */
        border-top-color: currentColor;
        opacity: 0.55;
    }
}
