.game-command-btn {
    /* Shared physical material for the primary battle commands.
       Placement remains surface-owned; finish is intentionally identical. */
    --game-command-rest-transform: translateY(0);
    --game-command-hover-transform: translateY(-2px);
    --game-command-active-transform: translateY(1px) scale(0.96);
    box-sizing: border-box;
    min-height: 48px;
    padding: 12px 25px;
    border: 2px solid rgba(238, 219, 241, 0.78);
    border-radius: 10px;
    background: linear-gradient(
        180deg,
        rgba(55, 29, 70, 0.94) 0%,
        rgba(28, 10, 39, 0.96) 100%
    );
    color: #f5e9f8;
    font-family: inherit;
    font-size: 18px;
    font-weight: 700;
    letter-spacing: 0.035em;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.65);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.14),
        0 5px 14px rgba(0, 0, 0, 0.48);
    transform: var(--game-command-rest-transform);
    transition:
        transform 160ms ease,
        border-color 160ms ease,
        background 160ms ease,
        box-shadow 160ms ease,
        opacity 160ms ease;
    cursor: pointer;
    outline: none;
    -webkit-tap-highlight-color: transparent;
}

/* `body:not(.action-intent-active)`: while an intent dialog owns the turn the
   commands are held (see `:disabled` below), and a held command must never
   light up. The pointer shield and the `inert` pass already stop hover from
   matching in practice — this makes it true in the cascade too, so the rule
   does not depend on which of those two happens to be doing the work. */
body:not(.action-intent-active) .game-command-btn:hover:not(:disabled) {
    border-color: rgba(255, 244, 255, 1);
    background: linear-gradient(
        180deg,
        rgba(76, 42, 92, 0.98) 0%,
        rgba(42, 17, 54, 0.98) 100%
    );
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.2),
        0 8px 18px rgba(0, 0, 0, 0.52);
    transform: var(--game-command-hover-transform);
}

body:not(.action-intent-active) .game-command-btn:active:not(:disabled) {
    background: linear-gradient(
        180deg,
        rgba(38, 17, 50, 0.98) 0%,
        rgba(24, 8, 34, 0.98) 100%
    );
    box-shadow:
        inset 0 2px 4px rgba(0, 0, 0, 0.35),
        0 2px 6px rgba(0, 0, 0, 0.4);
    transform: var(--game-command-active-transform);
}

.game-command-btn:focus-visible {
    outline: 3px solid #fff0a8;
    outline-offset: 3px;
    box-shadow:
        0 0 0 6px rgba(124, 90, 255, 0.5),
        inset 0 1px 0 rgba(255, 255, 255, 0.14);
}

/* HELD BY THE ACTION-INTENT DIALOG — same rule, not a second vocabulary.
   `endTurnBtn.disabled` does get set from the authoritative broadcast that
   follows `beginActionIntentRequest`, but that is a round trip away; the class
   lands the instant the dialog opens, so the command reads as unavailable
   from the first frame instead of a beat later. Sharing the declaration block
   with `:disabled` is the point — a held command and a disabled command are
   the same state to the player, and they cannot drift apart here. */
.game-command-btn:disabled,
body.action-intent-active .game-command-btn {
    border-color: rgba(238, 219, 241, 0.3);
    background: rgba(20, 14, 25, 0.82);
    color: rgba(238, 219, 241, 0.55);
    box-shadow: none;
    opacity: 0.62;
    transform: var(--game-command-rest-transform);
    cursor: not-allowed;
}

#end-turn-btn {
    --game-command-rest-transform: translateY(-50%);
    --game-command-hover-transform: translateY(-52%);
    --game-command-active-transform: translateY(-48%) scale(0.96);
}

.return-lobby-btn {
    --game-command-rest-transform: translateY(0);
    --game-command-hover-transform: translateY(-2px);
    --game-command-active-transform: translateY(1px) scale(0.96);
}

.opponent-reconnect-status {
    position: fixed;
    top: calc(env(safe-area-inset-top, 0px) + 12px);
    left: 50%;
    z-index: 9450;
    max-width: min(88vw, 460px);
    padding: 9px 18px;
    border: 1px solid rgba(255, 220, 151, 0.72);
    border-radius: 999px;
    background: rgba(20, 11, 31, 0.94);
    color: #fff1cb;
    font-weight: 700;
    text-align: center;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.48);
    transform: translateX(-50%);
    pointer-events: none;
}

body.game-suspended #game-view,
body.game-resuming #game-view {
    pointer-events: none;
}

@media (pointer: coarse) {
    .game-command-btn {
        background: rgb(42, 17, 54);
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .game-command-btn {
        transition: none;
    }

    .game-command-btn:hover:not(:disabled),
    .game-command-btn:active:not(:disabled) {
        transform: var(--game-command-rest-transform);
    }
}
