/* ===== AI TRADING PAGE =====
   Scoped under body.ai-trading-page (per-page stylesheet, not a shared
   reset) so nothing here leaks if this file were ever loaded elsewhere. */

body.ai-trading-page .ai-trading-main {
  padding: 28px 40px 80px;
  max-width: 960px;
}

/* ---- `hidden` must actually hide, page-wide ----
   The `hidden` attribute is only a UA style (`display:none`) at the LOWEST
   priority, so ANY `display:` rule in this file silently defeats it. That has
   already shipped twice here: the state panels (every visitor saw the spinner
   AND "not available" at once, because JS set `.hidden` and nothing happened —
   Quy 2026-07-28) and the modal overlays.

   This page now hides far more elements from JS — the two view modes, the
   status pill (`display:inline-block`), the strategy box, the My History
   section, the Change note, the minimum note, the chart legend — so instead of
   another per-class patch, the rule is stated once for the whole page. The two
   original narrow rules are kept below because they are load-bearing history,
   not because they are still needed.

   Anything that must be visible while carrying `hidden` would be a bug. */
body.ai-trading-page [hidden] { display: none !important; }

/* ---- Gate state panels (loading / unavailable / empty) ---- */
body.ai-trading-page .ai-state-panel[hidden] { display: none !important; }
body.ai-trading-page .ai-state-panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 80px 20px;
  text-align: center;
}
body.ai-trading-page .ai-spinner {
  width: 28px;
  height: 28px;
  border: 2px solid rgba(92, 184, 230, 0.2);
  border-top-color: var(--app-primary);
  border-radius: 50%;
  animation: ai-spin 0.8s linear infinite;
}
@keyframes ai-spin { to { transform: rotate(360deg); } }
body.ai-trading-page .ai-state-text {
  font-size: 14px;
  color: var(--app-text-muted-2);
}
body.ai-trading-page .ai-back-link {
  font-size: 13px;
  color: var(--app-primary);
  text-decoration: none;
}
body.ai-trading-page .ai-back-link:hover { text-decoration: underline; }

/* ---- Page header ---- */
body.ai-trading-page .ai-page-header {
  margin-bottom: 28px;
}
body.ai-trading-page .ai-breadcrumb {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: #6a6a7a;
  margin-bottom: 10px;
}
body.ai-trading-page .ai-breadcrumb a { color: #6a6a7a; text-decoration: none; }
body.ai-trading-page .ai-breadcrumb a:hover { color: var(--app-text-muted-3); }
body.ai-trading-page .ai-breadcrumb span { color: var(--app-text-1); font-weight: 500; }
body.ai-trading-page .ai-page-title {
  font-size: 22px;
  font-weight: 600;
  color: var(--app-text-strong);
}
body.ai-trading-page .ai-page-sub {
  margin-top: 6px;
  font-size: 14px;
  color: var(--app-text-muted-2);
}

/* ---- Bot list / card ---- */
body.ai-trading-page .ai-bot-list {
  display: flex;
  flex-direction: column;
  gap: 24px;
}
body.ai-trading-page .ai-bot-card {
  background: var(--app-surface-2);
  border: 1px solid var(--app-border);
  border-radius: var(--app-radius-md);
  padding: 24px;
}
body.ai-trading-page .ai-bot-card-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 12px;
  margin-bottom: 6px;
}
body.ai-trading-page .ai-bot-name {
  font-size: 17px;
  font-weight: 700;
  color: var(--app-text-strong);
}
body.ai-trading-page .ai-bot-meta {
  font-size: 12px;
  color: var(--app-text-muted-2);
}
body.ai-trading-page .ai-bot-meta-dot {
  margin: 0 6px;
  opacity: 0.5;
}

/* Status pill (bot running state — Active / Paused) */
body.ai-trading-page .ai-status-pill {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
}
body.ai-trading-page .ai-status-pill.active {
  background: rgba(61, 220, 132, 0.16);
  color: #3ddc84;
}
body.ai-trading-page .ai-status-pill.paused {
  background: rgba(224, 160, 80, 0.15);
  color: var(--app-sell);
}

body.ai-trading-page .ai-bot-description {
  margin: 14px 0;
  font-size: 13px;
  line-height: 1.6;
  color: var(--app-text-muted-2);
}
body.ai-trading-page .ai-bot-description p { margin: 0 0 8px; }
body.ai-trading-page .ai-bot-description p:last-child { margin-bottom: 0; }

/* Strategy summary box */
body.ai-trading-page .ai-strategy-box {
  background: rgba(92, 184, 230, 0.06);
  border: 1px solid rgba(92, 184, 230, 0.2);
  border-radius: var(--app-radius-sm);
  padding: 14px 16px;
  margin: 14px 0 18px;
  font-size: 12px;
  line-height: 1.6;
  color: var(--app-text-1);
}
body.ai-trading-page .ai-strategy-box-title {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--app-primary);
  margin-bottom: 8px;
}
body.ai-trading-page .ai-strategy-row { margin-bottom: 4px; }
body.ai-trading-page .ai-strategy-row:last-child { margin-bottom: 0; }
body.ai-trading-page .ai-strategy-row b { color: var(--app-text-strong); font-weight: 600; }

/* ---- Sections (Recent Signals / Closed Cycles / My History) ---- */
body.ai-trading-page .ai-section {
  margin-top: 20px;
}
body.ai-trading-page .ai-section-title {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--app-text-muted-2);
  margin-bottom: 10px;
}
body.ai-trading-page .ai-table-wrap {
  overflow-x: auto;
  border-radius: var(--app-radius-sm);
  border: 1px solid var(--app-border);
}
body.ai-trading-page .ai-table {
  width: 100%;
  min-width: 460px;
  border-collapse: collapse;
}
body.ai-trading-page .ai-table thead th {
  background: rgba(var(--app-content-overlay-rgb), 0.03);
  padding: 10px 14px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  color: var(--app-text-muted-2);
  text-align: left;
  white-space: nowrap;
}
body.ai-trading-page .ai-table tbody td {
  padding: 10px 14px;
  font-size: 12.5px;
  color: var(--app-text-1);
  border-top: 1px solid var(--app-border);
  white-space: nowrap;
}
body.ai-trading-page .ai-table tbody tr:hover {
  background: rgba(92, 184, 230, 0.03);
}
body.ai-trading-page .ai-table-empty-row td {
  text-align: center;
  padding: 20px;
  color: var(--app-text-muted-2);
  white-space: normal;
}
body.ai-trading-page .ai-table-loading {
  padding: 16px;
  font-size: 12.5px;
  color: var(--app-text-muted-2);
}

/* Action badges (BUY / CLOSE / HOLD) */
body.ai-trading-page .ai-action-badge {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.3px;
}
body.ai-trading-page .ai-action-badge.buy { background: rgba(92, 184, 230, 0.15); color: var(--app-buy); }
body.ai-trading-page .ai-action-badge.close { background: rgba(224, 160, 80, 0.15); color: var(--app-sell); }
body.ai-trading-page .ai-action-badge.hold { background: rgba(var(--app-content-overlay-rgb), 0.08); color: var(--app-text-muted-2); }

body.ai-trading-page .ai-result-positive { color: #3ddc84; font-weight: 600; }
body.ai-trading-page .ai-result-negative { color: var(--app-sell); font-weight: 600; }
body.ai-trading-page .ai-result-neutral { color: var(--app-text-muted-2); }

/* ===================================================================
   "YOUR POSITION" STRIP

   Pinned under the detail header. It is the first thing a user with money in
   the market reads, so it is a card rather than a line of prose, and it never
   scrolls sideways: the figures WRAP.

   Note the `display: flex` below — that is exactly the rule that would defeat
   the `hidden` attribute this element spends most of its life carrying. The
   page-wide `[hidden] { display: none !important; }` at the top of this file
   is what keeps it hidden, and there is a test pinning that rule.
   =================================================================== */
body.ai-trading-page .ai-position-strip {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 0 0 18px;
  padding: 14px 16px;
  background: var(--app-surface-2);
  border: 1px solid var(--app-border);
  border-left: 3px solid var(--app-primary);
  border-radius: var(--app-radius-sm);
}
/* Flat = no exposure, so it must not look like a position. One quiet line, no
   accent edge, no card weight. */
body.ai-trading-page .ai-position-strip.is-flat {
  border-left-color: var(--app-border);
  padding: 10px 16px;
}
body.ai-trading-page .ai-strip-flat-line {
  font-size: 12.5px;
  color: var(--app-text-muted-2);
  font-variant-numeric: tabular-nums;
}

body.ai-trading-page .ai-strip-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 10px;
}
body.ai-trading-page .ai-strip-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--app-text-muted-2);
}

/* State chip — hue in the background, wording in the text (#889). The wording
   alone has to carry the meaning: `Entering` and `Closing out` are different
   states with the same amber, and colour never distinguishes them. */
body.ai-trading-page .ai-strip-chip {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 20px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.2px;
}
body.ai-trading-page .ai-strip-chip.is-open { background: rgba(61, 220, 132, 0.16); color: #3ddc84; }
body.ai-trading-page .ai-strip-chip.is-entering,
body.ai-trading-page .ai-strip-chip.is-closing,
body.ai-trading-page .ai-strip-chip.is-closing-out { background: rgba(92, 184, 230, 0.16); color: var(--app-buy); }
body.ai-trading-page .ai-strip-chip.is-review { background: rgba(224, 160, 80, 0.16); color: var(--app-sell); }
/* Money reserved with no exposure state to explain it — neutral, because there
   is nothing going on in the market to report. */
body.ai-trading-page .ai-strip-chip.is-reserved {
  background: rgba(var(--app-content-overlay-rgb), 0.08);
  color: var(--app-text-muted-2);
}
/* Signal-only bot: the strip reports SIGNALS, never a position, and the chip
   must not borrow a position colour — neutral, like `is-reserved`. */
body.ai-trading-page .ai-strip-chip.is-signal {
  background: rgba(var(--app-content-overlay-rgb), 0.08);
  color: var(--app-text-muted-2);
}

/* Price freshness. A caption on the numbers, never a replacement for the
   states next to it — a price outage degrades the figure and nothing else. */
body.ai-trading-page .ai-strip-flag {
  font-size: 11px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 20px;
  background: rgba(224, 160, 80, 0.12);
  color: var(--app-sell);
}

body.ai-trading-page .ai-strip-figures {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 26px;
}
body.ai-trading-page .ai-strip-figure {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
body.ai-trading-page .ai-strip-figure-label {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  color: var(--app-text-muted-2);
}
body.ai-trading-page .ai-strip-figure-value {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--app-text-strong);
  font-variant-numeric: tabular-nums;
}
body.ai-trading-page .ai-strip-note {
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--app-text-muted-2);
}

/* Ultimo — the same #889 treatment the rest of this page gets: these are
   accent-coloured TEXT on a LIGHT card (`--app-sell` #e0a050 at ~1.9:1,
   `#3ddc84` at ~1.6:1, `--app-buy` #5cb8e6 at ~2.2:1). The hue stays in the
   background; the text moves to a neutral token. Nothing is lost — every chip
   states its meaning in words and the PnL badge carries an explicit +/-.
   The PnL badge itself needs no rule here: it reuses `.ai-result-badge`, which
   is already covered further down this file. Ultimo-only ⇒ Vestex renders
   byte-identically. */
html[data-brand="ultimo"] body.ai-trading-page .ai-strip-chip.is-open,
html[data-brand="ultimo"] body.ai-trading-page .ai-strip-chip.is-entering,
html[data-brand="ultimo"] body.ai-trading-page .ai-strip-chip.is-closing,
html[data-brand="ultimo"] body.ai-trading-page .ai-strip-chip.is-closing-out,
html[data-brand="ultimo"] body.ai-trading-page .ai-strip-chip.is-review,
html[data-brand="ultimo"] body.ai-trading-page .ai-strip-flag {
  color: var(--app-text-1);
}

/* ---- CTA area ----
   Rendered TWICE on the detail page (top + bottom) from one function off one
   piece of state, so the two can never disagree. The row stacks its controls
   above an optional eligibility note. */
body.ai-trading-page .ai-cta-row {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--app-border);
}
body.ai-trading-page .ai-cta-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}
/* The TOP instance sits directly under the strategy box, where a full-width
   divider would read as the end of a section rather than the start of one. */
body.ai-trading-page .ai-cta-top {
  border-top: none;
  padding-top: 0;
  margin-top: 18px;
  margin-bottom: 4px;
}
/* "Can I join / why not", from the eligibility block the API was already
   returning. Neutral by default; a hard refusal is marked. */
body.ai-trading-page .ai-cta-note {
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--app-text-muted-2);
  max-width: 62ch;
}
body.ai-trading-page .ai-cta-note.is-blocked {
  color: var(--app-sell);
}
body.ai-trading-page .ai-copying-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border-radius: 20px;
  background: rgba(61, 220, 132, 0.12);
  color: #3ddc84;
  font-size: 13px;
  font-weight: 600;
}
body.ai-trading-page .ai-copying-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #3ddc84;
}

/* Buttons — 44px minimum touch target throughout */
body.ai-trading-page .ai-btn-primary,
body.ai-trading-page .ai-btn-secondary {
  min-height: 44px;
  padding: 0 20px;
  border-radius: var(--app-radius-sm);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
body.ai-trading-page .ai-btn-primary {
  background: var(--app-primary);
  color: var(--app-primary-fg);
  border: none;
}
body.ai-trading-page .ai-btn-primary:hover { background: var(--app-primary-hover); }
body.ai-trading-page .ai-btn-primary:disabled { background: rgba(var(--app-content-overlay-rgb), 0.12); color: var(--app-text-muted-2); cursor: not-allowed; }
body.ai-trading-page .ai-btn-secondary {
  background: transparent;
  color: var(--app-text-1);
  border: 1px solid rgba(var(--app-content-overlay-rgb), 0.15);
}
body.ai-trading-page .ai-btn-secondary:hover { background: rgba(var(--app-content-overlay-rgb), 0.06); border-color: rgba(var(--app-content-overlay-rgb), 0.25); }

/* ===================================================================
   LIST VIEW — lightweight bot cards (the whole card is the link)
   =================================================================== */
body.ai-trading-page .ai-bot-card-link {
  display: block;
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s, background 0.15s;
}
body.ai-trading-page .ai-bot-card-link:hover {
  border-color: var(--app-primary);
  background: var(--app-surface-1);
}
/* Keyboard users get the same affordance as the hover state — the card is the
   only control in the list view, so losing its focus ring would strand them. */
body.ai-trading-page .ai-bot-card-link:focus-visible {
  outline: 2px solid var(--app-primary);
  outline-offset: 2px;
}
body.ai-trading-page .ai-bot-card-chip-row { margin: 12px 0 4px; }

body.ai-trading-page .ai-bot-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 32px;
  margin-top: 14px;
}
body.ai-trading-page .ai-bot-stat-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  color: var(--app-text-muted-2);
  margin-bottom: 3px;
}
body.ai-trading-page .ai-bot-stat-value {
  font-size: 14px;
  font-weight: 600;
  color: var(--app-text-strong);
}
body.ai-trading-page .ai-bot-card-cue {
  display: inline-block;
  margin-top: 16px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--app-primary);
}

/* ===================================================================
   DETAIL VIEW (?bot=)
   =================================================================== */
body.ai-trading-page .ai-detail-title-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 12px;
}
body.ai-trading-page .ai-detail-link {
  display: inline-block;
  margin-top: 10px;
  font-size: 12.5px;
  color: var(--app-primary);
  text-decoration: none;
}
body.ai-trading-page .ai-detail-link:hover { text-decoration: underline; }

/* Mount points for the chart (PR7) and the two tables (PR5).
   NO height, NO padding, NO min-height on the slot itself — the chart module
   sizes its own container and any box model here would fight it. The neutral
   placeholder is a CHILD, so it carries its own padding. */
body.ai-trading-page .ai-slot { display: block; }
body.ai-trading-page .ai-slot-empty {
  padding: 28px 20px;
  border: 1px solid var(--app-border);
  border-radius: var(--app-radius-sm);
  text-align: center;
  font-size: 12.5px;
  color: var(--app-text-muted-2);
}
body.ai-trading-page .ai-chart-legend {
  margin-top: 10px;
  font-size: 12px;
  line-height: 1.6;
  color: var(--app-text-muted-2);
}

/* ---- Modal (consent + stop-copying) ---- */
body.ai-trading-page .ai-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: var(--z-modal, 1200);
  padding: 16px;
}
body.ai-trading-page .ai-modal-overlay[hidden] { display: none !important; }
body.ai-trading-page .ai-modal {
  background: var(--app-surface-2);
  border: 1px solid var(--app-border);
  border-radius: var(--app-radius-md);
  width: 100%;
  max-width: 460px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  color: var(--app-text-strong);
}
body.ai-trading-page .ai-modal-sm { max-width: 400px; }
body.ai-trading-page .ai-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 20px;
  border-bottom: 1px solid var(--app-border);
}
body.ai-trading-page .ai-modal-header h3 { margin: 0; font-size: 16px; font-weight: 600; }
body.ai-trading-page .ai-modal-close {
  background: transparent;
  border: none;
  color: var(--app-text-muted-2);
  font-size: 24px;
  cursor: pointer;
  line-height: 1;
  min-width: 44px;
  min-height: 44px;
}
body.ai-trading-page .ai-modal-close:hover { color: var(--app-text-strong); }
body.ai-trading-page .ai-modal-body {
  padding: 20px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
body.ai-trading-page .ai-modal-plain-text {
  font-size: 13px;
  line-height: 1.6;
  color: var(--app-text-1);
}
body.ai-trading-page .ai-modal-balance-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  background: rgba(var(--app-content-overlay-rgb), 0.04);
  border-radius: var(--app-radius-sm);
  font-size: 13px;
  color: var(--app-text-muted-2);
}
body.ai-trading-page .ai-modal-balance-value {
  font-weight: 700;
  color: var(--app-primary);
  font-size: 15px;
}

body.ai-trading-page .ai-alloc-control { display: flex; flex-direction: column; gap: 10px; }
body.ai-trading-page .ai-alloc-label { font-size: 12px; color: var(--app-text-muted-2); font-weight: 600; }
body.ai-trading-page .ai-alloc-row { display: flex; align-items: center; gap: 14px; }
body.ai-trading-page .ai-alloc-slider {
  flex: 1;
  min-height: 44px;
  accent-color: var(--app-primary);
  cursor: pointer;
}
/* The control keeps moving after the per-entry cap binds, while the USDT figure
   below it freezes — which reads as a hidden ceiling rather than a cap. Desaturate
   the thumb while that is true so the mismatch is visible; the cap note already
   says what is happening. Not `disabled`: the higher percentages remain a valid
   choice, they just stop changing the amount TODAY, and they will matter again as
   soon as the balance is smaller. (Minamide follow-up 4.) */
body.ai-trading-page .ai-alloc-slider.is-capped {
  accent-color: var(--app-text-muted-2);
}
body.ai-trading-page .ai-alloc-number-wrap {
  display: flex;
  align-items: center;
  gap: 4px;
  background: rgba(var(--app-content-overlay-rgb), 0.04);
  border: 1px solid rgba(var(--app-content-overlay-rgb), 0.12);
  border-radius: var(--app-radius-sm);
  padding: 0 10px;
  min-height: 44px;
}
body.ai-trading-page .ai-alloc-number {
  width: 48px;
  min-height: 42px;
  background: transparent;
  border: none;
  color: var(--app-text-strong);
  font-size: 14px;
  text-align: right;
}
body.ai-trading-page .ai-alloc-number:focus { outline: none; }
body.ai-trading-page .ai-alloc-pct-suffix { font-size: 13px; color: var(--app-text-muted-2); }
body.ai-trading-page .ai-alloc-summary {
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--app-text-1);
  background: rgba(92, 184, 230, 0.06);
  border: 1px solid rgba(92, 184, 230, 0.2);
  border-radius: var(--app-radius-sm);
  padding: 10px 12px;
}

/* Pilot cap notice — amber, because it CHANGES the figure above rather than
   merely annotating it. */
body.ai-trading-page .ai-alloc-cap-note {
  margin-top: 8px;
  font-size: 12px;
  line-height: 1.6;
  color: var(--app-sell);
  background: rgba(224, 160, 80, 0.08);
  border: 1px solid rgba(224, 160, 80, 0.28);
  border-radius: var(--app-radius-sm);
  padding: 8px 12px;
}

/* The bot's per-entry FLOOR, evaluated live on every slider move. Amber like
   the cap note, because both change what will actually happen rather than
   merely annotating the figure — but this one also DISABLES the agree button,
   since below the floor the engine skips the user on every cycle. */
body.ai-trading-page .ai-alloc-min-note {
  margin-top: 8px;
  font-size: 12px;
  line-height: 1.6;
  color: var(--app-sell);
  background: rgba(224, 160, 80, 0.08);
  border: 1px solid rgba(224, 160, 80, 0.28);
  border-radius: var(--app-radius-sm);
  padding: 8px 12px;
}

/* CHANGE mode only. Deliberately styled as a NOTICE rather than fine print:
   the snapshot rule ("an open position is unchanged") is the one thing a user
   adjusting their percentage could reasonably assume the other way round. */
body.ai-trading-page .ai-change-note {
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--app-text-1);
  background: rgba(92, 184, 230, 0.06);
  border: 1px solid rgba(92, 184, 230, 0.2);
  border-radius: var(--app-radius-sm);
  padding: 10px 12px;
}

body.ai-trading-page .ai-consent-bullets {
  margin: 0;
  padding-left: 18px;
  font-size: 12px;
  line-height: 1.7;
  color: var(--app-text-muted-2);
}
body.ai-trading-page .ai-consent-bullets li { margin-bottom: 2px; }

body.ai-trading-page .ai-modal-error {
  font-size: 12.5px;
  color: #ef4444;
  background: rgba(239, 68, 68, 0.08);
  border: 1px solid rgba(239, 68, 68, 0.25);
  border-radius: var(--app-radius-sm);
  padding: 10px 12px;
}

body.ai-trading-page .ai-modal-footer {
  padding: 16px 20px;
  border-top: 1px solid var(--app-border);
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}
body.ai-trading-page .ai-modal-btn-cancel,
body.ai-trading-page .ai-modal-btn-primary,
body.ai-trading-page .ai-modal-btn-danger {
  border: none;
  border-radius: var(--app-radius-sm);
  min-height: 44px;
  padding: 0 18px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
body.ai-trading-page .ai-modal-btn-cancel {
  background: transparent;
  color: var(--app-text-muted-2);
  border: 1px solid rgba(var(--app-content-overlay-rgb), 0.15);
}
body.ai-trading-page .ai-modal-btn-cancel:hover { color: var(--app-text-strong); border-color: rgba(var(--app-content-overlay-rgb), 0.3); }
body.ai-trading-page .ai-modal-btn-primary {
  background: var(--app-primary);
  color: var(--app-primary-fg);
}
body.ai-trading-page .ai-modal-btn-primary:hover { background: var(--app-primary-hover); }
body.ai-trading-page .ai-modal-btn-primary:disabled {
  background: rgba(var(--app-content-overlay-rgb), 0.12);
  color: var(--app-text-muted-2);
  cursor: not-allowed;
}
body.ai-trading-page .ai-modal-btn-danger {
  background: rgba(224, 160, 80, 0.16);
  color: var(--app-sell);
}
body.ai-trading-page .ai-modal-btn-danger:hover { background: rgba(224, 160, 80, 0.26); }
body.ai-trading-page .ai-modal-btn-danger:disabled {
  background: rgba(var(--app-content-overlay-rgb), 0.08);
  color: var(--app-text-muted-2);
  cursor: not-allowed;
}

/* ---- Toasts (same visual language as trade-futures.css, page-scoped here
   since this page does not load that stylesheet) ---- */
body.ai-trading-page .toast-container {
  position: fixed;
  top: 70px;
  right: 24px;
  z-index: var(--z-toast, 1300);
  display: flex;
  flex-direction: column-reverse;
  gap: 8px;
  pointer-events: none;
}
body.ai-trading-page .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;
}
body.ai-trading-page .toast.show { transform: translateX(0); opacity: 1; }
body.ai-trading-page .toast.hide { transform: translateX(120%); opacity: 0; }
body.ai-trading-page .toast-icon {
  width: 28px; height: 28px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0; font-size: 14px;
}
body.ai-trading-page .toast.success .toast-icon { background: rgba(61, 220, 132, 0.16); color: #3ddc84; }
body.ai-trading-page .toast.error .toast-icon { background: rgba(224, 100, 80, 0.15); color: #e06450; }
body.ai-trading-page .toast-body { flex: 1; }
body.ai-trading-page .toast-title { font-size: 13px; font-weight: 700; color: var(--app-text-1); margin-bottom: 2px; }
body.ai-trading-page .toast-message { font-size: 12px; color: var(--app-text-muted-2); }
/* Ultimo: the toast is a DARK ISLAND on a light shell — `background:#1e1e32`
   with neutral text tokens that brand-boot.js remaps to #1a1a1a, i.e. dark text
   on a dark panel (1.07:1, invisible). Same defect and same fix as #901 in
   trade-futures.css:665; this page needs its own copy because it defines its
   own scoped `.toast` and does not load that file. These two toasts are the
   ONLY confirmation a user gets that a bot started or stopped trading their
   money, so they must be readable on both brands. Ultimo-only ⇒ Vestex
   zero-diff. */
html[data-brand="ultimo"] body.ai-trading-page .toast {
  --app-text-strong: #e2e8f0;
  --app-text-1: #e0e0e8;
  --app-text-muted-2: #8a8a9a;
}

/* Ultimo, part 2 (Quy 2026-07-28) — the remaining four accent-on-light cases.
   The toast above is a dark island, so it only needed its tokens re-mapped.
   These five are the opposite problem: accent-coloured TEXT on Ultimo's LIGHT
   card, where `--app-sell` (#e0a050) and `#3ddc84` land at ~1.5-2.0:1 and
   `--app-primary` (#f5b50a) at ~1.6:1.

   Fix follows #889 rather than inventing darker hexes: the HUE stays in the
   background and the border, the TEXT moves to a neutral token. Nothing is lost
   semantically — the chip keeps its green tint, the cap note its amber wash, and
   the PnL figures already carry an explicit +/- sign in the text
   (js/ai-trading.js:42-47), so colour was redundant there.

   Ultimo-only ⇒ Vestex renders byte-identically. */
html[data-brand="ultimo"] body.ai-trading-page .ai-alloc-cap-note,
html[data-brand="ultimo"] body.ai-trading-page .ai-modal-balance-value,
html[data-brand="ultimo"] body.ai-trading-page .ai-copying-chip,
html[data-brand="ultimo"] body.ai-trading-page .ai-result-positive,
html[data-brand="ultimo"] body.ai-trading-page .ai-result-negative,
/* Added with the detail mode (PR4), same rule, same reason: `--app-sell`
   (#e0a050) and `--app-primary` (#f5b50a) as TEXT on Ultimo's light card.
   The minimum note is the one that gates the agree button and the blocked
   note is the one that says why a user cannot join — both have to be legible
   before anything else in their section. Hue stays in the background/border. */
html[data-brand="ultimo"] body.ai-trading-page .ai-alloc-min-note,
html[data-brand="ultimo"] body.ai-trading-page .ai-cta-note.is-blocked,
html[data-brand="ultimo"] body.ai-trading-page .ai-bot-card-cue,
html[data-brand="ultimo"] body.ai-trading-page .ai-detail-link {
  color: var(--app-text-1);
}
/* The kill switch. Its label must be readable before anything else on the page. */
html[data-brand="ultimo"] body.ai-trading-page .ai-modal-btn-danger {
  color: var(--app-text-strong);
}

body.ai-trading-page .toast-close {
  background: none; border: none; color: #6a6a7a; cursor: pointer;
  font-size: 16px; padding: 4px; line-height: 1; flex-shrink: 0;
  min-width: 44px; min-height: 44px;
}
body.ai-trading-page .toast-close:hover { color: var(--app-text-1); }

/* ===================================================================
   RECENT TRADES + MY HISTORY (PR5)

   One row per round-trip in both tables. The shared vocabulary:
     .ai-cell-pair    price is the hero, time/status is the subtitle
     .ai-result-badge sign + hue-in-the-background (#889)
     .ai-trade-row    click/Enter expands .ai-trade-detail-row (K/D)
     .ai-history-note the funds-held message, ALWAYS visible

   Both tables live inside .ai-table-wrap (overflow-x:auto), so a wide table
   scrolls inside its own container and the page body never scrolls sideways.
   =================================================================== */

body.ai-trading-page .ai-trades-table { min-width: 520px; }
body.ai-trading-page .ai-history-table { min-width: 760px; }

/* Price/time cell ---------------------------------------------------- */
body.ai-trading-page .ai-cell-pair { vertical-align: top; }
body.ai-trading-page .ai-cell-price {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--app-text-strong);
  font-variant-numeric: tabular-nums;
}
body.ai-trading-page .ai-cell-time {
  margin-top: 3px;
  font-size: 11.5px;
  color: var(--app-text-muted-2);
  font-variant-numeric: tabular-nums;
}
/* The open / under-review side. Amber rather than neutral because it is a
   state the user should notice, not a missing value. */
body.ai-trading-page .ai-cell-status {
  margin-top: 3px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--app-sell);
}
/* An entered cycle that got stuck is not an ordinary open position, so it does
   not get to look like one. Hue in the background, per the badge rule. */
body.ai-trading-page .ai-cell-status.is-review {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 20px;
  background: rgba(224, 160, 80, 0.16);
}
body.ai-trading-page .ai-dir-mark { font-size: 10px; line-height: 1; }
body.ai-trading-page .ai-dir-mark.buy { color: var(--app-buy); }
body.ai-trading-page .ai-dir-mark.sell { color: var(--app-sell); }

body.ai-trading-page .ai-cell-num,
body.ai-trading-page .ai-cell-held { font-variant-numeric: tabular-nums; }
body.ai-trading-page .ai-cell-state { color: var(--app-text-1); }

/* Result badge -------------------------------------------------------
   The SIGN is in the text and the HUE is in the background, so the badge
   survives Ultimo's light shell and colour-blind readers (#889 rule). */
body.ai-trading-page .ai-result-badge {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 20px;
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
body.ai-trading-page .ai-result-badge.is-up { background: rgba(61, 220, 132, 0.16); color: #3ddc84; }
body.ai-trading-page .ai-result-badge.is-down { background: rgba(224, 160, 80, 0.16); color: var(--app-sell); }
body.ai-trading-page .ai-result-badge.is-flat {
  background: rgba(var(--app-content-overlay-rgb), 0.08);
  color: var(--app-text-muted-2);
}

/* Expandable row (K/D detail) ---------------------------------------- */
body.ai-trading-page .ai-trade-row.is-expandable { cursor: pointer; }
body.ai-trading-page .ai-trade-row.is-expandable:focus-visible {
  outline: 2px solid var(--app-primary);
  outline-offset: -2px;
}
body.ai-trading-page .ai-row-cue {
  margin-left: 8px;
  font-size: 10px;
  color: var(--app-text-muted-2);
}
body.ai-trading-page .ai-trade-row[aria-expanded="true"] .ai-row-cue { transform: rotate(180deg); display: inline-block; }
/* `.ai-table tbody td` is (0,2,3); these have to out-specify it or the detail
   row keeps the row border and the cell padding of an ordinary row. */
body.ai-trading-page .ai-table tbody .ai-trade-detail-row td {
  padding: 0 14px 12px;
  border-top: none;
  white-space: normal;
}
body.ai-trading-page .ai-trade-detail {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 26px;
  padding: 12px 14px;
  border-radius: var(--app-radius-sm);
  background: rgba(92, 184, 230, 0.06);
  border: 1px solid rgba(92, 184, 230, 0.2);
}
body.ai-trading-page .ai-detail-item { display: flex; flex-direction: column; gap: 2px; }
body.ai-trading-page .ai-detail-label {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  color: var(--app-text-muted-2);
}
body.ai-trading-page .ai-detail-value {
  font-size: 13px;
  font-weight: 600;
  color: var(--app-text-strong);
  font-variant-numeric: tabular-nums;
}
body.ai-trading-page .ai-detail-note {
  flex: 1 1 100%;
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--app-text-muted-2);
}

/* The funds-held message ---------------------------------------------
   money.js writes NO ledger entry for a participant parked in needs_review,
   so Transaction History cannot show this case at all and this note is the
   only place a user can find out why their available balance is down. It is
   therefore never collapsed and never a tooltip. Amber wash, like the other
   notices that change what will actually happen. */
body.ai-trading-page .ai-table tbody .ai-history-note-row td {
  padding: 0 14px 12px;
  border-top: none;
  white-space: normal;
}
body.ai-trading-page .ai-history-note {
  font-size: 12px;
  line-height: 1.6;
  color: var(--app-sell);
  background: rgba(224, 160, 80, 0.08);
  border: 1px solid rgba(224, 160, 80, 0.28);
  border-radius: var(--app-radius-sm);
  padding: 8px 12px;
}
body.ai-trading-page .ai-history-row.is-review td { border-top-color: rgba(224, 160, 80, 0.35); }

/* Show more ----------------------------------------------------------- */
body.ai-trading-page .ai-table-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  margin-top: 12px;
}
body.ai-trading-page .ai-table-error {
  font-size: 12px;
  line-height: 1.6;
  color: var(--app-sell);
}

/* Ultimo — same #889 treatment as the block above: these are accent-coloured
   TEXT on a LIGHT card (`--app-sell` #e0a050 at ~1.9:1, `#3ddc84` at ~1.6:1).
   The hue stays in the background and the border; the text moves to a neutral
   token. Nothing is lost: the result badge already carries an explicit +/-,
   the open/under-review subtitle says so in words, and the funds-held note
   keeps its amber wash. The note in particular has to be legible before
   anything else in the table — it is the only place a user learns their money
   is held. Ultimo-only ⇒ Vestex renders byte-identically. */
html[data-brand="ultimo"] body.ai-trading-page .ai-result-badge.is-up,
html[data-brand="ultimo"] body.ai-trading-page .ai-result-badge.is-down,
html[data-brand="ultimo"] body.ai-trading-page .ai-cell-status,
html[data-brand="ultimo"] body.ai-trading-page .ai-history-note,
html[data-brand="ultimo"] body.ai-trading-page .ai-table-error {
  color: var(--app-text-1);
}
/* The two directional marks are shape + position, not just hue, so they keep
   their colour — but --app-sell on white is too weak to see at 10px. */
html[data-brand="ultimo"] body.ai-trading-page .ai-dir-mark.sell { color: #b06f18; }

/* ---- Responsive ---- */
@media (max-width: 1024px) {
  body.ai-trading-page .ai-trading-main { padding: 24px 20px 60px; }
}
@media (max-width: 600px) {
  body.ai-trading-page .ai-trading-main { padding: 20px 16px 60px; }
  body.ai-trading-page .ai-bot-card { padding: 18px; }
  body.ai-trading-page .ai-alloc-row { flex-wrap: wrap; }
  body.ai-trading-page .toast-container { right: 8px; left: 8px; top: auto; bottom: 70px; }
  body.ai-trading-page .toast { min-width: auto; }
  body.ai-trading-page .ai-modal { max-width: 96vw; }

  /* Spec §10b. The BOTTOM CTA goes full-width; the TOP one keeps its natural
     width so it does not shove the chart down the page. Both wrap rather than
     scroll — the page body must never scroll sideways. No fixed heights and no
     vh units anywhere in this block: the mobile sidebar regression (#919) came
     from exactly that. */
  body.ai-trading-page .ai-cta-bottom .ai-cta-controls { gap: 10px; }
  body.ai-trading-page .ai-cta-bottom .ai-cta-controls > .ai-btn-primary,
  body.ai-trading-page .ai-cta-bottom .ai-cta-controls > .ai-btn-secondary {
    flex: 1 1 100%;
  }
  body.ai-trading-page .ai-cta-bottom .ai-copying-chip { flex: 1 1 100%; justify-content: center; }
  body.ai-trading-page .ai-cta-controls > .ai-btn-primary,
  body.ai-trading-page .ai-cta-controls > .ai-btn-secondary { padding: 0 14px; }

  body.ai-trading-page .ai-bot-stats { gap: 12px 20px; }
  body.ai-trading-page .ai-detail-title-row { gap: 8px; }
  body.ai-trading-page .ai-slot-empty { padding: 22px 14px; }

  /* Spec §10b — the two round-trip tables stack into cards rather than
     scrolling. My History is six columns wide; at 360px a horizontal scroller
     would hide the State column, which is the one carrying "under review".
     Header row is dropped and each cell labels itself from `data-label`.
     No heights and no vh anywhere here: #919 came from exactly that. */
  body.ai-trading-page .ai-trades-table,
  body.ai-trading-page .ai-history-table { min-width: 0; }
  body.ai-trading-page .ai-trades-table thead,
  body.ai-trading-page .ai-history-table thead { display: none; }
  body.ai-trading-page .ai-trades-table tbody tr,
  body.ai-trading-page .ai-history-table tbody tr { display: block; }
  body.ai-trading-page .ai-trade-row,
  body.ai-trading-page .ai-history-row {
    border-top: 1px solid var(--app-border);
    padding: 8px 0;
  }
  body.ai-trading-page .ai-trades-table tbody td,
  body.ai-trading-page .ai-history-table tbody td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 14px;
    border-top: none;
    white-space: normal;
    padding: 4px 14px;
  }
  body.ai-trading-page .ai-trades-table tbody td[data-label]::before,
  body.ai-trading-page .ai-history-table tbody td[data-label]::before {
    content: attr(data-label);
    flex: 0 0 auto;
    font-size: 10.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.3px;
    color: var(--app-text-muted-2);
  }
  /* The price cells keep price-over-time stacking, so their label is pinned to
     the left instead of being a flex sibling of the two stacked lines. */
  body.ai-trading-page .ai-trades-table tbody td.ai-cell-pair,
  body.ai-trading-page .ai-history-table tbody td.ai-cell-pair {
    display: block;
    position: relative;
    padding-left: 74px;
    text-align: right;
  }
  body.ai-trading-page .ai-trades-table tbody td.ai-cell-pair::before,
  body.ai-trading-page .ai-history-table tbody td.ai-cell-pair::before {
    position: absolute;
    left: 14px;
    top: 5px;
  }
  body.ai-trading-page .ai-cell-price { justify-content: flex-end; }
  /* Detail and funds-held rows span the card; they label themselves in words.
     Written against `.ai-table tbody` so they out-specify the stacked-cell rule
     three declarations above. */
  body.ai-trading-page .ai-table tbody .ai-trade-detail-row td,
  body.ai-trading-page .ai-table tbody .ai-history-note-row td {
    display: block;
    padding: 4px 14px 10px;
  }
  body.ai-trading-page .ai-table-actions { align-items: stretch; }
  body.ai-trading-page .ai-show-more { width: 100%; }

  /* The position strip becomes a two-up grid rather than a horizontal scroller:
     at 360px five wrapped figures would otherwise leave Est. PnL — the number
     the strip exists for — off the first line and half of it clipped. A grid
     keeps the labels aligned as they wrap. No heights and no vh here: #919 came
     from exactly that. */
  body.ai-trading-page .ai-position-strip { padding: 12px 14px; }
  body.ai-trading-page .ai-strip-figures {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px 14px;
  }
  body.ai-trading-page .ai-strip-figure { min-width: 0; }
  body.ai-trading-page .ai-strip-figure-value { overflow-wrap: anywhere; }
}
