/* ===== 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. */

/* FULL WIDTH (Takaya feedback item 9, 2026-09-04): no max-width here, on
   purpose — this page carries three charts and mirrors .trade-main
   (trade-option.css), which is padding-only, so AI Trading fills the viewport
   exactly like Spot/Futures. The old 960px cap was an undocumented leftover of
   the PR #906 scaffold, not a design decision. Uniformity contract: EVERY
   section (hero tiles, status, charts, tables, prospectus, pot panel) is a
   stretch child of this one container / of #aiDetailView's flex column, so
   they all share the same left/right edges — any reading-measure cap must be
   INTERNAL to a section's box (see the prospectus columns rule), never a
   per-section max-width that would stagger the right edges. */
body.ai-trading-page .ai-trading-main {
  padding: 28px 40px 80px;
}

/* ---- `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);
}

/* ---- Presentation config (design §6f) ----
   `horizonBadge` and `subtitle`, admin2-editable in place. Deliberately NOT
   styled as a status pill: the status pill states a MACHINE fact (is this bot
   running) in a colour that means something, and the horizon chip states an
   editorial classification. Sharing the pill's styling would make an operator's
   free-text label look like a system state. Neutral surface, no colour coding,
   no uppercasing — an operator's capitalisation is preserved as typed. */
body.ai-trading-page .ai-horizon-badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.2px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--app-border);
  color: var(--app-text-muted-2);
}
body.ai-trading-page .ai-bot-subtitle {
  margin-bottom: 8px;
  font-size: 13px;
  color: var(--app-text-muted-2);
}
/* The name's gloss (2026-09-09). Quieter and tighter to the title than the
   subtitle below it: it is an aside about the WORD, not a second description of
   the bot, and it must not compete with either the name above or the editorial
   line under it. Sits close to the title on purpose — the two read as one unit. */
body.ai-trading-page .ai-detail-name-note {
  margin-top: 4px;
  font-size: 13px;
  color: var(--app-text-muted-2);
  opacity: 0.85;
}
body.ai-trading-page .ai-detail-subtitle {
  margin-top: 8px;
  font-size: 14.5px;
  color: var(--app-text-muted-2);
}

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);
}
/* The notes moved into a wrapper when the strip stopped rebuilding itself on
   every mark-price refresh (2026-09-09): a stable container is what lets the
   renderer write into the rows already on screen. It re-creates the spacing the
   notes had as direct children of the strip's own column, and collapses when
   there are none — an empty flex item would otherwise leave the strip a 10px
   gap taller than it was before. */
body.ai-trading-page .ai-strip-notes {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
body.ai-trading-page .ai-strip-notes:empty { display: none; }

/* 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);
}
/* Virtual round trips (roadmap #17) — visually distinct from the real
   closed/wins row above so a simulated number is never mistaken for one
   backed by real money. */
body.ai-trading-page .ai-bot-stats-signal-only {
  margin-top: 6px;
}
body.ai-trading-page .ai-bot-stat-signal-only .ai-bot-stat-label {
  color: var(--app-text-muted-2);
  font-style: italic;
}
body.ai-trading-page .ai-bot-stat-signal-only .ai-bot-stat-value {
  font-size: 13px;
  font-weight: 500;
  color: var(--app-text-muted);
}

/* Stage 3 item #13 — Overview card: all-time index % + sparkline + P/L. */
body.ai-trading-page .ai-bot-index-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 12px;
}
body.ai-trading-page .ai-bot-index-label {
  font-size: 13px;
  font-weight: 600;
}
body.ai-trading-page .ai-bot-index-ended {
  color: var(--app-text-muted-2);
  font-style: italic;
  font-weight: 500;
}
/* Same coloring convention as .ai-result-positive/.ai-result-negative
   below, kept separate so the index label's exact shade can diverge from
   the trade-result copy without touching either. */
body.ai-trading-page .ai-bot-index-label.ai-result-positive { color: #3ddc84; }
body.ai-trading-page .ai-bot-index-label.ai-result-negative { color: var(--app-sell); }
/* Same shape/opacity convention as .mo-sparkline (market-overview.css) —
   the underlying window.VestexSparkline helper is the SAME code, this is
   only the container sizing, which differs per card layout. */
body.ai-trading-page .ai-bot-sparkline {
  width: 72px;
  height: 24px;
  flex-shrink: 0;
}
body.ai-trading-page .ai-bot-sparkline path.spark-line { stroke-width: 1.5; fill: none; }
body.ai-trading-page .ai-bot-sparkline path.spark-fill { opacity: 0.12; }

body.ai-trading-page .ai-bot-pnl-row {
  margin-top: 8px;
  font-size: 13px;
}
body.ai-trading-page .ai-bot-pnl-label { color: var(--app-text-muted-2); }
body.ai-trading-page .ai-bot-pnl-value { 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);
}

/* STATUS card first line (manager 2026-09-07): three facts, one line. */
body.ai-trading-page .ai-strip-first-line {
  font-size: 14px;
  font-weight: 600;
  color: var(--app-text-strong);
  margin: 6px 0 10px;
}

/* ===================================================================
   OVERVIEW — the fund-screener row list (owner item D13, 2026-09-07)
   Contract: docs/handoffs/DESIGN-AI-OVERVIEW-2026-09-07.md
   Mockup:   docs/handoffs/AI-OVERVIEW-MOCKUP-2026-09-07.html

   The list is capped at 1320px and left-aligned under the page title — a
   fund list is content-width, never full-bleed on a wide monitor. Header and
   every row share ONE grid, so a column cannot drift between them.

   Colours come from the brand tokens wherever one exists (`--app-primary` IS
   the mockup's cyan #5cb8e6, `--app-primary-fg` its ink), so the Ultimo
   whitelabel re-themes this list with the rest of the page. The three that
   have no token — the BTC/USDT unit colours and the amber reference note —
   are declared once here, on the list itself.
   =================================================================== */
body.ai-trading-page .ai-ov-list {
  /* THE ACCENT IS THE BRAND'S, not a literal cyan. Ultimo overrides
     `--app-primary` to amber and runs a LIGHT theme, so a hard-coded
     rgba(92,184,230,…) tint would sit under an amber bar, and white-alpha
     separators would be invisible on it. Every soft/derived colour below is
     mixed from a token, with the Vestex literal as the fallback declaration
     for any engine that cannot parse `color-mix` (it drops that declaration
     and keeps the one above it). */
  --ov-cyan: var(--app-primary);
  --ov-cyan-ink: var(--app-primary-fg);
  --ov-cyan-soft: rgba(92, 184, 230, 0.10);
  --ov-cyan-soft: color-mix(in srgb, var(--app-primary) 10%, transparent);
  --ov-cyan-soft-hover: rgba(92, 184, 230, 0.15);
  --ov-cyan-soft-hover: color-mix(in srgb, var(--app-primary) 16%, transparent);
  --ov-cyan-rule: rgba(92, 184, 230, 0.35);
  --ov-cyan-rule: color-mix(in srgb, var(--app-primary) 35%, transparent);
  /* Neutrals mixed from the TEXT colour, so they invert with the theme
     instead of assuming a dark ground. */
  --ov-line-h: rgba(255, 255, 255, 0.16);
  --ov-line-h: color-mix(in srgb, var(--app-text-strong) 22%, transparent);
  --ov-sep: rgba(255, 255, 255, 0.07);
  --ov-sep: color-mix(in srgb, var(--app-text-strong) 10%, transparent);
  --ov-row-hover: rgba(255, 255, 255, 0.025);
  --ov-row-hover: color-mix(in srgb, var(--app-text-strong) 4%, transparent);
  /* The two currency colours are the CURRENCY's, not the brand's: BTC orange
     and USDT teal mean the same thing on every whitelabel, and both clear
     4.5:1 on the light and the dark panel. */
  --ov-btc: #f7931a;
  --ov-usdt: #2bb3a3;
  --ov-amber: var(--app-sell);
  max-width: 1320px;
  background: var(--app-surface-2);
  border: 1px solid var(--app-border);
  border-radius: var(--app-radius-md);
  overflow: hidden;
  /* Every breakpoint below is a CONTAINER query on this element, not a media
     query: the list is what runs out of room (the sidebar takes width from it
     at a viewport size that says nothing about the list), so the columns must
     drop when the LIST narrows, not when the window does. */
  container-type: inline-size;
}
body.ai-trading-page .ai-ov-cols {
  display: grid;
  /* TOTAL P/L is 176px, not 140px, because its sub-line is the widest one in
     the table and it is a DISCLOSURE: "per 1 BTC · reference + 12 live" is the
     longest form, ~174px at 11.5px. At 140px it ellipsised to
     "per 1 BTC · reference 2…" — which is the marker that stops +4.37037029 BTC
     reading as realized money, cut off exactly where it stops working. The
     owner's own rule for this table (2026-09-11): "If a column still cannot
     hold its widest value, the column's minimum width grows before anything is
     shrunk further." The `live` breakpoint below moves by the same 36px so the
     relationship the old 140px encoded is kept — see there. */
  grid-template-columns: minmax(220px, 1fr) 120px 96px 176px 80px 140px 124px 132px;
  column-gap: 12px;
  align-items: center;
  padding: 0 16px;
}
body.ai-trading-page .ai-ov-num { font-variant-numeric: tabular-nums; }

/* ---- sticky header with the three-state sort ---- */
body.ai-trading-page .ai-ov-hdr {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--app-surface-1);
  border-bottom: 1px solid var(--app-border);
  min-height: 38px;
}
body.ai-trading-page .ai-ov-hdr button,
body.ai-trading-page .ai-ov-hdr span {
  all: unset;
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--app-text-muted-2);
  white-space: nowrap;
  cursor: default;
  padding: 10px 0;
}
body.ai-trading-page .ai-ov-hdr button { cursor: pointer; }
body.ai-trading-page .ai-ov-hdr button:hover { color: var(--app-text-strong); }
body.ai-trading-page .ai-ov-hdr button:focus-visible {
  outline: 2px solid var(--ov-cyan);
  outline-offset: -2px;
}
body.ai-trading-page .ai-ov-arr { font-size: 9px; opacity: 0; transition: opacity 0.15s; }
body.ai-trading-page .ai-ov-hdr button:hover .ai-ov-arr { opacity: 0.5; }
body.ai-trading-page .ai-ov-hdr [aria-sort] button { color: var(--app-text-strong); }
body.ai-trading-page .ai-ov-hdr [aria-sort] button .ai-ov-arr { opacity: 1; }
body.ai-trading-page .ai-ov-hdr .ai-ov-r { justify-content: flex-end; }
body.ai-trading-page .ai-ov-hdr [role="columnheader"] { display: flex; }
body.ai-trading-page .ai-ov-hdr .ai-ov-r[role="columnheader"] { justify-content: flex-end; }

/* ---- rows ---- */
body.ai-trading-page .ai-ov-row {
  position: relative;
  min-height: 60px;
  border-bottom: 1px solid var(--ov-sep);
  transition: background 0.12s;
}
body.ai-trading-page .ai-ov-row:last-child { border-bottom: 0; }
body.ai-trading-page .ai-ov-row:hover { background: var(--ov-row-hover); }
/* Copied rows are unmistakable: a 3px bar, a tint and the chip — never colour
   alone (the chip carries the word). */
body.ai-trading-page .ai-ov-mine::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--ov-cyan);
}
body.ai-trading-page .ai-ov-stopped::before { background: var(--ov-line-h); }
body.ai-trading-page .ai-ov-copying { background: var(--ov-cyan-soft); }
body.ai-trading-page .ai-ov-copying:hover { background: var(--ov-cyan-soft-hover); }
/* The thin cyan rule that closes the pinned group. */
body.ai-trading-page .ai-ov-pin-end { border-bottom: 1px solid var(--ov-cyan-rule); }

body.ai-trading-page .ai-ov-cell { min-width: 0; }
body.ai-trading-page .ai-ov-r { text-align: right; }
body.ai-trading-page .ai-ov-l1 {
  font-size: 15px;
  font-weight: 600;
  line-height: 20px;
  white-space: nowrap;
  color: var(--app-text-strong);
}
body.ai-trading-page .ai-ov-l1.ai-ov-empty { color: var(--app-text-muted-2); font-weight: 500; }
/* The two headline figures are one step larger than the rest. */
body.ai-trading-page .ai-ov-c-win .ai-ov-l1,
body.ai-trading-page .ai-ov-c-pnl .ai-ov-l1 { font-size: 17px; }
body.ai-trading-page .ai-ov-unit { font-size: 11px; font-weight: 600; margin-left: 3px; }
body.ai-trading-page .ai-ov-u-btc { color: var(--ov-btc); }
body.ai-trading-page .ai-ov-u-usdt { color: var(--ov-usdt); }
body.ai-trading-page .ai-ov-l2 {
  font-size: 11.5px;
  line-height: 15px;
  color: var(--app-text-muted-2);
  margin-top: 1px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
body.ai-trading-page .ai-ov-l2.ai-ov-ref { color: var(--ov-amber); }
/* The stopped row's "Copy again" on its own line. It inherits `.ai-ov-l2`, so
   the ellipsis has to be turned OFF here: an action the reader cannot finish
   reading is worse than one that wraps. On its own line it is ~58px against a
   120px column and never reaches the edge. */
body.ai-trading-page .ai-ov-l2-action {
  overflow: visible;
  text-overflow: clip;
}

/* ---- the Bot cell: name is the row's stretched link ---- */
body.ai-trading-page .ai-ov-name {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
body.ai-trading-page .ai-ov-namelink {
  color: var(--app-text-strong);
  text-decoration: none;
  font-size: 15px;
  font-weight: 600;
  line-height: 20px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* The whole row opens the bot page. Buttons and inline links are SIBLINGS
   with z-index 1, never inside the anchor. */
body.ai-trading-page .ai-ov-namelink::after { content: ""; position: absolute; inset: 0; }
body.ai-trading-page .ai-ov-namelink:focus-visible { outline: none; }
body.ai-trading-page .ai-ov-namelink:focus-visible::after {
  outline: 2px solid var(--ov-cyan);
  outline-offset: -2px;
}

/* ---- chips ---- */
body.ai-trading-page .ai-ov-chip {
  display: inline-flex;
  align-items: center;
  height: 18px;
  padding: 0 7px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
  flex: none;
  border: 1px solid var(--ov-line-h);
  color: var(--app-text-muted-2);
}
body.ai-trading-page .ai-ov-chip-btc { border-color: var(--ov-btc); color: var(--ov-btc); }
body.ai-trading-page .ai-ov-chip-usdt { border-color: var(--ov-usdt); color: var(--ov-usdt); }
body.ai-trading-page .ai-ov-chip-paused { border-color: var(--ov-amber); color: var(--ov-amber); }
body.ai-trading-page .ai-ov-chip-copying {
  background: var(--ov-cyan);
  border-color: var(--ov-cyan);
  color: var(--ov-cyan-ink);
  height: 20px;
  font-size: 10.5px;
}
body.ai-trading-page .ai-ov-chip-stopped { height: 20px; font-size: 10.5px; }

/* ---- the Copy control and inline links: siblings ABOVE the stretched link ---- */
body.ai-trading-page .ai-ov-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 34px;
  padding: 0 14px;
  border-radius: 9px;
  font-weight: 600;
  font-size: 13px;
  background: var(--ov-cyan);
  color: var(--ov-cyan-ink);
  border: 0;
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
  position: relative;
  z-index: 1;
}
body.ai-trading-page .ai-ov-btn-ghost {
  background: transparent;
  border: 1px solid var(--ov-cyan);
  color: var(--ov-cyan);
}
body.ai-trading-page .ai-ov-btn-ghost:hover { background: var(--ov-cyan-soft); }
body.ai-trading-page .ai-ov-btn:focus-visible { outline: 2px solid var(--app-text-strong); outline-offset: 2px; }
body.ai-trading-page .ai-ov-linkish {
  color: var(--ov-cyan);
  font-size: 12px;
  text-decoration: none;
  position: relative;
  z-index: 1;
}

/* ---- loading / error states ---- */
body.ai-trading-page .ai-ov-skeleton .ai-ov-row { pointer-events: none; }
body.ai-trading-page .ai-ov-skel-bar {
  height: 12px;
  border-radius: 6px;
  background: var(--ov-sep);
}
body.ai-trading-page .ai-ov-error {
  max-width: 1320px;
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding: 20px;
  background: var(--app-surface-2);
  border: 1px solid var(--app-border);
  border-radius: var(--app-radius-md);
}

/* ---- progressive hiding: Live, then Last closed, then Your pot, before the
   two-line collapse. Each rule drops BOTH the header cell and the body cell,
   and re-states the grid so the remaining columns keep their widths. ---- */
body.ai-trading-page .ai-ov-figs { display: none; }
/* EACH BREAKPOINT IS ITS OWN TEMPLATE'S ARITHMETIC, not a round number.
   A template fits when `Σ tracks + 12px × (n−1) gaps + 32px padding` is at most
   the container; below that the grid overflows and `.ai-ov-list`'s
   `overflow: hidden` CLIPS the rightmost column — Your P/L simply disappears at
   the right edge, with no scrollbar to say so.
   The old 1167 / 1050 / 900 / 760 each left such a band (25px, 23px, 7px wide),
   and widening TOTAL P/L would have widened them to 61px, 59px and 43px. So
   every breakpoint now equals what its own template needs:
       8 cols  1088 + 84 + 32 = 1204
       7 cols  1008 + 72 + 32 = 1112
       6 cols   868 + 60 + 32 =  960
       5 cols   724 + 48 + 32 =  804
   Found by Codex R1 on this change; the bands it removes were there before it.
   The twins live in OVERVIEW_HIDE_AT / OVERVIEW_STACK_AT (js/ai-trading.js) and
   a test recomputes this arithmetic rather than restating the four numbers. */
@container (max-width: 1204px) {
  body.ai-trading-page .ai-ov-cols {
    grid-template-columns: minmax(220px, 1fr) 120px 96px 176px 140px 124px 132px;
  }
  body.ai-trading-page .ai-ov-c-live,
  body.ai-trading-page .ai-ov-hdr [data-key="live"] { display: none; }
}
@container (max-width: 1112px) {
  body.ai-trading-page .ai-ov-cols {
    grid-template-columns: minmax(220px, 1fr) 120px 96px 176px 124px 132px;
  }
  body.ai-trading-page .ai-ov-c-closed,
  body.ai-trading-page .ai-ov-hdr [data-key="closed"] { display: none; }
}
@container (max-width: 960px) {
  body.ai-trading-page .ai-ov-cols {
    grid-template-columns: minmax(200px, 1fr) 120px 96px 176px 132px;
  }
  body.ai-trading-page .ai-ov-c-pot,
  body.ai-trading-page .ai-ov-hdr [data-key="pot"] { display: none; }
}
/* ---- narrow: the header goes, each row becomes two lines. No horizontal
   scroll at any width; the hidden columns are on the bot page. ---- */
@container (max-width: 804px) {
  body.ai-trading-page .ai-ov-hdr { display: none; }
  body.ai-trading-page .ai-ov-cols {
    grid-template-columns: 1fr auto;
    grid-template-areas: "bot status" "figs figs";
    row-gap: 6px;
    padding: 12px 16px;
  }
  body.ai-trading-page .ai-ov-cell { display: none; }
  body.ai-trading-page .ai-ov-c-bot { display: block; grid-area: bot; }
  body.ai-trading-page .ai-ov-c-status { display: block; grid-area: status; text-align: right; }
  body.ai-trading-page .ai-ov-figs {
    display: flex;
    grid-area: figs;
    gap: 14px;
    font-size: 13px;
    color: var(--app-text-muted-2);
    flex-wrap: wrap;
  }
  body.ai-trading-page .ai-ov-figs b { color: var(--app-text-strong); font-weight: 600; }
  body.ai-trading-page .ai-ov-name { flex-wrap: wrap; row-gap: 4px; }
  body.ai-trading-page .ai-ov-namelink { white-space: normal; }
  body.ai-trading-page .ai-ov-c-bot .ai-ov-l2 { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  body.ai-trading-page .ai-ov-row,
  body.ai-trading-page .ai-ov-arr { transition: none; }
}

/* ---- Overview TABLE (manager item D, 2026-09-07) — SUPERSEDED by the row
   list above (item D13). Kept only because `.ai-bot-card*` shares the token
   choices; nothing renders `.ai-bot-table` any more. ---- */
body.ai-trading-page .ai-bot-table-wrap {
  width: 100%;
  overflow-x: auto;
  background: var(--app-surface-2);
  border: 1px solid var(--app-border);
  border-radius: var(--app-radius-md);
}
body.ai-trading-page .ai-bot-table {
  width: 100%;
  min-width: 760px;
  border-collapse: collapse;
  font-size: 13.5px;
}
body.ai-trading-page .ai-bot-table th {
  text-align: left;
  padding: 12px 14px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  color: var(--app-text-muted-2);
  border-bottom: 1px solid var(--app-border);
  white-space: nowrap;
}
body.ai-trading-page .ai-bot-table td {
  padding: 12px 14px;
  vertical-align: top;
  border-bottom: 1px solid var(--app-border);
  color: var(--app-text-strong);
}
body.ai-trading-page .ai-bot-table tbody tr:last-child td { border-bottom: 0; }
body.ai-trading-page .ai-bot-row { cursor: pointer; transition: background 0.15s; }
body.ai-trading-page .ai-bot-row:hover { background: var(--app-surface-1); }
body.ai-trading-page .ai-bot-row-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  line-height: 1.35;
}
body.ai-trading-page .ai-bot-row-line + .ai-bot-row-line { margin-top: 4px; }
body.ai-trading-page .ai-bot-row-sub { font-size: 12px; color: var(--app-text-muted-2); }
body.ai-trading-page .ai-bot-row-link { text-decoration: none; color: inherit; }
body.ai-trading-page .ai-bot-row-link:hover { color: var(--app-primary); }
body.ai-trading-page .ai-bot-row-link:focus-visible { outline: 2px solid var(--app-primary); outline-offset: 2px; }
body.ai-trading-page .ai-bot-table .ai-bot-name { font-size: 15px; }
body.ai-trading-page .ai-bot-table .ai-bot-index-row { margin-top: 0; justify-content: flex-start; }
body.ai-trading-page .ai-bot-cell-dates,
body.ai-trading-page .ai-bot-cell-mine { white-space: nowrap; }
body.ai-trading-page .ai-bot-mine-active { color: #3ddc84; font-weight: 600; }
body.ai-trading-page .ai-bot-cell-pnl { font-weight: 600; }

/* ===================================================================
   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);
}

/* ---- Full-history chart (layout v2 row D) ----
   The canvas owns its own pixel height (set per draw, desktop vs mobile), so
   nothing here fixes one: a height here and a height in the module would be
   two sources of truth for the same number. The wrapper only has to give the
   canvas a width to measure and survive a closed <details> at zero width. */
body.ai-trading-page .ai-history-chart {
  width: 100%;
  min-height: 1px;
}

body.ai-trading-page .ai-history-chart-canvas {
  display: block;
  width: 100%;
}

body.ai-trading-page .ai-history-chart-caption {
  margin: 10px 0 0;
  font-size: 12px;
  line-height: 1.6;
  color: var(--app-text-muted-2);
}

body.ai-trading-page .ai-history-chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  margin-top: 8px;
  font-size: 12px;
  color: var(--app-text-muted-2);
}

body.ai-trading-page .ai-history-chart-legend span {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

body.ai-trading-page .ai-history-chart-legend i {
  width: 10px;
  height: 10px;
  border-radius: 2px;
  background: currentColor;
}

/* The swatches repeat the canvas's palette, and both sides read the SAME brand
   tokens — a legend that hard-codes a colour is a legend that lies the first
   time a partner brand swaps the theme. Entry green is the one literal, and it
   is literal in the module too (it is not a brand token there either). */
body.ai-trading-page .ai-history-chart-legend i[data-swatch="line"] { background: var(--app-primary); }
body.ai-trading-page .ai-history-chart-legend i[data-swatch="band"] { background: var(--app-sell); opacity: 0.45; }
body.ai-trading-page .ai-history-chart-legend i[data-swatch="entry"] { background: #2fbf71; }
body.ai-trading-page .ai-history-chart-legend i[data-swatch="exit"] { background: var(--app-sell); }

/* ---- Your Performance (Stage 3 item #14) ---- */
body.ai-trading-page .ai-yp-headline {
  display: flex;
  flex-wrap: wrap;
  gap: 20px 32px;
  margin-bottom: 16px;
}
body.ai-trading-page .ai-yp-stat-label {
  font-size: 12px;
  color: var(--app-text-muted-2);
  margin-bottom: 4px;
}
body.ai-trading-page .ai-yp-stat-value {
  font-size: 18px;
  font-weight: 700;
  color: var(--app-text-strong);
}
body.ai-trading-page .ai-yp-stat-value.ai-result-positive { color: #3ddc84; }
body.ai-trading-page .ai-yp-stat-value.ai-result-negative { color: var(--app-sell); }
/* Item #15: BTC-margin bots' USD-equivalent, secondary to the BTC figure
   above it — never the same weight, the BTC amount stays authoritative. */
body.ai-trading-page .ai-yp-stat-usd {
  margin-top: 2px;
  font-size: 13px;
  font-weight: 500;
  color: var(--app-text-muted-2);
}
body.ai-trading-page .ai-yp-chart-wrap {
  border: 1px solid var(--app-border);
  border-radius: var(--app-radius-sm);
  padding: 8px;
}
/* Item #15: BTC/USD chart toggle. */
body.ai-trading-page .ai-yp-chart-toggle {
  display: flex;
  gap: 6px;
  margin-bottom: 8px;
}
body.ai-trading-page .ai-yp-toggle-btn {
  padding: 4px 12px;
  font-size: 12px;
  font-weight: 600;
  border: 1px solid var(--app-border);
  border-radius: var(--app-radius-sm);
  background: transparent;
  color: var(--app-text-muted-2);
  cursor: pointer;
}
body.ai-trading-page .ai-yp-toggle-btn[aria-pressed="true"] {
  background: var(--app-primary);
  border-color: var(--app-primary);
  color: var(--app-primary-fg);
}
body.ai-trading-page .ai-yp-toggle-btn:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}
/* NO height/padding on the chart mount div itself — same convention as
   .ai-slot: the chart module (lightweight-charts here) sizes its own
   container. */
body.ai-trading-page .ai-yp-chart { min-height: 220px; }

/* ---- Participant vs non-participant layout (Stage 3 item #4e) ----
   #aiDetailView becomes a flex column so its DIRECT children can be
   reordered visually via `order`, without ever moving a DOM node (see the
   HTML comment above #aiDetailView, and js/ai-trading.js
   renderDetailLayout()). DOM source order is unchanged and stays the
   fallback for no-CSS/screen-reader contexts. `order` values below apply
   ONLY to genuine direct children — nothing inside .ai-detail-accordion
   gets one, since that internal sequence never differs between layouts. */
body.ai-trading-page #aiDetailView {
  display: flex;
  flex-direction: column;
}

/* Participant: position strip -> Your Performance -> status line ->
   description/CTA-top -> accordion (collapsed) -> PROSPECTUS (collapsed) ->
   CTA-bottom.

   The prospectus sits at the BOTTOM of this layout on the owner's §7 rule:
   "for users already participating, this must not clutter the page —
   collapsed by default and/or placed below the operational content for
   them". Both halves of that, not either: collapsed (js/ai-trading.js
   renderDetailLayout()) AND last but for the CTA. */
body.ai-trading-page #aiDetailView.ai-layout-participant > #aiPositionStrip { order: 1; }
body.ai-trading-page #aiDetailView.ai-layout-participant > #aiYourPerformanceSection { order: 2; }
body.ai-trading-page #aiDetailView.ai-layout-participant > #aiBotStatusLine { order: 3; }
body.ai-trading-page #aiDetailView.ai-layout-participant > #aiDetailDescription { order: 4; }
body.ai-trading-page #aiDetailView.ai-layout-participant > #aiCtaTop { order: 4; }
body.ai-trading-page #aiDetailView.ai-layout-participant > #aiDetailAccordion { order: 5; }
body.ai-trading-page #aiDetailView.ai-layout-participant > #aiProspectus { order: 6; }
body.ai-trading-page #aiDetailView.ai-layout-participant > #aiCtaBottom { order: 7; }

/* Visitor (non-participant): bot performance first -> position strip
   (empty for a normal bot, the Signals strip for a signal-only one) ->
   description -> PROSPECTUS (forced open) -> accordion (forced open) ->
   CTA-bottom. CTA-top, Your Performance and the status line are hidden
   entirely (no order needed).

   The prospectus comes BEFORE the record here, and before the only CTA:
   "fully visible before first participation" (§7). This is the mirror of its
   participant placement above, which is precisely why it is a separate
   element from the accordion rather than a section inside it. */
body.ai-trading-page #aiDetailView.ai-layout-visitor > #aiBotPerformanceSection { order: 1; }
body.ai-trading-page #aiDetailView.ai-layout-visitor > #aiPositionStrip { order: 2; }
body.ai-trading-page #aiDetailView.ai-layout-visitor > #aiDetailDescription { order: 3; }
body.ai-trading-page #aiDetailView.ai-layout-visitor > #aiProspectus { order: 4; }
body.ai-trading-page #aiDetailView.ai-layout-visitor > #aiDetailAccordion { order: 5; }
body.ai-trading-page #aiDetailView.ai-layout-visitor > #aiCtaBottom { order: 6; }
body.ai-trading-page #aiDetailView.ai-layout-visitor > #aiCtaTop { display: none; }
body.ai-trading-page #aiDetailView.ai-layout-visitor > #aiYourPerformanceSection,
body.ai-trading-page #aiDetailView.ai-layout-visitor > #aiBotStatusLine {
  display: none;
}
/* Hidden (not participant-relevant) rather than order-less — a participant
   already has Your Performance for "see my results", so bot-performance
   would duplicate it. `[hidden]` already wins on its own (page-wide rule
   above), this just documents intent alongside the visitor rule it mirrors. */
body.ai-trading-page #aiDetailView.ai-layout-participant > #aiBotPerformanceSection {
  display: none;
}

/* One-line bot status (participant layout). Deliberately plain — a status
   LINE, not another stat card. */
body.ai-trading-page .ai-bot-status-line {
  font-size: 13px;
  color: var(--app-text-muted-2);
  margin: 10px 0;
}

/* "Bot details & full record" accordion (participant layout, collapsed by
   default; visitor layout forces `open` and hides the <summary> toggle so
   it reads as an ordinary always-expanded section). Native <details>/
   <summary> — no custom JS state machine, no hand-rolled ARIA. */
body.ai-trading-page .ai-detail-accordion {
  margin-top: 8px;
}
body.ai-trading-page .ai-detail-accordion-summary {
  cursor: pointer;
  list-style: none;
  font-size: 13px;
  font-weight: 600;
  color: var(--app-text-1);
  padding: 12px 14px;
  border: 1px solid var(--app-border);
  border-radius: var(--app-radius-sm);
  user-select: none;
}
body.ai-trading-page .ai-detail-accordion-summary::-webkit-details-marker { display: none; }
body.ai-trading-page .ai-detail-accordion-summary::before {
  content: '▸';
  display: inline-block;
  margin-right: 8px;
  transition: transform 0.15s ease;
}
body.ai-trading-page .ai-detail-accordion[open] > .ai-detail-accordion-summary::before {
  transform: rotate(90deg);
}
body.ai-trading-page #aiDetailView.ai-layout-visitor .ai-detail-accordion-summary {
  display: none;
}
/* The accordion's OWN direct children (strategy/chart/Recent Trades/My
   History) keep their existing .ai-section margin-top spacing — no flex
   here, plain block flow, so their relative order stays pure DOM order. */

/* ---- PROSPECTUS (design §7) ----
   Its own <details>, styled deliberately UNLIKE the record accordion above:
   that one is a drawer of tables and charts, this is prose a customer is
   meant to read. Wider line-height, a visible panel behind it, and — in the
   visitor layout, where it is forced open — no summary toggle, so it reads
   as a section of the page rather than as something optional. */
body.ai-trading-page .ai-prospectus {
  margin-top: 16px;
  border: 1px solid var(--app-border);
  border-radius: var(--app-radius-sm);
  background: var(--app-surface-2);
}
body.ai-trading-page .ai-prospectus-summary {
  cursor: pointer;
  list-style: none;
  font-size: 13px;
  font-weight: 600;
  color: var(--app-text-1);
  padding: 12px 14px;
  user-select: none;
}
body.ai-trading-page .ai-prospectus-summary::-webkit-details-marker { display: none; }
body.ai-trading-page .ai-prospectus-summary::before {
  content: 'B8';
  display: inline-block;
  margin-right: 8px;
  transition: transform 0.15s ease;
}
body.ai-trading-page .ai-prospectus[open] > .ai-prospectus-summary::before {
  transform: rotate(90deg);
}
/* Forced open for a visitor (renderDetailLayout()), so the toggle would be a
   control that does nothing — same treatment the record accordion gets. */
body.ai-trading-page #aiDetailView.ai-layout-visitor .ai-prospectus-summary {
  display: none;
}
body.ai-trading-page .ai-prospectus-body {
  padding: 4px 18px 18px;
  font-size: 13.5px;
  line-height: 1.75;
  color: var(--app-text-muted-2);
}
body.ai-trading-page #aiDetailView.ai-layout-visitor .ai-prospectus-body {
  padding-top: 18px;
}
body.ai-trading-page .ai-prospectus-section { margin-top: 18px; }
body.ai-trading-page .ai-prospectus-section:first-child { margin-top: 0; }
body.ai-trading-page .ai-prospectus-heading {
  margin: 0 0 6px;
  font-size: 13px;
  font-weight: 700;
  color: var(--app-text-strong);
}
body.ai-trading-page .ai-prospectus-body p { margin: 0 0 8px; }
body.ai-trading-page .ai-prospectus-body p:last-child { margin-bottom: 0; }
/* Reading measure on the full-width page (Takaya item 9): the prospectus CARD
   still spans the container edge-to-edge like every other section — the line
   length is capped INSIDE it with CSS columns, so its box never wraps to its
   own narrower right edge (the staggered-edge patchwork the owner banned).
   Scoped to the IN-FLOW element only (#aiDetailView > .ai-prospectus):
   renderStrategyModal() moves this same node into the strategy modal dialog,
   where a multi-column body would fight the narrow dialog width. */
@media (min-width: 1200px) {
  body.ai-trading-page #aiDetailView > .ai-prospectus .ai-prospectus-body {
    columns: 46ch;
    column-gap: 44px;
  }
  body.ai-trading-page #aiDetailView > .ai-prospectus .ai-prospectus-heading {
    break-after: avoid;
  }
}
/* Owner review still outstanding (§11-4). Amber, the page's existing
   "attention, not danger" colour — this is a caveat about the text, not a
   warning about money. */
body.ai-trading-page .ai-prospectus-draft {
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: var(--app-radius-sm);
  background: rgba(224, 160, 80, 0.12);
  color: var(--app-sell);
  font-size: 12px;
  font-weight: 600;
}

/* ---- 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; }
body.ai-trading-page .ai-signal-table { min-width: 620px; }

/* Signal record ------------------------------------------------------
   It ACCUMULATES, so it scrolls vertically inside its own box instead of
   growing the page without limit. The header stays put while the rows move —
   a record you have to scroll is useless if you lose the column meanings.
   Horizontal overflow is still .ai-table-wrap's job; this only adds height. */
body.ai-trading-page .ai-signal-scroll {
  max-height: 22rem;
  overflow-y: auto;
}
body.ai-trading-page .ai-signal-scroll thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--app-surface, #12151c);
}
/* A skipped decision is real content, not an error — dimmed, never red: the
   bot deciding NOT to trade is the strategy working, and colouring it as a
   failure would teach the reader to distrust a healthy run. */
body.ai-trading-page .ai-signal-row.is-skipped { opacity: 0.72; }

/* 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);
}
/* A virtual round trip's honesty label — sits under the result badge so the
   decision-close prices in the row are never mistaken for fills. */
body.ai-trading-page .ai-simulated-badge {
  display: block;
  margin-top: 3px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  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);
}
/* "Conditions at the time of this trade" (manager 2026-09-04 item 4): the
   parameter snapshot the cycle carries, under its own heading so a rule is
   never read as an indicator value. Same box, a second one when both exist. */
body.ai-trading-page .ai-trade-detail + .ai-trade-detail { margin-top: 8px; }
body.ai-trading-page .ai-detail-subhead {
  flex: 1 1 100%;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.2px;
  color: var(--app-text-strong);
}
body.ai-trading-page .ai-history-table tbody tr.is-expandable { cursor: pointer; }
body.ai-trading-page .ai-history-table tbody tr.is-expandable .ai-row-cue { margin-left: 6px; opacity: 0.7; }

/* "Live rules differ from the reference backtest since <date>" — the server's
   own sentence when a certified value has moved. Amber, like every other
   notice on this page that changes how the figures should be read. */
body.ai-trading-page .ai-live-rules-note {
  margin: 8px 0 0;
  padding: 8px 12px;
  border-radius: var(--app-radius-sm);
  background: rgba(224, 160, 80, 0.12);
  border: 1px solid rgba(224, 160, 80, 0.35);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--app-text-strong);
}

/* The "Changes" memo in Strategy details — dated plain text, newest first. */
body.ai-trading-page .ai-changes-list {
  margin: 0;
  padding-left: 18px;
  font-size: 13px;
  line-height: 1.7;
}
body.ai-trading-page .ai-changes-note { color: var(--app-text-muted-2); }

/* "Fees not included." — the one small note beside every price-result P/L
   (manager item 6): under the performance curve and under My History. */
body.ai-trading-page .ai-fees-note {
  margin: 6px 0 0;
  font-size: 11.5px;
  line-height: 1.5;
  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; }
}

/* ======================================================================
   LAYOUT v2 — the reference record (owner 2026-08-31: "nobody reads prose
   first"). Everything below is scoped under #aiDetailView.ai-restack or the
   record/modal elements themselves, so a bot without a reference record
   renders byte-identically to the rules above this line.
   ====================================================================== */

/* --- hero stat tiles (renderHeroRecord) ------------------------------- */
/* §4-2 (owner, 2026-09-02): the provenance line reads as if it qualified the
   card BELOW it. It belongs to the tiles. `.ai-hero-block` binds the grid and
   the note into one unit with a small internal gap; the section carries the
   clear gap that separates that unit from whatever card follows. */
body.ai-trading-page .ai-hero-record { margin-top: 16px; margin-bottom: 28px; }
body.ai-trading-page .ai-hero-block {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
body.ai-trading-page .ai-hero-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
}
body.ai-trading-page .ai-hero-tile {
  background: var(--app-surface-2, rgba(255, 255, 255, 0.03));
  border: 1px solid var(--app-border, rgba(255, 255, 255, 0.08));
  border-radius: 10px;
  padding: 14px 14px 12px;
  min-width: 0;
}
body.ai-trading-page .ai-hero-tile-win { border-left: 3px solid #3ddc84; }
body.ai-trading-page .ai-hero-tile-btc { border-left: 3px solid var(--app-buy, #5cb8e6); }
body.ai-trading-page .ai-hero-tile-usd { border-left: 3px solid var(--app-sell, #e0a050); }
body.ai-trading-page .ai-hero-tile-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--app-text-2);
}
body.ai-trading-page .ai-hero-tile-value {
  margin-top: 6px;
  font-size: 22px;
  font-weight: 700;
  color: var(--app-text-1);
  overflow-wrap: anywhere;
}
body.ai-trading-page .ai-hero-tile-value small {
  font-size: 12px;
  font-weight: 600;
  color: var(--app-text-2);
}
body.ai-trading-page .ai-hero-tile-sub {
  margin-top: 4px;
  font-size: 12px;
  color: var(--app-text-2);
}
body.ai-trading-page .ai-hero-note {
  margin: 0;
  font-size: 12px;
  color: var(--app-text-2);
}
/* §6b (owner, 2026-09-03): the qualification comes BEFORE the numbers it
   qualifies. Deliberately not styled as fine print — a disclaimer set smaller
   and fainter than the claim it qualifies is a disclaimer nobody reads, which
   is the whole objection this line exists to answer. Same size as the tile
   sub-text, but at full text colour and carrying a rule that ties it to the
   tiles below rather than to the card above. */
body.ai-trading-page .ai-hero-claim {
  margin: 0;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--app-border, rgba(255, 255, 255, 0.08));
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--app-text-1);
}
@media (max-width: 900px) {
  body.ai-trading-page .ai-hero-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 480px) {
  body.ai-trading-page .ai-hero-grid { grid-template-columns: minmax(0, 1fr); }
}

/* --- "Read strategy details" (layout v2, item 5) — tinted so it is
       discoverable, worded as a document; both are the owner's words. --- */
body.ai-trading-page .ai-strategy-details-btn {
  margin-left: auto;
  padding: 7px 14px;
  border-radius: 8px;
  border: 1px solid rgba(92, 184, 230, 0.45);
  background: rgba(92, 184, 230, 0.14);
  color: var(--app-text-1);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
body.ai-trading-page .ai-strategy-details-btn:hover { background: rgba(92, 184, 230, 0.24); }

/* --- the strategy modal ----------------------------------------------- */
body.ai-trading-page .ai-strategy-modal {
  border: 1px solid var(--app-border, rgba(255, 255, 255, 0.12));
  border-radius: 12px;
  padding: 0;
  width: min(760px, calc(100vw - 32px));
  background: var(--app-surface-1, #14141f);
  color: var(--app-text-1);
}
/* Flex ONLY while open. An unconditional `display: flex` on a <dialog>
   overrides the UA's `dialog:not([open]) { display: none }` and the closed
   modal renders inline on the page (Codex layout-v2 R1, P0) — the exact
   display-defeats-hiding bug class this page has shipped twice before.
   No viewport-height unit on purpose (#919 pins): the UA already caps an
   open <dialog>'s block size to the viewport, and the flex column hands
   that height to the scrollable body. */
body.ai-trading-page .ai-strategy-modal[open] {
  display: flex;
  flex-direction: column;
  /* CENTERING (owner browser review, 2026-09-02: "it currently opens pinned
     top-left"). The UA centres a modal <dialog> with its own `margin: auto`,
     which an author `display: flex` here does not remove — but any author
     margin reaching this element does, and the page's dialogs inherit one.
     Stated explicitly so the modal's position stops depending on which other
     stylesheet loaded. `auto` on all four sides centres both axes; the UA
     still caps the open dialog's block size to the viewport, so a long
     prospectus scrolls in the body rather than growing past the screen. */
  margin: auto;
}
body.ai-trading-page .ai-strategy-modal::backdrop { background: rgba(0, 0, 0, 0.6); }
body.ai-trading-page .ai-strategy-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--app-border, rgba(255, 255, 255, 0.08));
}
body.ai-trading-page .ai-strategy-modal-head h2 { margin: 0; font-size: 15px; }
body.ai-trading-page .ai-strategy-modal-close {
  border: 1px solid var(--app-border, rgba(255, 255, 255, 0.15));
  background: transparent;
  color: var(--app-text-2);
  border-radius: 8px;
  padding: 5px 12px;
  font-size: 12px;
  cursor: pointer;
}
body.ai-trading-page .ai-strategy-modal-body {
  padding: 6px 18px 18px;
  overflow-y: auto;
  flex: 1;
  min-height: 0;
}
/* Inside the modal, the modal IS the disclosure — the details chrome and
   the accordion-era borders are noise there. */
body.ai-trading-page .ai-strategy-modal-body .ai-prospectus-summary { display: none; }
body.ai-trading-page .ai-strategy-modal-body .ai-prospectus,
body.ai-trading-page .ai-strategy-modal-body .ai-strategy-box {
  border: 0;
  margin-top: 8px;
  padding: 0;
  background: transparent;
}

/* --- the 22-row reference table (renderReferenceTrades) ---------------- */
body.ai-trading-page .ai-ref-trades-line {
  margin: 0 0 10px;
  font-size: 13px;
  color: var(--app-text-2);
}
/* ---- Strategy details modal: the chart key + the drawdown note ----
   Both live inside the modal (owner browser review, 2026-09-02). The swatch
   colour arrives as `--key-color`, set inline from the SAME brand tokens the
   chart modules read — so the key cannot disagree with the chart it explains
   after a partner brand swaps the theme. */
body.ai-trading-page .ai-chart-key,
body.ai-trading-page .ai-ref-drawdown-note {
  margin: 0 0 18px;
}
body.ai-trading-page .ai-chart-key h3,
body.ai-trading-page .ai-ref-drawdown-note h3 {
  margin: 0 0 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--app-text-1);
}
body.ai-trading-page .ai-chart-key-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 7px;
}
body.ai-trading-page .ai-chart-key-list li {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--app-text-2);
}
/* One box per mark kind, each shaped like the thing it stands for: a line
   swatch, a dashed rule, a colour wash, a filled triangle, a hollow one. */
body.ai-trading-page .ai-chart-key-mark {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  margin-top: 2px;
}
body.ai-trading-page .ai-chart-key-mark.is-swatch {
  height: 3px;
  margin-top: 8px;
  border-radius: 2px;
  background: var(--key-color);
}
body.ai-trading-page .ai-chart-key-mark.is-dash {
  height: 0;
  margin-top: 8px;
  border-top: 2px dashed var(--app-text-muted-2);
}
body.ai-trading-page .ai-chart-key-mark.is-wash {
  height: 12px;
  border-radius: 2px;
  background: var(--key-color);
}
body.ai-trading-page .ai-chart-key-mark.is-up,
body.ai-trading-page .ai-chart-key-mark.is-down,
body.ai-trading-page .ai-chart-key-mark.is-hollow {
  width: 0;
  height: 0;
  margin-top: 4px;
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
}
body.ai-trading-page .ai-chart-key-mark.is-up { border-bottom: 9px solid var(--key-color); }
body.ai-trading-page .ai-chart-key-mark.is-down { border-top: 9px solid var(--key-color); }
/* Hollow = a decision the strategy declined. Drawn as an outline so it reads
   as "considered and skipped" rather than "taken", which is the whole point
   of the mark on the chart. */
body.ai-trading-page .ai-chart-key-mark.is-hollow {
  border-bottom: 9px solid transparent;
  position: relative;
}
body.ai-trading-page .ai-chart-key-mark.is-hollow::after {
  content: '';
  position: absolute;
  left: -4px;
  top: 1px;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-bottom: 6px solid var(--key-color);
  opacity: 0.45;
}
body.ai-trading-page .ai-chart-key-note {
  margin: 10px 0 0;
  font-size: 12px;
  color: var(--app-text-muted-2);
}

body.ai-trading-page .ai-ref-trades-scroll { overflow-x: auto; }
body.ai-trading-page .ai-ref-trades-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
  white-space: nowrap;
}
body.ai-trading-page .ai-ref-trades-table th {
  text-align: left;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--app-text-2);
  padding: 8px 10px;
  border-bottom: 1px solid var(--app-border, rgba(255, 255, 255, 0.1));
}
body.ai-trading-page .ai-ref-trades-table td {
  padding: 7px 10px;
  border-bottom: 1px solid var(--app-border, rgba(255, 255, 255, 0.05));
  color: var(--app-text-1);
}
body.ai-trading-page .ai-ref-trades-table td.ai-ref-win { color: #3ddc84; font-weight: 600; }
body.ai-trading-page .ai-ref-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  background: rgba(224, 160, 80, 0.14);
  border: 1px solid rgba(224, 160, 80, 0.4);
  color: var(--app-sell, #e0a050);
}

/* "Forced test" — a trade an operator opened and closed to verify the
   execution path (owner, 2026-09-08). It sits on the CUSTOMER's own row: their
   money moved, so the trade is in their history and their P/L, and the badge
   is what explains why the bot's public record does not count it. Deliberately
   quieter than the result badges beside it — it is a footnote about
   provenance, not an outcome. */
body.ai-trading-page .ai-trade-badge.is-forced {
  display: inline-block;
  margin-left: 8px;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  background: var(--app-surface-3, rgba(255, 255, 255, 0.06));
  border: 1px solid var(--app-border-1, rgba(255, 255, 255, 0.16));
  color: var(--app-text-2);
  white-space: nowrap;
  cursor: help;
}

/* --- the re-stack itself (renderDetailLayout adds .ai-restack) ---------
   Same CSS-order mechanism as the participant/visitor layouts above.
   Visitor: the record first, CTA under it (the visitor cta-top
   display-none rule is overridden here — layout v2 item 6 wants the CTA
   twice), charts and the trades table (inside the accordion, summary
   chrome hidden), prose LAST. Participant: YOUR POSITION pinned on top,
   then the record. */
body.ai-trading-page #aiDetailView.ai-restack.ai-layout-visitor > #aiHeroRecord { order: 1; }
body.ai-trading-page #aiDetailView.ai-restack.ai-layout-visitor > #aiCtaTop { display: flex; order: 2; }
body.ai-trading-page #aiDetailView.ai-restack.ai-layout-visitor > #aiBotPerformanceSection { order: 3; }
body.ai-trading-page #aiDetailView.ai-restack.ai-layout-visitor > #aiDetailAccordion { order: 4; }
body.ai-trading-page #aiDetailView.ai-restack.ai-layout-visitor > #aiDetailDescription { order: 5; }
body.ai-trading-page #aiDetailView.ai-restack.ai-layout-visitor > #aiCtaBottom { order: 6; }

body.ai-trading-page #aiDetailView.ai-restack.ai-layout-participant > #aiPositionStrip { order: 1; }
body.ai-trading-page #aiDetailView.ai-restack.ai-layout-participant > #aiYourPerformanceSection { order: 2; }
body.ai-trading-page #aiDetailView.ai-restack.ai-layout-participant > #aiBotStatusLine { order: 3; }
body.ai-trading-page #aiDetailView.ai-restack.ai-layout-participant > #aiHeroRecord { order: 4; }
body.ai-trading-page #aiDetailView.ai-restack.ai-layout-participant > #aiCtaTop { order: 5; }
body.ai-trading-page #aiDetailView.ai-restack.ai-layout-participant > #aiDetailAccordion { order: 6; }
body.ai-trading-page #aiDetailView.ai-restack.ai-layout-participant > #aiDetailDescription { order: 7; }
body.ai-trading-page #aiDetailView.ai-restack.ai-layout-participant > #aiCtaBottom { order: 8; }

/* YOUR POSITION pins for subscribers (layout v2, item 3). Sticky, not
   fixed — it yields its space back and never overlaps the footer. */
body.ai-trading-page #aiDetailView.ai-restack.ai-layout-participant > #aiPositionStrip {
  position: sticky;
  /* The shell's .app-topbar is FIXED and 52px tall (dashboard.css) — a
     strip stuck at top:0 slides underneath it (Codex layout-v2 R1, P1). */
  top: 52px;
  z-index: 30;
  background: var(--app-surface-1, #14141f);
}

/* The accordion is forced open under the re-stack (its chart and trades ARE
   the page) and its summary chrome disappears — one element, one more CSS
   state, same pattern the visitor layout already uses for it. */
body.ai-trading-page #aiDetailView.ai-restack .ai-detail-accordion-summary { display: none; }

/* --- row C: the reference splice ---------------------------------------- */
/* The on-chart source label the owner's splice decision requires — one line,
   bottom-left, above the chart but below any dialog. The container is the
   chart module's own mount target, which is positioned by the widget. */
body.ai-trading-page .ai-splice-note {
  position: absolute;
  left: 8px;
  bottom: 8px;
  z-index: 5;
  padding: 3px 8px;
  border-radius: 6px;
  font-size: 11px;
  color: var(--app-text-2);
  background: var(--app-surface-1, rgba(20, 20, 31, 0.85));
  border: 1px solid var(--app-border, rgba(255, 255, 255, 0.12));
  pointer-events: none;
}
body.ai-trading-page #aiChartSlot { position: relative; }

/* The 2023-10-23 divergence row is GONE (owner §0, 2026-09-02): the record no
   longer contains the trade, so there is no row to annotate. The explanation
   moved into the Strategy details reference section.

   A LIVE row's badge, and a losing row's result cell. The badge is the only
   thing that distinguishes the two halves of the record (§1), so it must read
   as a different thing at a glance — the page's win colour, against the
   reference badge's amber. */
body.ai-trading-page .ai-live-badge {
  background: rgba(61, 220, 132, 0.14);
  border-color: rgba(61, 220, 132, 0.4);
  color: #3ddc84;
}
body.ai-trading-page .ai-ref-trades-table td.ai-ref-loss {
  color: var(--app-sell, #e0a050);
  font-weight: 600;
}

/* ---- THE ALLOCATION POT (panel + modal) ---------------------------------
   The pot panel sits directly under YOUR POSITION for a participant, next to
   the number its two buttons act on. Row F sits under it — both are given the
   SAME `order` as Your Performance rather than renumbering the whole sequence,
   so their relative position falls out of DOM source order (pot panel, row F,
   Your Performance), which is exactly the reading order intended. */
body.ai-trading-page #aiDetailView.ai-layout-participant > #aiPotPanel,
body.ai-trading-page #aiDetailView.ai-restack.ai-layout-participant > #aiPotPanel,
body.ai-trading-page #aiDetailView.ai-layout-participant > #aiMyEquitySection,
body.ai-trading-page #aiDetailView.ai-restack.ai-layout-participant > #aiMyEquitySection {
  order: 2;
}
/* A visitor has no pot by definition — the panel and row F are hidden for the
   same reason Your Performance is, and `[hidden]` already wins on its own. This
   states the intent alongside the rule it mirrors. */
body.ai-trading-page #aiDetailView.ai-layout-visitor > #aiPotPanel,
body.ai-trading-page #aiDetailView.ai-layout-visitor > #aiMyEquitySection {
  display: none;
}

/* MY HISTORY, "directly under 'Your performance', participants only" (owner,
   2026-09-08). Same device as the pot panel above: the SAME `order` as Your
   Performance in both participant layouts, so its position comes from DOM
   source order (pot panel, row F, Your Performance, My History) instead of
   from a renumbered table — and moving it again is a move of one <section>.
   The visitor rule is the participants-only half: js/ai-trading.js already
   hides the section for a non-participant, and this makes the visitor layout
   incapable of showing it even if a render leaves it unhidden. */
body.ai-trading-page #aiDetailView.ai-layout-participant > #aiMyHistorySection,
body.ai-trading-page #aiDetailView.ai-restack.ai-layout-participant > #aiMyHistorySection {
  order: 2;
}
body.ai-trading-page #aiDetailView.ai-layout-visitor > #aiMyHistorySection {
  display: none;
}

body.ai-trading-page .ai-pot-value {
  font-size: 26px;
  font-weight: 700;
  color: var(--app-primary);
  font-variant-numeric: tabular-nums;
  margin: 4px 0 2px;
}
body.ai-trading-page .ai-pot-meta {
  font-size: 12px;
  color: var(--app-text-muted-2);
  margin-bottom: 12px;
}
/* The §6 reservation line + its cancel, and the expected-execution estimate.
   The reservation is informational — it must not read as a debit, so it keeps
   the muted meta styling; only the cancel affords action. */
body.ai-trading-page .ai-pot-reservation {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 4px;
  color: var(--app-text, #d8d8e0);
}
/* ITEM 8 (owner, 2026-09-08): a pending return is not a footnote. It used to
   be a muted grey line under a large number and the owner missed it; it is now
   an amber banner sitting directly under the figure it qualifies. Amber, not
   red: money coming BACK to the customer on schedule is not an error — it is
   the same hue this page already gives the "sell"/attention side, and the
   sentence carries the meaning on its own for anyone who cannot see the hue. */
body.ai-trading-page .ai-pot-reservation-banner {
  margin: 2px 0 12px;
  padding: 8px 12px;
  border-radius: var(--app-radius-sm);
  border: 1px solid rgba(224, 160, 80, 0.35);
  background: rgba(224, 160, 80, 0.12);
  color: var(--app-text-strong);
  font-size: 12.5px;
  font-weight: 600;
}
body.ai-trading-page .ai-pot-expected {
  margin-bottom: 12px;
}
body.ai-trading-page .ai-pot-cancel-reservation {
  background: none;
  border: none;
  padding: 0;
  font-size: 12px;
  color: var(--app-primary);
  text-decoration: underline;
  cursor: pointer;
}

/* EDIT / CANCEL ON THE BANNER (owner, 2026-09-10). While a return is reserved
   these are the ONLY way to change it — the "Return to balance" button is not
   rendered at all — so they are real controls, not decoration on a status line.
   They are <button>s, so keyboard focus and Enter/Space come for free; what has
   to be added is the touch target. 44px is the figure the owner named, and it is
   bought with padding and a negative margin so the text still sits on the
   banner's baseline instead of pushing the sentence apart. */
body.ai-trading-page .ai-pot-banner-action {
  background: none;
  border: none;
  font-size: 12px;
  font-weight: 700;
  color: var(--app-primary);
  text-decoration: underline;
  cursor: pointer;
  min-height: 44px;
  min-width: 44px;
  padding: 0 8px;
  margin: -12px 0;
  line-height: 1;
}
body.ai-trading-page .ai-pot-banner-action:focus-visible {
  outline: 2px solid var(--app-primary);
  outline-offset: 2px;
  border-radius: 4px;
}
@media (hover: hover) {
  body.ai-trading-page .ai-pot-banner-action:hover { text-decoration: none; }
}

/* ITEM 11's two return modes, laid out (owner D12, 2026-09-10): "each option on
   its own line with its description under it". They had no CSS at all, so two
   <label>s and four <span>s were all inline boxes and ran together on one line
   — the second option's title read as the tail of the first option's note, and
   the radios ended up mid-sentence.

   `display: grid` and NOT `!important`, deliberately: the page-wide
   `[hidden] { display: none !important; }` at the top of this file still wins
   over these rules while the row carries the attribute (js/ai-trading-pot.js
   sets it for every verb but `withdraw`), which is the same arrangement the
   amount row below and the state panels above already depend on. Adding
   `!important` here would be exactly the defect that rule exists to prevent. */
body.ai-trading-page .ai-pot-mode-group {
  display: grid;
  gap: 12px;
  margin-bottom: 16px;
}
/* Two columns, aligned to the START of the block: the radio sits on the
   title's line. Vertically centring it against the whole option would park it
   beside the wrapped note, pointing at the description rather than the choice. */
body.ai-trading-page .ai-pot-mode-option {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: start;
  gap: 10px;
  cursor: pointer;
}
body.ai-trading-page .ai-pot-mode-option input[type='radio'] {
  margin: 0;
  /* Onto the title's optical centre — the title is 13px on a 1.35 line box. */
  margin-top: 3px;
}
/* The title and its note are inline spans; without this they share a line and
   the "on its own line" half of the ruling is only half done. */
body.ai-trading-page .ai-pot-mode-title {
  display: block;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--app-text-1);
}
body.ai-trading-page .ai-pot-mode-note {
  display: block;
  margin-top: 3px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--app-text-muted-2);
}

body.ai-trading-page .ai-pot-amount-label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: var(--app-text-muted-2);
  margin-bottom: 8px;
}
body.ai-trading-page .ai-pot-amount-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
body.ai-trading-page .ai-pot-amount-input {
  flex: 1;
  min-height: 44px;
  padding: 10px 12px;
  border-radius: var(--app-radius-sm);
  border: 1px solid var(--app-border);
  background: rgba(var(--app-content-overlay-rgb), 0.04);
  color: var(--app-text-1);
  font-size: 16px;
  font-variant-numeric: tabular-nums;
}
body.ai-trading-page .ai-pot-amount-input:disabled {
  opacity: 0.5;
}
body.ai-trading-page .ai-pot-amount-unit {
  font-size: 14px;
  font-weight: 700;
  color: var(--app-text-muted-2);
  min-width: 48px;
}
/* MAX (manager item 5) — fills the full returnable / available amount. */
body.ai-trading-page .ai-pot-amount-max {
  min-height: 36px;
  padding: 0 12px;
  border-radius: var(--app-radius-sm);
  border: 1px solid var(--app-border);
  background: rgba(var(--app-content-overlay-rgb), 0.06);
  color: var(--app-text-1);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.4px;
  cursor: pointer;
}
body.ai-trading-page .ai-pot-amount-max:hover:not(:disabled) {
  background: rgba(var(--app-content-overlay-rgb), 0.12);
}
body.ai-trading-page .ai-pot-amount-max:disabled {
  opacity: 0.4;
  cursor: default;
}
/* The always-visible start floor under the Amount field (allocate verb only).
   A hint, not an error: it states the rule before the user can trip on it. */
body.ai-trading-page .ai-pot-min-note {
  font-size: 12px;
  color: var(--app-text-muted-2);
  margin: 6px 0 0;
}
body.ai-trading-page .ai-pot-all-row {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--app-text-1);
  min-height: 44px;
  cursor: pointer;
}

/* ---- Pot-over-time chart: granularity, and the movement list (design §3) ----
   Appended for the 2026-09-07 item 10 fix. Nothing above is modified — these
   are new selectors for DOM the chart module builds inside #aiMyEquitySlot. */

/* The 1H / 1D / 1M radiogroup. 44px targets, per §3's accessibility line — the
   height is on the BUTTON rather than the row so a touch target is the thing
   the finger actually lands on. */
body.ai-trading-page .ai-pot-granularity {
  display: flex;
  gap: 6px;
  margin-bottom: 8px;
}
body.ai-trading-page .ai-pot-gran-btn {
  min-width: 44px;
  min-height: 44px;
  padding: 4px 12px;
  font-size: 12px;
  font-weight: 600;
  border: 1px solid var(--app-border);
  border-radius: var(--app-radius-sm);
  background: transparent;
  color: var(--app-text-muted-2);
  cursor: pointer;
}
body.ai-trading-page .ai-pot-gran-btn[aria-checked="true"] {
  background: var(--app-primary);
  border-color: var(--app-primary);
  color: var(--app-primary-fg);
}
body.ai-trading-page .ai-pot-gran-btn:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

/* `Show as list` — the keyboard and touch route to the same events the tooltip
   shows. A touch device has no hover at all, so this is not an extra. */
body.ai-trading-page .ai-pot-events-toggle {
  margin-top: 10px;
  min-height: 44px;
  padding: 4px 12px;
  font-size: 12px;
  font-weight: 600;
  border: 1px solid var(--app-border);
  border-radius: var(--app-radius-sm);
  background: transparent;
  color: var(--app-text-muted-2);
  cursor: pointer;
}

/* The panel is toggled with the `hidden` attribute. This rule exists BECAUSE a
   `display` declaration silently defeats `hidden` — the panel below is a flex
   /block context, so it says so explicitly rather than trusting the UA sheet. */
body.ai-trading-page .ai-pot-events-panel {
  display: block;
  margin-top: 8px;
  max-height: 320px;
  overflow: auto;
}
body.ai-trading-page .ai-pot-events-panel[hidden] {
  display: none;
}

body.ai-trading-page .ai-pot-events-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--app-text-1);
}
body.ai-trading-page .ai-pot-events-table caption {
  text-align: left;
  padding-bottom: 6px;
  font-size: 12px;
  color: var(--app-text-muted-2);
}
body.ai-trading-page .ai-pot-events-table th,
body.ai-trading-page .ai-pot-events-table td {
  padding: 5px 8px;
  text-align: left;
  border-bottom: 1px solid var(--app-border);
  white-space: nowrap;
}
body.ai-trading-page .ai-pot-events-table th {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--app-text-muted-2);
}
/* Amounts and balances right-aligned, so the decimal points line up and a
   satoshi in the last place is visible as a difference in the column. */
body.ai-trading-page .ai-pot-events-table td:nth-child(3),
body.ai-trading-page .ai-pot-events-table td:nth-child(4),
body.ai-trading-page .ai-pot-events-table th:nth-child(3),
body.ai-trading-page .ai-pot-events-table th:nth-child(4) {
  text-align: right;
}

/* The out-of-date state (§3): the pot moved between the two reads. A message,
   never a blank section — the pot panel above is showing a number. */
body.ai-trading-page .ai-pot-chart-stale {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  padding: 12px 0;
}
