/* ========== BUY CRYPTO PAGE ========== */

.buy-main {
  padding: 28px 40px 80px;
}

/* Page Header */
.buy-page-header {
  margin-bottom: 28px;
}

.buy-breadcrumb {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  margin-bottom: 10px;
}

.buy-breadcrumb a {
  color: #5a5a6a;
  text-decoration: none;
  transition: color 0.15s;
}

.buy-breadcrumb a:hover {
  color: var(--app-primary);
}

.buy-breadcrumb svg {
  color: #3a3a4a;
}

.buy-breadcrumb span {
  color: var(--app-text-muted-2);
}

.buy-page-title {
  font-family: 'Inter', -apple-system, sans-serif;
  font-size: 26px;
  font-weight: 700;
  color: var(--app-text-1);
  margin: 0 0 6px;
}

.buy-page-sub {
  font-size: 14px;
  color: #6a6a7a;
  margin: 0;
}

/* Layout */
.buy-layout {
  display: grid;
  grid-template-columns: 1fr 390px;
  gap: 20px;
  align-items: start;
}

/* Card Base */
.buy-card {
  background: var(--app-surface-1);
  border: 1px solid rgba(var(--app-content-overlay-rgb),0.06);
  border-radius: 12px;
  padding: 20px;
}

.buy-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
}

.buy-card-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--app-text-1);
}

/* Search */
.buy-search-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
  background: rgba(var(--app-content-overlay-rgb),0.04);
  border: 1px solid rgba(var(--app-content-overlay-rgb),0.08);
  border-radius: 8px;
  padding: 6px 12px;
  transition: border-color 0.15s;
}

.buy-search-wrap:focus-within {
  border-color: rgba(92, 184, 230, 0.3);
}

.buy-search-wrap svg {
  color: #4a4a5a;
  flex-shrink: 0;
}

.buy-search {
  background: rgba(var(--app-content-overlay-rgb),0.04);
  border: 1px solid rgba(var(--app-content-overlay-rgb),0.08);
  border-radius: 8px;
  color: var(--app-text-1);
  font-size: 13px;
  font-family: inherit;
  outline: none;
  width: 140px;
  padding: 6px 10px;
  transition: border-color 0.15s;
}

.buy-search:focus {
  border-color: rgba(92, 184, 230, 0.3);
}

.buy-search::placeholder {
  color: #4a4a5a;
}

/* Quick Pills */
.buy-quick-pills {
  display: flex;
  gap: 6px;
  margin-bottom: 14px;
  flex-wrap: wrap;
}

.quick-pill {
  padding: 6px 16px;
  background: rgba(var(--app-content-overlay-rgb),0.03);
  border: 1px solid rgba(var(--app-content-overlay-rgb),0.06);
  border-radius: 20px;
  color: var(--app-text-muted-2);
  font-size: 12px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: all 0.15s;
}

.quick-pill:hover {
  color: var(--app-text-1);
  border-color: rgba(var(--app-content-overlay-rgb),0.12);
}

.quick-pill.active {
  color: var(--app-primary);
  border-color: rgba(92, 184, 230, 0.3);
  background: rgba(92, 184, 230, 0.08);
}

/* Asset List */
.buy-asset-list {
  max-height: 520px;
  overflow-y: auto;
}

.buy-asset-list::-webkit-scrollbar {
  width: 4px;
}

.buy-asset-list::-webkit-scrollbar-thumb {
  background: rgba(92, 184, 230, 0.3);
  border-radius: 2px;
}
.buy-asset-list::-webkit-scrollbar-thumb:hover {
  background: rgba(92, 184, 230, 0.5);
}

.buy-asset-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 14px 16px;
  border-radius: 10px;
  cursor: pointer;
  transition: all 0.15s;
  border: 1px solid transparent;
  /* Codex review R1 (Medium, a11y): rows are real <button> elements now (were
     non-focusable <div onclick>, unreachable by keyboard) — reset the UA
     button chrome so the look is byte-identical to before. */
  background: none;
  appearance: none;
  -webkit-appearance: none;
  font: inherit;
  color: inherit;
  text-align: left;
}

.buy-asset-row:hover {
  background: rgba(var(--app-content-overlay-rgb),0.03);
}

.buy-asset-row.selected {
  background: rgba(92, 184, 230, 0.06);
  border-color: rgba(92, 184, 230, 0.15);
}

.buy-asset-row:focus-visible,
.qt-swap-icon:focus-visible,
.buy-sell-tab:focus-visible {
  outline: 2px solid var(--app-primary);
  outline-offset: 2px;
}

.buy-asset-left {
  display: flex;
  align-items: center;
  gap: 12px;
  /* A flex item will not shrink below its content width without this, which on
     a 360px phone pushes the eight-decimal holding off the row. The name and
     ticker ellipsise instead — see `.buy-asset-name`. */
  min-width: 0;
}

/* The text column inside it needs the same release, or the ellipsis below
   never engages. */
.buy-asset-left > div {
  min-width: 0;
}

.buy-asset-icon {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-weight: 700;
  color: var(--app-text-white);
  flex-shrink: 0;
}

.buy-asset-icon.btc { background: linear-gradient(135deg, #f7931a, #e8840f); }
.buy-asset-icon.eth { background: linear-gradient(135deg, #627eea, #5470d6); }
.buy-asset-icon.sol { background: linear-gradient(135deg, #9945ff, #14f195); color: var(--app-text-white); }
.buy-asset-icon.xrp { background: linear-gradient(135deg, #23292f, #3a4148); }
.buy-asset-icon.bnb { background: linear-gradient(135deg, #f3ba2f, #e0a820); }
.buy-asset-icon.doge { background: linear-gradient(135deg, #c3a634, #b89a20); }
.buy-asset-icon.ada { background: linear-gradient(135deg, #0033ad, #0044cc); }
.buy-asset-icon.avax { background: linear-gradient(135deg, #e84142, #d63637); }
.buy-asset-icon.link { background: linear-gradient(135deg, #2a5ada, #1e4fc4); }
.buy-asset-icon.dot { background: linear-gradient(135deg, #e6007a, #cc006b); }

/* "Bitcoin Cash" next to "0.00000000 BCH" on a narrow phone is more than the
   row has room for. The name is the half that can be abbreviated without
   losing information the customer cannot get elsewhere — the ticker is right
   underneath it, and the number must stay exact. */
.buy-asset-name {
  font-size: 14px;
  font-weight: 600;
  color: var(--app-text-1);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.buy-asset-ticker {
  font-size: 12px;
  color: #6a6a7a;
  margin-top: 1px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* One line now, not a two-line stack: the market price and the 24h change are
   both gone from every row (manager 2026-09-16 — "The rate is never shown
   anywhere"), so all this holds is a tradable row's holding line or a pointer
   row's destination. `.buy-asset-price` and `.buy-asset-change` went with them. */
.buy-asset-right {
  text-align: right;
  /* The quantity is the one thing on the row that may not be squeezed or
     wrapped mid-number — the asset NAME gives way instead (see below). */
  flex-shrink: 0;
}

/* The customer's own holding, quantity only, at eight decimals on every row
   (manager 2026-09-17). It carried these declarations as an inline `style`
   attribute while it was built by string concatenation in the renderer; it is a
   class now because eight decimals on every row — including 0.00000000 — makes
   it the widest thing on the right-hand side, and it needs real rules:

     `white-space: nowrap` so "0.00000000 BTC" can never break across lines.
     `tabular-nums` so the decimal points line up down the column, which is the
     whole reason for a fixed number of places.

   Together with `.buy-asset-left { min-width: 0 }` below, a narrow phone
   truncates a long asset name and keeps the number whole, rather than the
   other way round. */
.buy-asset-holding {
  font-size: 11px;
  color: var(--app-primary);
  text-align: right;
  margin-top: 2px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* The "Trade on Spot →" pointer. Inherited `.buy-asset-change`'s box before its
   own rules were deleted; it is its own class now because it never had anything
   to do with a percentage change. */
.buy-asset-elsewhere {
  font-size: 11px;
  font-weight: 500;
  margin-top: 1px;
  color: var(--app-primary);
  white-space: nowrap;
}

/* ========== PURCHASE PANEL ========== */
.buy-form-card {
  position: sticky;
  top: 80px;
}

/* Selected Asset Header */
.buy-selected-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* The right-hand side is now a three-line price block rather than a small
     percentage pill, so it is allowed to drop under the asset name on a narrow
     panel instead of squeezing the name. */
  flex-wrap: wrap;
  gap: 10px;
  padding-bottom: 20px;
  border-bottom: 1px solid rgba(var(--app-content-overlay-rgb),0.06);
  margin-bottom: 20px;
}

.buy-selected-info {
  display: flex;
  align-items: center;
  gap: 12px;
}

.buy-selected-name {
  font-size: 16px;
  font-weight: 700;
  color: var(--app-text-1);
}

/* THE PRICE, in the header, per tab (manager 2026-09-16).
   Replaces both the old `.buy-selected-price` (the Bitget mid, removed
   2026-09-10) and `.buy-selected-change` (the 24h percentage, removed now). It
   is DELIBERATELY built out of var(--app-*) tokens alone: the two it replaced
   each carried a fixed green/red hue and therefore each needed an Ultimo
   override at the bottom of this file to stay legible on a light surface. A
   price is neither up nor down, so this one resolves correctly on both brands
   with no override at all — and those overrides are gone with the classes. */
.buy-selected-price {
  text-align: right;
  min-width: 0;
}

.buy-selected-price-label {
  font-size: 11px;
  font-weight: 500;
  color: var(--app-text-muted-3);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}

.buy-selected-price-value {
  font-size: 14px;
  font-weight: 700;
  color: var(--app-text-1);
  font-variant-numeric: tabular-nums;
  margin-top: 2px;
  white-space: nowrap;
}

.buy-selected-price-note {
  /* Readable, not a footnote (Quy 2026-10-05): the note tells the customer the price is a
     reference and locks on the next screen, so it uses the body text colour at 12px. */
  font-size: 12px;
  font-weight: 500;
  color: var(--app-text-1);
  margin-top: 4px;
  line-height: 1.4;
  /* Reserve two lines (manager, 2026-10-06): the caption wraps to two lines on
     most widths, so the block keeps that height while loading, on error and on
     refresh, and nothing below it moves. */
  min-height: 2.8em;
}

/* Input Fields */
.buy-field {
  margin-bottom: 4px;
}

.buy-field-label {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 12px;
  font-weight: 500;
  color: #6a6a7a;
  margin-bottom: 8px;
}

.buy-field-balance {
  color: #5a5a6a;
  font-variant-numeric: tabular-nums;
}

.buy-field-hint {
  color: #4a4a5a;
  font-style: italic;
}

.buy-input-row {
  display: flex;
  align-items: center;
  background: rgba(var(--app-content-overlay-rgb),0.04);
  border: 1px solid rgba(var(--app-content-overlay-rgb),0.08);
  border-radius: 10px;
  transition: border-color 0.15s;
}

.buy-input-row:focus-within {
  border-color: rgba(92, 184, 230, 0.3);
}

.buy-amount-input {
  flex: 1;
  min-width: 0;
  background: none;
  border: none;
  color: var(--app-text-1);
  font-size: 20px;
  font-weight: 700;
  padding: 16px 16px;
  outline: none;
  font-variant-numeric: tabular-nums;
  font-family: inherit;
}

.buy-amount-input.receive {
  color: var(--app-primary);
}

.buy-amount-input::placeholder {
  color: #3a3a4a;
}

.buy-currency-badge {
  padding: 8px 14px;
  margin-right: 8px;
  background: rgba(var(--app-content-overlay-rgb),0.06);
  border-radius: 8px;
  font-size: 13px;
  font-weight: 700;
  color: var(--app-text-muted-2);
  letter-spacing: 0.5px;
  white-space: nowrap;
  flex-shrink: 0;
}

.buy-currency-badge.crypto {
  color: var(--app-primary);
  background: rgba(92, 184, 230, 0.1);
}

/* Quick Amounts */
.buy-quick-amounts {
  display: flex;
  gap: 6px;
  margin-top: 8px;
}

.buy-quick-amt {
  flex: 1;
  padding: 7px 0;
  background: rgba(var(--app-content-overlay-rgb),0.03);
  border: 1px solid rgba(var(--app-content-overlay-rgb),0.06);
  border-radius: 6px;
  color: #6a6a7a;
  font-size: 12px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: all 0.15s;
}

.buy-quick-amt:hover {
  color: var(--app-text-1);
  border-color: rgba(var(--app-content-overlay-rgb),0.12);
}

.buy-quick-amt.active {
  color: var(--app-primary);
  border-color: rgba(92, 184, 230, 0.3);
  background: rgba(92, 184, 230, 0.06);
}

/* Swap Divider */
.buy-swap-divider {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px 0;
}

.buy-swap-icon {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(var(--app-content-overlay-rgb),0.04);
  border: 1px solid rgba(var(--app-content-overlay-rgb),0.08);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #6a6a7a;
}

/* ========== PAYMENT METHOD ========== */
.buy-payment-section {
  margin-top: 20px;
  margin-bottom: 20px;
}

.buy-payment-options {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.buy-payment-option {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  background: rgba(var(--app-content-overlay-rgb),0.02);
  border: 1px solid rgba(var(--app-content-overlay-rgb),0.06);
  border-radius: 10px;
  cursor: pointer;
  transition: all 0.15s;
}

.buy-payment-option:hover {
  background: rgba(var(--app-content-overlay-rgb),0.04);
}

.buy-payment-option.selected {
  background: rgba(92, 184, 230, 0.04);
  border-color: rgba(92, 184, 230, 0.2);
}

.buy-payment-option input[type="radio"] {
  display: none;
}

.payment-radio {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 2px solid rgba(var(--app-content-overlay-rgb),0.15);
  flex-shrink: 0;
  position: relative;
  transition: all 0.15s;
}

.buy-payment-option.selected .payment-radio {
  border-color: var(--app-primary);
}

.buy-payment-option.selected .payment-radio::after {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  right: 3px;
  bottom: 3px;
  border-radius: 50%;
  background: var(--app-primary);
}

.payment-icon {
  width: 36px;
  height: 36px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.payment-icon.wallet {
  background: rgba(92, 184, 230, 0.1);
  color: var(--app-primary);
}

.payment-icon.stable {
  background: rgba(78, 203, 113, 0.1);
  color: #4ecb71;
}

.payment-icon.card {
  background: rgba(168, 168, 184, 0.1);
  color: var(--app-text-muted-3);
}

.payment-info {
  flex: 1;
}

.payment-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--app-text-1);
}

.payment-detail {
  font-size: 11px;
  color: #5a5a6a;
  margin-top: 2px;
}

.payment-fee {
  font-size: 11px;
  font-weight: 600;
  color: var(--app-text-muted-2);
  background: rgba(var(--app-content-overlay-rgb),0.04);
  padding: 3px 10px;
  border-radius: 4px;
  white-space: nowrap;
}

/* ========== ORDER SUMMARY ========== */
.buy-summary {
  padding: 16px 0;
  border-top: 1px solid rgba(var(--app-content-overlay-rgb),0.06);
  border-bottom: 1px solid rgba(var(--app-content-overlay-rgb),0.06);
  margin-bottom: 20px;
}

.buy-summary-row {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  color: #6a6a7a;
  padding: 5px 0;
}

.buy-summary-row span:last-child {
  color: var(--app-text-muted-3);
  font-variant-numeric: tabular-nums;
}

.buy-summary-row.total {
  color: var(--app-text-1);
  font-weight: 700;
  font-size: 14px;
  padding-top: 10px;
  margin-top: 6px;
  border-top: 1px solid rgba(var(--app-content-overlay-rgb),0.04);
}

.buy-summary-row.total span:last-child {
  color: var(--app-text-1);
}

/* ========== BUY BUTTON ========== */
/* v7: Vestex trading color scheme — Buy = blue (var(--app-primary)), Sell = amber (var(--app-sell)). Green/red prohibited.
   v8 (Quy 2026-08-25): for THIS converter's own tab-toggle + submit CTA only, Buy and Sell
   now share the same brand-primary color instead — Ultimo's --app-primary (#f5b50a gold)
   visually collided with the platform's fixed --app-sell (#e0a050 amber), making the two
   modes hard to tell apart at a glance. Spec has no color-differentiation requirement here;
   mode is already conveyed by the "Buy"/"Sell" text label. The long/short amber convention
   used elsewhere (Futures, order books, PnL) is untouched — this comment covers only the
   rules below it in this file. */
.buy-submit-btn {
  width: 100%;
  padding: 16px;
  border: none;
  border-radius: 10px;
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
  transition: all 0.2s;
  letter-spacing: 0.3px;
  font-family: inherit;
  background: linear-gradient(135deg, var(--app-primary), #4aa6d6);
  color: var(--app-text-white);
}

.buy-submit-btn:hover {
  background: linear-gradient(135deg, #6ec5ef, var(--app-primary));
  box-shadow: 0 4px 24px rgba(92, 184, 230, 0.3);
  transform: translateY(-1px);
}

.buy-submit-btn:active {
  transform: translateY(0);
}

.buy-disclaimer {
  font-size: 11px;
  color: #4a4a5a;
  text-align: center;
  margin-top: 14px;
  line-height: 1.5;
}

/* ========== RESPONSIVE ========== */
@media (max-width: 1024px) {
  .buy-main {
    padding: 24px 20px 60px;
  }
  .buy-layout {
    grid-template-columns: 1fr;
  }
  .buy-form-card {
    position: static;
  }
}

@media (max-width: 600px) {
  .buy-main {
    padding: 20px 16px 60px;
  }
  .buy-page-title {
    font-size: 22px;
  }
  .buy-amount-input {
    font-size: 18px;
    padding: 14px 14px;
  }
  .buy-quick-amounts {
    flex-wrap: wrap;
  }
  .buy-quick-amt {
    flex: 0 0 calc(33.33% - 4px);
  }
}

/* ========== BUY/SELL TABS ========== */
.buy-sell-tabs {
  display: flex;
  gap: 0;
  margin-bottom: 20px;
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid rgba(var(--app-content-overlay-rgb),0.1);
}
.buy-sell-tab {
  flex: 1;
  padding: 12px;
  background: var(--app-surface-card);
  color: var(--app-text-muted-2);
  border: none;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  transition: background 0.15s, color 0.15s;
}
.buy-sell-tab.active {
  background: var(--app-primary);
  color: var(--app-primary-fg);
}
/* No #sellTab.active override (Quy 2026-08-25 ruling — see v8 note above):
   #sellTab always also carries .buy-sell-tab, so it inherits the rule above
   as-is — guaranteeing permanent parity with Buy-active via the cascade
   instead of duplicating the literal values (Codex review round 1 finding). */

/* ==========================================================================
   UNIFIED FROM/TO CONVERTER (Quick Trade v2 UI restructure, 2026-08-24)
   Both Buy and Sell render into these same .qt-* elements — see
   docs/handoffs/QUY-QUICK-TRADE-HANBAIJO-2026-08-20.md §3. Buy: FROM=USDT,
   TO=asset. Sell: FROM=asset, TO=USDT. Built on the existing .buy-input-row /
   .buy-currency-badge visual language so both directions share one design,
   not two.
   ========================================================================== */
.qt-field {
  margin-bottom: 4px;
}
.qt-field-label {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 12px;
  font-weight: 500;
  color: var(--app-text-muted-2);
  margin-bottom: 8px;
}
.qt-field-balance {
  color: var(--app-text-muted-3);
  font-variant-numeric: tabular-nums;
}
.qt-field-hint {
  color: var(--app-text-muted-2);
  font-style: italic;
}
.qt-input-row {
  display: flex;
  align-items: center;
  background: rgba(var(--app-content-overlay-rgb),0.04);
  border: 1px solid rgba(var(--app-content-overlay-rgb),0.08);
  border-radius: 10px;
  transition: border-color 0.15s;
}
.qt-input-row:focus-within {
  border-color: rgba(92, 184, 230, 0.3);
}
.qt-amount-input {
  flex: 1;
  min-width: 0;
  background: none;
  border: none;
  color: var(--app-text-1);
  font-size: 20px;
  font-weight: 700;
  padding: 16px;
  outline: none;
  font-variant-numeric: tabular-nums;
  font-family: inherit;
}
.qt-amount-input.receive {
  color: var(--app-primary);
}
/* Waiting on the server's price. The browser never computes a receive amount
   (see buy-crypto-v2.html's MIN_GATE_ASSUMED_FEE_RATE comment), so between a
   keystroke and the preview response there is genuinely no number to show —
   this dims whatever is there rather than inventing one. Opacity only: on the
   silent 30s redisplay the previous real amount stays readable. */
.qt-amount-input.is-pending {
  opacity: 0.45;
}
.qt-amount-input::placeholder {
  color: var(--app-text-muted-3);
}
.qt-currency-badge {
  padding: 8px 14px;
  margin-right: 8px;
  background: rgba(var(--app-content-overlay-rgb),0.06);
  border-radius: 8px;
  font-size: 13px;
  font-weight: 700;
  color: var(--app-text-muted-2);
  letter-spacing: 0.5px;
  white-space: nowrap;
  flex-shrink: 0;
}
.qt-currency-badge.crypto {
  color: var(--app-primary);
  background: rgba(92, 184, 230, 0.1);
}
.qt-quick-amounts {
  display: flex;
  gap: 6px;
  margin-top: 8px;
}
.qt-quick-amounts .buy-quick-amt { flex: 1; }

.qt-swap-divider {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px 0;
}
.qt-swap-icon {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(var(--app-content-overlay-rgb),0.04);
  border: 1px solid rgba(var(--app-content-overlay-rgb),0.08);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--app-text-muted-2);
  cursor: pointer;
  padding: 0;
  transition: all 0.15s;
}
.qt-swap-icon:hover {
  color: var(--app-primary);
  border-color: rgba(92, 184, 230, 0.3);
  transform: rotate(180deg);
}

/* The `.qt-reference-price` / `.qt-reference-label` / `.qt-reference-value` /
   `.qt-reference-note` rules that stood here are GONE with the "Rate / All fees
   included" row they styled (manager 2026-09-16 — the price moved to the
   selected-asset header, where it is on screen before an amount is typed).

   That row also carried the `border-top` that separated the form from the CTA.
   `.qt-cap-note--spaced` below carries it now, so the panel keeps its division
   rather than collapsing the amount fields straight onto the button. */
.qt-cap-note {
  font-size: 11px;
  color: var(--app-text-muted-3);
  text-align: center;
  margin-bottom: 12px;
  transition: color 0.15s;
}
.qt-cap-note--spaced {
  border-top: 1px solid rgba(var(--app-content-overlay-rgb),0.06);
  margin-top: 18px;
  padding-top: 14px;
}
.qt-cap-note--exceeded {
  color: var(--app-sell);
  font-weight: 600;
}

/* Shared CTA — SAME visual weight for Buy and Sell (fixes the earlier
   "muted/disabled-looking" Sell button: no default opacity, no baked-in
   inline styles — :disabled alone controls the muted state). */
.qt-submit-btn {
  width: 100%;
  padding: 16px;
  border: none;
  border-radius: 10px;
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
  transition: all 0.2s;
  letter-spacing: 0.3px;
  font-family: inherit;
  background: linear-gradient(135deg, var(--app-primary), var(--app-primary-grad-end, var(--app-primary)));
  color: var(--app-primary-fg);
}
/* JS still toggles the qt-submit-btn--sell class in switchMode() (buy-crypto-v2.html),
   but it no longer carries its own styling (Quy 2026-08-25 ruling — see v8 note above):
   the element always also has the base .qt-submit-btn class, so removing the
   per-variant rule below guarantees permanent parity with Buy via the cascade
   instead of duplicating .qt-submit-btn's literal values (Codex review round 1
   finding — same reasoning as the removed #sellTab.active rule above). */
.qt-submit-btn:hover:not(:disabled) {
  box-shadow: 0 4px 24px rgba(92, 184, 230, 0.3);
  transform: translateY(-1px);
}
.qt-submit-btn:active:not(:disabled) {
  transform: translateY(0);
}
.qt-submit-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

/* ========== RECENT ORDERS (history) ========== */
/* Full width, below both columns — NOT inside the sticky 390px order panel,
   where it sat under the whole form and was never seen. */
.qt-history-card {
  margin-top: 20px;
  width: 100%;
  /* revealRecentOrders() scrolls this to the top of the viewport; leave room for
     the fixed header so its own title is not tucked underneath. */
  scroll-margin-top: 80px;
}
.qt-history-empty {
  padding: 24px;
  text-align: center;
  color: var(--app-text-muted-3);
  font-size: 13px;
}
.qt-history-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  min-width: 480px;
}
.qt-history-table th {
  text-align: left;
  font-weight: 600;
  color: var(--app-text-muted-2);
  padding: 8px 12px;
  border-bottom: 1px solid rgba(var(--app-content-overlay-rgb),0.08);
  white-space: nowrap;
}
.qt-history-table td {
  padding: 10px 12px;
  color: var(--app-text-1);
  border-bottom: 1px solid rgba(var(--app-content-overlay-rgb),0.04);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.qt-status-badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 600;
  color: var(--app-text-muted-2);
  background: rgba(var(--app-content-overlay-rgb),0.06);
}
.qt-status-badge.is-filled {
  color: #4ecb71;
  background: rgba(78, 203, 113, 0.1);
}
.qt-status-badge.is-confirming {
  color: var(--app-primary);
  background: rgba(92, 184, 230, 0.1);
}
.qt-status-badge.is-failed {
  color: #e65c5c;
  background: rgba(230, 92, 92, 0.1);
}

/* ========== CONFIRM MODALS (shared overlay/box chrome) ========== */
.buy-confirm-overlay {
  display: none;
  position: fixed;
  top: 0; left: 0; width: 100%; height: 100%;
  background: rgba(0,0,0,0.7);
  z-index: var(--z-modal, 1200);
  align-items: center;
  justify-content: center;
}
.buy-confirm-overlay.show { display: flex; }
.buy-confirm-box {
  background: var(--app-surface-1);
  border: 1px solid rgba(var(--app-content-overlay-rgb),0.1);
  border-radius: 12px;
  padding: 28px;
  max-width: 420px;
  width: 90%;
  position: relative;
}
.buy-confirm-actions {
  display: flex;
  gap: 12px;
}
.buy-confirm-cancel {
  flex: 1;
  padding: 12px;
  border-radius: 8px;
  border: 1px solid rgba(var(--app-content-overlay-rgb),0.15);
  background: transparent;
  color: var(--app-text-muted-2);
  font-size: 14px;
  cursor: pointer;
  font-family: inherit;
}
.buy-confirm-ok {
  flex: 1;
  padding: 12px;
  border-radius: 8px;
  border: none;
  background: var(--app-primary);
  color: var(--app-primary-fg);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  transition: opacity 0.15s;
}
.buy-confirm-ok:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.qt-modal-body {
  font-size: 14px;
  color: var(--app-text-muted-2);
  line-height: 1.6;
  margin-bottom: 20px;
}

/* ---- Firm-quote confirm screen (spec §3/§4) ---- */
.qt-confirm-title {
  margin: 0 0 20px;
  font-size: 18px;
  font-weight: 600;
  color: var(--app-text-strong);
}
.qt-countdown-row {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 20px;
  padding-bottom: 20px;
  border-bottom: 1px solid rgba(var(--app-content-overlay-rgb),0.08);
}
.qt-countdown-ring {
  --qt-countdown-frac: 1;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  font-weight: 700;
  color: var(--app-primary);
  background:
    conic-gradient(var(--app-primary) calc(var(--qt-countdown-frac) * 360deg), rgba(var(--app-content-overlay-rgb),0.08) 0deg);
  transition: background 0.2s linear;
}
.qt-countdown-ring span {
  background: var(--app-surface-1);
  width: 38px;
  height: 38px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.qt-countdown-ring--danger {
  color: var(--app-sell);
}
.qt-countdown-ring--danger span { color: var(--app-sell); }
.qt-countdown-caption {
  font-size: 12px;
  color: var(--app-text-muted-2);
}
.qt-countdown-sub {
  font-size: 15px;
  font-weight: 600;
  color: var(--app-text-1);
}
.qt-confirm-rows {
  margin-bottom: 8px;
}
.qt-confirm-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 0;
  font-size: 14px;
  color: var(--app-text-muted-2);
}
.qt-confirm-row span:last-child {
  color: var(--app-text-strong);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
/* The fee disclosure, moved here off the price line (manager 2026-09-17: "The
   fee disclosure stays in the terms and in the confirmation step, not next to
   the price"). Quiet, like a footnote to the three amounts above it — it is a
   statement about numbers the customer has already read, not a fourth number. */
.qt-confirm-fee-note {
  font-size: 11px;
  color: var(--app-text-muted-3);
  line-height: 1.5;
  margin: 0 0 14px;
}
.qt-confirm-expired-note {
  font-size: 12px;
  color: var(--app-sell);
  background: rgba(224, 160, 80, 0.1);
  border-radius: 8px;
  padding: 10px 12px;
  margin: 4px 0 16px;
}

/* ========== RESPONSIVE ========== */
@media (max-width: 600px) {
  .qt-quick-amounts { flex-wrap: wrap; }
  .qt-quick-amounts .buy-quick-amt { flex: 0 0 calc(33.33% - 4px); }
  .qt-history-table { min-width: 420px; }
}

/* ==========================================================================
   Brand-aware theming (Ultimo, app.ultimox.io) — follows the same convention
   as ai-trading.css: html[data-brand="ultimo"] body.<page>-page .selector.
   Most of this page already resolves correctly through var(--app-*) tokens
   (surfaces, borders, text, primary/sell) with zero extra rules needed; the
   overrides below are only for the few places a fixed hue is used as a TEXT
   color against Ultimo's light surfaces, where the raw hex would be too
   faint to read (mirrors ai-trading.css's documented reasoning).
   ========================================================================== */
/* SHRUNK on 2026-09-16, not edited: four of the six selectors named
   `.buy-asset-change` / `.buy-selected-change`, and both classes are gone —
   no row shows a 24h change and the header shows a PRICE. A price is neither up
   nor down, so its replacement (`.buy-selected-price-*`) is built from
   var(--app-*) tokens and needs no override on either brand; the same is true of
   `.buy-asset-elsewhere`, which already used var(--app-primary). What is left
   here is the status badge, which genuinely is a fixed green/red. */
html[data-brand="ultimo"] body.buy-crypto-page .qt-status-badge.is-filled {
  color: #2f9e52;
}
html[data-brand="ultimo"] body.buy-crypto-page .qt-status-badge.is-failed {
  color: #c94f4f;
}
/* Removed (Quy 2026-08-25 ruling — see v8 note near "BUY BUTTON" above):
   .qt-submit-btn--sell no longer has its own amber background, so it no
   longer needs its own text-color override either — it now inherits
   color: var(--app-primary-fg) from the base .qt-submit-btn rule, same as
   Buy. Keeping this override would have forced white text onto Ultimo's
   gold background, which is unreadable. */

/* ===== ORDER-OUTCOME TOASTS =====
   Same visual language as the toasts on trade-spot / trade-futures, with its
   own class prefix because this page does not load trade-spot.css. Reported
   here rather than in the generic modal so that finishing a purchase does not
   hand the customer a second box to dismiss — see the container's comment in
   buy-crypto-v2.html. */
.qt-toast-container {
  position: fixed;
  top: 70px;
  right: 20px;
  /* BELOW the confirm modal. A toast from the last order can still be on screen
     when the next confirm screen opens, and a modal that can be overlapped —
     and clicked through — is not a modal.

     Deliberately NOT `var(--z-toast)`: that global token is 1300 (style.css),
     which is ABOVE `--z-modal: 1200`, so using it would have done the opposite
     of what this rule is for. Derived from the modal's own token instead, so it
     stays one layer under the modal wherever that token is retuned. The global
     toast token is left alone — every other page's toasts have no modal of
     this kind to sit under, and retuning it for them is not this change's
     business. */
  z-index: calc(var(--z-modal, 1200) - 1);
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* The container spans the corner permanently; only the toasts inside it are
     ever hit targets, or it would swallow clicks on whatever sits beneath. */
  pointer-events: none;
}
.qt-toast {
  pointer-events: auto;
  background: var(--app-surface-2, #1e2038);
  border: 1px solid rgba(var(--app-content-overlay-rgb), 0.1);
  border-radius: 8px;
  padding: 12px 16px;
  min-width: 280px;
  max-width: min(360px, calc(100vw - 40px));
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
  animation: qtToastIn 0.2s ease;
  transition: opacity 0.3s ease;
  display: flex;
  align-items: flex-start;
  gap: 12px;
}
.qt-toast.success { border-left: 3px solid var(--app-primary); }
.qt-toast.error   { border-left: 3px solid var(--app-sell); }
.qt-toast.info    { border-left: 3px solid var(--app-text-muted-3); }
.qt-toast-text { flex: 1; min-width: 0; }
.qt-toast-close {
  flex: none;
  border: 0;
  padding: 0 2px;
  background: transparent;
  color: var(--app-text-muted-3);
  font: inherit;
  font-size: 18px;
  line-height: 1.1;
  cursor: pointer;
}
.qt-toast-close:hover { color: var(--app-text-strong); }
.qt-toast-title { font-size: 13px; font-weight: 700; color: var(--app-text-strong); margin-bottom: 2px; }
.qt-toast-msg   { font-size: 12px; color: var(--app-text-muted-3); line-height: 1.45; }
@keyframes qtToastIn {
  from { opacity: 0; transform: translateX(20px); }
  to   { opacity: 1; transform: translateX(0); }
}
/* On a narrow screen the corner is where the header sits, so the toast takes
   the full width under it instead of overhanging. */
@media (max-width: 640px) {
  .qt-toast-container { top: 62px; right: 12px; left: 12px; }
  .qt-toast { min-width: 0; max-width: none; }
}
/* Respect a reader who has asked the OS for less motion. */
@media (prefers-reduced-motion: reduce) {
  .qt-toast { animation: none; }
}
/* revealRecentOrders() scrolls this card to the top of the viewport; leave room
   for the fixed header so its own title is not tucked underneath. */
/* scroll-margin-top now lives on .qt-history-card, beside its layout rule. */
