/* ══════════════════════════════════════════════════════════════════
   ACCESSIBILITY + BUSY-BUTTON STATE
   Loaded LAST so it wins over earlier resets.
   Adapted from Chronos wwwroot/css/chronos/19-a11y.css + 20-spinner.css
   (violet ring/spinner -> Hyperion magenta --color-primary).
   ══════════════════════════════════════════════════════════════════ */

/* ── Focus-visible ring — keyboard nav only, mouse clicks stay ring-free ── */

a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible,
[role="button"]:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
    border-radius: 3px;
}

/* ── Busy button state — one spinner for every in-flight .btn-app action ── */

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

.btn-app.is-loading {
    position: relative;
    pointer-events: none;
    color: transparent !important;
}

.btn-app.is-loading > * { visibility: hidden; }

.btn-app.is-loading::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 1.05em;
    height: 1.05em;
    margin: -0.525em 0 0 -0.525em;
    border: 2px solid var(--color-primary);
    border-top-color: transparent;
    border-radius: 50%;
    visibility: visible;
    animation: btn-app-spin 0.7s linear infinite;
}

/* White ring on the filled/gradient buttons — their label is white, but
   color:transparent above killed currentColor, so the ink is set explicitly. */
.btn-app--fill.is-loading::after,
.btn-app--danger.is-loading::after {
    border-color: #fff;
    border-top-color: transparent;
}

@media (prefers-reduced-motion: reduce) {
    .btn-app.is-loading::after { animation-duration: 1.6s; }
}
