/* #530: interactive :hover rules are individually wrapped in
   @media (hover: hover) and (pointer: fine) below/above — without the guard,
   mobile browsers emulate hover on tap and the style STICKS until the next tap
   (order buttons kept their hover skin after use). Deliberately NOT wrapped:
   scrollbar :hover (no scrollbar hover exists on touch) and the .has-tip /
   .order-insight-wrap reveal rules — on touch, the emulated tap-hover is the
   ONLY way those tooltips/popups can be opened at all. */
/* ============================================
   Futures Trading Page - Specific Styles
   Loads trade-option.css for shared styles
   ============================================ */

/* Grid order: Chart(1) → OrderBook(2) → OrderPanel(3) */
/* All three columns match height. Order panel is compact by default; */
/* it grows naturally when TP/SL or More Options are expanded. */
.trade-top-grid { align-items: start; }
.trade-chart-card { order: 1; height: 700px; min-height: 0; }
.trade-orderbook { order: 2; height: 700px; overflow-y: auto; }
.trade-order-panel { order: 3; }

/* --- Compact order panel: trim spacing to fit ~700px without scroll --- */
.trade-order-panel { padding: 16px; }
.trade-order-panel .order-side-toggle { margin-bottom: 12px; }
.trade-order-panel .order-side-btn { padding: 8px; font-size: 13px; }

/* BUG-007: Long/Short active state colors (Futures uses long/short, not buy/sell) */
.order-side-btn.long.active {
  background: rgba(92, 184, 230, 0.15);
  color: var(--app-primary);
}
.order-side-btn.short.active {
  background: rgba(224, 160, 80, 0.15);
  color: var(--app-sell);
}
.trade-order-panel .leverage-section { margin-bottom: 10px; }
.trade-order-panel .order-type-row { margin-bottom: 10px; }
.trade-order-panel .order-field { margin-bottom: 10px; }
.trade-order-panel .order-field label { margin-bottom: 4px; }
.trade-order-panel .order-input { padding: 8px 0; font-size: 14px; }
.trade-order-panel .input-mode-toggle { margin-bottom: 8px; }
.trade-order-panel .tpsl-section { margin-bottom: 8px; }
.trade-order-panel .tpsl-toggle { padding: 6px 0; }
.trade-order-panel .more-options { margin-bottom: 8px; }
.trade-order-panel .order-summary { padding: 8px 0; margin-bottom: 10px; }
.trade-order-panel .order-summary-row { padding: 3px 0; }
.trade-order-panel .order-summary-row.total { padding-top: 6px; }
.trade-order-panel .order-submit-btn { padding: 12px; margin-bottom: 8px; font-size: 14px; }
.trade-order-panel .order-balance-info { font-size: 11px; }
.order-balance-info-secondary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 4px 0;
  font-size: 11px;
  color: var(--app-text-muted-2);
}

/* Contract Type Tags */
.type-tag.perp { color: var(--app-primary); background: rgba(92, 184, 230, 0.1); }
/* Margin badge in the instrument heading — same chip shape as the lifecycle
   tag beside it, a different colour so the two are not read as one word. */
.type-tag.margin-tag { color: #f0a050; background: rgba(240, 160, 80, 0.12); }
.type-tag.futures { color: #f0a050; background: rgba(240, 160, 80, 0.1); }
.type-tag.equity { color: #7c3aed; background: rgba(124, 58, 237, 0.1); }

/* Equity Perps — company name in contract list */
.contract-company { color: #9ca3af; font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 180px; }

/* Leverage Slider */
.leverage-section { margin-bottom: 16px; }
.leverage-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
.leverage-label { font-size: 12px; color: var(--app-text-muted-2); font-weight: 500; }
.leverage-value { font-size: 14px; font-weight: 700; color: var(--app-primary); }
.leverage-slider { width: 100%; -webkit-appearance: none; height: 4px; border-radius: 2px; background: rgba(var(--app-content-overlay-rgb),0.08); outline: none; }
.leverage-slider::-webkit-slider-thumb { -webkit-appearance: none; width: 18px; height: 18px; border-radius: 50%; background: var(--app-primary); cursor: pointer; box-shadow: 0 2px 8px rgba(92,184,230,0.3); }
.leverage-slider-wrap { position: relative; }
.leverage-marks { display: flex; justify-content: space-between; font-size: 10px; color: #9a9aaa; margin-top: 6px; padding: 0 2px; user-select: none; }
.leverage-presets { display: flex; gap: 4px; margin-top: 6px; }
.leverage-preset-btn { flex: 1; background: rgba(var(--app-content-overlay-rgb),0.03); border: 1px solid rgba(var(--app-content-overlay-rgb),0.06); color: var(--app-text-muted-2); font-size: 11px; font-weight: 600; padding: 5px 0; border-radius: 4px; cursor: pointer; transition: all 0.15s; }
@media (hover: hover) and (pointer: fine) {
.leverage-preset-btn:hover { color: var(--app-text-1); border-color: rgba(var(--app-content-overlay-rgb),0.12); }
}
.leverage-preset-btn.active { color: var(--app-primary); border-color: rgba(92,184,230,0.3); background: rgba(92,184,230,0.06); }

/* Funding Rate Display */
.funding-info { display: flex; align-items: center; gap: 12px; padding: 10px 16px; background: rgba(var(--app-content-overlay-rgb),0.02); border: 1px solid rgba(var(--app-content-overlay-rgb),0.04); border-radius: 8px; margin-bottom: 16px; }
.funding-item { display: flex; flex-direction: column; gap: 2px; }
.funding-item-label { font-size: 10px; color: #5a5a6a; text-transform: uppercase; letter-spacing: 0.3px; }
.funding-item-value { font-size: 12px; font-weight: 600; color: var(--app-text-muted-3); font-variant-numeric: tabular-nums; }
.funding-item-value.positive { color: var(--app-buy); }
.funding-item-value.negative { color: var(--app-sell); }

/* Active Contracts List */
.contracts-tabs { display: flex; gap: 4px; padding: 8px 16px; border-bottom: 1px solid rgba(var(--app-content-overlay-rgb),0.06); overflow-x: auto; }
.contracts-tab { background: none; border: 1px solid rgba(var(--app-content-overlay-rgb),0.08); color: var(--app-text-muted-2); font-size: 12px; font-weight: 500; padding: 5px 12px; border-radius: 6px; cursor: pointer; transition: all 0.15s; white-space: nowrap; }
@media (hover: hover) and (pointer: fine) {
.contracts-tab:hover { background: rgba(var(--app-content-overlay-rgb),0.04); color: #c0c0d0; }
}
.contracts-tab.active { background: rgba(92,184,230,0.1); border-color: rgba(92,184,230,0.3); color: var(--app-primary); }
.tab-count { font-size: 10px; color: inherit; opacity: 0.7; margin-left: 2px; }
.contracts-search-wrap { padding: 6px 16px; }
.contracts-search { width: 100%; background: rgba(var(--app-content-overlay-rgb),0.04); border: 1px solid rgba(var(--app-content-overlay-rgb),0.08); border-radius: 6px; padding: 6px 12px; font-size: 12px; color: var(--app-text-1); outline: none; }
.contracts-search:focus { border-color: rgba(92,184,230,0.3); }
.contracts-search::placeholder { color: #5a5a6a; }
.contracts-scroll { overflow-x: auto; max-height: 500px; overflow-y: auto; }
.contracts-table { min-width: 700px; }
.contracts-list { }
.contracts-loading { padding: 24px; text-align: center; color: #5a5a6a; font-size: 13px; }
.contracts-header { display: grid; grid-template-columns: 2.2fr 1fr 0.8fr 0.9fr 0.8fr 0.8fr 70px; gap: 8px; padding: 8px 16px; font-size: 11px; color: #5a5a6a; text-transform: uppercase; letter-spacing: 0.3px; border-bottom: 1px solid rgba(var(--app-content-overlay-rgb),0.06); position: sticky; top: 0; background: var(--app-surface-card); z-index: 1; }
.contracts-row { display: grid; grid-template-columns: 2.2fr 1fr 0.8fr 0.9fr 0.8fr 0.8fr 70px; gap: 8px; align-items: center; padding: 10px 16px; border-bottom: 1px solid rgba(var(--app-content-overlay-rgb),0.04); cursor: pointer; transition: background 0.15s; }
@media (hover: hover) and (pointer: fine) {
.contracts-row:hover { background: rgba(var(--app-content-overlay-rgb),0.02); }
}
.contracts-row.active { background: rgba(92,184,230,0.04); border-left: 3px solid var(--app-primary); }
.contract-name { display: flex; align-items: center; gap: 10px; font-size: 14px; font-weight: 600; color: var(--app-text-1); }
.contract-icon { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; min-width: 28px; border-radius: 6px; font-size: 12px; font-weight: 700; color: var(--app-text-white); flex-shrink: 0; }
.contract-type { font-size: 11px; color: var(--app-text-muted-2); font-weight: 400; margin-left: 6px; white-space: nowrap; }
.contract-expiry { font-size: 10px; color: #c9a84c; font-weight: 500; }
.contract-price { font-size: 13px; font-weight: 600; color: var(--app-text-1); font-variant-numeric: tabular-nums; }
.contract-change { font-size: 12px; font-weight: 500; }
.contract-change.positive { color: var(--app-buy); }
.contract-change.negative { color: var(--app-sell); }
.contract-funding { font-size: 12px; font-weight: 500; }
.contract-funding.positive { color: var(--app-buy); }
.contract-funding.negative { color: var(--app-sell); }
.contract-oi, .contract-vol { font-size: 12px; color: var(--app-text-muted-3); font-variant-numeric: tabular-nums; }
.contract-trade-btn { background: rgba(92,184,230,0.08); border: 1px solid rgba(92,184,230,0.2); color: var(--app-primary); font-size: 11px; font-weight: 600; padding: 5px 14px; border-radius: 4px; cursor: pointer; transition: all 0.15s; }
@media (hover: hover) and (pointer: fine) {
.contract-trade-btn:hover { background: rgba(92,184,230,0.15); border-color: rgba(92,184,230,0.4); }
}


/* Input Mode Toggle (Quantity / Margin) */
.input-mode-toggle {
  display: flex;
  gap: 4px;
  margin-bottom: 12px;
  background: rgba(var(--app-content-overlay-rgb),0.03);
  border-radius: 8px;
  padding: 3px;
}
.input-mode-btn {
  flex: 1;
  background: none;
  border: none;
  color: var(--app-text-muted-2);
  font-size: 11px;
  font-weight: 600;
  padding: 6px 0;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.15s;
}
@media (hover: hover) and (pointer: fine) {
.input-mode-btn:hover { color: #b0b0c0; }
}
.input-mode-btn.active {
  background: rgba(92,184,230,0.1);
  color: var(--app-primary);
}

/* Margin calc result */
.margin-calc-result {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
  padding: 8px 12px;
  background: rgba(92,184,230,0.05);
  border: 1px solid rgba(92,184,230,0.12);
  border-radius: 8px;
  font-size: 12px;
  color: var(--app-text-muted-3);
}
.margin-calc-arrow { color: var(--app-primary); font-size: 14px; }
.margin-qty-label { color: var(--app-text-muted-2); font-size: 12px; }
.margin-qty-input {
  background: none;
  border: none;
  border-bottom: 1px dashed rgba(var(--app-content-overlay-rgb),0.15);
  color: var(--app-text-1);
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  width: 70px;
  text-align: center;
  padding: 2px 4px;
  outline: none;
  font-family: inherit;
}
.margin-qty-input:focus { border-bottom-color: var(--app-primary); }
.margin-qty-suffix { color: var(--app-text-muted-2); font-size: 11px; }
.margin-calc-value { color: var(--app-text-muted-2); font-size: 11px; margin-left: auto; }
.margin-quick-btns { margin-top: 6px; }

/* Price row with BBO */
.price-row-with-bbo {
  display: flex;
  gap: 6px;
  align-items: stretch;
}
.price-row-with-bbo .order-input-wrap { flex: 1; }
/* BUG #49/#56: red border on invalid price tick */
.order-input-wrap.input-invalid { border-color: #f85149 !important; }

/* BBO Button */
.bbo-btn {
  background: rgba(92,184,230,0.08);
  border: 1px solid rgba(92,184,230,0.2);
  color: var(--app-primary);
  font-size: 11px;
  font-weight: 700;
  padding: 0 14px;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.15s;
  letter-spacing: 0.5px;
  white-space: nowrap;
  flex-shrink: 0;
}
@media (hover: hover) and (pointer: fine) {
.bbo-btn:hover { background: rgba(92,184,230,0.15); border-color: rgba(92,184,230,0.4); color: #7ccbf0; }
}
.bbo-btn.flash { background: rgba(92,184,230,0.25); }

/* TP/SL Section */
.tpsl-section { margin-bottom: 14px; }
.tpsl-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  background: rgba(var(--app-content-overlay-rgb),0.03);
  border: 1px dashed rgba(var(--app-content-overlay-rgb),0.1);
  color: #9a9aaa;
  font-size: 12px;
  font-weight: 500;
  padding: 8px 0;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.15s;
}
@media (hover: hover) and (pointer: fine) {
.tpsl-toggle:hover { color: #a0a0b0; border-color: rgba(var(--app-content-overlay-rgb),0.18); background: rgba(var(--app-content-overlay-rgb),0.05); }
}
.tpsl-toggle.active { display: none; }
.tpsl-fields { display: flex; flex-direction: column; gap: 8px; }
.tpsl-row { display: flex; align-items: center; gap: 8px; }
.tpsl-label {
  font-size: 11px;
  font-weight: 700;
  width: 26px;
  min-width: 26px;
  text-align: center;
  padding: 4px 0;
  border-radius: 4px;
}
.tpsl-label.tp { color: var(--app-primary); background: rgba(92,184,230,0.1); }
.tpsl-label.sl { color: var(--app-sell); background: rgba(224,160,80,0.1); }
.tpsl-input-wrap { flex: 1; }
.tpsl-input { font-size: 13px !important; padding: 8px 0 !important; }
.tpsl-input::placeholder { color: #4a4a5a; font-weight: 400; }
.tpsl-close {
  background: none; border: none; color: #5a5a6a; cursor: pointer;
  font-size: 16px; padding: 4px 6px; line-height: 1; transition: color 0.15s;
}
@media (hover: hover) and (pointer: fine) {
.tpsl-close:hover { color: var(--app-sell); }
}

/* More Options */
.more-options { margin-bottom: 14px; }
.more-options-summary {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  font-size: 12px;
  color: var(--app-text-muted-2);
  cursor: pointer;
  padding: 6px 0;
  user-select: none;
  list-style: none;
  transition: color 0.15s;
}
.more-options-summary::-webkit-details-marker { display: none; }
@media (hover: hover) and (pointer: fine) {
.more-options-summary:hover { color: #a0a0b0; }
}
.more-options-summary svg { transition: transform 0.2s; }
.more-options[open] .more-options-summary svg { transform: rotate(180deg); }
.more-options-body { padding-top: 10px; }

/* Time in Force */
.tif-field { margin-bottom: 0 !important; }
.tif-field label { margin-bottom: 6px; }
.tif-tabs { display: flex; gap: 4px; }
.tif-btn {
  flex: 1;
  background: rgba(var(--app-content-overlay-rgb),0.03);
  border: 1px solid rgba(var(--app-content-overlay-rgb),0.08);
  color: var(--app-text-muted-2);
  font-size: 11px;
  font-weight: 600;
  padding: 6px 0;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.15s;
}
@media (hover: hover) and (pointer: fine) {
.tif-btn:hover { color: #a0a0b0; border-color: rgba(var(--app-content-overlay-rgb),0.15); }
}
.tif-btn.active { color: var(--app-primary); border-color: rgba(92,184,230,0.3); background: rgba(92,184,230,0.06); }

/* Order Insight */
.order-insight-wrap {
  position: relative;
  margin-bottom: 12px;
}
.order-insight-trigger {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 6px 0;
  font-size: 12px;
  color: #6ea8cc;
  cursor: pointer;
  transition: color 0.15s;
  user-select: none;
}
@media (hover: hover) and (pointer: fine) {
.order-insight-trigger:hover { color: #8cc4e8; }
}
.order-insight-trigger svg { opacity: 0.7; }
.order-insight-popup {
  display: none;
  position: absolute;
  bottom: calc(100% + 8px);
  left: 0;
  right: 0;
  background: #1e2038;
  border: 1px solid rgba(92,184,230,0.2);
  border-radius: 10px;
  padding: 14px 16px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.5);
  z-index: 100;
  animation: insightFadeIn 0.15s ease;
}
.order-insight-wrap:hover .order-insight-popup,
.order-insight-popup.pinned { display: block; }
@keyframes insightFadeIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }
.order-insight-content {
  font-size: 12px;
  line-height: 1.6;
  color: #c0c0d0;
}
.order-insight-content strong { color: var(--app-text-1); }
.order-insight-content .insight-warn { color: #e6a84c; }
.order-insight-content .insight-risk { color: var(--app-sell); }
.order-insight-content .insight-ok { color: var(--app-primary); }

/* Position / Orders Tabs */
.trade-your-position { margin-bottom: 16px; }
.pos-tabs { display: flex; gap: 0; }
.pos-tab {
  background: none;
  border: none;
  color: #6b7280;
  font-size: 13px;
  font-weight: 600;
  padding: 8px 16px;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: all 0.15s;
}
@media (hover: hover) and (pointer: fine) {
.pos-tab:hover { color: #c8c8d8; }
}
.pos-tab.active { color: var(--app-text-1); border-bottom-color: var(--app-primary); }
.pos-tab-count { font-size: 11px; color: var(--app-primary); font-weight: 600; margin-left: 4px; }
.pos-tab-content { display: none; }
.pos-tab-content.active { display: block; }

/* Cancel button in orders table */
.order-cancel-btn {
  font-size: 10px;
  font-weight: 600;
  padding: 4px 10px;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.15s;
  border: 1px solid rgba(224,80,80,0.3);
  background: rgba(224,80,80,0.08);
  color: #e05050;
}
@media (hover: hover) and (pointer: fine) {
.order-cancel-btn:hover { background: rgba(224,80,80,0.18); }
}
.order-cancel-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.order-status-new { color: var(--app-primary); }
.order-status-partial { color: var(--app-sell); }
.pos-table-wrap { overflow-x: auto; }
.pos-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.pos-table thead th {
  color: #7a7a8a;
  font-weight: 500;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  padding: 6px 10px;
  border-bottom: 1px solid rgba(var(--app-content-overlay-rgb),0.06);
  text-align: right;
}
.pos-table thead th:first-child { text-align: left; }
.pos-table thead th:nth-child(2) { text-align: center; }
.pos-table thead th:last-child { text-align: center; }
.pos-table tbody td {
  padding: 10px 10px;
  color: #c8c8d8;
  font-weight: 500;
  text-align: right;
  border-bottom: 1px solid rgba(var(--app-content-overlay-rgb),0.03);
}
.pos-table tbody td:first-child { text-align: left; color: var(--app-text-1); font-weight: 700; }
.pos-table tbody td:nth-child(2) { text-align: center; }
.pos-table tbody td:last-child { text-align: center; }
@media (hover: hover) and (pointer: fine) {
.pos-table tbody tr:hover { background: rgba(var(--app-content-overlay-rgb),0.02); }
}

/* Bug #338 (Quang QA BUG-44 2026-06-08): Side column on Equity Tokens /
   Futures positions table was inheriting the default `.pos-table tbody td`
   right-align and looked misaligned next to the centered Type column.
   On the 3-up trade pages (futures + equity), the Side column is column 3
   on BOTH posTable (Symbol/Type/Side/...) and ordersTable
   (Time/Symbol/Side/...) — so a single nth-child(3) rule covers both.
   Scoped to `body.trade-page-3up` so the trade-option.html positions
   table (where column 3 is `Size`, a numeric value) keeps its right-
   aligned default. */
body.trade-page-3up .pos-table thead th:nth-child(3),
body.trade-page-3up .pos-table tbody td:nth-child(3) {
  text-align: center;
}
.pos-side-long { color: var(--app-buy); font-weight: 700; }
.pos-side-short { color: var(--app-sell); font-weight: 700; }
.pos-pnl-positive { color: var(--app-buy); font-weight: 600; }
.pos-pnl-negative { color: var(--app-sell); font-weight: 600; }
.pos-close-btns { display: flex; gap: 4px; justify-content: center; }
.pos-close-btn {
  font-size: 10px;
  font-weight: 600;
  padding: 4px 10px;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.15s;
  border: 1px solid;
}
.pos-close-limit { background: rgba(var(--app-content-overlay-rgb),0.04); border-color: rgba(var(--app-content-overlay-rgb),0.1); color: #a0a0b0; }
@media (hover: hover) and (pointer: fine) {
.pos-close-limit:hover { background: rgba(var(--app-content-overlay-rgb),0.08); color: var(--app-text-1); }
}
.pos-close-market { background: rgba(224,160,80,0.08); border-color: rgba(224,160,80,0.2); color: var(--app-sell); }
@media (hover: hover) and (pointer: fine) {
.pos-close-market:hover { background: rgba(224,160,80,0.15); }
}

/* Futures V.2 close button. Scoped to that page (body.futures2-page), so the
   BitMEX page keeps its amber close-market variant byte-identical.

   Colour comes only from brand variables: this is the control a user presses to
   get OUT of a position, so it has to be legible on Vestex dark AND Ultimo light.
   The amber  above would land at ~2.0:1 on Ultimo — the same
   defect as #889/#901, and the worst possible place for it. Hue stays in the
   background and border; the label is a neutral token. */
body.futures2-page .pos-close-btn {
  background: rgba(var(--app-content-overlay-rgb), 0.06);
  border-color: rgba(var(--app-content-overlay-rgb), 0.18);
  color: var(--app-text-1);
}
@media (hover: hover) and (pointer: fine) {
body.futures2-page .pos-close-btn:hover:not(:disabled) {
  background: rgba(var(--app-content-overlay-rgb), 0.12);
  color: var(--app-text-strong);
}
}
body.futures2-page .pos-close-btn:disabled { opacity: 0.55; cursor: not-allowed; }
/* BUG #415 — Add Margin button (mirrors close-btn sizing; uses the buy/primary accent) */
.pos-add-margin-btn { font-size: 10px; font-weight: 600; padding: 4px 10px; border-radius: 4px; cursor: pointer; transition: all 0.15s; border: 1px solid; background: rgba(92,184,230,0.08); border-color: rgba(92,184,230,0.2); color: var(--app-primary); }
@media (hover: hover) and (pointer: fine) {
.pos-add-margin-btn:hover { background: rgba(92,184,230,0.15); }
}
.pos-add-margin-btn:disabled { opacity: 0.6; cursor: default; }

/* AI Chat Model Selector */
.chat-model-select {
  background: rgba(var(--app-content-overlay-rgb),0.06);
  border: 1px solid rgba(var(--app-content-overlay-rgb),0.1);
  border-radius: 6px;
  color: var(--app-text-muted-3);
  font-size: 11px;
  font-weight: 500;
  padding: 4px 8px;
  outline: none;
  cursor: pointer;
  font-family: inherit;
  -webkit-appearance: none;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238a8a9a' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 8px center;
  padding-right: 22px;
  transition: all 0.15s;
}
@media (hover: hover) and (pointer: fine) {
.chat-model-select:hover {
  border-color: rgba(92,184,230,0.3);
  color: var(--app-text-1);
}
}
.chat-model-select:focus {
  border-color: rgba(92,184,230,0.4);
}
.chat-model-select option {
  background: var(--app-surface-card);
  color: var(--app-text-1);
}

/* Liquidation Price Warning */
.liq-warning { display: flex; align-items: center; gap: 8px; padding: 10px 14px; background: rgba(224,160,80,0.06); border: 1px solid rgba(224,160,80,0.12); border-radius: 8px; margin-top: 12px; font-size: 12px; color: var(--app-sell); }
.liq-warning svg { flex-shrink: 0; }

/* ===== RESPONSIVE =====
   BUG #15: layout-affecting rules now live in trade-option.css under
   `body.trade-page-3up`. Below are only Futures/Equity-specific compact
   adjustments (position table, instrument bar). Boundary aligned with
   the new Narrow breakpoint (<1024px). */

/* Mid band (1024-1439px): no empty gap between the chart and the order book.
   trade-option.css lays this band out as a 2x2 grid (`grid-template-rows:
   auto auto`): chart row 1, order book row 2, order panel spanning both. When
   the panel is taller than chart + gap + book (logged-in panel, TP/SL open,
   and always sooner on INFIN8TI whose Poppins font makes the panel ~10%
   taller), the grid splits the excess EQUALLY over both auto rows; the chart
   and book cards have fixed heights, so the row-1 share showed up as an empty
   band under "Charts by TradingView". Making row 2 the only flexible track
   sends all the excess there, and the book (size-contained so its long ladder
   cannot inflate the row; min-height keeps the old 280px) stretches to fill
   it. When the panel fits, row 2 stays exactly 280px — layout unchanged.
   Scoped to body.futures2-page (only trade-futures.html) and to the dark
   brands (vestex + infin8ti): Ultimo is excluded so app.ultimox.io stays
   pixel-identical (owner request) — it never reported the gap. */
@media (min-width: 1024px) and (max-width: 1439px) {
  html:not([data-brand="ultimo"]) body.trade-page-3up.futures2-page .trade-top-grid {
    grid-template-rows: auto 1fr;
  }
  html:not([data-brand="ultimo"]) body.trade-page-3up.futures2-page .trade-top-grid > .trade-orderbook {
    height: auto !important;
    min-height: 280px;
    max-height: none;
    contain: size;
  }
}

/* Tablet — instrument bar stacks, order panel always visible.
   #543: the .instrument-bar / .inst-bar-metrics / .inst-metric-divider column
   flip used to be re-declared here (and again in trade-option.css's 860px
   block) with the exact same values as trade-option.css's 1024px block. Every
   page that loads this file also loads trade-option.css, so the duplicates
   were pure shadowed weight — the stacking rules now live ONLY in
   trade-option.css (1200px + 1024px blocks). */
@media (max-width: 1023px) {
  .trade-order-panel { max-width: none; }
  .pos-table { font-size: 11px; }
  .pos-table thead th, .pos-table tbody td { padding: 8px 6px; }
}

/* Mobile */
@media (max-width: 768px) {
  /* #543: .instrument-bar padding 12px 16px !important was declared here AND
     in trade-option.css's 768px block. The trade-option.css copy (which every
     page loading this file also loads) is the one that stays. */
  .inst-bar-symbol { font-size: 16px !important; }
  .trade-main { padding: 12px 16px 60px !important; }

  /* Order panel — ensure it never disappears */
  .trade-order-panel { padding: 16px !important; }
  /* #526: iOS Safari auto-zooms (and stays zoomed) on focusing any input under
     16px — the compact panel's 14px inputs triggered it on every Amount tap.
     16px at touch widths only; the desktop 14px (line ~32) is untouched. */
  .trade-order-panel .order-input,
  .trade-order-panel select { font-size: 16px; }
  /* #23: the #526 rule above is SCOPED TO .trade-order-panel, so it never
     reached the contract picker's search box — `.inst-symbol-search` (13px,
     line ~1261) lives inside .inst-symbol-dropdown, outside the order panel.
     Newly reachable now that the BTC picker ships: focusing a sub-16px input
     makes iOS Safari zoom the page in, and it never zooms back out. Own rule
     rather than an extra selector on the #526 line so each fix stays legible.
     Desktop keeps 13px — this is the touch-width override only. */
  .inst-symbol-search { font-size: 16px; }
  /* #525: same 44px touch floor as the trade-page-3up rule in trade-option.css
     — this compact-panel rule (line ~17) otherwise wins ties on v1/v2 Futures. */
  .trade-order-panel .order-side-btn { min-height: 44px; }
  /* #527: 9px tick labels → 11px floor (font-size only). */
  .leverage-marks { font-size: 11px; }

  /* #22: THE LEVERAGE SLIDER'S OWN BOX WAS 4px TALL (line ~74). The 18px thumb
     is painted overflow, not hit area — so on a phone the pointer target for a
     control whose drag AND arrow keys CHANGE LEVERAGE was a 4px band, and a
     mis-grab scrolls the page instead of setting leverage.

     The input grows to the 44px Apple-HIG floor while the PAINTED track stays
     exactly 4px. The track is repainted as a centred 4px background-image over
     a transparent background-color, deliberately NOT as padding +
     background-clip: content-box — padding on <input type=range> is honoured
     inconsistently across engines, whereas a background-image is not. The thumb
     is centred in the content box by every engine, so it lands on the repainted
     strip and does not move. Same rgba() as the base rule → identical pixels.
     Focus is handled by the shared :focus-visible ring (#53, trade-option.css);
     the base `outline: none` here has lower specificity and no longer wins. */
  .leverage-slider {
    height: 44px;
    background-color: transparent;
    background-image: linear-gradient(rgba(var(--app-content-overlay-rgb),0.08), rgba(var(--app-content-overlay-rgb),0.08));
    background-repeat: no-repeat;
    background-position: center;
    background-size: 100% 4px;
  }

  /* Position table — horizontal scroll */
  .pos-table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .pos-table { min-width: 700px; }
  .pos-table thead th, .pos-table tbody td { padding: 8px 8px; font-size: 11px; }

  /* Contract list */
  .contracts-header, .contracts-row { font-size: 11px; padding: 8px 12px; }
  .contracts-scroll { max-height: 300px; }

  /* AI Chat */
  .ai-chat-panel { width: calc(100vw - 32px) !important; right: 16px !important; bottom: 70px !important; max-height: 60vh !important; }

  /* Funding info */
  .funding-info { flex-wrap: wrap; padding: 8px 12px; gap: 8px; }

  /* Leverage presets */
  .leverage-presets { flex-wrap: wrap; }
}

/* Small mobile */
@media (max-width: 480px) {
  .trade-chart-card { height: 400px; }
  .trade-main { padding: 8px 8px 60px !important; }
  .inst-bar-symbol { font-size: 14px !important; }
  /* #527: 11px floor — font-size only, the row's grid is owned elsewhere. */
  .metric-label { font-size: 11px !important; }
  .metric-value { font-size: 12px !important; }

  .price-row-with-bbo { flex-direction: column; gap: 6px; }
  .bbo-btn { width: 100%; padding: 8px 0; text-align: center; }


  .ai-chat-panel { width: calc(100vw - 16px) !important; right: 8px !important; left: 8px !important; bottom: 60px !important; max-height: 70vh !important; }

  /* Contracts table scroll */
  .contracts-header, .contracts-row {
    grid-template-columns: 2fr 1fr 0.8fr 70px;
  }
  .contracts-header span:nth-child(5),
  .contracts-header span:nth-child(6),
  .contracts-row span:nth-child(5),
  .contracts-row span:nth-child(6) {
    display: none;
  }
}

/* ============================================
   Order Confirmation Modal
   ============================================ */
.order-confirm-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,0.6); z-index: 9000;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; pointer-events: none; transition: opacity 0.2s;
}
.order-confirm-overlay.show { opacity: 1; pointer-events: auto; }

.order-confirm-modal {
  background: var(--app-surface-card); border: 1px solid rgba(var(--app-content-overlay-rgb),0.1);
  border-radius: 12px; padding: 24px; width: 380px; max-width: 90vw;
  transform: scale(0.95); transition: transform 0.2s;
}
.order-confirm-overlay.show .order-confirm-modal { transform: scale(1); }

.order-confirm-title {
  font-size: 16px; font-weight: 700; color: var(--app-text-1); margin-bottom: 20px;
  display: flex; align-items: center; gap: 8px;
}
.order-confirm-title .side-badge {
  font-size: 12px; font-weight: 700; padding: 3px 10px; border-radius: 4px;
  text-transform: uppercase; letter-spacing: 0.5px;
}
.side-badge.long { background: rgba(92,184,230,0.15); color: var(--app-primary); }
.side-badge.short { background: rgba(224,160,80,0.15); color: var(--app-sell); }

.order-confirm-details { margin-bottom: 20px; }
.order-confirm-row {
  display: flex; justify-content: space-between; padding: 8px 0;
  border-bottom: 1px solid rgba(var(--app-content-overlay-rgb),0.04);
  font-size: 13px;
}
.order-confirm-row:last-child { border-bottom: none; }
.order-confirm-row .label { color: var(--app-text-muted-2); }
.order-confirm-row .value { color: var(--app-text-1); font-weight: 600; }
.order-confirm-row.total-row { border-top: 1px solid rgba(var(--app-content-overlay-rgb),0.08); padding-top: 12px; margin-top: 4px; }
.order-confirm-row.total-row .label { color: var(--app-text-1); font-weight: 700; }
.order-confirm-row.total-row .value { font-weight: 700; font-size: 14px; }

.order-confirm-actions {
  display: flex; gap: 10px;
}
.order-confirm-actions button {
  flex: 1; padding: 12px; border-radius: 8px; font-size: 14px;
  font-weight: 700; cursor: pointer; border: none; transition: all 0.15s;
}
.btn-confirm-cancel {
  background: rgba(var(--app-content-overlay-rgb),0.06); color: var(--app-text-muted-2);
}
@media (hover: hover) and (pointer: fine) {
.btn-confirm-cancel:hover { background: rgba(var(--app-content-overlay-rgb),0.1); color: var(--app-text-1); }
}
.btn-confirm-execute.long {
  background: linear-gradient(135deg, var(--app-primary), #4a9fd4); color: var(--app-text-white);
}
@media (hover: hover) and (pointer: fine) {
.btn-confirm-execute.long:hover { background: linear-gradient(135deg, #6cc4f0, var(--app-primary)); }
}
.btn-confirm-execute.short {
  background: linear-gradient(135deg, var(--app-sell), #c88a40); color: var(--app-text-white);
}
@media (hover: hover) and (pointer: fine) {
.btn-confirm-execute.short:hover { background: linear-gradient(135deg, #eab060, var(--app-sell)); }
}

/* ============================================
   Toast Notifications
   ============================================ */
/* BUG #327: anchor moved from bottom-right to top-right so the toast no
   longer overlaps the TP/SL "not yet available" yellow warning at the
   bottom of the order panel (#tpslUnavailableNotice — kept visible per
   #227) nor the AI Chat FAB (.ai-chat-fab at bottom-right z-index 1000).
   Matches Spot Trading's top-right toast convention (#122 precedent).
   flex-direction: column-reverse is preserved — with the top anchor it
   now places newest toast closest to the anchor (conventional). z-index,
   transform/transition (toast.show slide-in from right) all unchanged.
   The mobile (max-width 480px) override below intentionally keeps
   bottom-stuck because the stacked mobile layout doesn't have the same
   right-column overlap problem. */
.toast-container {
  position: fixed; top: 70px; right: 24px; z-index: 9500;
  display: flex; flex-direction: column-reverse; gap: 8px;
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  display: flex; align-items: center; gap: 10px;
  background: #1e1e32; border: 1px solid rgba(var(--app-content-overlay-rgb),0.08);
  border-radius: 10px; padding: 14px 18px; min-width: 300px; max-width: 420px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.4);
  transform: translateX(120%); opacity: 0;
  transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.35s;
}
.toast.show { transform: translateX(0); opacity: 1; }
.toast.hide { transform: translateX(120%); opacity: 0; }

.toast-icon {
  width: 28px; height: 28px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0; font-size: 14px;
}
.toast.success .toast-icon { background: rgba(92,184,230,0.15); color: var(--app-primary); }
.toast.error .toast-icon { background: rgba(224,100,80,0.15); color: #e06450; }

.toast-body { flex: 1; }
.toast-title { font-size: 13px; font-weight: 700; color: var(--app-text-1); margin-bottom: 2px; }
.toast-message { font-size: 12px; color: var(--app-text-muted-2); }

.toast-close {
  background: none; border: none; color: #6a6a7a; cursor: pointer;
  font-size: 16px; padding: 4px; line-height: 1; flex-shrink: 0;
}
@media (hover: hover) and (pointer: fine) {
.toast-close:hover { color: var(--app-text-1); }
}

/* Ultimo: the toast is a DARK ISLAND (same rationale + same technique as the
   Trade Wizard modal below). `.toast` hard-codes `background: #1e1e32`, but its
   text uses the neutral tokens — which brand-boot.js remaps to #1a1a1a on
   Ultimo's light shell. Result: dark text on a dark panel, i.e. an invisible
   toast on EVERY page that loads this file (futures, futures V.2, options,
   equity, portfolio). Re-map the neutrals back to Vestex dark WITHIN the toast
   scope. Selector is Ultimo-only → Vestex zero-diff. */
html[data-brand="ultimo"] .toast {
  --app-text-strong: #e2e8f0;
  --app-text-1: #e0e0e8;
  --app-text-muted-2: #8a8a9a;
}

/* Futures V.2 only: a filled order is the one toast a user must be able to read
   at a glance, so give the success title the conventional green rather than the
   blue that reads as "info". Scoped to this page — the other four pages that
   share `.toast` keep their existing blue, since recolouring them was not asked
   for and they are working. */
body.futures2-page .toast.success .toast-title { color: #3ddc84; }
body.futures2-page .toast.success .toast-icon {
  background: rgba(61,220,132,0.16);
  color: #3ddc84;
}

@media (max-width: 480px) {
  .toast-container { right: 8px; left: 8px; bottom: 70px; }
  .toast { min-width: auto; }
  .order-confirm-modal { padding: 18px; }
}

/* =====================================================================
   TRADE WIZARD
   ===================================================================== */

/* Wizard trigger button in chat header */
.chat-wizard-btn {
  display: flex; align-items: center; gap: 4px;
  background: rgba(92,184,230,0.15); color: var(--app-primary);
  border: 1px solid rgba(92,184,230,0.3); border-radius: 6px;
  padding: 3px 8px; font-size: 11px; font-weight: 600;
  cursor: pointer; transition: all 0.2s;
  white-space: nowrap;
}
@media (hover: hover) and (pointer: fine) {
.chat-wizard-btn:hover { background: rgba(92,184,230,0.25); border-color: var(--app-primary); }
}

/* Overlay */
.wizard-overlay {
  position: fixed; inset: 0; z-index: 9100;
  background: rgba(0,0,0,0.65); backdrop-filter: blur(4px);
  display: flex; align-items: center; justify-content: center;
  opacity: 0; pointer-events: none; transition: opacity 0.25s ease;
}
.wizard-overlay.show { opacity: 1; pointer-events: auto; }

/* Modal */
.wizard-modal {
  background: var(--app-surface-card); border: 1px solid rgba(var(--app-content-overlay-rgb),0.1);
  border-radius: 16px; width: 460px; max-width: 94vw;
  max-height: 88vh; display: flex; flex-direction: column;
  transform: scale(0.95); transition: transform 0.25s ease;
  box-shadow: 0 20px 60px rgba(0,0,0,0.5);
}
.wizard-overlay.show .wizard-modal { transform: scale(1); }

/* Header */
.wizard-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 20px 12px; border-bottom: 1px solid rgba(var(--app-content-overlay-rgb),0.06);
}
.wizard-title {
  font-size: 16px; font-weight: 700; color: var(--app-text-1);
  background: linear-gradient(90deg, var(--app-primary), #8dd0f0);
  -webkit-background-clip: text; -webkit-text-fill-color: transparent;
}
.wizard-close {
  background: none; border: none; color: #6b7280; font-size: 22px;
  cursor: pointer; padding: 0 4px; line-height: 1;
}
@media (hover: hover) and (pointer: fine) {
.wizard-close:hover { color: var(--app-text-1); }
}

/* Progress dots */
.wizard-progress {
  display: flex; align-items: center; justify-content: center;
  gap: 0; padding: 14px 20px 10px;
}
.wizard-dot {
  width: 28px; height: 28px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 700; color: #6b7280;
  background: rgba(var(--app-content-overlay-rgb),0.05); border: 2px solid rgba(var(--app-content-overlay-rgb),0.08);
  transition: all 0.3s; flex-shrink: 0;
}
.wizard-dot.active { border-color: var(--app-primary); color: var(--app-primary); background: rgba(92,184,230,0.1); }
.wizard-dot.done { border-color: var(--app-primary); background: var(--app-primary); color: var(--app-text-white); }
.wizard-line {
  width: 24px; height: 2px; background: rgba(var(--app-content-overlay-rgb),0.08);
  flex-shrink: 0; transition: background 0.3s;
}
.wizard-line.done { background: var(--app-primary); }

/* Body */
.wizard-body {
  flex: 1; overflow-y: auto; padding: 16px 20px;
  min-height: 260px;
}
.wizard-body::-webkit-scrollbar { width: 4px; }
.wizard-body::-webkit-scrollbar-thumb { background: rgba(var(--app-content-overlay-rgb),0.1); border-radius: 2px; }

/* Step title + subtitle */
.wz-step-title { font-size: 15px; font-weight: 700; color: var(--app-text-1); margin-bottom: 4px; }
.wz-step-sub { font-size: 12px; color: var(--app-text-muted-2); margin-bottom: 16px; line-height: 1.4; }

/* Asset grid (Step 1) */
.wz-asset-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
}
.wz-asset-card {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 12px 8px; border-radius: 10px; cursor: pointer;
  background: rgba(var(--app-content-overlay-rgb),0.03); border: 1.5px solid rgba(var(--app-content-overlay-rgb),0.06);
  transition: all 0.2s;
}
@media (hover: hover) and (pointer: fine) {
.wz-asset-card:hover { border-color: rgba(92,184,230,0.3); background: rgba(92,184,230,0.04); }
}
.wz-asset-card.selected { border-color: var(--app-primary); background: rgba(92,184,230,0.08); box-shadow: 0 0 12px rgba(92,184,230,0.15); }
.wz-asset-icon {
  width: 36px; height: 36px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; font-weight: 800; color: var(--app-text-white);
}
.wz-asset-name { font-size: 13px; font-weight: 700; color: var(--app-text-1); }
.wz-asset-price { font-size: 11px; color: var(--app-text-muted-2); }

/* Option cards (Steps 2, 3, 4) */
.wz-option-list { display: flex; flex-direction: column; gap: 10px; }
.wz-option-card {
  padding: 14px 16px; border-radius: 12px; cursor: pointer;
  background: rgba(var(--app-content-overlay-rgb),0.03); border: 1.5px solid rgba(var(--app-content-overlay-rgb),0.06);
  transition: all 0.2s;
}
@media (hover: hover) and (pointer: fine) {
.wz-option-card:hover { border-color: rgba(92,184,230,0.3); }
}
.wz-option-card.selected { border-color: var(--app-primary); background: rgba(92,184,230,0.06); }
.wz-option-card.disabled { opacity: 0.4; pointer-events: none; }
.wz-option-title { font-size: 14px; font-weight: 700; color: var(--app-text-1); margin-bottom: 6px; display: flex; align-items: center; gap: 8px; }
.wz-option-tag { font-size: 10px; padding: 2px 6px; border-radius: 4px; font-weight: 600; }
.wz-option-tag.recommended { background: rgba(92,184,230,0.15); color: var(--app-primary); }
.wz-option-tag.advanced { background: rgba(224,160,80,0.15); color: var(--app-sell); }
.wz-option-desc { font-size: 12px; color: var(--app-text-muted-2); line-height: 1.5; }
.wz-option-desc ul { margin: 4px 0 0; padding-left: 16px; }
.wz-option-desc li { margin-bottom: 3px; }

/* Direction cards (Step 4) */
.wz-dir-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.wz-dir-card {
  padding: 20px 16px; border-radius: 14px; cursor: pointer; text-align: center;
  background: rgba(var(--app-content-overlay-rgb),0.03); border: 2px solid rgba(var(--app-content-overlay-rgb),0.06);
  transition: all 0.25s;
}
@media (hover: hover) and (pointer: fine) {
.wz-dir-card:hover { border-color: rgba(var(--app-content-overlay-rgb),0.15); }
}
.wz-dir-card.selected.long { border-color: var(--app-primary); background: rgba(92,184,230,0.08); }
.wz-dir-card.selected.short { border-color: var(--app-sell); background: rgba(224,160,80,0.08); }
.wz-dir-icon { font-size: 28px; margin-bottom: 8px; }
.wz-dir-label { font-size: 16px; font-weight: 800; margin-bottom: 4px; }
.wz-dir-card.long .wz-dir-label { color: var(--app-primary); }
.wz-dir-card.short .wz-dir-label { color: var(--app-sell); }
.wz-dir-hint { font-size: 11px; color: var(--app-text-muted-2); }

/* Leverage & Amount (Step 5) */
.wz-field { margin-bottom: 16px; }
.wz-field-label { font-size: 12px; color: var(--app-text-muted-2); margin-bottom: 6px; font-weight: 600; }
.wz-leverage-wrap { display: flex; align-items: center; gap: 10px; }
.wz-lev-slider {
  flex: 1; -webkit-appearance: none; appearance: none; height: 6px;
  border-radius: 3px; outline: none; cursor: pointer;
  background: linear-gradient(90deg, #22c55e 0%, #eab308 40%, #ef4444 100%);
}
.wz-lev-slider::-webkit-slider-thumb {
  -webkit-appearance: none; width: 18px; height: 18px;
  border-radius: 50%; background: var(--app-text-1); border: 2px solid var(--app-primary);
  cursor: pointer; box-shadow: 0 0 6px rgba(92,184,230,0.4);
}
.wz-lev-value {
  min-width: 48px; text-align: center; font-size: 16px;
  font-weight: 800; color: var(--app-text-1);
}
.wz-risk-label {
  font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 4px;
  margin-top: 6px; display: inline-block;
}
.wz-risk-low { background: rgba(34,197,94,0.15); color: #22c55e; }
.wz-risk-med { background: rgba(234,179,8,0.15); color: #eab308; }
.wz-risk-high { background: rgba(239,68,68,0.15); color: #ef4444; }
.wz-risk-extreme { background: rgba(239,68,68,0.25); color: #ff4444; }

.wz-amount-input {
  width: 100%; padding: 10px 12px; border-radius: 8px;
  background: rgba(var(--app-content-overlay-rgb),0.04); border: 1px solid rgba(var(--app-content-overlay-rgb),0.08);
  color: var(--app-text-1); font-size: 15px; font-weight: 600;
  outline: none; box-sizing: border-box;
}
.wz-amount-input:focus { border-color: var(--app-primary); }
.wz-pct-btns { display: flex; gap: 6px; margin-top: 8px; }
.wz-pct-btn {
  flex: 1; padding: 6px; border-radius: 6px; font-size: 12px; font-weight: 700;
  background: rgba(var(--app-content-overlay-rgb),0.04); border: 1px solid rgba(var(--app-content-overlay-rgb),0.08);
  color: var(--app-text-muted-2); cursor: pointer; transition: all 0.15s;
}
@media (hover: hover) and (pointer: fine) {
.wz-pct-btn:hover { border-color: var(--app-primary); color: var(--app-primary); }
}
.wz-pct-btn.active { border-color: var(--app-primary); background: rgba(92,184,230,0.1); color: var(--app-primary); }

.wz-calc-row {
  display: flex; justify-content: space-between; padding: 6px 0;
  font-size: 12px; border-bottom: 1px solid rgba(var(--app-content-overlay-rgb),0.04);
}
.wz-calc-label { color: var(--app-text-muted-2); }
.wz-calc-value { color: var(--app-text-1); font-weight: 600; }

/* Review (Step 6) */
.wz-review-table { width: 100%; }
.wz-review-row {
  display: flex; justify-content: space-between; align-items: center;
  padding: 8px 0; border-bottom: 1px solid rgba(var(--app-content-overlay-rgb),0.04);
}
.wz-review-row:last-child { border-bottom: none; }
.wz-review-label { font-size: 12px; color: var(--app-text-muted-2); }
.wz-review-value { font-size: 13px; color: var(--app-text-1); font-weight: 600; }
.wz-review-total { font-size: 14px; font-weight: 800; color: var(--app-primary); }

.wz-info-note {
  font-size: 11px; color: var(--app-text-muted-2); background: rgba(92,184,230,0.06);
  border-left: 3px solid var(--app-primary); padding: 8px 10px; border-radius: 4px;
  margin-top: 12px; line-height: 1.4;
}

/* Footer */
.wizard-footer {
  display: flex; gap: 10px; padding: 12px 20px 16px;
  border-top: 1px solid rgba(var(--app-content-overlay-rgb),0.06);
}
.wizard-btn {
  flex: 1; padding: 10px; border-radius: 8px; font-size: 13px;
  font-weight: 700; cursor: pointer; transition: all 0.2s; border: none;
}
.wizard-btn-back {
  background: rgba(var(--app-content-overlay-rgb),0.06); color: var(--app-text-muted-2);
}
@media (hover: hover) and (pointer: fine) {
.wizard-btn-back:hover { background: rgba(var(--app-content-overlay-rgb),0.1); color: var(--app-text-1); }
}
.wizard-btn-back.hidden { visibility: hidden; }
.wizard-btn-next {
  background: linear-gradient(135deg, var(--app-primary), #4a9fd4); color: var(--app-text-white);
}
@media (hover: hover) and (pointer: fine) {
.wizard-btn-next:hover { background: linear-gradient(135deg, #6cc4f0, var(--app-primary)); }
}
.wizard-btn-next:disabled { opacity: 0.4; cursor: not-allowed; }
.wizard-btn-customize {
  background: rgba(92,184,230,0.12); color: var(--app-primary); border: 1px solid rgba(92,184,230,0.3);
}
@media (hover: hover) and (pointer: fine) {
.wizard-btn-customize:hover { background: rgba(92,184,230,0.2); border-color: var(--app-primary); }
}
.wizard-btn-next.submit {
  background: linear-gradient(135deg, #22c55e, #16a34a);
}
@media (hover: hover) and (pointer: fine) {
.wizard-btn-next.submit:hover { background: linear-gradient(135deg, #2dd468, #22c55e); }
}

/* Ultimo: the Trade Wizard modal is a DARK ISLAND (same rationale as the AI-chat
   panel in trade-option.css) — it must stay dark on Ultimo's light shell. Re-map
   the neutral tokens back to Vestex dark WITHIN the modal scope; all wz-* steps +
   header/footer use var(--app-*) so they flip to dark automatically. Brand accents
   (Ultimo gold) are left inherited. Scoped → Vestex zero-diff. (futures/equity) */
html[data-brand="ultimo"] .wizard-modal {
  --app-surface-1: #1a1a1f;
  --app-surface-2: #111827;
  --app-surface-card: #1a1a2e;
  --app-text-strong: #e2e8f0;
  --app-text-1: #e0e0e8;
  --app-text-muted: #8a94a6;
  --app-text-muted-2: #8a8a9a;
  --app-text-muted-3: #a8a8b8;
  --app-border: rgba(255, 255, 255, 0.06);
  --app-content-overlay-rgb: 255, 255, 255;
}
/* Ultimo: the Next CTA base rule gradients into a hardcoded blue (#4a9fd4 /
   #6cc4f0) that clashes with Ultimo gold once the modal is dark. Re-map ONLY on
   Ultimo to a clean gold gradient using accent tokens (Vestex base rule untouched
   → zero-diff). :not(.submit) so the final green "Place Order" submit state
   (.wizard-btn-next.submit) is NOT overridden — else this higher-specificity rule
   would clobber its green gradient on Ultimo. --app-primary-hover is gold on Ultimo. */
html[data-brand="ultimo"] .wizard-btn-next:not(.submit) {
  background: linear-gradient(135deg, var(--app-primary), var(--app-primary-hover));
}
@media (hover: hover) and (pointer: fine) {
html[data-brand="ultimo"] .wizard-btn-next:not(.submit):hover {
  background: linear-gradient(135deg, var(--app-primary-hover), var(--app-primary));
}
}

/* Live price display */
.wz-live-price {
  text-align: center; padding: 10px; margin-bottom: 14px;
  background: rgba(var(--app-content-overlay-rgb),0.03); border-radius: 8px;
}
.wz-live-price-val { font-size: 22px; font-weight: 800; color: var(--app-text-1); }
.wz-live-price-label { font-size: 11px; color: var(--app-text-muted-2); margin-top: 2px; }

/* Responsive */
@media (max-width: 768px) {
  .wizard-modal { width: 100%; max-width: calc(100vw - 32px); }
}
@media (max-width: 480px) {
  .wz-asset-grid { grid-template-columns: repeat(2, 1fr); }
  .wizard-modal { border-radius: 12px; }
  .wizard-body { padding: 12px 14px; }
  .wizard-header { padding: 12px 14px 10px; }
  .wizard-footer { padding: 10px 14px 12px; }
}

/* ============================================
   Custom Confirm / Alert Modal
   ============================================ */
.vestex-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.65);
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(4px);
  animation: vModalFadeIn .15s ease;
}
@keyframes vModalFadeIn { from { opacity: 0; } to { opacity: 1; } }

/* Brand-neutral by construction. The panel already follows the brand
   (var(--app-surface-2): #111827 on Vestex, #f5f5f7 on Ultimo's light shell),
   so every colour on top of it must follow too. Hardcoded near-white text here
   is why Ultimo showed an invisible title on a real-money confirmation.
   Unlike `.toast`, which bakes in a dark #1e1e32 panel and therefore has to
   re-map the neutrals, this dialog inherits the brand and needs no per-brand
   rule — including for brands that do not exist yet. */
.vestex-modal {
  background: var(--app-surface-2);
  border: 1px solid rgba(var(--app-content-overlay-rgb),.1);
  border-radius: 14px;
  padding: 28px 32px 24px;
  max-width: 400px;
  width: 90%;
  text-align: center;
  box-shadow: 0 12px 48px rgba(0,0,0,.5);
  animation: vModalSlide .2s ease;
}
@keyframes vModalSlide { from { transform: translateY(-10px) scale(.97); opacity: 0; } to { transform: none; opacity: 1; } }

.vestex-modal-icon {
  margin-bottom: 16px;
}
.vestex-modal-icon svg {
  width: 48px;
  height: 48px;
}

.vestex-modal-title {
  font-size: 16px;
  font-weight: 600;
  color: var(--app-text-strong);
  margin-bottom: 8px;
}

.vestex-modal-body {
  font-size: 13px;
  color: var(--app-text-muted);
  line-height: 1.6;
  margin-bottom: 24px;
}

.vestex-modal-actions {
  display: flex;
  gap: 10px;
  justify-content: center;
}

.vestex-modal-btn {
  padding: 10px 24px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  border: none;
  transition: background .15s, opacity .15s;
  min-width: 100px;
}
@media (hover: hover) and (pointer: fine) {
.vestex-modal-btn:hover { opacity: .9; }
}

.vestex-modal-btn.btn-cancel {
  background: rgba(var(--app-content-overlay-rgb),.06);
  color: var(--app-text-muted);
  border: 1px solid rgba(var(--app-content-overlay-rgb),.1);
}
@media (hover: hover) and (pointer: fine) {
.vestex-modal-btn.btn-cancel:hover {
  background: rgba(var(--app-content-overlay-rgb),.1);
  color: var(--app-text-1);
}
}

.vestex-modal-btn.btn-danger {
  background: var(--app-sell);
  color: #0a0e17;
}
@media (hover: hover) and (pointer: fine) {
.vestex-modal-btn.btn-danger:hover {
  background: #e8b060;
}
}

.vestex-modal-btn.btn-primary {
  background: var(--app-primary);
  color: var(--app-primary-fg);
}

.vestex-modal-btn.btn-error {
  background: rgba(248,81,73,.15);
  color: #f85149;
  border: 1px solid rgba(248,81,73,.2);
}

/* ============================================
   Shared Instrument Symbol Dropdown
   Used by Futures / Options / Equity pages
   (Spot has its own spot-symbol-* classes)
   ============================================ */
.inst-symbol-selector {
  position: relative;
  display: inline-block;
}

.inst-symbol-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  color: inherit;
}

.inst-symbol-btn .inst-bar-symbol {
  margin: 0;
}

.inst-symbol-btn svg {
  color: #5a5a6a;
  transition: transform 0.2s;
  flex-shrink: 0;
}

/* Futures2 (/trade-futures) reuses this selector for its instrument picker.
   With a single offered instrument the button is DISABLED and must read as the
   static heading it replaces — no pointer affordance for a control that does
   nothing. v1 never disables this button, so this rule is inert there. */
.inst-symbol-btn:disabled {
  cursor: default;
}

.inst-symbol-selector.open .inst-symbol-btn svg {
  transform: rotate(180deg);
}

.inst-symbol-dropdown {
  display: none;
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  width: 340px;
  max-height: 460px;
  background: #1a1f2e;
  border: 1px solid rgba(var(--app-content-overlay-rgb),0.1);
  border-radius: 8px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.5);
  z-index: 100;
  overflow: hidden;
  flex-direction: column;
}

.inst-symbol-selector.open .inst-symbol-dropdown {
  display: flex;
}

.inst-symbol-search {
  width: 100%;
  background: rgba(var(--app-content-overlay-rgb),0.04);
  border: none;
  border-bottom: 1px solid rgba(var(--app-content-overlay-rgb),0.06);
  padding: 12px 14px;
  color: var(--app-text-1);
  font-size: 13px;
  font-family: inherit;
  outline: none;
  box-sizing: border-box;
}

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

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

.inst-symbol-tabs {
  display: flex;
  gap: 4px;
  padding: 6px 10px;
  border-bottom: 1px solid rgba(var(--app-content-overlay-rgb),0.06);
  background: rgba(var(--app-content-overlay-rgb),0.02);
  flex-wrap: wrap;
}

.inst-symbol-tab {
  background: none;
  border: none;
  color: var(--app-text-muted-2);
  padding: 5px 10px;
  font-size: 12px;
  border-radius: 4px;
  cursor: pointer;
  font-family: inherit;
  transition: background 0.1s, color 0.1s;
}

@media (hover: hover) and (pointer: fine) {
.inst-symbol-tab:hover {
  color: var(--app-text-1);
  background: rgba(var(--app-content-overlay-rgb),0.04);
}
}

.inst-symbol-tab.active {
  color: var(--app-primary);
  background: rgba(92,184,230,0.1);
}

.inst-symbol-list {
  flex: 1;
  overflow-y: auto;
  max-height: 380px;
}

.inst-symbol-list::-webkit-scrollbar {
  width: 3px;
}

.inst-symbol-list::-webkit-scrollbar-thumb {
  background: rgba(92, 184, 230, 0.3);
  border-radius: 2px;
}

.inst-dd-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  cursor: pointer;
  transition: background 0.1s;
  gap: 8px;
}

@media (hover: hover) and (pointer: fine) {
.inst-dd-item:hover {
  background: rgba(var(--app-content-overlay-rgb),0.04);
}
}

.inst-dd-item.active {
  background: rgba(92,184,230,0.08);
}

.inst-dd-item-left {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  flex: 1;
}

.inst-dd-item-icon {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  font-weight: 700;
  color: #0a0e17;
}

.inst-dd-item-symbol {
  font-size: 13px;
  font-weight: 600;
  color: var(--app-text-1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.inst-dd-item-sub {
  font-size: 11px;
  color: #6a6a7a;
  font-weight: 400;
  margin-left: 6px;
}

/* `.inst-dd-item-margin` — the per-row `Margin: BTC` chip — was DELETED here
   (owner ruling 2026-08-07), not merely unrendered. The page IS the margin
   group, so the chip said the same thing on every row of a page while being
   the one `flex-shrink: 0` element in the name cell — it took the width the
   contract name needed to say something that varied. The identity lives on the
   heading chip (`.type-tag.margin-tag` / `#instMarginTag`) and on every other
   §5 surface. Dead style left behind is a style somebody re-attaches. */

.inst-dd-item-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  flex-shrink: 0;
}

.inst-dd-item-price {
  font-size: 13px;
  color: var(--app-text-muted-3);
  font-variant-numeric: tabular-nums;
}

.inst-dd-item-change {
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.inst-dd-item-change.positive { color: var(--app-buy); }
.inst-dd-item-change.negative { color: var(--app-sell); }

/* ---- Futures2 RICH instrument picker (/trade-futures only) ------------------
   The v2 controller adds .inst-picker-rich to its dropdown when more than one
   instrument is offered; v1's plain dropdown never gains the class, so every
   rule below is inert there. The panel is a full-width selector: chip rows
   (base coin / favourites, lifecycle / expiry), a search box, and a small
   table (label · time left · last price · 24h change · 24h volume) that
   scrolls INTERNALLY — the page never scrolls sideways for it. */

/* ONE PANEL WIDTH FOR BOTH SHAPES (2026-08-18). The chooser used to be 560px
   and the ladder 680px, through a `:has(.inst-picker-list-ladder)` override
   that is now DELETED rather than left declaring the same number twice.

   680 is not a widening for its own sake — it is what pays for the chooser's
   new TIME LEFT column WITHOUT taking anything from the contract name. At 560
   the chooser's five tracks left the name ~245px; at 680 its six tracks leave
   it ~267px. The column is added and the row's primary key comes out AHEAD,
   which is the only version of "add a column" this panel accepts (see the floor
   note below and bug #499), and the geometry test in
   futures2-picker-mobile-polish.test.js pins that comparison so it cannot
   quietly stop being true. The ladder's own layout is unchanged — it was
   already 680 and keeps all five of its columns at every rung it had. */
.inst-symbol-dropdown.inst-picker-rich {
  width: min(680px, calc(100vw - 24px));
  max-width: calc(100vw - 24px);
  max-height: min(540px, 72vh);
}

.inst-picker-chips {
  row-gap: 4px;
}

/* THE NAME TRACK HAS A FLOOR, and the header and the rows declare the SAME
   tracks — they are two separate `grid-template-columns` and a change to one
   without the other misaligns every column silently.

   `minmax(180px, …)` rather than `minmax(0, …)` is the load-bearing part. An
   `fr` track is free to be squeezed below its own content, and a grid item's
   `min-width: auto` does not save it, so the contract name — the row's PRIMARY
   KEY — collapsed to `B.` and `B..` while fixed numeric tracks kept every pixel
   they asked for. Two rows rendering as `B.` and `B..` are indistinguishable on
   a page whose entire purpose is telling similarly-named contracts apart, so
   the name gets the floor and the NUMERIC columns are what drop at narrow
   widths (see the media queries below). */
.inst-picker-head {
  display: grid;
  grid-template-columns: 28px minmax(150px, 1fr) 96px 88px 60px 68px;
  gap: 8px;
  align-items: center;
  padding: 8px 14px 4px;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: #6a6a7a;
}

.inst-dd-item.inst-picker-row {
  display: grid;
  grid-template-columns: 28px minmax(150px, 1fr) 96px 88px 60px 68px;
  gap: 8px;
  align-items: center;
}

.inst-picker-head span:nth-child(n+3),
.inst-picker-row .inst-dd-item-price,
.inst-picker-row .inst-dd-item-change,
.inst-picker-row .inst-dd-item-vol {
  text-align: right;
}

/* WITHIN the name cell, the shrink order is explicit — because without one the
   children shrank together and the SYMBOL, the only part that identifies the
   contract, lost width to a descriptive label that merely repeats it.

   THE ORDER, AND WHAT HAPPENS PAST THE END OF IT (bug #499, second half). The
   sub-label yields first and effectively alone: flex distributes shrinkage in
   proportion to `shrink factor x base width`, so a factor of 200 against the
   symbol's 1 means the label is exhausted before the symbol gives up a pixel.

   But the symbol's factor is 1, NOT 0, and that is the deliberate part. An
   unshrinkable child in a cell narrower than its content does not stay inside
   the cell — it OVERFLOWS it and paints over the next column. That is exactly
   what the owner saw: the `Margin:` chip was `flex-shrink: 0`, the track had no
   floor, and the chip rendered ON TOP of the expiry text in the neighbouring
   column. Both of those are gone, and this is the guarantee that the same
   failure cannot come back through a different child: past the floor the symbol
   ellipsises INSIDE its own cell. Truncated-but-contained is recoverable and
   legible; painted-over-the-neighbour is two facts in one place and neither is
   readable. The floors above are what stop it reaching that point at all. */
.inst-picker-row .inst-dd-item-symbol {
  flex: 0 1 auto;
  min-width: 0;
}

.inst-picker-row .inst-dd-item-sub {
  flex: 1 200 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* SPACING COMES FROM THE FLEX `gap`, NOT FROM MARGINS ON THE CHILDREN.
     A `margin-left` survives its element being ellipsised to zero width, so a
     collapsed sub-label was still charging for space it no longer occupied.
     The gap only applies BETWEEN items that are actually there. */
  margin-left: 0;
}

.inst-picker-row .inst-dd-item-open {
  margin-left: 0;
}

.inst-dd-item-vol {
  font-size: 12px;
  color: var(--app-text-muted-3);
  font-variant-numeric: tabular-nums;
}

.inst-fav-btn {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  padding: 2px;
  color: #6a6a7a;
  font-family: inherit;
}

@media (hover: hover) and (pointer: fine) {
.inst-fav-btn:hover {
  color: var(--app-text-1);
}
}

.inst-fav-btn.fav {
  color: var(--app-sell);
}

.inst-picker-empty {
  padding: 20px 14px;
  font-size: 12px;
  color: #6a6a7a;
  text-align: center;
}

.inst-picker-list {
  max-height: 340px;
}

/* MARGIN SPLIT — the picker has two shapes, one per page.
   ---------------------------------------------------------------------------
   The grid above is the ASSET CHOOSER (USDT Margin): star, name, TIME LEFT,
   price, 24h, volume — SIX columns. The TERM LADDER (BTC Margin) is the same
   list minus `24h`, which it has never carried and should not: every rung there
   is written on one underlying, so that number would repeat itself down the
   whole column. Across the chooser's nineteen bases it varies and is one of the
   two things an asset is chosen on.

   THE FIRST THREE TRACKS ARE DELIBERATELY IDENTICAL — star, name, TIME LEFT, at
   28 / floor-150 / 96. It is not tidiness: `refreshPickerCountdowns` reaches
   the countdown cell by INDEX 2 on both shapes, and one painter
   (`paintTimeLeftCell`) writes it for both. Move the column on one page and the
   live countdown on that page silently stops re-reading the clock — bug #500,
   which is the reason the mechanism exists at all.

   WHY THE CHOOSER HAS TIME LEFT (2026-08-18). Because most of its rows have an
   expiry and the panel was not showing it. The linear offer is majority dated;
   those rows simply sort low, the list being volume-ordered and a far-dated
   book trading thinly, so the omission did not show up in a screenshot. The
   date is in the served label already — the countdown is its ACTIONABLE form,
   the same distinction the ladder's column was built on.

   PAID FOR BY WIDTH, NOT BY THE NAME. See the single 680px panel width above:
   the chooser's name cell comes out WIDER after the column than before it.

   NO EXPIRY-DATE COLUMN (owner ruling 2026-08-07). It used to sit here at a
   fixed 190px and it was a restatement three times over: the contract name
   carries the date (`BTC-14AUG26`), `TIME LEFT` carries the actionable form,
   and spec §4 puts the full `Expires … UTC / … JST` stamp on the SELECTED
   instrument panel. The full stamp now also lives on each row's `title`. See
   `pickerLadderRowEl` in trading-futures-v2.js for the same note from the
   markup side.

   THE LADDER HAS NO EXPIRY CHIP ROW either (same ruling). Ten rows, already
   ordered by expiry: eleven filter chips above them would be clutter, not
   navigation. The ladder IS the expiry navigation.

   DENSITY, NOT PADDING: the answer to "there are only ten of them" is that each
   row says what it costs, how much trades there, how long it has left and
   whether the customer is already in it — not a short list stretched to fill a
   panel. */

/* The ladder's `:has(.inst-picker-list-ladder)` WIDTH override lived here and
   is GONE: both shapes now take the single 680px width declared above, so the
   rule restated a number rather than changing one. It also carried higher
   specificity than the plain compound, which forced every later width rule
   (the phone sheet's included) to name both selectors to beat it. One width,
   one selector, one thing for the sheet to override. */

/* The ladder shape is carried by a CLASS on the row, not inferred from a child
   cell. The old selector was `:has(.inst-dd-item-expiry)` — the very cell the
   ruling above deletes — so removing the column would have silently reverted
   every ladder row to the asset chooser's tracks.

   THE VOLUME TRACK IS 68px, NOT 72 (2026-08-18, and this is a fix, not a
   preference). These five tracks have to survive all the way down to a 521px
   viewport, where the panel is 497px and 495 of that is usable once the border
   comes off. At 72 they wanted 497 including the list's 3px scrollbar — two
   pixels of the Volume column were being clipped by the panel's
   `overflow: hidden` at the bottom of this rung's range, on every ladder,
   since the 640px rung was removed. `900.00M` is ~50px at 12px tabular-nums,
   so 68 is still generous. Found by the geometry test in
   futures2-picker-mobile-polish.test.js, which does this arithmetic for every
   rung of both shapes rather than trusting a comment. */
.inst-picker-head-ladder,
.inst-dd-item.inst-picker-row.inst-picker-row-ladder {
  grid-template-columns: 28px minmax(150px, 1fr) 96px 88px 68px;
}

.inst-picker-head-ladder span:nth-child(n+3),
.inst-picker-row .inst-dd-item-left-time {
  text-align: right;
}

.inst-dd-item-left-time {
  font-size: 12px;
  color: var(--app-text-2, #8a8a9a);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ESCALATION inside the final 24h, and again once new entries are refused.
   Both phases come from the SERVED clock snapped to whole minutes, so the
   styling cannot flicker back and forth across a re-render boundary. */
.inst-dd-item-left-time.expiry-soon {
  color: var(--app-sell);
  font-weight: 600;
}

.inst-dd-item-left-time.expiry-closed,
.inst-dd-item-left-time.expiry-expired {
  color: var(--app-sell);
  font-weight: 700;
  white-space: normal;
}

/* "You already have money here." The single most common reason to reopen this
   menu, so it is marked — and, on the asset chooser, sorted first. */
.inst-dd-item-open {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--app-buy);
  background: rgba(92, 184, 230, 0.16);
  border-radius: 4px;
  padding: 2px 6px;
  margin-left: 6px;
  white-space: nowrap;
  flex-shrink: 0;
}

/* CROSS-GROUP NAVIGATION HINT — a link rendered among the results, never a
   result. It is deliberately NOT styled as a row: it must not read as
   something that can be traded, and the keyboard handler branches on the row's
   explicit type rather than on how it looks. */
.inst-dd-item.inst-picker-hint {
  display: block;
  padding: 10px 14px;
  font-size: 12px;
  font-weight: 600;
  color: var(--app-primary);
  background: rgba(92, 184, 230, 0.06);
  border-top: 1px solid var(--app-border, rgba(255, 255, 255, 0.06));
  cursor: pointer;
}

@media (hover: hover) and (pointer: fine) {
.inst-dd-item.inst-picker-hint:hover {
  background: rgba(92, 184, 230, 0.12);
}
}

/* SINGLE ROW, HORIZONTAL SCROLL — never a wrap.
   ---------------------------------------------------------------------------
   `.inst-symbol-tabs` sets `flex-wrap: wrap` for the v1 page, and with nineteen
   base coins that produced the three-line block of chips the redesign exists to
   remove. This is a longer selector so it wins at every width, and it is
   restated inside the media queries below because that is where a later edit
   would most easily reintroduce the wrap.

   `flex-shrink: 0` IS THE ROW'S HEIGHT FLOOR (bug #514). `overflow-y: hidden`
   zeroes a flex item's automatic minimum size, so inside the panel's
   height-capped column (`.inst-symbol-dropdown`, max-height min(540px, 72vh))
   this row was the ONE item free to shrink below its content — and on a short
   viewport a full 19-row list pushed the panel to its cap and the chips
   collapsed to a bare 4px horizontal scrollbar until a search narrowed the
   list. The LIST is the panel's scroll region; it is what yields, never a
   fixed row of controls. */
.inst-symbol-tabs.inst-picker-chips-scroll {
  flex-wrap: nowrap;
  flex-shrink: 0;
  overflow-x: auto;
  overflow-y: hidden;
  row-gap: 0;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
  /* #552(c): A SCROLL CUE THAT ONLY SHOWS WHEN THERE IS SOMETHING TO SCROLL TO.
     The classic four-layer trick: two COVER gradients painted in the panel
     background sit at the edges with `background-attachment: local`, so they
     travel WITH the content; two SHADOW gradients sit at the same edges with
     `scroll`, pinned to the box. At either end of the scroll range the local
     cover slides exactly over its shadow and hides it; the moment content
     extends past an edge the cover has moved away and the shadow shows — a
     fade cue with no JS, no extra DOM, and no resize observers to forget.
     The cover colour is the panel's own background (#1a1f2e above), which is
     what makes the hide exact. */
  background:
    linear-gradient(90deg, #1a1f2e 40%, rgba(26, 31, 46, 0)) left center / 26px 100% no-repeat,
    linear-gradient(270deg, #1a1f2e 40%, rgba(26, 31, 46, 0)) right center / 26px 100% no-repeat,
    linear-gradient(90deg, rgba(var(--app-content-overlay-rgb), 0.16), rgba(var(--app-content-overlay-rgb), 0)) left center / 14px 100% no-repeat,
    linear-gradient(270deg, rgba(var(--app-content-overlay-rgb), 0.16), rgba(var(--app-content-overlay-rgb), 0)) right center / 14px 100% no-repeat;
  background-attachment: local, local, scroll, scroll;
}

.inst-symbol-tabs.inst-picker-chips-scroll::-webkit-scrollbar {
  height: 4px;
}

.inst-symbol-tabs.inst-picker-chips-scroll::-webkit-scrollbar-thumb {
  background: rgba(var(--app-content-overlay-rgb), 0.18);
  border-radius: 2px;
}

/* A chip must keep its own width rather than being squeezed to fit the row —
   squeezing is wrapping by another name. */
.inst-symbol-tabs.inst-picker-chips-scroll > * {
  flex: 0 0 auto;
  white-space: nowrap;
}

/* #57: A DATED CONTRACT THE VENUE HAS NOT TRADED YET SAYS SO. The row's price
   cell renders "No price yet" (see pickerPriceCell) — muted but LEGIBLE, a
   deliberate statement rather than the data-hole a lone dim dash reads as. */
.inst-dd-item-price.inst-dd-item-no-price {
  color: var(--app-text-2, #8a8a9a);
  font-size: 11px;
  font-weight: 500;
  white-space: nowrap;
}

/* A NEVER-TRADED CONTRACT STILL HAS A PRICE — the venue's MARK, and it must
   never be mistaken for a trade. The styling carries HALF the distinction and
   the wording carries the other half (see pickerPriceCell): this rule mutes the
   cell to the SAME colour as the "No price yet" state above, deliberately, so a
   customer scanning the column sees at a glance which rows carry a real last
   trade (bright, --app-text-muted-3) and which carry a reference price (muted)
   — WITHOUT having to read the '≈' or the tag. Reading them then says exactly
   which price it is.

   The number keeps the price cell's 13px and tabular figures, because its whole
   value is being COMPARABLE down the column: the spread across expiries is the
   term structure, and it only reads as term structure if the digits line up. */
.inst-dd-item-price.inst-dd-item-mark-price {
  color: var(--app-text-2, #8a8a9a);
  font-weight: 500;
  white-space: nowrap;
}

/* The tag rides SMALLER than its number — it labels the figure, it is not
   competing with it — and it lives inside the price span so every rung that
   drops the price column drops the tag with it, automatically. */
.inst-dd-item-mark-tag {
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.02em;
  opacity: 0.8;
}

/* NOBODY IS QUOTING THIS CONTRACT — the one row state that is a WARNING rather
   than a data state, and the only one styled as such.

   It is deliberately the OPPOSITE treatment to the two muted states above.
   "No price yet" and the mark are both muted BECAUSE they are less than a real
   trade — quieter information, quieter styling. "No market" is not less
   information, it is a reason not to click, so it takes the same amber
   (--app-sell) and weight the expiry escalation uses a few rules up. One
   caution vocabulary on this panel, not two: a customer who has learned that
   amber-on-a-row means "read this before you act" gets the same signal here.

   NOT RED. A contract nobody quotes is not an error and not a delisting — it is
   a live instrument waiting for a maker, and it may have a book again in an
   hour. Amber says "look"; red would say "broken", which would be a lie about
   the instrument and would make the panel look alarming on what is, for a
   far-dated expiry, an entirely ordinary condition. */
.inst-dd-item-price.inst-dd-item-no-market {
  color: var(--app-sell);
  font-weight: 600;
  white-space: nowrap;
}

/* THE ROW RECEDES AS A UNIT. The cell carries the words; this carries the
   shape, and the shape is what a customer actually reads while scanning 55
   rows. Dimming the whole row — name, countdown, volume — is what stops the
   eye on the way past; without it the warning only exists for someone already
   looking at the price column, which is precisely the customer who did not
   need it.

   TUNED TO RECEDE, NOT TO DISAPPEAR: at 0.62 the row is plainly still there,
   still readable, still selectable. The instrument is real and someone may be
   watching it for a market to appear, so this must never read as "removed" —
   only as "not this one". The price cell is exempted back to full strength so
   the amber warning is not dimmed by the very rule that frames it. */
.inst-picker-row.inst-picker-row-no-market {
  opacity: 0.62;
}

.inst-picker-row.inst-picker-row-no-market .inst-dd-item-no-market {
  opacity: 1;
}

/* Hover lifts the row — the customer has singled it out deliberately, and a row
   they are pointing at should be legible while they read the tooltip that
   explains why it is flagged.

   GUARDED, like every other :hover on this page (#530). On a touch device
   `:hover` latches after a tap and does not clear, so an unguarded rule would
   leave the row permanently un-dimmed on the phone — quietly deleting the
   scanning half of the warning for the customers most likely to be scanning. */
@media (hover: hover) and (pointer: fine) {
  .inst-picker-row.inst-picker-row-no-market:hover {
    opacity: 0.85;
  }
}

/* #552(a): THE SHEET BAR — title + close for the phone-width full-screen
   sheet. In the DOM it is the panel's LAST child (the [search, chips, head,
   list] order is indexed by the keyboard wiring and pinned by tests); at
   phone widths `order: -1` lifts it to the top of the open panel's flex
   column. Desktop never shows it — the rules that show it live in the phone
   rung's own media block below. */
.inst-picker-sheet-bar {
  display: none;
}

/* NARROWING DROPS A NUMERIC COLUMN — never the contract name.
   ---------------------------------------------------------------------------
   A number a customer can look up elsewhere is worth less than the name of the
   thing they are about to trade. `TIME LEFT` survives every rung on both shapes
   because it is the only column that EXPIRES, and the only one not restated on
   the ticker bar the moment a row is chosen — `Last Price`, `24h` and `Volume`
   all are. So the drop order is, narrowing: Volume, then 24h, then Last Price.

   THE 640px RUNG IS BACK, and the note that removed it was right at the time.
   It was deleted when dropping the per-row `Margin:` chip took ~82px out of the
   name cell's minimum and the five-column ladder began fitting every viewport
   down to 520 — "a width that quietly hides a column early" is exactly what a
   rung with nothing to do is. The chooser's sixth column gives it something to
   do again: six tracks need a 564px panel, which a viewport narrower than
   ~588px cannot offer, and past that point the grid would overflow its own
   panel rather than squeeze (the name track has a px floor, deliberately). The
   rung is chooser-only — the ladder is five columns and still fits to 520.

   EVERY CHOOSER GRID ON THIS LADDER IS `:not(...-ladder)`-SCOPED, at 640, 520
   and 400 alike, so the three rungs carry EQUAL specificity and plain source
   order decides which wins. The 520 rung's chooser rule used to be the bare
   compound; a higher-specificity rule at 640 would then have beaten it at phone
   widths and the sixth column would have survived onto a 380px screen. Same
   class of silent half-override the 400px rung's `:not()` was written for. */

/* Small-desktop / tablet. CHOOSER ONLY: it loses Volume, the first of the three
   restated-elsewhere numbers, leaving star · name · time left · price · 24h.
   The ladder is untouched here — it has five columns, not six, and they fit.

   THE SURVIVING TRACKS ARE THE BASE TRACKS, byte for byte, with the sixth
   simply removed. A rung that also re-tunes the widths it keeps is a second
   design to hold in your head, and the arithmetic says it is unnecessary: at
   the bottom of this rung's range (a 521px viewport) the panel is 497px, of
   which 495 survives the border and 464 the row padding and the list's 3px
   scrollbar — against 454 needed. Ten pixels spare, so nothing has to be
   shaved. (`box-sizing: border-box` comes from the global `*` rule in
   style.css; the geometry test in futures2-picker-mobile-polish.test.js does
   this sum for every rung of both shapes.) */
@media (max-width: 640px) {
  .inst-picker-head:not(.inst-picker-head-ladder),
  .inst-dd-item.inst-picker-row:not(.inst-picker-row-ladder) {
    grid-template-columns: 28px minmax(150px, 1fr) 96px 88px 60px;
  }
  /* Chooser head: 1 '' · 2 Instrument · 3 Time left · 4 Last Price · 5 24h ·
     6 Volume. Only 6 goes. */
  .inst-picker-head:not(.inst-picker-head-ladder) span:nth-child(6),
  .inst-picker-row:not(.inst-picker-row-ladder) .inst-dd-item-vol {
    display: none;
  }
}

/* Phone widths. The CHOOSER additionally loses 24h (star · name · time left ·
   price); the LADDER loses Volume and Last Price (star · name · time left).
   #552(a) rides the same rung: the panel stops being a dropdown squeezed into
   the viewport and becomes a full-screen sheet, with the sheet bar (title + ✕,
   built by renderPicker, display:none on desktop) lifted to the top via
   order:-1. */
@media (max-width: 520px) {
  .inst-picker-head:not(.inst-picker-head-ladder),
  .inst-dd-item.inst-picker-row:not(.inst-picker-row-ladder) {
    grid-template-columns: 24px minmax(110px, 1fr) 96px 84px;
  }
  /* Unscoped on purpose — this hides the SAME NUMBERS on both shapes, and the
     shapes differ only in what sits at 5. Chooser: 5 = 24h, 6 = Volume, both
     go. Ladder: 5 = Volume, goes. `.inst-dd-item-change` exists on chooser rows
     only, `.inst-dd-item-vol` on both. */
  .inst-picker-head span:nth-child(n+5),
  .inst-picker-row .inst-dd-item-change,
  .inst-picker-row .inst-dd-item-vol {
    display: none;
  }
  .inst-picker-head-ladder,
  .inst-dd-item.inst-picker-row.inst-picker-row-ladder {
    grid-template-columns: 24px minmax(110px, 1fr) 96px;
  }
  /* Ladder head: 4 = Last Price, 5 = Volume. Both go. */
  .inst-picker-head-ladder span:nth-child(n+4),
  .inst-picker-row-ladder .inst-dd-item-price {
    display: none;
  }
  /* #552(a): FULL-SCREEN SHEET. ONE selector now — both shapes share the single
     680px desktop width above, so the ladder's higher-specificity `:has()`
     variant that this rule used to have to name alongside the plain compound is
     gone with it. The list becomes the sheet's one scroll region. */
  .inst-symbol-dropdown.inst-picker-rich {
    position: fixed;
    inset: 0;
    top: 0;
    left: 0;
    width: 100vw;
    max-width: none;
    height: 100%;
    max-height: none;
    border-radius: 0;
    border: none;
    z-index: 1000;
  }
  .inst-symbol-dropdown.inst-picker-rich .inst-picker-list {
    flex: 1;
    max-height: none;
  }
  .inst-picker-sheet-bar {
    display: flex;
    order: -1;
    align-items: center;
    justify-content: space-between;
    flex-shrink: 0;
    padding: 12px 14px;
    border-bottom: 1px solid rgba(var(--app-content-overlay-rgb), 0.08);
  }
  .inst-picker-sheet-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--app-text-1);
  }
  .inst-picker-sheet-close {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--app-text-2, #8a8a9a);
    font-size: 16px;
    line-height: 1;
    padding: 6px 8px;
    font-family: inherit;
  }
}

/* #552(b): ONE MORE RUNG DOWN THE SAME LADDER — the smallest phones. Four
   tracks do not fit here: star · name · time left · price needs a 366px panel
   and a 320px phone offers 292px, so the grid would overflow rather than
   squeeze. The name has a px floor and keeps it (ULT-MARGIN-35 was the reverse
   failure — a secondary column squeezing the name toward that floor).

   SO LAST PRICE GOES, and the choice between it and TIME LEFT is the one this
   whole ladder has been making at every rung: the price is on the ticker bar
   the instant a row is chosen, and the countdown is on nothing else. It is also
   the choice the LADDER already made at its own 520px rung, for the same
   reason — so at the narrowest width the two shapes land on the IDENTICAL three
   tracks, which is where a chooser and a ladder should agree if they agree
   anywhere.

   THE COST, STATED: a perpetual row's countdown cell reads `n/a`, so on the
   smallest phones a perpetual shows its name and `n/a` and nothing else. That
   is the price of one convention instead of two — `paintTimeLeftCell` renders
   the same `n/a` the ladder has always rendered for BTC-PERP, and a countdown
   column left BLANK on perpetuals would read as a data hole, the exact
   distinction `pickerPriceCell` keeps three states to avoid.

   The ladder shape is already at its 3-track floor and is untouched here. */
@media (max-width: 400px) {
  /* `:not(...-ladder)` is load-bearing: the ladder head carries BOTH classes
     at equal specificity, so a bare `.inst-picker-head` here — declared later
     — would win the cascade and shear the ladder's head off its rows' 96px
     track. The rows never had that problem (their ladder selector carries
     three classes), which is exactly the silent half-override to refuse. */
  .inst-picker-head:not(.inst-picker-head-ladder),
  .inst-dd-item.inst-picker-row:not(.inst-picker-row-ladder) {
    grid-template-columns: 24px minmax(110px, 1fr) 96px;
  }
  /* Chooser head: 4 = Last Price (5 = 24h and 6 = Volume went at the rungs
     above). Scoped off the ladder, whose own price cell was already hidden at
     the 520px rung by its own rule — two rules for one cell is how a later
     edit removes one of them and cannot tell which. */
  .inst-picker-head:not(.inst-picker-head-ladder) span:nth-child(4),
  .inst-picker-row:not(.inst-picker-row-ladder) .inst-dd-item-price {
    display: none;
  }
}

/* Restated at mobile width, where the shared rule's `flex-wrap: wrap` would do
   the most damage: nineteen base chips wrapped onto four lines pushes the list
   itself off the screen. */
@media (max-width: 720px) {
  .inst-symbol-tabs.inst-picker-chips-scroll {
    flex-wrap: nowrap;
    flex-shrink: 0;
    overflow-x: auto;
  }
}

.inst-dd-empty {
  padding: 20px 14px;
  text-align: center;
  color: #6a6a7a;
  font-size: 12px;
}

/* BUG #85: Stop order — Stop Price (trigger) field */
.trigger-basis-note {
  color: #6a6a7a;
  font-size: 10px;
  font-weight: 400;
  margin-left: 6px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
}
#stopPxField .order-input {
  /* Match priceInput styling so the two fields look symmetric */
  font-variant-numeric: tabular-nums;
}
#stopPxTickHint {
  font-variant-numeric: tabular-nums;
}

/* Ultimo: futures contract dropdown = dark-island (raw #1a1f2e). Re-map content
   tokens to light-on-dark (symbol/search/placeholder flipped dark = invisible),
   same as the spot pair dropdown. Scoped → vestex zero-diff. audit 2026-06-25 */
html[data-brand="ultimo"] .inst-symbol-dropdown {
  --app-text-strong: #e2e8f0;
  --app-text-1: #e0e0e8;
  --app-text-muted: #8a94a6;
  --app-text-muted-2: #8a8a9a;
  --app-text-muted-3: #a8a8b8;
  --app-content-overlay-rgb: 255, 255, 255;
}
html[data-brand="ultimo"] .inst-symbol-search::placeholder { color: #8a8a9a; }

/* Ultimo: positions table data cells used raw #c8c8d8 (light gray, for dark theme)
   → faint/invisible on the light bg. Make them dark/readable. audit 2026-06-25 */
html[data-brand="ultimo"] .pos-table tbody td { color: var(--app-text-1); }

/* Close-only / equity-off notice — shown as a POPUP on the Long/Short submit
   click while the runtime gate is ON (manager 2026-07-24; replaced the former
   top-of-form banner). Reuses the order-confirm overlay for a consistent modal. */
.closeonly-popup-modal {
  max-width: 380px;
  text-align: left;
  padding: 22px 22px 18px;
}
.closeonly-popup-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--app-text-strong);
  margin-bottom: 10px;
  padding-left: 10px;
  border-left: 3px solid #e0a050;
}
.closeonly-popup-body {
  font-size: 13px;
  line-height: 1.6;
  color: var(--app-text-1);
  margin: 0 0 18px;
}
.closeonly-popup-ok {
  display: block;
  width: 100%;
  padding: 10px 14px;
  border: none;
  border-radius: 10px;
  background: var(--app-primary);
  color: var(--app-primary-fg);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
.closeonly-popup-ok:hover { background: var(--app-primary-hover); }
}

/* Futures2 picker trigger — the catalog opener beside the symbol h1.
   SCOPED TO #instPicker, which only v2 renders: v1's selector is
   #instSymbolSelector and keeps its own layout untouched (there, the h1 lives
   INSIDE the button and the caret trails it).

   v2 keeps the h1 OUTSIDE the button on purpose — with a single offered
   instrument the trigger is display:none and the row must render as a plain
   static heading, not a dead button. Two siblings in an inline-block would
   stack, so the container is a flex row and the caret precedes the name. */
#instPicker {
  display: flex;
  align-items: center;
  gap: 8px;
}
#instPicker .inst-symbol-btn { flex: none; }

/* #22: the v2 trigger is ICON-ONLY — a 14x14 caret in a `padding: 0` button
   (.inst-symbol-btn, line ~1201), i.e. a 14px touch target on the control that
   opens the contract catalog. 44px box at touch widths, caret centred inside
   it; the <svg> itself is untouched, so nothing about the trigger's look
   changes except the invisible area around it. Scoped to #instPicker: v1's
   selector (#instSymbolSelector) wraps the whole h1 and is already far larger,
   and must not be re-boxed. Inert while a single instrument is offered (the
   controller keeps the button display:none) — it matters the moment a second
   contract is offered and the caret appears. */
@media (max-width: 768px) {
  #instPicker .inst-symbol-btn {
    min-width: 44px;
    min-height: 44px;
    justify-content: center;
  }
}

/* ============================================================
   Futures2 heading bar — RESPONSIVE, scoped to body.futures2-page
   ============================================================
   v2 added a margin badge ("Margin: BTC" / "Margin: USDT") to tell two
   same-named instruments apart, and a description. The shared `.instrument-bar`
   is `justify-content: space-between` with NO wrap and NO min-width:0, so the
   extra width had nowhere to go: the symbol broke mid-word ("BTC-" / "PERP"),
   the description collapsed into a narrow 3-line column, and the right-hand
   metrics ($PREMIUM, open interest) were pushed off-screen and CLIPPED —
   silently, with no scrollbar to hint that data was missing.

   The rule everywhere below: content may WRAP or SCROLL, but must never be
   cut off. Scoped to .futures2-page so v1 futures, spot and options — which
   share every one of these class names — are untouched. */
.futures2-page .instrument-bar {
  flex-wrap: wrap;
  row-gap: 12px;
  column-gap: 20px;
}

/* Without min-width:0 a flex item refuses to shrink below its content, which
   is what pushed the metrics past the right edge instead of compressing. */
.futures2-page .inst-bar-left {
  flex: 1 1 320px;
  min-width: 0;
}

.futures2-page .inst-bar-title-row {
  flex-wrap: wrap;
  row-gap: 6px;
  min-width: 0;
}

/* A contract name is one token — breaking it mid-word makes it unreadable. */
.futures2-page .inst-bar-symbol {
  white-space: nowrap;
}

/* Its own line rather than a squeezed column between the badges and the
   metrics. Full basis, so it wraps as prose at whatever width remains. */
.futures2-page .inst-description {
  flex: 1 1 100%;
  min-width: 0;
  color: var(--app-text-muted-2);
  font-size: 13px;
  font-weight: 400;
  line-height: 1.4;
}

/* #503 — what this contract COSTS, on its own line directly under the
   description that says what it IS (Quy 2026-08-27).

   IT SITS BELOW RATHER THAN INLINE, and that was decided by a test, not by
   taste: futures2-ui-polish-frontend.test.js asserts the description's
   textContent by EXACT equality, so nesting this clause inside #instDescription
   would have broken a pinned assertion. A sibling leaves that contract intact.

   HEIGHT IS THE WHOLE DESIGN CONSTRAINT HERE. Everything below — chart, order
   panel, the form itself — shifts down by whatever this line takes, so it is
   deliberately smaller than the 13px description and tightly led: ~15px added
   on desktop. It is allowed to wrap on a narrow phone; .inst-description above
   it already wraps as prose at whatever width remains, so the heading row
   handles that case by construction rather than by a breakpoint.

   11px, and NO override in any @media block. That is #527's lesson: an 11px fix
   added at one breakpoint was silently defeated by an older 10px rule surviving
   inside @media (max-width: 480px). 11px is the agreed floor for secondary
   labels, so this line holds it at every width. */
.futures2-page .inst-cost-note {
  flex: 1 1 100%;
  min-width: 0;
  margin-top: 2px;
  color: var(--app-text-muted-2);
  font-size: 11px;
  font-weight: 400;
  line-height: 1.35;
}

/* The metrics keep their own line when the heading needs it, and scroll
   INSIDE their own box rather than overflowing the page. */
.futures2-page .inst-bar-metrics {
  flex: 1 1 auto;
  min-width: 0;
  justify-content: flex-end;
  overflow-x: auto;
  scrollbar-width: thin;
}
.futures2-page .inst-metric { flex: none; }

@media (max-width: 1024px) {
  .futures2-page .inst-bar-metrics { justify-content: flex-start; }
}

/* THE 320px BASIS IS A WIDTH ONLY WHILE THE BAR IS A ROW. At <=1200px the
   shared rules flip .instrument-bar to flex-direction: column (trade-option.css
   1200/1024px blocks and the 1023px block above), and a flex-basis resolves
   against the MAIN axis — so the same 320px silently becomes a HEIGHT, and
   .inst-bar-left is forced ~230px taller than its content. An auto-height
   container gives flex-shrink no negative space to work with, so the dead
   block just sits there between the subtitle and the metrics row (bug #508).
   Once the axis is vertical the basis has no job to do: `auto` sizes to
   content on either axis. 1200px, not 1024 — the earliest column flip is
   trade-option.css's 1200px block, and matching a lower breakpoint would
   leave the 1024-1200px band broken. */
@media (max-width: 1200px) {
  .futures2-page .inst-bar-left { flex: 1 1 auto; }
}

/* ===== #521: Positions / Open Orders / Order History tab labels at 360px ====
   At 360px (Galaxy S8-S23) "Open Orders" and "Order History" each broke onto
   two lines while "Positions" stayed on one, so the three labels sat on
   different baselines. A tab label is one token: it may scroll, never wrap.
   The row scrolls horizontally for whatever width the three labels need.
   Mobile only — at 390px+ everything already fits on one line, and nowrap
   with room to spare changes nothing. */
@media (max-width: 768px) {
  .pos-tabs { overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: thin; }
  .pos-tab { white-space: nowrap; flex: 0 0 auto; }
}

/* ===== #522: AI chat FAB vs. device safe areas (Futures V.2) ================
   The page already shrinks the FAB to 44px at bottom:16px and reserves 92px
   under .trade-main (its own <style> block) — but with zero
   env(safe-area-inset-*) anywhere, on an iPhone the button sat ON the home
   indicator, and the reserved padding ignored the inset too. The page's
   viewport meta now carries viewport-fit=cover (required, or every env()
   below reads 0 on exactly the devices that need it), and these rules add
   the inset on top of the page's own offsets.

   `html body.futures2-page …` on purpose: the page's inline rules are
   `body.futures2-page …` and come AFTER the stylesheets, so winning the
   cascade takes strictly higher specificity, not source order. On devices
   without insets env() is 0px and both rules compute to exactly the page's
   own values — zero change anywhere but notched/home-indicator phones. */
@media (max-width: 768px) {
  /* Two-line declarations: a browser without env() SYNTAX drops the whole
     calc() line (env()'s second argument only covers an unknown variable,
     not unsupported syntax), so the plain-px line before each one is what
     such a browser keeps — the same values the page's own rules set. */
  html body.futures2-page .ai-chat-fab {
    bottom: 16px;
    bottom: calc(16px + env(safe-area-inset-bottom, 0px));
    right: 16px;
    right: calc(16px + env(safe-area-inset-right, 0px));
  }
  html body.futures2-page .trade-main {
    padding-bottom: 92px !important;
    padding-bottom: calc(92px + env(safe-area-inset-bottom, 0px)) !important;
  }
}

/* ===== #544: instrument metrics row — stable grid at Galaxy widths =========
   Free flex-wrap put seven metrics on two ragged lines at 360px (3 + 4, the
   busier line below, Open Interest hard against the right edge) while 390px
   and 412px happened to wrap 4 + 3. Below 380px the row becomes a fixed
   two-column grid: the same shape at every narrow width, no dependence on
   label lengths (tolerates .metric-label growing), and the .inst-metric
   right padding (@1200 block, trade-option.css) keeps the right-hand gutter.
   The 6px gap comes from the shared `.inst-bar-metrics { gap: 6px !important }`
   and applies to the grid unchanged. minmax(0, 1fr) so no metric can force
   the row past the viewport. Scoped to .futures2-page — no other page moves.

   #47: THE GRID WAS THE RIGHT SHAPE BUT THE WRONG WIDTH. At <=1024px the
   shared rules flip .instrument-bar to `flex-direction: column` with
   `align-items: flex-start !important` (trade-option.css ~1899), so a child
   that does not stretch shrink-wraps its own content — the two tracks measured
   97.45px each (201px with the 6px gap) inside a 358px content box at 360px,
   leaving ~150px of the row unused on the right while the values inside stayed
   cramped. `width: 100%` hands the two `1fr` tracks the whole row (~176px
   each) without touching the column COUNT that #544 fixed. No border or
   padding on this box, so 100% is exactly the bar's content width — it cannot
   overflow, and minmax(0, 1fr) still caps any single long value. */
@media (max-width: 380px) {
  .futures2-page .inst-bar-metrics {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    width: 100%;
  }
}

/* ===== #54: Order History is off-screen at 320/360px with no scroll cue =====
   #521 stopped the three tab labels wrapping and made .pos-tabs scroll
   (~2216) — but it added no affordance, so at 320px and 360px the third tab
   ("Order History") sits entirely outside a ~262px container and the row looks
   like a plain two-tab strip. Galaxy S8-S23 is 360px, so this hides order
   history from a very common device.

   BREAKPOINT CORRECTED 2026-08-31 (Canh re-test, ULT-MARGIN-54). The two
   changes below were originally gated at 380px, which left the defect alive on
   the widest device that has it. His measurements:

     390px viewport -> ~321px container : CLIPS (media query never fired)
     360px viewport -> ~291px container : CLIPS
     320px viewport -> ~251px container : CLIPS
     406px viewport -> ~340px container : fits exactly, no fix needed

   The padded strip is ~292px, so 390px would have FIT had the rule applied —
   the fix was correct and simply 10px too narrow. The gate is now 405px, the
   last width below Canh's measured fit point. Note the affordance is
   self-hiding, so widening the gate cannot show a cue where nothing overflows.

   Two changes, both below 405px, and NEITHER reintroduces wrapping (#521's
   `white-space: nowrap` / `flex: 0 0 auto` stay):

   1. The padding drops 16px -> 8px a side. Three tabs at 13px/600 need roughly
      62 + 74 + 88px of text; at 32px of padding each that is ~340px, at 16px
      each it is ~292px. Still wider than 262px at 320px — which is exactly why
      the cue below is not optional — but "Order History" now starts on screen
      at 360px instead of beginning past the right edge.

   2. A self-hiding edge fade. Two `local` cover gradients scroll WITH the tabs
      and sit over two `scroll` gradients pinned to the box, so the cue appears
      only on the side that still has content off-screen and disappears when
      that end is reached — no permanently-faded last tab. Pure CSS: no JS, no
      scroll listener. The cover colour is var(--app-surface-1), the .trade-card
      background this row sits directly on (trade-option.css ~197), so it is
      correct on both brands; the cue itself is the same
      rgba(var(--app-content-overlay-rgb), …) overlay token every other edge in
      these sheets uses, so it reads on dark and light alike. The global
      ::-webkit-scrollbar (6px, trade-option.css ~13) remains as the
      pointer-device cue; this covers the touch browsers that hide it. */
@media (max-width: 405px) {
  .pos-tab { padding: 8px 8px; }
  .pos-tabs {
    background:
      linear-gradient(to right, var(--app-surface-1) 60%, rgba(0, 0, 0, 0)) left center,
      linear-gradient(to left, var(--app-surface-1) 60%, rgba(0, 0, 0, 0)) right center,
      linear-gradient(to right, rgba(var(--app-content-overlay-rgb), 0.28), rgba(0, 0, 0, 0)) left center,
      linear-gradient(to left, rgba(var(--app-content-overlay-rgb), 0.28), rgba(0, 0, 0, 0)) right center;
    background-repeat: no-repeat;
    background-size: 28px 100%, 28px 100%, 14px 100%, 14px 100%;
    background-attachment: local, local, scroll, scroll;
  }
}
