/* One breakpoint tier below Bootstrap's smallest (sm, 576px), in the same shape
   as its display utilities so markup reads identically: `d-none d-xxs-table-cell`
   shows a cell only at 480px and up. Reach for the Bootstrap utilities first —
   these exist purely because the xxs tier doesn't ship with them. Add more
   d-xxs-* variants here as something actually needs them. */
@media (min-width: 480px) {
    .d-xxs-inline { display: inline !important; }
    .d-xxs-block { display: block !important; }
    .d-xxs-table-cell { display: table-cell !important; }
}

.wrapper {
	min-height: 100vh;
    padding-bottom: 60px;
}
@media (max-width: 991.98px) {
    .container-lg.wrapper {
        padding-inline: 40px;
    }
}
@media (max-width: 767.98px) {
    .container-lg.wrapper {
        padding-inline: 25px;
    }
}
.nav-top {
	align-items: center;   /* center every item on the cross axis so the account badge sits on the icon centerline */
	padding-top: 15px;
	padding-bottom: 10px;
	border-bottom: 1px solid var(--color-border);
	margin-bottom: 35px;
}

.btn.btn-link.color-info {
    color: var(--color-info);
    text-decoration: none;
}
.btn.btn-link.color-info:hover {
    color: var(--color-info-hover);
    text-decoration: underline;
}
table.table th, table.table td { font-size: 0.85rem; }
table.table th {
    color: var(--color-text-muted);
}
table.table.monitors th { font-size: 0.8rem; }

/* Sortable column headers (positions table). The caret is always present to
   signal the column is sortable; it's dimmed until that column is the active
   sort, when both the header text and caret brighten. */
table.table th.sortable-th { cursor: pointer; user-select: none; white-space: nowrap; }
table.table th.sortable-th:hover { color: var(--color-text); }
table.table th.sortable-th .sort-caret { margin-left: 5px; opacity: 0.4; font-size: 0.75rem; }
table.table th.sortable-th.sorted { color: var(--color-text); }
table.table th.sortable-th.sorted .sort-caret { opacity: 1; }

.table-wrapper {
    border: 2px solid var(--color-border-subtle);
    padding: 10px;
    border-radius: 6px;
}
.table-wrapper table.table th {
    padding-bottom: 10px;
}

/* Bear call spread expirations ("chains") as Bootstrap nav-tabs (Daily / Weekly /
   Monthly / Quarterly) over a bordered content panel. Bootstrap borders only the
   active tab + the nav's bottom edge and leaves the panel open, so add the panel's
   left/right/bottom edges to box the dates of the tab being viewed. Each date is a
   pill link that loads the chain; the active link (currently loaded chain) is filled. */
.chain-tab-content {
    border: 1px solid var(--color-border);
    border-top: 0;                      /* nav bottom-border + active tab form the top edge */
    border-radius: 0 0 0.375rem 0.375rem;
    padding: 15px;
}
.chain-tabs .nav-item button {
    padding: 10px 15px 6px 15px;
}
.chain-tabs .nav-link {                 /* tighter tabs for a thin control row */
    padding: 0.2rem 0.75rem;
    font-size: 0.8rem;
    color: var(--color-text-muted);
}
.chain-tabs .nav-link.active {
    /* color: #212529;  */
    color: var(--color-info);
    font-weight: bold;
}
/* Disabled cadence tab — a symbol with no expirations of that type (used on the
   open-interest surface). Without this the shared .nav-link rule above would
   leave it looking clickable. */
.chain-tabs .nav-link:disabled,
.chain-tabs .nav-link.disabled {
    color: var(--color-text-disabled);
    opacity: 0.55;
    cursor: default;
}
.chain-tabs .exp-label {
    font-size: 0.8rem;
    font-weight: bold;
    color: var(--color-text-muted);
}
.chain-link {
    display: inline-block;
    margin: 0.35rem 0.5rem .35rem 0;
    padding: 0.1rem 0.5rem;
    color: var(--color-primary);
    text-decoration: none;
    cursor: pointer;
    font-variant-numeric: tabular-nums;
    font-size: 0.85rem;
    background-color: var(--color-surface);
    border-radius: 3px;
    text-align: center;
}
.chain-link:hover { background-color: var(--color-primary-soft); border-color: var(--color-primary); }
/* Days-to-expiration suffix on a date pill ("Aug 31 (38d)"). Inherits the link's
   colour — dimmed by opacity, not a fixed colour — so it stays readable on the
   filled .active pill too. */
.chain-dte { font-size: 0.9em; opacity: 0.65; }
.chain-link.active {
    background-color: var(--color-primary);
    border-color: var(--color-primary);
    color: var(--color-text-on-accent);
}
.chain-empty { color: var(--color-text-disabled); }

/* Bear call spread OTM strikes table: numeric, monospaced figures so columns
   line up. The underlying's last price shows in a thin bar above the table
   (.strikes-underlying-bar), outside the scrolling region. */
.strikes-table { font-variant-numeric: tabular-nums; }

/* Underlying-price reference bar, sitting just above and outside the strikes
   table. Thin grey border matches the expirations box (.chain-tab-content). */
.strikes-underlying-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    border: 1px solid var(--color-border);
    background-color: var(--color-inset);
    border-radius: 0.375rem;
    padding: 0.4rem 0.75rem;
    margin-bottom: 0.5rem;
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
}
.strikes-underlying-bar .strikes-underlying-label { color: var(--color-text-muted); }
.strikes-underlying-bar .strikes-underlying-price { font-weight: 700; }
.strikes-underlying-bar .strikes-underlying-change { font-weight: 600; }
.strikes-underlying-bar .strikes-change-up { color: var(--color-up); }
.strikes-underlying-bar .strikes-change-down { color: var(--color-down); }
.strikes-underlying-bar .strikes-change-flat { color: var(--color-text-muted); }
.strikes-underlying-bar .strikes-underlying-range { color: var(--color-text-muted); }
/* The volatilities the Std Dev rows measure against. flex-basis 100% drops it onto
   its own line inside the same bordered box, under the spot/range line. */
.strikes-underlying-bar .strikes-vol-note {
    flex-basis: 100%;
    color: var(--color-text-muted);
}

/* Pivoted layout: each strike is a column and the field labels live in a frozen
   left column. The strike columns scroll horizontally while the label column
   stays pinned. border-collapse must be separate so the sticky label cells paint
   an opaque band that strike columns slide *under* — collapsed borders bleed
   through and look torn at the frozen edge. */
.strikes-scroll { overflow-x: auto; overflow-y: hidden; }
.strikes-pivot { border-collapse: separate; border-spacing: 0; }
/* Min width on the strike columns so the table overflows -> scrolls; a right
   border on each strike cell draws the vertical grid lines (Bootstrap supplies
   the horizontal cell borders, and the frozen label keeps its own box-shadow
   divider, so the vertical borders live on the strike <td>s only). */
.strikes-pivot td { min-width: 84px; border-right: 1px solid var(--color-border-subtle); padding: 8px; }

/* Frozen left label column: pinned, opaque band, with a right-edge divider
   (box-shadow, so it can't scroll away). Labels read muted and left-aligned. */
.strikes-pivot .strikes-rowlabel {
    position: sticky;
    left: 0;
    z-index: 2;
    text-align: right;
    white-space: nowrap;
    /* Wide enough for the LONGEST label of any row, shown or hidden. The frozen
       column sizes to max(min-width, widest VISIBLE label), so a label that
       overflows this would shift the whole table sideways every time its row is
       toggled. Measured widest is "Std Dev HV30"/"Std Dev EWMA" at ~116px — the
       labels are proportional, so count pixels, not characters ("Open Interest"
       is longer but narrower). Re-measure before adding a longer row label. */
    min-width: 120px;
    color: var(--color-text-muted);
    background-color: var(--color-surface);
    box-shadow: 1px 0 0 var(--color-border);
    padding: 8px;

}

/* Strike-price row reads bold/bright over the muted body. */
.strikes-pivot .strikes-row-strike td { color: var(--color-text); font-weight: 700; }
.strikes-pivot .strikes-row-strike .strikes-rowlabel { color: var(--color-text); }

/* Hover a field row to trace it across every strike (subtle, mockup parity).
   Targets td only, so the frozen label <th> band stays opaque. */
.strikes-pivot tbody tr:hover td { background-color: rgba(255, 255, 255, 0.04); }

/* Selected strike column highlights amber — applied per-cell across the column,
   never on the frozen label cell. The :hover-qualified selector keeps the amber
   winning over the row-hover trace above. */
.strikes-pivot td.leg-selected,
.strikes-pivot tbody tr:hover td.leg-selected { background-color: var(--color-warning-soft); }

/* Std Dev volatility-basis checkboxes. The control row (symbol + expirations +
   these) is tight, so keep the four on ONE line: Bootstrap's form-check-inline
   right margin is the only gap they need, and wrapping would orphan the refresh
   icon beside a half-empty second line. */
.sigma-basis-group .form-check-inline { margin-right: 0.6rem; }
.sigma-basis-group .form-check-inline:last-child { margin-right: 0; }
.sigma-basis-group .form-check-label { white-space: nowrap; }

/* Rotate icon beside the strikes dropdown: line-height matches the select's
   height so the icon centers on the control in the bottom-aligned filter row. */
.strikes-refresh {
    display: inline-block;
    font-size: 1.15rem;
    line-height: 38px;
    color: var(--color-text);
}

/* Dim-and-restore pulse while a fragment reloads in place — same effect as
   .clock-refreshing on the market clock. JS toggles .refreshing. */
.refresh-fade { transition: opacity 0.3s ease; }
.refresh-fade.refreshing { opacity: 0.35; }

/* "Jump to: 1 STD / 1.5 STD" quick-scroll links under the strikes table. */
.strikes-jump { color: var(--color-text-muted); }
.strikes-jump-label { margin-right: 0.35rem; }
.strikes-jump-link { color: var(--color-warning); text-decoration: none; cursor: pointer; }
.strikes-jump-link:hover { text-decoration: underline; }

/* Queued-order panel: a persistent draft pinned top-right. `top` clears the
   transient toast's strip (fixed at top:10px, ~45px tall) so a save/error message
   doesn't land on the panel's title and ✕ — the toast still wins the overlap at
   z-index 1100 if the viewport is short. */
.order-queue {
    position: fixed;
    right: 24px;
    top: 70px;
    z-index: 1090;
    width: 440px;
    background-color: var(--color-surface);
    border: 2px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    padding: 12px 16px;
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
}
.order-queue-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 2px;
}
.order-queue-title { font-weight: 700; }
/* Quote-refresh spinner just right of the title; visibility (not display)
   so the head doesn't reflow when it blinks on. JS toggles .show each poll. */
.order-queue-spinner {
    margin-left: 8px;
    margin-right: auto;   /* keep the close ✕ pinned to the far right */
    color: var(--color-text-muted);
    visibility: hidden;
}
.order-queue-spinner.show { visibility: visible; }
.order-queue-close { color: var(--color-text-muted); text-decoration: none; }
.order-queue-close:hover { color: var(--color-text); }
/* Chart-this-spread link, just left of the close ✕. */
.order-queue-chart { color: var(--color-text-muted); text-decoration: none; margin-right: 12px; }
.order-queue-chart:hover { color: var(--color-text); }
.order-queue-sub { line-height: 1.3; }

.order-legs {
    margin: 10px 0;
    padding: 8px 0;
    border-top: 1px solid var(--color-border);
    border-bottom: 1px solid var(--color-border);
}
.order-leg,
.order-leg-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 2px 0;
}
.order-leg-head { justify-content: flex-end; }   /* align Bid/Ask labels over their columns */
.order-leg .leg-desc { font-weight: 600; }
.order-leg .leg-bid { margin-left: auto; }       /* push the bid/ask pair to the right */
.leg-bid,
.leg-ask { width: 3.4em; text-align: right; }
.order-queue-loading { padding: 16px 0; text-align: center; }
.leg-badge {
    font-size: 0.7rem;
    font-weight: 700;
    padding: 1px 6px;
    border-radius: 4px;
    width: 3.2em;
    text-align: center;
}
.leg-badge.leg-sell { color: var(--color-text-on-accent); background-color: var(--color-down); }
.leg-badge.leg-buy { color: var(--color-text-on-accent); background-color: var(--color-up); }

.order-metric {
    display: flex;
    justify-content: space-between;
    padding: 1px 0;
}
.order-queue-foot {
    margin-top: 8px;
    text-align: center;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* Pricing-mode radios: Mid Price (mid) and Limit @ Market (natural). Each label
   wraps a real radio and shows its computed net credit; the checked one marks
   the order's working limit price. Deliberately NOT the submit button's blue —
   the selected option goes light grey so the two controls read differently.
   Labelled by intent (not bid/ask) so the same control serves debit verticals. */
.order-price-modes { display: flex; gap: 8px; margin: 10px 0 4px; }
.price-mode {
    flex: 1 1 0;
    border: 1px solid var(--color-border);
    background-color: var(--color-surface);
    color: var(--color-text);
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.25;
    padding: 5px 8px;
    border-radius: var(--radius);
    text-align: center;
    cursor: pointer;
    margin-bottom: 0;
}
.price-mode .price-mode-radio {
    margin-right: 4px;
    vertical-align: -1px;
    cursor: inherit;
}
.price-mode .price-mode-val {
    display: block;
    font-size: 0.95rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
/* The Limit Order pill's price dropdown, sitting where .price-mode-val sits
   in the other pills. */
.price-mode .limit-price-select {
    width: 78px;
    margin: 2px auto 0;
    padding: 1px 4px 1px 8px;
    font-size: 0.85rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
/* Pricing-mode tooltips: lifted above the pinned toast — Bootstrap appends tips
   to <body> at z-index 1080, under .order-queue's 1090 (still below the
   transient top-right toast at 1100). */
.queue-tooltip {
    --bs-tooltip-zindex: 1095;
    --bs-tooltip-bg: var(--color-elevated);
    --bs-tooltip-color: var(--color-text);
    --bs-tooltip-opacity: 1;
}
.queue-tooltip .tooltip-inner {
    border: 1px solid var(--color-border);
    box-shadow: var(--shadow-lg);
}

.price-mode:hover:not(.disabled) { border-color: var(--color-border-strong); }
.price-mode.active {
    border-color: var(--color-border-strong);
    background-color: var(--color-elevated);
}
.price-mode.disabled { opacity: 0.5; cursor: not-allowed; }

/* Qty + Review & Submit row between the pricing buttons and the metrics. */
.order-submit-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 10px 0 6px;
}
.order-qty-label { flex: 0 0 auto; }
.order-qty-select { width: 64px; flex: 0 0 auto; }
.order-auto-pt-select { width: 84px; flex: 0 0 auto; }
.order-submit-btn { flex: 1 1 0; }

/* PAPER badge — amber pill marking the whole submit flow as paper-only. Sits
   on the toast's strategy line (flex row pushes it to the right edge). */
.paper-badge,
.live-badge {
    display: inline-block;
    padding: 1px 6px;
    border-radius: 4px;
    color: var(--color-text-on-accent);
    font-weight: 700;
    font-size: 0.7rem;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    vertical-align: middle;
}
/* Paper = brand yellow, Live = green — the two accounts read distinct at a glance. */
.paper-badge { background-color: var(--color-primary); }
.live-badge { background-color: var(--color-up); }

/* The nav badge is a clickable shortcut into the switch-account modal. */
.account-badge-link { text-decoration: none; }
.account-badge-link:hover { opacity: 0.85; }

/* Switch-account modal: stacked radio "cards", one per account. */
.account-choice-list { display: flex; flex-direction: column; gap: 0.5rem; }
.account-choice {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--color-border, #444);
    border-radius: 6px;
    cursor: pointer;
    margin: 0;
}
.account-choice:has(input:checked) { border-color: var(--color-info); }
.account-choice-body { display: flex; align-items: center; gap: 0.6rem; }
.account-choice-desc { font-size: 0.85rem; color: var(--color-text-muted, #9aa); }

/* Real-money warning shown in the modal (when Live is selected) and on the
   order toast (when the active account is live). */
.account-live-warn,
.order-live-warn {
    margin-top: 0.75rem;
    padding: 0.5rem 0.6rem;
    border: 1px solid var(--color-down);
    border-radius: 6px;
    background-color: var(--color-warning-soft);
    color: var(--color-down);
    font-size: 0.85rem;
}
.order-live-warn { margin-top: 0.5rem; }
.order-queue-sub-flex {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

/* Submitted state: the panel goes green and the footer flips from DRAFT to
   submitted · status · #id (painted client-side; polling stops on success). */
.order-queue.submitted { border-color: var(--color-up); }
.order-queue-foot.submitted { color: var(--color-up); font-weight: 600; }

/* Status line under the buttons: disabled reason / stale-quote / no-credit. */
.order-pricing-note {
    font-size: 0.75rem;
    color: var(--color-text-muted);
    margin-bottom: 2px;
}
.order-pricing-note.stale { color: var(--color-warning); }
.order-pricing-note i { margin-right: 4px; }

.nav-link {
    color: var(--color-info);
}

a.brand {
    display: flex;
    font-weight: bold;
    padding: 0.5rem;
    text-decoration: none;
}
a.brand:hover {
    color: unset;
}
a.brand > div {
    padding-inline: 4px;
}
a.brand .l1 {
    color: #333;
    background-color: #fafafa;
    border-top-left-radius: 4px;
    border-bottom-left-radius: 4px;
}
a.brand .l2 {
    color: #333;
    background-color: var(--color-secondary);
}
a.brand .l3 {
    color: #333;
    background-color: var(--color-primary);
    padding-inline: 5px;
}
a.brand .l4 {
    color: #333;
    background-color: var(--color-down);
    padding-inline: 8px;
    border-top-right-radius: 4px;
    border-bottom-right-radius: 4px;
}
a.nav-link.nav-acct:hover {
    color:unset;
}

h1.title {
    font-size: 1.5rem;
    margin-bottom: 25px;
}
/* Below Bootstrap's sm breakpoint the page title shares its row with a link and
   a badge, so it drops a step rather than pushing them onto a second line. */
@media (max-width: 575.98px) {
    h1.title { font-size: 1.1rem; }
}

/* ===================== Utilities ===================== */
.w-fit { width: fit-content; }
.w-75p { width: 75px; }
.w-100p { width: 100px; }
.w-220p { width: 220px; }
.mw-90 { max-width: 90px; }
.mw-400 { max-width: 400px; }
.mw-500 { max-width: 500px; }
.mw-600 { max-width: 600px; }
.cursor-pointer { cursor: pointer; }
.no-underline { text-decoration: none; }
.text-bold { font-weight: bold; }
.text-08 { font-size: 0.8rem; }
.text-09 { font-size: 0.9rem; }


/* ===================== Toast ===================== */
.toast-outer {
    position: fixed;
    top: 10px;
    right: 40px;
    background-color: var(--color-white);
    border: 2px solid var(--color-border);
    box-shadow: var(--shadow-lg);
    z-index: 1100;
    width: auto;
    min-width: 300px;
    max-width: 500px;
    border-radius: var(--radius);
    display: none;
}
.toast-content {
    padding: 12px 20px;
    display: flex;
    align-items: center;
    column-gap: 12px;
    font-weight: bold;
    font-size: 0.9rem;
}
.toast-outer .toast-icon {
    font-size: 1.15rem;
}
.toast-outer.success {
    border-color: var(--color-up);
}
.toast-outer.success .toast-content {
    background-color: var(--color-up);
    color: var(--color-text-on-accent);
    border-radius: var(--radius);
}
.toast-outer.success .toast-icon {
    color: var(--color-text-on-accent);
}
.toast-outer.error {
    border-color: var(--color-down);
}
.toast-outer.error .toast-content {
    background-color: var(--color-down);
    color: var(--color-text-on-accent);
    border-radius: var(--radius);
}
.toast-outer.error .toast-icon {
    color: var(--color-text-on-accent);
}
.toast-outer.working {
    border-color: var(--color-working);
}
.toast-outer.working .toast-content {
    background-color: var(--color-working-bg);
    border-radius: var(--radius);
}
.toast-outer.working .toast-icon {
    color: var(--color-working);
}

ol.breadcrumb {
    padding: 5px 10px 10px 5px;
    font-size: 0.9rem;
}
ol.breadcrumb li { font-weight: bold; }
ol.breadcrumb li a {
    font-weight: normal;
}

label.form-label {
    color: var(--color-text-muted);
    font-size: 0.85rem;
    font-weight: bold;
    padding-left: 5px;
    margin-bottom: 3px;
}
label.form-check-label {
    color: var(--color-text-muted);
    font-size: 0.85rem;
    font-weight: bold;
    /* padding-left: 5px; */
}
.form-check .form-check-input {
    margin-left: -1.35em;
}

form.form-border {
    padding: 20px;
    border: 1px solid var(--color-border);
    /* box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); */
    box-shadow: var(--shadow-lg);
}
form p.title {
    font-size: 1.2rem;
    font-weight: bold;
}
/* Market clock widget (home page) */
.market-clock-error {
    padding: 12px 16px;
    border: 1px solid var(--color-warning);
    background-color: var(--color-warning-soft);
    border-radius: 4px;
    font-size: 0.9rem;
}
.market-clock-error i {
    color: var(--color-warning);
    margin-right: 6px;
}
.clock-hero {
    height: 100%;
}
.clock-hero-head {
    display: flex;
    align-items: center;
    margin-bottom: 8px;
}
.clock-hero-label {
    font-weight: bold;
}
.clock-status-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-left: auto;
    padding: 3px 10px;
    border-radius: 12px;
    font-size: 0.8rem;
    font-weight: bold;
    white-space: nowrap;
}
.clock-badge-open {
    background-color: var(--color-up);
    color: var(--color-text-on-accent);
}
.clock-badge-soon {
    background-color: var(--color-warning);
    color: var(--color-text-on-accent);
}
.clock-badge-closed {
    background-color: var(--color-border-strong);
    color: var(--color-text);
}
.clock-hero-countdown {
    font-size: 1.4rem;
    font-weight: bold;
}
.clock-hero-secondary {
    font-size: 0.9rem;
    color: var(--color-text-muted);
    margin-top: 2px;
}
.clock-hero-localtime {
    color: var(--color-text-disabled);
    margin-top: 4px;
}
.clock-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    margin-right: 6px;
}
.clock-dot-open {
    background-color: var(--color-up);
}
.clock-dot-soon {
    background-color: var(--color-warning);
}
.clock-dot-closed {
    background-color: var(--color-text-disabled);
}
.clock-tone-open {
    border-left: 3px solid var(--color-up);
}
.clock-tone-soon {
    border-left: 3px solid var(--color-warning);
}
.clock-tone-closed {
    border-left: 3px solid var(--color-border-strong);
}
.clock-table {
    font-size: 0.9rem;
}
.clock-table .clock-status-label {
    white-space: nowrap;
}
/* .page-title-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
} */
.clock-refresh-note {
    font-size: 0.9rem;
    color: var(--color-text);
    font-variant-numeric: tabular-nums;
    margin-left: auto;
}
.clock-outer {
    transition: opacity 0.3s ease;
}
.clock-outer.clock-refreshing {
    opacity: 0.35;
}
.stream-panel {
    max-width: 420px;
}
.stream-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    margin-right: 6px;
}
.stream-dot-connecting {
    background-color: var(--color-warning);
}
.stream-dot-live {
    background-color: var(--color-up);
}
.stream-dot-closed {
    background-color: var(--color-down);
}
/* Ladder legs-refresh spinner: sits right of the stream dot, sized/colored to
   read as a subtle "greeks updating" cue rather than a page-load spinner. */
.ladder-legs-spinner {
    width: 0.85rem;
    height: 0.85rem;
    border-width: 0.15em;
    color: var(--color-text-muted);
}
.stream-symbol {
    margin-right: 4px;
}
.stream-counts {
    font-size: 0.9rem;
    font-variant-numeric: tabular-nums;
}
.stream-hint {
    font-size: 0.9rem;
    color: var(--color-text-muted);
}
.stream-controls {
    margin-top: 12px;
    padding: 12px 0;
    border-top: 1px solid var(--color-border);
    border-bottom: 1px solid var(--color-border);
}

/* Orders monitor table (/orders) */
.orders-table td {
    vertical-align: middle;
}
.order-desc-label {
    font-weight: 600;
    margin-right: 8px;
}
.bid-mid-ask {
    word-spacing: 5px;
}
.submitted-at {
    cursor: help;
}
.status-badge {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 10px;
    font-size: 0.75rem;
    font-weight: 600;
    white-space: nowrap;
}
.status-badge.status-open {
    color: var(--color-text-on-accent);
    background-color: var(--color-primary);
}
.status-badge.status-filled {
    color: var(--color-text);
    background-color: var(--color-border-strong);
}
.status-badge.status-canceled {
    color: var(--color-text);
    background-color: var(--color-border-strong);
}
.status-badge.status-rejected {
    color: var(--color-text-on-accent);
    background-color: var(--color-down);
}
.status-badge.status-replaced {
    color: var(--color-text-on-accent);
    background-color: var(--color-secondary);
}
.filled-avg {
    display: block;
    color: var(--color-text-muted);
    font-size: 0.75rem;
}
/* Sub-label under the role: the order's directional intent (Sell to Open, etc.). */
.order-intent {
    display: block;
    color: var(--color-text-muted);
    font-size: 0.75rem;
}
/* Clickable Limit value: reads like the plain number, invites a click on hover. */
.limit-edit-btn {
    color: var(--color-text);
    font-size: inherit;
    font-weight: inherit;
    line-height: inherit;
    vertical-align: baseline;
    text-decoration: none;
    border: 0;
}
.limit-edit-btn:hover,
.limit-edit-btn:focus {
    color: var(--color-primary);
    text-decoration: underline;
}
.orders-table-foot {
    text-align: end;
    margin: 0 0 15px 0;
    font-size: 0.8rem;
}

/* Positions monitor table (/positions) */
.leg-badge.pos-short { color: var(--color-text-on-accent); background-color: var(--color-down); }
.leg-badge.pos-long { color: var(--color-text-on-accent); background-color: var(--color-up); }
.positions-table .pnl-pos { color: var(--color-up); font-weight: 600; }
.positions-table .pnl-neg { color: var(--color-down); font-weight: 600; }
/* P&L cell "▲ +$N (+N%)": keep the arrow, dollars and percent on one line. */
.positions-table .pnl-cell { white-space: nowrap; }

/* Profit-taker controls in the spread's order-history table */
.pt-cell { cursor: default; white-space: nowrap; }
.pt-percent-select { font-size: 0.8rem; }
.pt-create-row td {

}

/* Click-to-expand spread rows */
.spread-row { cursor: pointer; }
.spread-row:hover { background-color: var(--color-elevated); }
.spread-legs-cell { padding: 15px 15px 15px 15px !important; background-color: var(--color-inset); }

.spread-legs-table,
.spread-orders-table,
.trade-logs-table {
    background-color: var(--color-inset);
    font-size: 0.85rem;
    border: 1px solid var(--color-border);
    margin-bottom: 20px;
}

.spread-legs-table th,
.spread-orders-table th,
.trade-logs-table th {
    font-size: 0.72rem;
    color: var(--color-text-muted);
    font-weight: 600;
    border-top: 0;
}
.spread-legs-table > :not(caption) > * > * { background-color: transparent; }
.spread-orders-table > :not(caption) > * > * { background-color: transparent; }
.trade-logs-table > :not(caption) > * > * { background-color: transparent; }
/* Totals row across the bottom of a legs table — a heavier top rule + bold
   figures set it apart from the per-leg rows above. Not scoped to
   .spread-legs-table: the open-legs view (/positions/legs) reuses the same
   totals row on a full-width table. */
tfoot .leg-totals-row > td {
    border-top: 2px solid var(--color-border);
    font-weight: 600;
    padding-top: 0.5rem;
}
tfoot .leg-totals-label {
    color: var(--color-text-muted);
    font-weight: 600;
}
/* Separate the order history from the legs table above it. */
.spread-orders-table { margin-top: 0.75rem !important; border-top: 1px solid var(--color-border-subtle); }
/* Contract cell carries the full OCC symbol in a hover tooltip, and .leg-tip does
   the same for the greek / Std Dev cells (per-contract value behind the position
   figure) — dotted underline + help cursor signal there's more on hover. */
.leg-contract,
.leg-tip {
    border-bottom: 1px dotted var(--color-text-muted);
    cursor: help;
}
.leg-greek {
    color: var(--color-text-muted);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.78rem;
}

/* Poll spinner left of the positions filter — visibility (not display) keeps
   its slot so the dropdown doesn't shift as it toggles each poll tick. */
.poll-spinner { visibility: hidden; color: var(--color-up); }
.poll-spinner.is-active { visibility: visible; }

/* Reconciliation drift flag — amber warning next to the status badge when a
   position diverges from the broker's positions snapshot. */
.drift-flag {
    color: var(--color-warning);
    font-size: 0.8rem;
    margin-left: 5px;
    cursor: help;
}

/* ===================== Watchlists (/lists) ===================== */
/* Day-change cell: same green/red convention as the account page's dayChange,
   with the percent de-emphasized next to the dollar change. */
.wl-up { color: var(--color-up); font-weight: 600; }
.wl-down { color: var(--color-down); font-weight: 600; }
.wl-change-pct { font-weight: 400; }
/* Per-row remove control — keep the icon button compact in the cell. */
.wl-remove-btn { line-height: 1; }
/* Drag-to-reorder: a narrow leading handle column. The handle is the only
   grab target (SortableJS handle: '.wl-drag-handle'). */
.wl-drag-cell { width: 34px; }
.wl-drag-handle {
    color: var(--color-text-muted);
    cursor: grab;
}
.wl-drag-handle:active { cursor: grabbing; }
.watchlist-assets-table tr:hover .wl-drag-handle,
.watchlists-table tr:hover .wl-drag-handle { color: var(--color-text); }
/* Drag feedback: the placeholder gap and the row being dragged. Shared by the
   symbols table (within a list) and the watchlists table (the lists themselves). */
.watchlist-assets-table .sortable-ghost,
.watchlists-table .sortable-ghost {
    opacity: 0.4;
    background-color: var(--color-elevated);
}
.watchlist-assets-table .sortable-chosen,
.watchlists-table .sortable-chosen {
    background-color: var(--color-elevated);
}

/* ===================== Auth / login ===================== */
/* Login screen only: center the lone MarketMonitors brand in the top nav. */
.nav-top.login-nav {
    justify-content: center;
}
.login-wrap {
    max-width: 400px;
    margin: 80px auto 0;
    padding: 40px 36px;
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    box-shadow: var(--shadow-lg);
}
.login-heading {
    text-align: center;
    color: var(--color-text);
    font-weight: 800;
    font-size: 2.1rem;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    margin-bottom: 6px;
}
.login-subtitle {
    text-align: center;
    color: var(--color-text-muted);
    font-size: 1.1rem;
    margin-bottom: 34px;
}
.login-error {
    margin-bottom: 22px;
}
.login-label {
    display: block;
    color: var(--color-text);
    font-weight: 700;
    font-size: 0.95rem;
    margin-bottom: 8px;
}
.login-input {
    width: 100%;
    padding: 12px 14px;
    background-color: var(--color-inset);
    color: var(--color-text);
    border: 1px solid var(--color-border);
    border-radius: 6px;
    font-size: 1rem;
    margin-bottom: 26px;
}
.login-input:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 2px var(--color-focus-ring);
}
/* Login "Sign In" button: kept as a deliberate gold brand accent. */
.login-btn {
    width: 100%;
    padding: 12px;
    background-color: #f5c84a;
    color: #1a1a1a;
    border: none;
    border-radius: 6px;
    font-weight: 700;
    font-size: 1rem;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    cursor: pointer;
}
.login-btn:hover {
    background-color: #ecbb33;
}

/* Logout control sits in the top nav; the form wrapper keeps it a flex item and
   the button is stripped of its default chrome so it reads like a nav link. */
.logout-form {
    margin: 0;
}
.logout-link {
    background: none;
    border: none;
    cursor: pointer;
}

/* AI-review detail: bordered, vertically-scrolling boxes for long text / JSON
   fields. The wrapper carries the border; .scroll-content does the scrolling.
   The scrollbar rules use a descendant combinator so they style the inner
   scrolling element. */
.scroll-box {
    border: 1px solid var(--color-border);
    border-radius: .25rem;
}
.scroll-box ::-webkit-scrollbar {
    width: 10px;
}
.scroll-box ::-webkit-scrollbar-track {
    background: var(--color-inset);
}
.scroll-box ::-webkit-scrollbar-thumb {
    background-color: var(--color-border-strong);
    box-shadow: 0 0 1px rgba(255, 255, 255, .5);
}
.scroll-box ::-webkit-scrollbar-thumb:hover {
    background: var(--color-text-muted);
}
.scroll-box .scroll-content {
    min-height: 80px;
    max-height: 500px;
    overflow-y: scroll;
    scrollbar-gutter: stable;
    padding: 5px 8px 10px 10px;
}
/* The AI prompt preview is a centered modal — let its scroll area use more of
   the viewport (the id beats the .scroll-box .scroll-content specificity). */
#preview-ai-prompt-modal .scroll-content {
    max-height: 80vh;
}
.scroll-content pre {
    white-space: pre-wrap;
    word-break: break-word;
    margin: 0;
}
.scroll-content table {
    border: 1px solid var(--color-border);
    margin-bottom: 20px;
}
.scroll-content table td,
.scroll-content table th {
    padding: 4px 6px 4px 6px;
    font-size: 0.85rem;
}

/* Clickable AI-review log rows */
.ai-review-row {
    cursor: pointer;
}

/* Lightweight Charts container (autoSize tracks this box) */
.chart-container {
    width: 100%;
    height: 420px;
}

/* --- Price + volume chart page (/charts) ------------------------------ */
/* Taller than .chart-container to seat the candle pane + the volume pane. */
.price-chart {
    width: 100%;
    height: 600px;
    border: 1px solid var(--color-border);
    box-shadow: var(--shadow-lg);
}
/* Backtest single-run chart: three stacked panes (thin P&L + underlying
   candles + historical-volatility), so it's taller than .price-chart. */
.bt-run-chart {
    width: 100%;
    height: 720px;
    border: 1px solid var(--color-border);
    box-shadow: var(--shadow-lg);
}
.chart-toolbar .title {
    font-variant-numeric: tabular-nums;
}
/* Ticker + full security name stacked at the left of the chart toolbar:
   "SPY" on top, "SPDR S&P 500 ETF Trust" muted beneath it. */
.chart-symbol-id {
    display: flex;
    flex-direction: column;
    justify-content: center;
    line-height: 1.15;
}
.chart-symbol-name {
    max-width: 320px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-size: 1rem;
    color: var(--color-text-muted);
}
/* Last price + change shown beside the symbol. */
.chart-quote {
    display: inline-flex;
    align-items: baseline;
    gap: 0.5rem;
    font-variant-numeric: tabular-nums;
}
.chart-quote-last {
    font-size: 1.25rem;
    font-weight: 700;
}
.chart-quote-change {
    font-weight: 600;
}
.chart-quote-up {
    color: var(--color-up);
}
.chart-quote-down {
    color: var(--color-down);
}
.chart-tf-btn.active {
    background-color: var(--color-up);
    border-color: var(--color-up);
    color: #1b1b1b;
}
/* Dual-axis legend on the volatility chart: which line maps to which scale. */
.vol-legend {
    display: inline-flex;
    align-items: center;
    gap: 1rem;
    font-size: 0.9rem;
}
.vol-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    color: var(--color-text-muted);
}
.vol-legend-swatch {
    width: 14px;
    height: 3px;
    border-radius: 2px;
}
/* IV-percentile readout at the right of the volatility toolbar. Mirrors the
   backtest stat tile's label/value/sub type scale, but sits inline rather than in
   a grid. Toggled via the `hidden` attribute (Bootstrap's reboot carries
   [hidden]{display:none!important}, so it beats this display:flex). */
.vol-ivp {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 0.4rem 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    background: var(--color-bg-subtle, rgba(255, 255, 255, 0.02));
    cursor: help;   /* the title spells out the window; hint that it's there */
}
.vol-ivp-label {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--color-text-muted);
}
.vol-ivp-value {
    display: flex;
    align-items: baseline;
    gap: 0.45rem;
    font-size: 1.15rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.vol-ivp-sub {
    font-size: 0.8rem;
    font-weight: 400;
    color: var(--color-text-muted);
}
.vol-legend-hv .vol-legend-swatch { background-color: var(--color-up); }
/* Implied vol — only shown for symbols in the option store, so the item starts
   hidden and volatility.js reveals it when the series comes back non-empty. */
.vol-legend-iv .vol-legend-swatch { background-color: var(--color-primary); }
.vol-legend-price .vol-legend-swatch { background-color: var(--color-info); }
/* "Markets closed — live updates resume …" shown when the feed is quiet. */
.chart-market-status {
    font-size: 0.9rem;
    color: var(--color-warning);
}
/* Ticker -> /charts links inside tables: inherit the cell color, hint on hover. */
.symbol-chart-link {
    color: inherit;
    text-decoration: none;
}
.symbol-chart-link:hover {
    color: inherit;
    text-decoration: underline;
}

/* --- Theme roller (sandbox/chart) ------------------------------------- */
.theme-presets {
    display: flex;
    align-items: center;
    gap: 6px;
}
/* Each group is a labelled section; controls inside flow in a responsive grid */
.theme-group {
    margin-bottom: 1.25rem;
}
.theme-group-title {
    font-size: 0.85rem;
    font-weight: bold;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--color-text-muted);
    border-bottom: 1px solid var(--color-border);
    padding-bottom: 4px;
    margin-bottom: 10px;
}
.theme-controls {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: 10px 16px;
    align-items: end;
}
.theme-control {
    display: flex;
    flex-direction: column;
}
.theme-control .form-label {
    margin-bottom: 2px;
}
/* Color rows: label above, native swatch sized to a usable square */
.theme-control--color .theme-swatch {
    width: 100%;
    height: 32px;
    padding: 2px;
    border: 1px solid var(--color-border);
    border-radius: 0.25rem;
    background: var(--color-inset);
    cursor: pointer;
}
/* Checkbox cells align their box+label to the bottom of the grid row */
.theme-control--check {
    flex-direction: row;
    align-items: center;
    min-height: 32px;
}
.theme-control--check .form-check {
    margin-bottom: 0;
}
.is-hidden {
    display: none !important;
}

/* JSON output: header row + two side-by-side columns that wrap when narrow */
.theme-json-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 8px;
}
.theme-json-wrap {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
}
.theme-json-col {
    flex: 1 1 320px;
    min-width: 0;
}
.theme-json-col-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 4px;
}
.theme-json-col-head code {
    font-size: 0.8rem;
    color: var(--color-text-muted);
}
.theme-json-col pre {
    font-size: 0.8rem;
}

/* Account overview (/account) — paper-account financial snapshot.
   Reuses Bootstrap .card / .table and the shared .status-badge / .paper-badge;
   adds only the headline value, day-change colors, and table density. */
.acct-foot {
    text-align: end;
    margin: 0 0 12px 0;
    font-size: 0.8rem;
    color: var(--color-text-muted);
}
.acct-refresh-note {
    font-size: 0.8rem;
    color: var(--color-text-muted);
    white-space: nowrap;
}

.acct-hero-head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 6px;
}
.acct-hero-label {
    font-size: 0.85rem;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.acct-hero-value {
    font-size: 2rem;
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}
.acct-hero-change {
    margin-top: 4px;
    font-size: 0.95rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.acct-hero-change.acct-up { color: var(--color-up); }
.acct-hero-change.acct-down { color: var(--color-down); }
.acct-hero-change-pct { font-weight: 600; }

/* The status pill in the headline card uses the shared .status-badge base. */
.status-badge.acct-status-active {
    color: var(--color-text-on-accent);
    background-color: var(--color-up);
}
.status-badge.acct-status-warn {
    color: var(--color-text-on-accent);
    background-color: var(--color-warning);
}

.acct-table { margin-bottom: 0; }
.acct-table thead th {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--color-text-muted);
}
.acct-table .acct-label { color: var(--color-text-muted); }
.acct-table .acct-value {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Click-to-explain field labels on the account overview: dotted underline as
   the affordance, popover opens on focus (see _overview.html). */
.acct-info-label {
    color: inherit;
    cursor: help;
    text-decoration: underline dotted;
    text-underline-offset: 3px;
}
.acct-info-label:hover,
.acct-info-label:focus {
    color: var(--bs-link-color);
}

/* The explainer popovers (data-bs-custom-class) — a bit wider than Bootstrap's
   276px default so formulas don't wrap awkwardly. .acct-popover is the account
   overview's field explainers, .stat-popover the home page stat tiles; same
   treatment, two names so each page reads for itself. */
.acct-popover,
.stat-popover {
    max-width: 380px;
    font-size: 0.85rem;
}
.acct-popover code,
.stat-popover code {
    font-size: 0.8rem;
    white-space: nowrap;
}

/* Account hero: Portfolio Value on the left, the margin-cushion readout on the
   right. Cushion earns hero space because it is the single reading that says
   whether the account is sized correctly. Stacks on narrow screens. */
.acct-hero {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: stretch;
}
.acct-hero > .card-body { flex: 1 1 260px; }
.acct-hero-aside {
    flex: 0 1 280px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 16px 20px;
    border-inline-start: 1px solid var(--color-border);
}
.acct-hero-aside-value {
    margin-top: 4px;
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}
.acct-hero-aside-sub {
    font-size: 0.8rem;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}
@media (max-width: 575.98px) {
    .acct-hero { flex-direction: column; }
    .acct-hero-aside {
        border-inline-start: 0;
        border-top: 1px solid var(--color-border);
    }
}

/* Risk & Capacity panel (/account) — derived metrics, see utils/riskMetrics.
   Meter markup mirrors the API-usage meters but keeps its own class prefix so
   the two panels can diverge. Tones share the up/warn/down vocabulary. */
.risk-panel-head {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--color-text-muted);
    margin-bottom: 14px;
}
.risk-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 20px;
}
.risk-card-label {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--color-text-muted);
}
.risk-card-value {
    margin-top: 4px;
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}
.risk-card-note {
    font-size: 0.8rem;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}
.risk-meter {
    height: 8px;
    margin: 8px 0 6px 0;
    border-radius: 4px;
    background: var(--color-border);
    overflow: hidden;
}
.risk-meter-fill {
    height: 100%;
    transition: width 0.3s ease;
}
.risk-meter-fill.risk-fill-up { background: var(--color-up); }
.risk-meter-fill.risk-fill-warn { background: var(--color-warning); }
.risk-meter-fill.risk-fill-down { background: var(--color-down); }
.risk-up { color: var(--color-up); }
.risk-warn { color: var(--color-warning); }
.risk-down { color: var(--color-down); }

/* Capacity strip: how many more spreads fit, per strike width. */
.risk-capacity { margin-top: 22px; }
.risk-capacity .risk-card-label {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 10px;
}
.risk-capacity-row {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 10px;
}
.risk-capacity-item {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 8px 14px;
    border: 1px solid var(--color-border);
    border-radius: 6px;
}
.risk-capacity-width {
    font-size: 0.85rem;
    color: var(--color-text-muted);
}
.risk-capacity-count {
    font-size: 1.1rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* Capacity-by-utilization matrix. Both counts render server-side; the switch
   only flips which span is visible, so a partial swap costs no re-render. */
.risk-matrix .risk-card-label { justify-content: space-between; }
.risk-matrix-toggle {
    text-transform: none;
    letter-spacing: 0;
    padding-inline-start: 2.5em;
}
.risk-matrix-toggle .form-check-input { cursor: pointer; }
.risk-matrix-toggle .form-check-label {
    cursor: pointer;
    padding-inline-start: 8px;
}
.risk-matrix-width {
    align-self: center;
    font-size: 0.85rem;
    color: var(--color-text-muted);
}
/* Targets already passed — the zeros are a fact, not a glitch. */
.risk-matrix-empty { opacity: 0.45; }
/* Both grids render server-side; the switch picks which one is on screen. Its
   label names the grid you are looking at, so it swaps with them. */
.risk-matrix-mode-zero { display: none; }
.risk-matrix.is-zero .risk-matrix-mode-current { display: none; }
.risk-matrix.is-zero .risk-matrix-mode-zero { display: block; }
.risk-zero-off { display: none; }
.risk-matrix:not(.is-zero) .risk-zero-on { display: none; }
.risk-matrix:not(.is-zero) .risk-zero-off { display: inline; }
.risk-cap-condor { display: none; }
.risk-matrix.is-condor .risk-cap-directional { display: none; }
.risk-matrix.is-condor .risk-cap-condor { display: inline; }
/* Doubling only reads as a gain where there is something to double. */
.risk-matrix.is-condor .risk-capacity-item:not(.risk-matrix-empty) .risk-cap-condor { color: var(--color-up); }
.risk-table { margin-top: 20px; }

/* Generic placeholder for a partial that loads after the page shell renders
   (spinner + short message, centered in the region the partial will fill). */
.partial-loading {
    padding: 48px 16px;
    text-align: center;
    color: var(--color-text-muted);
    border: 1px solid var(--color-border);
    border-radius: 8px;
}

/* API Usage (/account/api-usage and /account/api-usage/openai).
   Hub = the provider list on the parent page; the rest is the OpenAI
   usage-and-cost report (stat cards + a by-model table). Design-token colors,
   tabular numerals on every numeric cell. */
.apiusage-hub {
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-width: 560px;
}
.apiusage-hub-item {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 16px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    color: var(--color-text);
    text-decoration: none;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}
.apiusage-hub-item:hover {
    border-color: var(--color-primary);
    background-color: var(--color-surface-2, rgba(255, 255, 255, 0.03));
}
.apiusage-hub-icon {
    font-size: 1.4rem;
    color: var(--color-info);
    width: 28px;
    text-align: center;
}
.apiusage-hub-text { flex: 1 1 auto; }
.apiusage-hub-title { font-weight: 600; }
.apiusage-hub-desc { font-size: 0.85rem; color: var(--color-text-muted); }
.apiusage-hub-chev { color: var(--color-text-muted); }

.apiusage-cards {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    margin-bottom: 20px;
}
.apiusage-card {
    flex: 1 1 180px;
    padding: 14px 16px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
}
.apiusage-card-label {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--color-text-muted);
    margin-bottom: 6px;
}
.apiusage-card-value {
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.apiusage-table { margin-bottom: 0; }
.apiusage-table thead th {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--color-text-muted);
}
.apiusage-table .apiusage-model {
    font-weight: 600;
    white-space: nowrap;
}
.apiusage-table .apiusage-num {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.apiusage-table tfoot .apiusage-total-row td {
    font-weight: 700;
    border-top: 2px solid var(--color-border);
}
.apiusage-foot {
    margin-top: 12px;
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

/* Alpaca page extras: a wide rate-limit card with a used/remaining meter. */
.apiusage-card-wide { flex: 2 1 320px; }
.apiusage-card-sub {
    font-size: 0.85rem;
    font-weight: 400;
    color: var(--color-text-muted);
}
.apiusage-card-note {
    margin-top: 6px;
    font-size: 0.8rem;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}
.apiusage-muted { color: var(--color-text-muted); }
.apiusage-meter {
    margin-top: 10px;
    height: 8px;
    border-radius: 4px;
    background-color: var(--color-border);
    overflow: hidden;
}
.apiusage-meter-fill {
    height: 100%;
    border-radius: 4px;
    transition: width 0.3s ease;
}
.apiusage-meter-fill.apiusage-up { background-color: var(--color-up); }
.apiusage-meter-fill.apiusage-warn { background-color: var(--color-warning); }
.apiusage-meter-fill.apiusage-down { background-color: var(--color-down); }

/* ===========================================================================
   Symbol combo box (Tom Select / MMCombo)
   Tom Select's default stylesheet is light and loads AFTER main.css (via the
   page's addl_css block), so these overrides are scoped under #ui-widget — the
   page wrapper that every view (and the combo box dropdown) renders inside — so
   their ID specificity wins regardless of load order.
   =========================================================================== */
.mm-combo-wrap { max-width: 320px; }
/* Compact widths where the combo box replaces a fixed-width symbol input
   (the chart toolbar and the bear-call-spread symbol field). */
.chart-symbol-combo { width: 200px; }
.bcs-symbol-combo { width: 200px; }

/* Match the native .form-select: same dark fill, border, radius, height, and
   the Bootstrap caret SVG on the right (Tom Select's default is a light gradient
   + its own triangle — both replaced here). */
#ui-widget .ts-wrapper.single .ts-control,
#ui-widget .ts-wrapper.single.input-active .ts-control,
#ui-widget .ts-control {
    min-height: 45px;
    padding-top: 0.375rem;
    padding-bottom: 0.375rem;
    padding-left: 0.75rem;               /* padding-right is Tom Select's caret reserve (~2rem) */
    background-color: #483e79;           /* matches .form-control / .form-select */
    background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='none' stroke='%23C6C7C8' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/></svg>");
    background-repeat: no-repeat;
    background-position: right 0.75rem center;
    background-size: 16px 12px;
    border: 1px solid var(--color-border);
    border-radius: 0.375rem;
    box-shadow: none;
    color: var(--color-text);
    /* Keep it to one line at a fixed height: the input shrinks instead of
       wrapping to a second row (which previously grew the box and shoved the
       page below it down when you clicked into a prepopulated field). */
    flex-wrap: nowrap;
    align-items: center;
}
/* We draw the form-select SVG caret, so suppress Tom Select's own ::after
   triangle (its caret-space reserve on the right is kept for our SVG). */
#ui-widget .ts-wrapper.single .ts-control:after { display: none; }
/* Let the text input collapse rather than force a 7rem min-width (the cause of
   the wrap); it flexes into whatever space is left beside the selected chip. */
#ui-widget .ts-control > input { min-width: 0 !important; flex: 1 1 auto; }
/* The selected single value (the "QQQ" chip) reads on the dark control. */
#ui-widget .ts-control .item { color: var(--color-text); }
#ui-widget .ts-control,
#ui-widget .ts-control input,
#ui-widget .ts-dropdown {
    color: var(--color-text);
    font-size: 1rem;
    line-height: 1.5;
}
#ui-widget .ts-control input::placeholder { color: var(--color-text-disabled); }
#ui-widget .ts-wrapper.focus .ts-control {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 0.25rem var(--color-focus-ring);
}

/* Dropdown surface + rows */
#ui-widget .ts-dropdown {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
}
#ui-widget .ts-dropdown .option { color: var(--color-text); }
#ui-widget .ts-dropdown .active { background-color: var(--color-elevated); color: var(--color-text); }
#ui-widget .ts-dropdown [data-selectable] .highlight {
    background: rgba(245, 200, 74, 0.25);   /* gold-tinted search match */
    border-radius: 1px;
}
#ui-widget .ts-dropdown .create { color: var(--color-text-muted); }
#ui-widget .ts-dropdown .create strong { color: var(--color-text); }

/* Optgroup (watchlist) headers. Overriding render.optgroup_header replaces
   Tom Select's default .optgroup-header markup, so style the rendered element
   (.mm-combo-group) directly — it carries no .optgroup-header class. */
#ui-widget .ts-dropdown .mm-combo-group {
    padding: 5px 8px;
    background: var(--color-surface);
    color: var(--color-text-muted);
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    border-top: 1px solid var(--color-border-subtle);
}
#ui-widget .ts-dropdown .optgroup:first-child .mm-combo-group { border-top: 0; }

/* Per-option layout: SYMBOL on the left, company name muted on the right. */
.mm-combo-opt {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
}
.mm-combo-sym { font-weight: 600; }
.mm-combo-name {
    color: var(--color-text-muted);
    font-size: 0.85rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ===========================================================================
   Large Moves (/historical-data/large-moves)
   =========================================================================== */
.lm-field { display: flex; flex-direction: column; gap: 2px; }
.lm-field-label {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--color-text-muted);
}
/* The Select Move dropdown gets its own full-width row so each option can lay
   out episode info in columns. */
.lm-move-row { margin-bottom: 1rem; }
.lm-move-row .lm-field,
.lm-move-row .ts-wrapper { width: 100%; }
/* Pseudo-table columns inside each option (and the selected item). min-widths
   keep the columns aligned across rows in the open dropdown. */
.lm-move-opt {
    display: flex;
    align-items: baseline;
    gap: 1rem;
    font-variant-numeric: tabular-nums;
    min-width: 0;
}
/* The selected item rendered inside the control: Tom Select's default
   `.ts-control > *` (inline-block) loads after main.css, so re-assert the flex
   row under the #ui-widget scope (same trick as the .ts-control overrides). */
#ui-widget .ts-control .lm-move-opt { display: flex; }
.lm-move-dates { font-weight: 600; min-width: 15rem; }
.lm-move-pct { font-weight: 600; min-width: 5rem; text-align: right; }
.lm-move-pct.lm-up { color: var(--color-up); }
.lm-move-pct.lm-down { color: var(--color-down); }
.lm-move-px { color: var(--color-text-muted); min-width: 11rem; }
.lm-move-hits { color: var(--color-text-muted); font-size: 0.85rem; margin-left: auto; }
/* Plain-words summary of the selected move, below the chart. */
.lm-explain {
    margin-top: 0.75rem;
    color: var(--color-text-muted);
    font-size: 0.9rem;
    line-height: 1.5;
}
.lm-explain strong { color: var(--color-text); font-variant-numeric: tabular-nums; }
.lm-explain .lm-up { color: var(--color-up); }
.lm-explain .lm-down { color: var(--color-down); }
/* Historical Options Chains button row + the expiration list in its modal */
.lm-chains-row { margin-top: 1rem; }
.lm-chains-intro { font-size: 0.9rem; margin-bottom: 0.75rem; }
.lm-chains-list { display: flex; flex-direction: column; gap: 0.35rem; }
.lm-chain-link { font-variant-numeric: tabular-nums; text-decoration: none; }
.lm-chain-link:hover { text-decoration: underline; }
/* Chain strikes table in the modal: fixed-height scroll box with a forced-
   visible scrollbar (same recipe as .scroll-box above) so it's obvious more
   strikes sit above and below. The fixed height also fixes the modal size in
   table mode; the expiration-list view never renders this container. */
.lm-chain-scroll {
    position: relative; /* anchors the ATM row's offsetTop for scroll-centering */
    height: 480px;
    overflow-y: scroll;
    scrollbar-gutter: stable;
    border: 1px solid var(--color-border);
    border-radius: 0.25rem;
}
.lm-chain-scroll::-webkit-scrollbar { width: 10px; }
.lm-chain-scroll::-webkit-scrollbar-track { background: var(--color-inset); }
.lm-chain-scroll::-webkit-scrollbar-thumb {
    background-color: var(--color-border-strong);
    box-shadow: 0 0 1px rgba(255, 255, 255, 0.5);
}
.lm-chain-scroll::-webkit-scrollbar-thumb:hover { background: var(--color-text-muted); }
.lm-chain-table { width: 100%; margin: 0; font-variant-numeric: tabular-nums; border-collapse: collapse; }
.lm-chain-table th, .lm-chain-table td { padding: 4px 10px; font-size: 0.85rem; }
.lm-chain-table td:nth-child(2), .lm-chain-table th:nth-child(2) { text-align: center; }
.lm-chain-table thead th { position: sticky; top: 0; z-index: 1; background: var(--color-inset); }
.lm-chain-atm td {
    background-color: var(--color-warning-soft);
    color: var(--color-text);
    font-weight: 600;
    text-align: center;
}
.lm-chain-occ { text-decoration: none; font-variant-numeric: tabular-nums; }
.lm-chain-occ:hover { text-decoration: underline; }

/* The snapshot echo line on the sandbox page */
.mm-combo-echo {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.75rem;
}
.mm-combo-echo-sym { font-size: 1.5rem; font-weight: 700; }
.mm-combo-echo-name { color: var(--color-text-muted); }
.mm-combo-echo-last { font-weight: 600; font-variant-numeric: tabular-nums; }
.mm-combo-echo-change { font-weight: 600; font-variant-numeric: tabular-nums; }

ul.list-strategies {
    padding-left: 20px;
}
ul.list-strategies li {
    padding-block: 5px;
}

.ui-box {
    border: 1px solid var(--color-border);
    background-color: var(--color-inset);
    border-radius: 0.375rem;
    padding: 15px 20px 20px 20px;
    margin-bottom: 0.5rem;
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
    box-shadow: var(--bs-box-shadow-sm);
}
.ui-box .title {
    font-size: 1.0rem;
    font-weight: bold;
    display: flex;
    align-items: center;
    justify-content: space-between;
    color: var(--color-text-muted);
    padding-bottom: 10px;
    border-bottom: 1px solid var(--color-border);
}
.ui-box .ui-box-row {
    font-size: 0.9rem;
    display: flex;
    align-items: center;
    padding-top: 15px;
    justify-content: space-between;
    /* color: var(--color-text-muted); */
}
.ui-box .ui-box-row a {
    color: var(--color-info);
}
.ui-box .ui-box-row a:hover {
    color: var(--color-info);
    /* text-decoration: underline; */
    opacity: 0.9;
}

/* ───────────────────────────────────────────────────────────────────────────
   Options Strategy Simulator (/options/strategies/simulator)
   Ported from the old trading-tools strategies.css, restyled for dark mode:
   hardcoded light backgrounds/borders/greys map to theme tokens; the green/red
   P&L colours already used Bootstrap's --bs-success/--bs-danger and carry over.
   ─────────────────────────────────────────────────────────────────────────── */
.sim-lead { font-size: 0.9rem; margin-bottom: 1rem; }
.sim-box { margin-bottom: 1rem; }
.sim-symbol-combo { width: 200px; }

.menu-strats,
.ui-stock,
.ui-leg,
.d-sliders {
    display: flex;
    column-gap: 20px;
    align-items: flex-end;
    flex-wrap: wrap;
}
.menu-strats label,
.ui-stock label,
.ui-leg label,
.d-sliders label {
    font-weight: 600;
    color: var(--color-text-muted);
    padding-bottom: 4px;
    display: block;
    text-align: center;
}
.ui-stock .f-symbol label,
.ui-leg .leg-label { text-align: left; }
.ui-leg .leg-label { padding-left: 12px; }
.ui-leg .f-qty label { text-align: left; padding-left: 11px; }

.f-rate { width: 130px; }
.f-rate input { text-align: center; padding-right: 5px; }

.ui-stock { column-gap: 25px; }
.ui-stock .price { max-width: 130px; }
.ui-stock .refresh-quote,
.ui-leg .f-leg-vol .refresh {
    cursor: pointer;
    color: var(--bs-link-color);
}
.ui-stock .refresh-quote { margin-left: 4px; }

.ui-legs { display: flex; flex-direction: column; }
.ui-leg { column-gap: 15px; padding-block: 5px; }
.ui-leg .f-strike { flex-basis: 110px; }
.ui-leg .f-exp-date { flex-basis: 200px; }
.ui-leg .f-exp-date .leg-exp { width: 100%; }
.ui-leg .f-days { flex-basis: 90px; }
.ui-leg .f-leg-vol { flex-basis: 120px; position: relative; }
.ui-leg .f-leg-vol .leg-vol { text-align: center; }
.ui-leg .f-leg-vol .refresh { position: absolute; bottom: 7px; left: 6px; width: fit-content; }
.ui-leg .f-remove { padding-bottom: 4px; }
.ui-leg .f-remove button.btn.btn-link { padding: 0; }
.ui-leg .f-symbol .o-symbol {
    font-size: 0.8rem;
    color: var(--color-text-muted);
    /* Match the sibling form-control height so this column is as tall as the
       others: with the row's align-items:flex-end, that lifts the "Symbol" label
       up to the other labels' row and centers the value on the controls / minus
       icon (otherwise the short span drops the whole column ~18px). */
    display: flex;
    align-items: center;
    min-height: 38px;
}

.sim-add-leg { text-decoration: none; }
.sim-add-leg:hover { text-decoration: underline; }

.d-sliders { align-items: flex-start; column-gap: 25px; }
.d-sliders .input-group-text { font-size: 0.8rem; font-weight: 600; color: var(--color-text-muted); }
.d-sliders .set-entry-price { max-width: 180px; }
.d-sliders .set-entry-price input { padding-left: 8px; }
.d-sliders .adjust-days { max-width: 200px; }
.d-sliders .adjust-days input { text-align: center; padding-right: 5px; }
.d-sliders .adjust-price { max-width: 300px; }
.reset-adj-wrap { padding-top: 2px; }
.reset-adj { font-size: 0.8rem; margin-left: 15px; cursor: pointer; }
.copy-model-value { display: inline-block; margin-top: 4px; font-size: 0.8rem; cursor: pointer; }
.form-range { height: 38px; }

/* Greeks / model-value table */
.ui-table {
    display: none;
    border: 1px solid var(--color-border-subtle);
    border-radius: 4px;
    overflow: hidden;
    font-size: 0.8rem;
    background-color: var(--color-bg);
}
.ui-table .row-labels,
.ui-table .row-values { display: flex; flex-wrap: nowrap; }
.ui-table .row-labels {
    font-weight: 600;
    color: var(--color-text-muted);
    padding: 15px 15px 10px 15px;
    border-bottom: 1px solid var(--color-border-subtle);
}
.ui-table .row-labels.totals {
    border-top: 1px solid var(--color-border-subtle);
    border-bottom: none;
    background-color: var(--color-surface);
    color: var(--color-text);
    padding-bottom: 15px;
}
.ui-table .row-values { padding: 10px 15px; }
.ui-table .cell { flex-basis: 90px; text-align: right; }
.ui-table .cell.leg { flex-basis: 150px; text-align: left; }
.ui-table .cell.net-value { margin-left: auto; }
.ui-table .cell.col-qty { flex-basis: 70px; }
.ui-table .cell.dollar-value { flex-basis: unset; margin-left: auto; }

/* Estimated P&L */
.ui-profit-loss { padding: 12px 4px; font-size: 0.9rem; display: flex; align-items: center; }
.ui-profit-loss label.pl { display: inline-block; margin-bottom: 0; font-size: 0.9rem; color: var(--color-text-muted); }
.ui-profit-loss .box-pl-pct { margin-left: auto; padding-right: 20px; font-weight: 500; font-size: 1rem; }
.ui-profit-loss .box-pl { font-size: 1.3rem; font-weight: bold; }
.ui-profit-loss .box-pl.profit { color: var(--bs-success); }
.ui-profit-loss .box-pl.loss { color: var(--bs-danger); }

@media (max-width: 991.98px) {
    .ui-table .cell { flex-basis: 100px; }
    .ui-table .cell.rho,
    .ui-table .cell.stdv { display: none; }
}

/* ===== Strike Ladder (/positions/ladder/:ocaGroup) ===== */
/* The canvas box the StrikeLadder plugin renders into. Migrated from the
   sandbox demo's inline styles; the framing color is the on-token equivalent
   of the sandbox's raw #5c4f8a. */
.ladder-wrapper {
    position: relative;
    margin-bottom: 15px;
}
.strike-ladder {
    width: 100%;
    height: 500px;
    border: 1px solid var(--color-border);
    box-shadow: var(--shadow-lg);
    padding: 15px;
    background-color: var(--color-inset);
}
.zoom-btns {
    position: absolute;
    top: 25px;
    left: 25px;
    width: fit-content;
}

/* Spread type (e.g. "Bear Call Spread"), pinned to the lower-left corner of the
   strike ladder canvas. A raised chip on the inset panel, matching the
   .pl-bid-mid-ask overlay on the right panel. */
.ladder-type-badge {
    position: absolute;
    bottom: 25px;
    left: 25px;
    padding: 8px 16px;
    font-size: 0.9rem;
    font-weight: 500;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    background-color: var(--color-surface);
    box-shadow: var(--shadow-lg);
}

/* The Profit/Loss Ladder canvas box (right column of the ladder view) —
   same framing as the strike ladder so the two read as a pair. */
.pl-ladder {
    width: 100%;
    height: 500px;
    border: 1px solid var(--color-border);
    box-shadow: var(--shadow-lg);
    padding: 15px;
    background-color: var(--color-inset);
}

/* Live net bid / mid / ask for the spread, pinned to the lower-right corner of
   the P/L ladder canvas (mirrors the .zoom-btns overlay on the left panel). A
   raised chip on the inset panel; fed by the same 3s legs poll as the mark. */
.pl-bid-mid-ask {
    position: absolute;
    bottom: 25px;
    right: 25px;
    text-align: center;
    padding: 8px 16px;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    background-color: var(--color-surface);
    box-shadow: var(--shadow-lg);
}
.pl-bma-head {
    font-size: 0.8rem;
    color: var(--color-text-muted);
    margin-bottom: 6px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--color-border);
}
.pl-bma-values {
    font-size: 0.9rem;
    font-variant-numeric: tabular-nums;
    word-spacing: 4px;
}


/* The page title is a position picker: a dropdown of every open spread that
   reloads the ladder on change. Sized to feel title-like; width tracks the
   selected label, capped so a long option can't overflow the row. */
.ladder-position-select {
    font-size: 1.15rem;
    font-weight: 500;
    max-width: 100%;
}

/* The per-leg detail table below the ladder canvas — same table the positions
   page shows in its expanded row. This wrapper is the inset panel (mirroring
   .spread-legs-cell); the inner .spread-legs-table supplies the bordered grid. */
.ladder-legs {
    padding-top: 24px;
    /* padding: 15px;
    background-color: var(--color-inset);
    border: 1px solid var(--color-border);
    border-radius: 6px; */
}
.ladder-legs .spread-legs-table {
    margin-bottom: 0;
}

/* Spread value-over-time chart (bottom of the ladder view): hourly candles of
   the spread's premium from 30 days before entry, framed like the ladder canvases
   above, plus an equal-height underlying pane below it (hence 740px, not 540px
   — the two panes split it; see the setContractData call in ladder.js).
   No padding — lightweight-charts autoSize sizes its canvas to the element. */
.spread-history-chart {
    width: 100%;
    height: 740px;
    border: 1px solid var(--color-border);
    box-shadow: var(--shadow-lg);
    background-color: var(--color-inset);
    margin-bottom: 15px;
}
/* Header link back to the underlying's own chart (/charts/options page). */
.spread-chart-link { color: var(--color-text); }
/* Text-only empty state (endpoint failed / closed position with no data). */
.spread-history-chart.spread-history-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-muted);
}

/* ===================== Open-interest surface (/options/open-interest) ===================== */
/* 3D OI bar chart (echarts-gl) and its Type / expiration controls. The symbol
   combo reuses the global #ui-widget .ts-* overrides; only its wrapper width
   is page-specific. */
.oi-surface-chart {
    width: 100%;
    height: 800px;
    border: 1px solid var(--color-border);
}
.oi-symbol-combo {
    width: 200px;
}
.oi-progress {
    font-size: 0.85rem;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}
.oi-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px 24px;
}
.oi-control {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 0;
    font-size: 0.85rem;
    color: var(--color-text-muted);
}
.oi-exp-checks {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 16px;
}
.oi-exp-check {
    font-size: 0.85rem;
    color: var(--color-text-muted);
    white-space: nowrap;
}

/* ===========================================================================
   Backtests (/backtests)
   =========================================================================== */
.bt-field { display: flex; flex-direction: column; gap: 2px; padding-block: 4px; }
.bt-field-label {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--color-text-muted);
    padding-left: 3px;
}
.bt-field .form-control { max-width: 9rem; }
/* Stop-rule checkboxes (Δ > 30 / strike breach), aligned with the selects. */
.bt-check-group {
    display: flex;
    gap: 0.75rem;
    align-items: center;
    min-height: 2.35rem;   /* match .form-select height so the row baselines */
}
.bt-check {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.85rem;
    white-space: nowrap;
    margin: 0;
    cursor: pointer;
}
.bt-section-title { font-size: 1.1rem; font-weight: 600; margin-bottom: 0.5rem; }
/* Summary stat tiles: above the backtest equity curve (.bt-stat-*) and on the
   home page (.stat-*). One rule set under two names — the bt- names predate the
   generic ones and are kept so the backtest views need no edit. */
.bt-stat-grid,
.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
    gap: 0.75rem;
}
.bt-stat-tile,
.stat-tile {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 0.6rem 0.8rem;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    background: var(--color-bg-subtle, rgba(255, 255, 255, 0.02));
}
.bt-stat-label,
.stat-label {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--color-text-muted);
}
.stat-symbol {
    font-size: 1rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--color-text);
}
.bt-stat-value,
.stat-value { font-size: 1.15rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.bt-stat-sub,
.stat-sub { font-size: 0.8rem; font-weight: 400; color: var(--color-text-muted); }
/* Home tiles are links to the page that explains the number. Keep the tile
   looking like a tile (no underline, inherited color) and lift it on hover. */
.home-stat-tile {
    text-decoration: none;
    color: inherit;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}
.home-stat-tile:hover {
    color: inherit;
    border-color: var(--color-primary);
    background: rgba(255, 255, 255, 0.05);
}
.home-stat-tile .stat-sub { font-variant-numeric: tabular-nums; }
/* Bordered card holding one titled block of stats — the breakdown cards on
   /account/performance and the Kelly ladders on /account/kelly. Named perf-*
   because that page defined them first; shared here rather than duplicated once
   a second page wanted the same idiom. */
.perf-panel {
    border: 1px solid var(--color-border);
    border-radius: 6px;
    padding: 0.75rem 0.9rem;
    height: 100%;
}
.perf-panel-title {
    font-size: 0.95rem;
    font-weight: 600;
    margin-bottom: 0.6rem;
}
.perf-count {
    color: var(--color-text-muted);
    font-weight: 400;
    font-size: 0.85rem;
}
/* Hand-drawn chart legend items. Shared because both /account/performance and
   /account/kelly draw their own legend rather than using a chart-library one —
   the swatch COLOURS stay in each page's stylesheet, only the shape is common. */
.perf-legend-item { display: inline-flex; align-items: center; gap: 0.4rem; }
.perf-swatch {
    width: 1.1rem;
    height: 0.2rem;
    border-radius: 1px;
    display: inline-block;
}
/* Home quote boxes: the stat tile plus a fund-name line under the ticker. Names
   run long ("SPDR Gold Trust, SPDR Gold Shares") and the grid tracks are narrow,
   so clip to one line — the full name stays in the title attribute. */
.quote-name {
    font-size: 0.72rem;
    color: var(--color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.home-quote-tile .stat-value { font-size: 1.2rem; color: var(--color-text); }
/* Thin header strip above the quote row, holding only the stream health dot. */
.quote-row-head {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    height: 1rem;
}
/* Run parameter chips: the full run configuration (every /backtests form field)
   shown at the top of a run's results page — one labeled chip per parameter. */
.bt-params { display: flex; flex-wrap: wrap; gap: 0.4rem 0.5rem; }
.bt-param {
    display: inline-flex;
    align-items: baseline;
    gap: 0.4rem;
    padding: 0.2rem 0.6rem;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    background: var(--color-bg-subtle, rgba(255, 255, 255, 0.02));
    font-size: 0.82rem;
    white-space: nowrap;
}
.bt-param-label { font-size: 0.66rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; color: var(--color-text-muted); }
.bt-param-value { font-weight: 600; font-variant-numeric: tabular-nums; }
.bt-up { color: var(--color-up); }
.bt-down { color: var(--color-down); }
/* Trades + saved-runs tables: numeric alignment. */
.bt-trades-table td, .bt-runs-table td { font-variant-numeric: tabular-nums; }
/* Saved-runs rows link to the run's results page (whole row clickable). */
.bt-run-row { cursor: pointer; }
/* Sweep leaderboard's hold-constant filter row: one dropdown per swept axis,
   sitting directly above that column's sortable header. Deliberately smaller
   than .form-select-sm — Bootstrap's caret gutter alone is wider than these
   numeric columns, so padding, caret and font all shrink to fit. */
.bt-filter-row th { padding: 0.3rem 0.4rem; }
.bt-filter-select {
    width: 100%;
    min-width: 4.4rem;
    padding: 0.05rem 1.1rem 0.05rem 0.35rem;
    background-position: right 0.25rem center;
    background-size: 11px 8px;
    font-size: 0.75rem;
    line-height: 1.4;
    border-radius: 4px;
}
/* Stop column: the credit-multiple stop loss plus the plan rule markers (Δ / K).
   Rule markers read as secondary — muted and slightly smaller than the multiple.
   (Distinct from .bt-stop-rule, the red loss-context Δ/K pill in the trades table.) */
.bt-stop-part + .bt-stop-part { margin-left: 0.35rem; }
.bt-stop-mark { color: var(--color-text-muted); font-size: 0.85em; }
/* Exit-reason badge per outcome. */
.bt-reason {
    display: inline-block;
    padding: 1px 7px;
    border-radius: 9px;
    font-size: 0.78rem;
    font-weight: 600;
    white-space: nowrap;
}
.bt-reason-profit_target { color: var(--color-up); background: rgba(64, 192, 87, 0.12); }
.bt-reason-stop_loss { color: var(--color-down); background: rgba(250, 82, 82, 0.12); }
.bt-reason-expired { color: var(--color-text); background: rgba(255, 255, 255, 0.08); }
.bt-reason-end_of_data { color: var(--color-text-muted); background: rgba(255, 255, 255, 0.05); }
.bt-reason-entry { color: var(--color-text-muted); background: rgba(255, 255, 255, 0.05); }
.bt-stale { color: var(--color-warning, #e8b339); cursor: help; }
/* Which stop rule fired (Δ = delta, K = strike breach), next to the reason badge. */
.bt-stop-rule {
    display: inline-block;
    min-width: 1.1rem;
    text-align: center;
    border-radius: 4px;
    font-size: 0.72rem;
    font-weight: 700;
    color: var(--color-down);
    background: rgba(250, 82, 82, 0.08);
}
/* ET clock time of an intraday fill, next to the exit date. */
.bt-exit-time { color: var(--color-text-muted); font-size: 0.82rem; white-space: nowrap; }
/* Entry/Exit tag on each split trade row (one position → an entry row + an exit row). */
.bt-type {
    display: inline-block;
    min-width: 3.1rem;
    text-align: center;
    padding: 1px 7px;
    border-radius: 9px;
    font-size: 0.78rem;
    font-weight: 600;
}
.bt-type-entry { color: var(--color-text-muted); background: rgba(255, 255, 255, 0.05); }
.bt-type-exit { color: var(--color-text); background: rgba(255, 255, 255, 0.10); }
/* Faint tint distinguishing exit rows from entry rows when the two interleave. */
.bt-event-exit td { background: rgba(255, 255, 255, 0.02); }
/* The Trades table sits in a capped-height scroll box so a long run (an entry +
   exit row per position) doesn't stretch the page. A visible custom thumb, plus
   right padding so the scrollbar never sits over the last (P&L) column. */
/* overflow-y:scroll + scrollbar-gutter:stable keeps the bar always visible and
   reserves its gutter (so it never overlaps the last column, even under the macOS
   overlay-scrollbar behavior that hides an `auto` bar) — the same recipe as
   .scroll-box above. A little extra padding-right breathes the P&L column off it. */
.bt-trades-scroll {
    max-height: 600px;
    overflow-y: scroll;
    scrollbar-gutter: stable;
    padding-right: 8px;
}
.bt-trades-scroll::-webkit-scrollbar { width: 10px; }
.bt-trades-scroll::-webkit-scrollbar-track { background: var(--color-inset); }
.bt-trades-scroll::-webkit-scrollbar-thumb {
    background-color: var(--color-border-strong);
    box-shadow: 0 0 1px rgba(255, 255, 255, .5);
    border-radius: 5px;
}
.bt-trades-scroll::-webkit-scrollbar-thumb:hover { background: var(--color-text-muted); }
/* Keep the header row visible while the body scrolls; opaque bg so scrolling rows
   don't bleed through. */
.bt-trades-scroll thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--color-elevated);
}
/* Narrow show/hide-line checkbox column. */
.bt-line-col { width: 2.2rem; }
.bt-line-toggle, #bt-line-toggle-all { cursor: pointer; }
/* ===================== Scheduled task logs (/logs/scheduled-tasks/:taskId) ===================== */
/* The Detail column holds one JSON blob per entry, often several hundred chars.
   Cap it at 40% of the table and scroll the overflow inside the cell so a chatty
   run doesn't stretch a row taller than the rest of the table. table-layout:fixed
   is what makes the percentage width bind. */
.task-logs-table { table-layout: fixed; }
.task-logs-table td { vertical-align: middle; }
.task-logs-detail-col { width: 40%; }
.task-logs-detail { max-height: 50px; overflow-y: auto; }
/* Bootstrap sets `word-wrap: break-word` on `code` itself, which beats an
   inherited overflow-wrap from the cell — so the break has to be declared on the
   code element. A long unbroken run of JSON (no spaces between props) otherwise
   escapes the 40% column and runs off the table. */
.task-logs-detail code { overflow-wrap: anywhere; word-break: break-word; }

/* Collapsible skipped-entries log below the trades table. */
.bt-skipped { margin-top: 0.75rem; font-size: 0.85rem; }
.bt-skipped ul { margin: 0.5rem 0 0 1rem; color: var(--color-text-muted); }
.bt-note { color: var(--color-text-muted); font-size: 0.9rem; }
