/* ============================================================
 | SyncBridge POS — Global submit/click loader
 |   • Thin top progress bar that auto-advances and snaps to 100%
 |   • Inline spinner on the clicked button (so the user sees it
 |     belongs to that exact action) + button is disabled
 |   • Auto-cancels if the form fails HTML5 validation
 |   • Auto-hides after a 15s safety timeout — never gets "stuck"
 ============================================================ */
#sb-progress {
    position: fixed;
    top: 0;
    left: 0;
    height: 3px;
    width: 0;
    background: linear-gradient(90deg, #2563eb, #06b6d4, #2563eb);
    background-size: 200% 100%;
    box-shadow: 0 0 8px rgba(37, 99, 235, .5);
    z-index: 999999;
    pointer-events: none;
    opacity: 0;
    transition: width 0s, opacity .2s;
}
#sb-progress.sb-active {
    opacity: 1;
    width: 80%;
    transition: width 8s cubic-bezier(0, 0.5, 0.2, 1), opacity .2s;
    animation: sb-shimmer 1.2s linear infinite;
}
#sb-progress.sb-done {
    opacity: 0;
    width: 100%;
    transition: width .25s ease-out, opacity .3s ease-out .1s;
}
@keyframes sb-shimmer {
    0%   { background-position: 0 0; }
    100% { background-position: -200% 0; }
}

/* Button spinner */
.sb-btn-loading {
    pointer-events: none;
    opacity: .85;
    position: relative;
}
.sb-btn-loading::after {
    content: '';
    display: inline-block;
    width: 14px;
    height: 14px;
    margin-left: 8px;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    vertical-align: -3px;
    animation: sb-spin .65s linear infinite;
}
@keyframes sb-spin { to { transform: rotate(360deg); } }
