/* ===========================================================================
   button.css
   ---------------------------------------------------------------------------
   One base class + modifiers. Replaces the eleven different button treatments
   found across the old pages (.button-soft, .ghost-link, .btn-primary,
   .action-btn, .pill-btn, inline-styled <button>, …).

   Structure:  .btn                      base
               .btn--primary|secondary|ghost|danger|buy|sell   intent
               .btn--sm|lg               size
               .btn--block               full width
               .btn--icon                square, icon only
               [data-loading]            busy state
   =========================================================================== */

.btn {
    /* inline-flex so an icon + label centre together and the element can sit
       inside a text line without baseline drift. */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--gap-inline);

    padding-block: var(--pad-control-y);
    padding-inline: var(--pad-control-x);
    min-height: var(--touch-target);

    border: 1px solid transparent;
    border-radius: var(--radius-md);

    font-family: inherit;
    font-size: var(--text-base);
    font-weight: var(--weight-semibold);
    line-height: 1.2;
    letter-spacing: var(--tracking-normal);
    text-align: center;
    white-space: nowrap;

    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;

    transition:
        background-color var(--duration-fast) var(--ease-out),
        border-color var(--duration-fast) var(--ease-out),
        color var(--duration-fast) var(--ease-out),
        transform var(--duration-instant) var(--ease-out);
}

/* A pressed button dips slightly — the only transform in the system, kept
   tiny so it reads as tactile rather than playful. */
.btn:active:not(:disabled) {
    transform: translateY(1px);
}

.btn:disabled,
.btn[aria-disabled="true"] {
    opacity: 0.45;
    cursor: not-allowed;
    transform: none;
}

/* ---------------------------------------------------------------------------
   Intents
   --------------------------------------------------------------------------- */

/* Primary — one per view. The action the page exists for. */
.btn--primary {
    background: var(--accent);
    color: var(--text-on-accent);
    border-color: var(--accent);
}

.btn--primary:hover:not(:disabled) {
    background: var(--accent-hover);
    border-color: var(--accent-hover);
}

.btn--primary:active:not(:disabled) {
    background: var(--accent-active);
}

/* Secondary — the common case: outlined, reads as available but not urgent. */
.btn--secondary {
    background: var(--surface-raised);
    color: var(--text);
    border-color: var(--border);
}

.btn--secondary:hover:not(:disabled) {
    background: var(--surface-hover);
    border-color: var(--border-strong);
}

/* Ghost — toolbar and table-row actions. No chrome until hovered. */
.btn--ghost {
    background: transparent;
    color: var(--text-secondary);
    border-color: transparent;
}

.btn--ghost:hover:not(:disabled) {
    background: var(--surface-hover);
    color: var(--text);
}

/* Danger — destructive and irreversible only (close position, reject, delete).
   Never used for "cancel" in a dialog: cancelling is not destructive. */
.btn--danger {
    background: var(--danger);
    /* Not #fff. Every other filled button takes --text-on-accent, which is
       near-black in the dark theme because the accent surfaces there are
       bright. --danger is a light rose in the dark theme, so white on it was
       2.75:1 — on the buttons that close a position and reject a withdrawal.
       Following the convention gives 6.91:1 and changes nothing in the light
       theme, where --text-on-accent is white already. */
    color: var(--text-on-accent);
    border-color: var(--danger);
}

.btn--danger:hover:not(:disabled) {
    background: var(--down-strong);
    border-color: var(--down-strong);
}

/* Quiet danger — destructive action that needs to stay visually calm inside
   a dense table row. */
.btn--danger-ghost {
    background: var(--danger-dim);
    color: var(--danger);
    border-color: transparent;
}

.btn--danger-ghost:hover:not(:disabled) {
    background: var(--danger);
    color: var(--text-on-accent);
}

/* -----------------------------------------------------------------------
   BUY / SELL — the two most consequential buttons in the product.

   They are deliberately NOT .btn--primary/.btn--danger: order side is a
   direction, not an intent, and must inherit the same --up/--down tokens as
   every price on the screen. If a colour-blind palette is ever introduced,
   these follow it automatically.

   They are also full-weight and larger by default: a mis-click here costs
   the user money, so the targets are generous and the labels unambiguous.
   ----------------------------------------------------------------------- */
.btn--buy {
    background: var(--up);
    color: #04160d;
    border-color: var(--up);
    font-weight: var(--weight-bold);
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
}

.btn--buy:hover:not(:disabled) {
    background: var(--up-strong);
    border-color: var(--up-strong);
}

.btn--sell {
    background: var(--down);
    color: #1c0407;
    border-color: var(--down);
    font-weight: var(--weight-bold);
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
}

.btn--sell:hover:not(:disabled) {
    background: var(--down-strong);
    border-color: var(--down-strong);
}

/* Unselected side in a buy/sell toggle: keeps the hue as a hint but stays
   clearly inactive so the armed side is never ambiguous. */
.btn--buy[aria-pressed="false"] {
    background: var(--up-dim);
    color: var(--up);
}

.btn--sell[aria-pressed="false"] {
    background: var(--down-dim);
    color: var(--down);
}

/* ---------------------------------------------------------------------------
   Sizes
   --------------------------------------------------------------------------- */
.btn--sm {
    padding-block: var(--space-2);
    padding-inline: var(--space-3);
    min-height: 32px;
    font-size: var(--text-xs);
    border-radius: var(--radius-sm);
}

.btn--lg {
    padding-block: var(--space-4);
    padding-inline: var(--space-6);
    min-height: 52px;
    font-size: var(--text-md);
    border-radius: var(--radius-lg);
}

.btn--block {
    display: flex;
    width: 100%;
}

/* The primary action of a long form, kept on screen. It sticks to the bottom
   of the viewport while its form is in view and stays inside that form, so it
   never floats over unrelated content. For a form long enough that its submit
   would otherwise sit below the fold. */
.btn--sticky {
    position: sticky;
    bottom: var(--space-4);
    z-index: var(--z-raised);
    box-shadow: var(--shadow-lg);
}

/* On a phone the bottom nav is fixed over the last 62px of the viewport; a
   sticky action at bottom: 16px sat underneath it (measured: 6px of a 53px
   button showing). It stops above the nav instead. */
@media (max-width: 768px) {
    .btn--sticky {
        bottom: calc(var(--bottom-nav-height, 62px) + env(safe-area-inset-bottom, 0px) + var(--space-3));
    }
}

/* A card clips its rounded corners with overflow: hidden, which also makes it
   a scroll container - and a sticky element sticks to its nearest scroll
   container, so inside a card the button above never moved. clip trims the
   same corners without becoming a scroll container. Only cards that hold a
   sticky action change; every other card keeps hidden. */
.card:has(.btn--sticky) {
    overflow: clip;
}

/* Disabled buttons fade with opacity, which on a button floating over a form
   let the field text behind show through its label. A sticky one stays solid
   and reads as disabled through muted colours instead. */
.btn--sticky:disabled,
.btn--sticky[aria-disabled="true"] {
    opacity: 1;
    background: var(--surface-raised);
    border-color: var(--border-subtle);
    color: var(--text-muted);
}

/* Icon-only. aria-label is mandatory — enforced by review, and the .sr-only
   fallback in ui.php renders a text label when none is supplied. */
.btn--icon {
    padding: 0;
    width: var(--touch-target);
    min-width: var(--touch-target);
    height: var(--touch-target);
}

.btn--icon.btn--sm {
    width: 32px;
    min-width: 32px;
    height: 32px;
}

/* ---------------------------------------------------------------------------
   Loading state.

   data-loading swaps the label for a spinner while preserving the button's
   measured width, so a submitting form does not reflow. aria-busy tells a
   screen reader the same thing.
   --------------------------------------------------------------------------- */
.btn[data-loading="true"] {
    color: transparent !important;
    pointer-events: none;
    position: relative;
}

.btn[data-loading="true"]::after {
    content: "";
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: 50%;
    width: 1em;
    height: 1em;
    margin-block-start: -0.5em;
    margin-inline-start: -0.5em;
    border: 2px solid currentColor;
    border-block-start-color: transparent;
    border-radius: 50%;
    /* The spinner needs a visible colour even though the label is
       transparent — borrow the text colour the button would have had. */
    color: var(--text);
    animation: btn-spin 600ms linear infinite;
}

.btn--primary[data-loading="true"]::after,
.btn--buy[data-loading="true"]::after,
.btn--sell[data-loading="true"]::after,
.btn--danger[data-loading="true"]::after {
    color: var(--text-on-accent);
}

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

/* ---------------------------------------------------------------------------
   Groups
   --------------------------------------------------------------------------- */

/* Segmented control — timeframe pickers (1m 5m 1H 1D), list filters. */
.btn-group {
    display: inline-flex;
    padding: var(--space-1);
    background: var(--surface-sunken);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    gap: var(--space-px);
}

.btn-group .btn {
    min-height: 30px;
    padding-block: var(--space-1);
    padding-inline: var(--space-3);
    font-size: var(--text-xs);
    font-weight: var(--weight-medium);
    border-radius: var(--radius-sm);
    background: transparent;
    border-color: transparent;
    color: var(--text-muted);
}

.btn-group .btn:hover:not(:disabled) {
    color: var(--text);
    background: var(--surface-hover);
}

.btn-group .btn[aria-pressed="true"],
.btn-group .btn.is-active {
    background: var(--accent-dim);
    color: var(--accent-text);
    font-weight: var(--weight-semibold);
}

/* Segments are 30px for dense desktop toolbars; on a touch screen they are
   the theme and language switches on the account page, too small to hit. */
@media (max-width: 768px) {
    .btn-group .btn {
        min-height: 40px;
    }
}

/* Action row — dialog footers, form submits. Wraps on narrow screens rather
   than overflowing, and reverses order so the primary action stays last in
   the DOM (correct for screen readers) while sitting at the inline end. */
.btn-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
}

/* A pair of actions inside a table cell, where the normal row gap would push
   the second button out of the column. */
.btn-row--tight {
    gap: var(--space-2);
    flex-wrap: nowrap;
}

.btn-row--end {
    justify-content: flex-end;
}

.btn-row--split {
    justify-content: space-between;
}

/* On phones a dialog's actions stack full width — thumbs, not cursors. */
@media (max-width: 480px) {
    .btn-row--stack-sm {
        flex-direction: column-reverse;
        align-items: stretch;
    }

    .btn-row--stack-sm .btn {
        width: 100%;
    }
}

/* Side-by-side buy/sell pair. Equal width so neither reads as the default. */
.btn-pair {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3);
}

/* ---------------------------------------------------------------------------
   Link-styled button. For "resend code" / "use a different method" — an
   action, not navigation, so it must be a <button> for keyboard semantics
   while looking like a link.
   --------------------------------------------------------------------------- */
.btn-link {
    display: inline;
    padding: 0;
    min-height: 0;
    background: none;
    border: 0;
    color: var(--accent-text);
    font: inherit;
    font-weight: var(--weight-medium);
    text-decoration: underline;
    text-underline-offset: 0.2em;
    cursor: pointer;
}

.btn-link:hover:not(:disabled) {
    color: var(--accent-hover);
}

.btn-link:disabled {
    color: var(--text-faint);
    text-decoration: none;
    cursor: not-allowed;
}
