:is(button, input).app-submit-button:disabled:not(.app-busy-button) {
    opacity: var(--app-submit-disabled-opacity, 0.55);
    box-shadow: none;
    cursor: progress;
}

.app-busy-button {
    --app-busy-spinner-size: 15px;
    --app-busy-spinner-gap: 8px;
    --app-busy-spinner-width: 2px;
    --app-busy-spinner-color: currentColor;
    --app-busy-spinner-delay: 140ms;
}

.app-busy-button__content {
    min-width: 0;
    max-width: 100%;
    display: inline-grid;
    align-items: center;
    justify-items: stretch;
}

.app-busy-button__idle,
.app-busy-button__pending {
    min-width: 0;
    grid-area: 1 / 1;
    display: inline-flex;
    align-items: center;
    justify-content: var(--app-busy-content-align, center);
    gap: var(--app-busy-spinner-gap);
    overflow-wrap: anywhere;
    white-space: normal;
}

.app-busy-button__pending {
    visibility: hidden;
}

.app-busy-button__pending::before {
    width: var(--app-busy-spinner-size);
    height: var(--app-busy-spinner-size);
    flex: 0 0 var(--app-busy-spinner-size);
    box-sizing: border-box;
    order: 1;
    margin-inline-start: var(--app-busy-spinner-margin, 0px);
    content: "";
    border: var(--app-busy-spinner-width) solid color-mix(in srgb, var(--app-busy-spinner-color) 25%, transparent);
    border-top-color: var(--app-busy-spinner-color);
    border-radius: 50%;
    opacity: 0;
}

.app-busy-button:is(.htmx-request, .is-busy, [aria-busy="true"]) .app-busy-button__pending::before {
    animation: app-busy-indicator-spin 680ms linear var(--app-busy-spinner-delay) infinite,
               app-busy-indicator-reveal 1ms linear var(--app-busy-spinner-delay) forwards;
}

.app-busy-button:is(.htmx-request, .is-busy, [aria-busy="true"]) {
    cursor: progress;
}

.app-busy-button:is(.htmx-request, .is-busy, [aria-busy="true"]) .app-busy-button__idle {
    visibility: hidden;
}

.app-busy-button:is(.htmx-request, .is-busy, [aria-busy="true"]) .app-busy-button__pending {
    visibility: visible;
}

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

@keyframes app-busy-indicator-reveal {
    to {
        opacity: 1;
    }
}

@media (prefers-reduced-motion: reduce) {
    .app-busy-button:is(.htmx-request, .is-busy, [aria-busy="true"]) .app-busy-button__pending::before {
        animation: app-busy-indicator-reveal 1ms linear var(--app-busy-spinner-delay) forwards;
    }
}
