/* ===== Base ===== */
* { box-sizing: border-box; }
[hidden] { display: none !important; }

/* ===== Audio-locked banner ===== */
/* Shown at the very top of the page while AudioContext is suspended.
   Auto-hides once a user gesture resumes it. Pulses gently to make it
   impossible to miss. */
#audio-gate {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 9999;
  padding: 10px 16px;
  background: linear-gradient(180deg, #f0b429 0%, #d99a14 100%);
  color: #2a2411;
  font: 600 14px -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  text-align: center;
  letter-spacing: 0.03em;
  box-shadow: 0 2px 8px rgba(0,0,0,0.35);
  cursor: pointer;
  animation: audio-gate-pulse 1.6s ease-in-out infinite;
}
@keyframes audio-gate-pulse {
  0%, 100% { filter: brightness(1.0); }
  50%      { filter: brightness(1.18); }
}
:root {
  --bg: #0f1115;
  --panel: #161a22;
  --panel-2: #1d2230;
  --border: #2a3142;
  --text: #e4e8f1;
  --muted: #8791a7;
  --accent: #4e8cff;
  --accent-hover: #3a78ea;
  --green: #2fbf71;
  --yellow: #f0b429;
  --red: #e15554;
  --pink: #ff4ba6;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
html, body {
  height: 100%;
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-size: 13px;
}
button, input, select, textarea {
  font: inherit;
  color: inherit;
}

/* ===== Top bar ===== */
.topbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px 14px;
  background: var(--panel);
  border-bottom: 1px solid var(--border);
}
.brand {
  font-weight: 700;
  letter-spacing: 0.04em;
}
.topbar-right {
  display: flex;
  gap: 14px;
  align-items: center;
  color: var(--muted);
}
.voice-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
}
.ws-status.online { color: var(--green); }
.ws-status.offline { color: var(--red); }

/* ===== Tab bar (center of topbar) ===== */
.tab-bar {
  display: flex;
  gap: 4px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 2px;
}
.tab-btn {
  background: transparent;
  border: 0;
  color: var(--muted);
  padding: 4px 14px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.12s, color 0.12s;
}
.tab-btn:hover { color: var(--text); }
.tab-btn.active {
  background: var(--accent);
  color: #fff;
}

/* ===== Layout: horizontal bands stacked vertically ===== */
.stack {
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: 10px;
  padding: 10px;
  height: calc(100vh - 40px);
}
/* When only one tab's panels are visible, switch the layout from grid to
   flex so the visible panel(s) can fill the height. With the 3-row grid in
   place, `display:none` siblings leave their tracks intact and the
   surviving panel gets auto-placed into the first track (which is 0px tall
   in this layout). Flex avoids the auto-placement trap entirely. */
body.tab-alerts .stack,
body.tab-positions .stack,
body.tab-history .stack {
  display: flex;
  flex-direction: column;
}
body.tab-alerts [data-tab-panel="positions"],
body.tab-alerts [data-tab-panel="history"] { display: none; }
body.tab-positions [data-tab-panel="alerts"],
body.tab-positions [data-tab-panel="history"] { display: none; }
body.tab-history [data-tab-panel="alerts"],
body.tab-history [data-tab-panel="positions"] { display: none; }
/* Alerts tab: ticket stays its natural height, history fills the rest. */
body.tab-alerts .ticket-panel { flex: 0 0 auto; }
body.tab-alerts .alert-panel  { flex: 1 1 auto; min-height: 0; }
/* Positions tab: the positions panel fills the whole screen. */
body.tab-positions .positions-panel { flex: 1 1 auto; min-height: 0; }
/* History tab: the history panel fills the whole screen. */
body.tab-history .history-panel { flex: 1 1 auto; min-height: 0; }

/* ===== History tab ===== */
.history-panel .hist-controls {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  color: var(--muted);
  text-transform: none;
  letter-spacing: 0;
}
.history-panel .hist-controls select,
.history-panel .hist-controls input[type="date"] {
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 3px 6px;
  font-size: 11px;
}
.history-panel .hist-custom-range {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.history-wrapper {
  overflow: auto;
  min-height: 0;
  flex: 1 1 auto;
}
.history-table {
  width: 100%;
  border-collapse: collapse;
  /* TastyTrade-style: system sans-serif at 13px with tabular
     numerics. Matches the Positions table for a consistent look. */
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;
  font-size: 13px;
  line-height: 1.35;
  font-variant-numeric: tabular-nums;
}
.history-table th {
  text-align: right;
  padding: 8px 12px;
  background: var(--panel-2);
  color: var(--muted);
  font-weight: 500;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 1;
}
.history-table th:first-child { text-align: left; }
.history-table td {
  padding: 7px 12px;
  border-bottom: 1px solid var(--border);
  text-align: right;
  font-weight: 400;
}
.history-table td:first-child { text-align: left; }
/* Clickable "parent" rows (period, underlying) get a hover state and a
   subtle disclosure caret. */
.history-table tr.hist-parent { cursor: pointer; }
.history-table tr.hist-parent:hover td { background: rgba(78, 140, 255, 0.06); }
.history-table tr.hist-parent .hist-caret {
  display: inline-block;
  width: 12px;
  text-align: center;
  color: var(--muted);
  transition: transform 0.12s;
}
.history-table tr.hist-parent.expanded .hist-caret {
  transform: rotate(90deg);
  color: var(--accent);
}
/* Nested rows for underlying (level 1) and leg (level 2) drilldowns. */
.history-table tr.hist-child-underlying td:first-child { padding-left: 32px; }
.history-table tr.hist-child-leg td:first-child        { padding-left: 56px; }
.history-table tr.hist-child-underlying td { background: rgba(0, 0, 0, 0.15); }
.history-table tr.hist-child-leg td        { background: rgba(0, 0, 0, 0.28); color: var(--muted); }
/* Cash / Deposits / Withdrawals rows are non-clickable, no expand caret. */
.history-table tr.hist-kind-cash td,
.history-table tr.hist-kind-deposit td,
.history-table tr.hist-kind-withdrawal td {
  cursor: default;
  color: var(--muted);
  font-style: italic;
}
.history-table tr.hist-kind-cash td:first-child,
.history-table tr.hist-kind-deposit td:first-child,
.history-table tr.hist-kind-withdrawal td:first-child {
  padding-left: 32px;
  color: var(--text);
  font-style: normal;
}
/* Deposits/Withdrawals nested under Cash — extra indent so the tree
   relationship is visually obvious. */
.history-table tr.hist-cash-child td:first-child {
  padding-left: 56px;
  color: var(--muted);
  font-style: italic;
}
/* Opening / Closing MV boundary rows in the leg drilldown — lighter
   font + italic to distinguish from raw transactions. */
.history-table tr.hist-child-leg.hist-boundary td {
  color: var(--text);
  font-style: italic;
}
.history-table td.pl-pos { color: var(--green); }
.history-table td.pl-neg { color: var(--red); }
.history-table .hist-loading {
  padding: 12px;
  color: var(--muted);
  font-style: italic;
}
.panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  min-height: 0;          /* allow grid children to shrink */
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.panel h2 {
  margin: 0 0 8px 0;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

/* ===== Ticket ===== */
.ticket-empty {
  color: var(--muted);
  padding: 10px;
  text-align: center;
  font-style: italic;
}
.ticket-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
  flex-wrap: wrap;
}
.tag {
  background: var(--panel-2);
  color: var(--muted);
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.tag-roll { background: #4a2a5c; color: #dfb5f0; }
.leg-progress {
  font-size: 11px;
  font-weight: normal;
  color: var(--muted);
  text-transform: none;
  letter-spacing: 0;
}
.ticket-raw {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 3px 7px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted);
  white-space: pre-wrap;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Spinner shown while OpenAI is thinking */
.spinner {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--yellow);
}
.spinner .spin {
  width: 12px;
  height: 12px;
  border: 2px solid var(--border);
  border-top-color: var(--yellow);
  border-radius: 50%;
  animation: trinity-spin 0.8s linear infinite;
  display: inline-block;
}
@keyframes trinity-spin { to { transform: rotate(360deg); } }

.reminder-indicator {
  font-size: 10px;
  text-transform: none;
  letter-spacing: 0;
  padding: 2px 8px;
  border-radius: 999px;
  background: #2a2411;
  color: var(--yellow);
  font-weight: normal;
}

/* ===== Leg ===== */
/* The outer .ticket-body now carries the form-box styling, so each .leg
   is just a layout wrapper for its row of fields. For rolls (2 legs),
   a thin divider separates them vertically. */
.leg {
  padding: 0;
  margin: 0;
  background: transparent;
  border: 0;
}
.leg + .leg {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--border);
}
.leg-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: flex-end;
}
.leg-action-badge {
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  align-self: flex-end;
  margin-bottom: 4px;
}
.leg-action-badge.open { background: #1d3f28; color: #6be5a0; }
.leg-action-badge.close { background: #3f1d1d; color: #e88e8e; }

.field {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.field label {
  font-size: 10px;
  text-transform: uppercase;
  color: var(--muted);
  letter-spacing: 0.04em;
}
.field input, .field select {
  background: var(--panel);
  border: 2px solid var(--border);
  border-radius: 4px;
  padding: 4px 6px;
  font-family: var(--mono);
  width: 6em;
}
/* Uniform width across all field inputs/selects including Type */
.field select[name="option_type"] { width: 6em; }
/* Field-source coloring */
.field.src-alert input,
.field.src-alert select {
  border-color: var(--green);
}
.field.src-context input,
.field.src-context select,
.field.src-position input,
.field.src-position select,
.field.src-inferred input,
.field.src-inferred select {
  border-color: var(--yellow);
  background: #2a2411;
}
.field.src-missing input,
.field.src-missing select {
  border-color: var(--red);
  background: #2a1111;
}
.field.src-user input,
.field.src-user select {
  border-color: var(--green);
  background: #112a18;
}

.leg-dollar-wrap {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.leg-dollar-wrap label {
  font-size: 10px;
  text-transform: uppercase;
  color: var(--muted);
  letter-spacing: 0.04em;
}
.leg-dollar {
  font-family: var(--mono);
  font-size: 12px;
  padding: 4px 6px;
  border: 2px solid var(--border);
  border-radius: 4px;
  background: var(--panel);
  min-width: 5.5em;
  display: inline-block;
  text-align: right;
}
.ticket-hdr-indicators {
  display: inline-flex;
  gap: 8px;
  align-items: center;
}

/* Button that flips BTO/STC */
.btn { cursor: pointer; border-radius: 5px; padding: 4px 10px; border: 1px solid var(--border); background: var(--panel); color: var(--text); font-size: 12px; }
.btn-sm { padding: 2px 8px; font-size: 11px; }
.btn-primary { background: var(--accent); border-color: var(--accent); color: white; }
.btn-primary:hover { background: var(--accent-hover); }
.btn-ghost { background: transparent; color: var(--muted); }
.btn-ghost:hover { color: var(--text); }
/* Primary action button — sized to sit on the same visual row as the form
   fields. Its label *is* the action (Buy to Open / Sell to Close / Place
   Roll); clicking it submits the order. */
.btn-primary-action {
  cursor: pointer;
  padding: 5px 14px;
  font-size: 13px;
  font-weight: 600;
  border: 2px solid var(--accent);
  border-radius: 4px;
  background: var(--accent);
  color: white;
  font-family: inherit;
  align-self: flex-end;
  margin-bottom: 0;
  white-space: nowrap;
}
.btn-primary-action.open  { background: #1d3f28; border-color: #2fbf71; color: #6be5a0; }
.btn-primary-action.close { background: #3f1d1d; border-color: #e15554; color: #e88e8e; }
.btn-primary-action.roll  { background: #4a2a5c; border-color: #dfb5f0; color: #dfb5f0; }
.btn-primary-action:hover { filter: brightness(1.15); }
.btn-primary-action:disabled { opacity: 0.5; cursor: not-allowed; }

/* Skip button matches field height/spacing */
.btn-skip {
  align-self: flex-end;
  margin-bottom: 0;
}

/* Total block — styled like a read-only field for visual consistency */
.total-wrap {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-family: var(--mono);
}
.total-wrap label {
  font-size: 10px;
  text-transform: uppercase;
  color: var(--muted);
  letter-spacing: 0.04em;
}
.total-wrap strong {
  font-size: 13px;
  padding: 4px 6px;
  border: 2px solid var(--border);
  border-radius: 4px;
  background: var(--panel);
  min-width: 5.5em;
  text-align: right;
}

/* Single form box that wraps the legs AND the Total/Skip/Place footer so
   they share one border and padding. Content flows inline on one row when
   there's space; wraps to multiple rows on narrow screens. */
.ticket-body {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  flex-wrap: wrap;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 10px;
  background: var(--panel-2);
}
.ticket-body .legs-container {
  flex: 1 1 auto;
  min-width: 0;
}
.ticket-body .ticket-footer-compact {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  flex: 0 0 auto;
}
.ticket-body .ticket-footer-compact strong { font-family: var(--mono); font-size: 13px; }

/* Legacy footer (still used for multi-leg wrapping) */
.ticket-footer {
  display: flex;
  align-items: center;
  gap: 14px;
  border-top: 1px solid var(--border);
  padding-top: 8px;
  flex-wrap: wrap;
}
.net-price-wrap {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.net-price-wrap label {
  font-size: 10px;
  color: var(--muted);
  text-transform: uppercase;
}
.net-price-wrap input {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 4px 6px;
  width: 6em;
  font-family: var(--mono);
}
.estimate-wrap {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-family: var(--mono);
}
.estimate-wrap strong { font-size: 14px; }
.actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
}

.order-status {
  margin-top: 6px;
  padding: 6px 8px;
  border-radius: 5px;
  font-family: var(--mono);
  font-size: 11px;
}
.order-status.placing { background: #2a2411; color: var(--yellow); }
.order-status.filled { background: #112a18; color: var(--green); }
.order-status.failed { background: #2a1111; color: var(--red); }

/* ===== Positions ===== */
.positions-panel { min-height: 0; display: flex; flex-direction: column; }
/* Body wrapper owns the scrollbar. Header table sits above it and
   never scrolls (so no sticky positioning needed). Column widths on
   both tables are LOCKED via shared colgroup + table-layout:fixed so
   the two align pixel-for-pixel. scrollbar-gutter: stable reserves
   the scrollbar's width in the body so the header + body columns
   stay aligned even when there's no scroll. */
.positions-body-wrapper {
  overflow-y: auto;
  overflow-x: hidden;
  flex: 1;
  min-height: 0;
  scrollbar-gutter: stable;
}
.positions-table {
  width: 100%;
  border-collapse: collapse;
  /* TastyTrade-style: system sans-serif, tabular numerics for column
     alignment, comfortable font size + row height (was monospace 12px,
     which looked cramped). Numbers are NOT bold — only aggregate
     rows (symbol/TOTALS) carry any additional weight. */
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;
  font-size: 13px;
  line-height: 1.35;
  font-variant-numeric: tabular-nums;
  table-layout: fixed;
}
.positions-header-table {
  margin-bottom: 0;
  border-bottom: none;
}
/* Column widths — applied via <col> classes so both tables share the
   same layout. Sum should slot cleanly into the panel; the Date
   column stretches with the remainder. */
/* Symbol column widened to 300px to hold the full pill row
   (G-pill placeholder + qty + expiry + dte + ITM + strike + type)
   without the last pill overlapping into Net P/L. The header's
   "Symbol / Price" flex layout uses ~168px of that; the extra 132px
   is for leaf-row pills. */
.positions-table col.col-sym  { width: 300px; }
.positions-table col.col-net  { width: 96px; }
.positions-table col.col-roi  { width: 72px; }
.positions-table col.col-num  { width: 96px; }
.positions-table col.col-date { width: 130px; }
/* Explicit overflow clip on the leaf-first cell so nothing can
   visually spill into the Net P/L column even if a pill exceeds the
   column width. */
.positions-table td.leaf-first,
.positions-table td.group-sym-cell {
  overflow: hidden;
}
.positions-table th {
  text-align: right;
  padding: 8px 10px;
  background: var(--panel-2);
  color: var(--muted);
  /* TastyTrade uses lightweight uppercase column labels with a bit
     of letter-spacing. Smaller font makes them recede so the data
     rows carry the visual weight. */
  font-weight: 500;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  cursor: pointer;
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 1;
}
.positions-table td {
  padding: 7px 10px;
  border-bottom: 1px solid var(--border);
  text-align: right;
  font-weight: 400;
}
/* Keep the first column (Symbol + leg pills) left-aligned so the ticker
   label reads naturally. */
.positions-table th:first-child,
.positions-table td:first-child { text-align: left; }
.positions-table tr.group-header td {
  background: #1b2132;
  color: var(--text);
  /* Symbol row is only slightly heavier than data rows — TastyTrade
     doesn't overload the eye with heavy bolds. */
  font-weight: 600;
  padding-top: 9px;
  padding-bottom: 9px;
}
/* Account-wide TOTALS row: same weight as symbol rows, marginally
   darker background so it reads as the roll-up without shouting. */
.positions-table tr.totals-header td {
  background: #232a3d;
  color: var(--text);
  font-weight: 600;
  border-bottom: 2px solid var(--border);
  padding-top: 9px;
  padding-bottom: 9px;
}
/* thead's TOTALS row uses tabular-nums right-aligned like tbody, and
   the first cell stays left-aligned. */
.positions-table thead tr.totals-header td {
  padding: 4px 8px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.positions-table thead tr.totals-header td.group-sym-cell {
  text-align: left;
}
.positions-table tr.totals-header .totals-label {
  color: var(--muted);
  text-transform: uppercase;
  font-size: 11px;
}
/* Right-side controls in the positions panel header (Show Closed Legs
   checkbox + refresh button). */
.pos-header-controls {
  display: inline-flex;
  align-items: center;
  gap: 12px;
}
.show-closed-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--muted);
  text-transform: none;
  letter-spacing: 0;
  cursor: pointer;
  user-select: none;
}
.show-closed-toggle input { cursor: pointer; }
.positions-table .underlying-mark {
  font-weight: 500;
  color: var(--text);     /* white — direction-tinting removed per spec */
}

/* Group header first cell: symbol then underlying price, both anchored
   to the LEFT side of the cell (to the left of where the leg row's
   G-pill appears). Fixed-width slots — symbol 56px, price 80px right-
   justified — so prices share a decimal-point column across rows even
   though symbols are different widths. Layout lives on an inner div;
   `display: flex` directly on a <td> drops the cell from the table
   column flow. */
.positions-table tr.group-header td.group-sym-cell .group-sym-grid {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
}
.positions-table tr.group-header .group-sym {
  display: inline-block;
  min-width: 56px;
  text-align: left;
}
.positions-table tr.group-header .underlying-mark {
  display: inline-block;
  min-width: 80px;
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  color: var(--text);    /* plain white — no day-change tinting */
}
.positions-table tr.leaf td:first-child {
  padding-left: 22px;
  color: var(--muted);
}
.positions-table tr.match {
  outline: 2px solid var(--pink);
  outline-offset: -2px;
  background: #311a28;
}

/* Drag & drop between trade groups within the same underlying symbol.
   Only open-leg rows are draggable; the row being dragged fades, and a
   candidate drop target gets a dashed accent-color outline. */
.positions-table tr.leaf[draggable="true"] { cursor: grab; }
.positions-table tr.leaf[draggable="true"]:active { cursor: grabbing; }
.positions-table tr.leaf.dragging td { opacity: 0.45; }
.positions-table tr.leaf.drop-target td {
  background: rgba(78, 140, 255, 0.18);
  outline: 2px dashed var(--accent);
  outline-offset: -2px;
}

/* Right-click context menu on an open-leg row. */
.pos-context-menu {
  position: fixed;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 0;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.55);
  z-index: 10000;
  min-width: 200px;
  font-size: 12px;
  color: var(--text);
  user-select: none;
}
.pos-context-item {
  padding: 7px 14px;
  cursor: pointer;
}
.pos-context-item:hover {
  background: var(--accent);
  color: #fff;
}
.positions-table td.pl-pos { color: var(--green); }
.positions-table td.pl-neg { color: var(--red); }

/* Symbol jumper — a small floating input triggered by any alpha
   keystroke while the Positions tab has focus (no other input
   active). Filters to visible symbols, live-scrolls to the best
   match, and flashes that symbol row briefly. */
.symbol-jumper {
  position: fixed;
  top: 96px;
  left: 50%;
  transform: translateX(-50%);
  background: #2a3145;
  padding: 8px 14px;
  border: 1px solid #46587a;
  border-radius: 8px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.55);
  z-index: 10000;
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 220px;
  font-family: var(--mono);
  font-size: 13px;
}
.jumper-label { color: var(--muted); font-weight: 700; }
.jumper-input {
  background: transparent;
  border: none;
  color: var(--text);
  font: inherit;
  text-transform: uppercase;
  letter-spacing: 1px;
  width: 100px;
  outline: none;
}
.jumper-match {
  color: var(--green);
  font-weight: 700;
  min-width: 60px;
  text-align: right;
}
.jumper-match.miss { color: var(--red); }

.positions-table tr.group-header.jumper-flash td {
  animation: jumperFlashPulse 1.5s ease-out;
}
@keyframes jumperFlashPulse {
  0%   { background: #4d6b8a; }
  60%  { background: #35485d; }
  100% { background: #1b2132; }
}

/* Aggregate rows (symbol header, trade-group header, TOTALS) set
   their own `color` at higher specificity than the base .pl-pos /
   .pl-neg rules above, which was making every aggregate value read
   as plain white. Re-assert red/green on those rows explicitly so
   the sign always jumps out — for TOTALS, symbol, AND group rows. */
.positions-table tr.totals-header td.pl-pos,
.positions-table tr.group-header td.pl-pos,
.positions-table tr.trade-group-header td.pl-pos { color: var(--green); }
.positions-table tr.totals-header td.pl-neg,
.positions-table tr.group-header td.pl-neg,
.positions-table tr.trade-group-header td.pl-neg { color: var(--red); }
.positions-table td.bid { color: var(--green); }
.positions-table td.ask { color: #ff8a8a; }

/* Leaf-row detail pills. Right-justified as a group so the last pill
   (C/P) lines up with the right-edge of the column. Strike and C/P are
   kept adjacent — the ITM badge sits earlier in the row so it never
   wedges between them.
   The flex layout lives on an inner wrapper — `display: flex` on a <td>
   takes it out of the table's column flow and shifts every following
   column off-grid (same trap as group-sym-cell). */
/* Grid (not flex) so every column is a fixed track and the pills land at
   exactly the same x on every row regardless of content width. The first
   1fr track soaks up the slack on the left, keeping the whole pill row
   anchored to the right edge of the td. */
.positions-table td.leaf-first .leaf-pills {
  display: grid;
  grid-template-columns: 1fr 44px 36px 42px 34px 38px 54px 22px;
  /*                        slack  G    qty   expiry dte    ITM   strike type */
  gap: 6px;
  align-items: center;
  width: 100%;
}
.positions-table td.leaf-first { padding-left: 22px; }
.positions-table .leaf-first span {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 1px 6px;
  font-size: 11px;
}
/* Fixed pill slot widths so every row lines up vertically, with or
   without the optional ITM badge. Each pill is centered inside its slot. */
/* Trade Group pill (G1, G42, …) — first pill in the row, only on the
   first leg of each group. Sized as a fixed slot so subsequent legs of
   the same group can render an empty placeholder and pills still line up. */
.positions-table .group-id-pill {
  min-width: 36px;
  text-align: center;
  font-size: 10px;
  font-weight: 600;
  color: var(--accent);
  background: #142640;
  border: 1px solid #1d3760;
  border-radius: 3px;
  padding: 1px 6px;
  font-variant-numeric: tabular-nums;
}
.positions-table .group-id-pill.placeholder {
  visibility: hidden;
  background: transparent !important;
  border-color: transparent !important;
  color: transparent;
}
/* The "+ / −" toggle that reveals closed legs. Sized as a fixed slot so
   rows with no toggle (placeholder) line up identically with rows that
   have one. The placeholder variant collapses all visible affordances
   (border, background, color) so there is literally nothing to see — only
   the reserved width remains. */
.positions-table .group-expand {
  display: inline-block;
  width: 22px;
  text-align: center;
  font-size: 14px;
  font-weight: 700;
  color: var(--accent);
  background: #142640;
  border: 1px solid #1d3760;
  border-radius: 50%;
  padding: 0;
  cursor: pointer;
  line-height: 20px;
  height: 22px;
  user-select: none;
}
.positions-table .group-expand:hover {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
/* Any open-leg row that owns closed legs is itself a click target — the
   user shouldn't have to land precisely on the 22px circle. */
.positions-table tr.leaf.has-closed { cursor: pointer; }
.positions-table tr.leaf.has-closed:hover td { background: rgba(78, 140, 255, 0.06); }
.positions-table .group-expand.placeholder {
  visibility: hidden;
  background: transparent !important;
  border-color: transparent !important;
  color: transparent;
  cursor: default;
}
/* When the same Group P/L (or Cap Out) number repeats on every leg row
   of a multi-leg group, we render it lightly on the non-first rows so
   the eye knows it's the same value, but the cell still has content
   (avoids the column-collapse off-by-one bug). */
.positions-table .group-pl-echo {
  opacity: 0.45;
  font-style: italic;
}

/* Closed (historical) legs appear in grey and a touch dimmer to set
   them apart from the live open legs while still keeping numbers
   legible. */
.positions-table tr.closed-leg td {
  color: #6c7488;
  background: rgba(255,255,255,0.015);
}
.positions-table tr.closed-leg td.bid,
.positions-table tr.closed-leg td.ask,
.positions-table tr.closed-leg .leaf-qty,
.positions-table tr.closed-leg .leaf-strike,
.positions-table tr.closed-leg .leaf-type.call,
.positions-table tr.closed-leg .leaf-type.put { color: #6c7488; }
/* Hide empty pills (e.g. dte/itm on closed grey rows) — content-less spans
   would otherwise render as little empty rectangles thanks to the leaf-pill
   border. visibility:hidden preserves the grid slot so columns still
   align across rows. */
.positions-table td.leaf-first .leaf-pills > span:empty {
  visibility: hidden;
  background: transparent !important;
  border-color: transparent !important;
}

/* Default white; sign-based color comes from the .pl-pos / .pl-neg class
   the renderer attaches to the qty span. Closed-leg override (further down)
   wins by specificity, keeping trim rows muted. */
.positions-table .leaf-qty    { color: var(--text); font-weight: 600; min-width: 30px; text-align: right; font-variant-numeric: tabular-nums; }
.positions-table .leaf-qty.pl-pos { color: var(--green); }
.positions-table .leaf-qty.pl-neg { color: var(--red); }
.positions-table .leaf-expiry { color: var(--muted); min-width: 38px; text-align: center; }
.positions-table .leaf-dte    { color: var(--muted); font-size: 10px; min-width: 32px; text-align: center; }
.positions-table .leaf-itm    { min-width: 36px; text-align: center; }
.positions-table .leaf-itm.placeholder {
  /* Keep the slot in the flex line so pills don't shift when a row has
     no ITM badge — we just hide it visually. */
  visibility: hidden;
  background: transparent;
  border-color: transparent;
  color: transparent;
}
.positions-table .leaf-strike { min-width: 40px; text-align: center; }
.positions-table .leaf-type   { min-width: 20px; text-align: center; }
/* Yellow when expiry is a "normal" distance away, red when expiring this
   calendar week (today through Friday inclusive). */
.positions-table .leaf-dte.normal {
  color: var(--yellow);
  border-color: #5b4a14;
}
.positions-table .leaf-dte.current-week {
  color: var(--red);
  border-color: #5b1414;
  background: #2a1111;
}
.positions-table .leaf-strike { color: var(--text); }
.positions-table .leaf-type.call { color: #6be5a0; }
.positions-table .leaf-type.put { color: #e88e8e; }
.positions-table .leaf-itm {
  color: var(--yellow);
  border-color: #5b4a14;
  background: #2a2411;
  font-weight: 600;
  font-size: 10px;
}

/* Opened column (rightmost): single-line "MM/DD HH:MM @ $425.00". */
.positions-table td.opened {
  font-size: 10px;
  white-space: nowrap;
  color: var(--muted);
}
.positions-table td.opened .opened-time { color: var(--text); }
.positions-table td.opened .opened-price { color: var(--muted); }

/* ===== Alert panel (bottom) ===== */
.alert-panel { flex-shrink: 0; }
.alert-row {
  display: grid;
  grid-template-columns: 360px 1fr;
  gap: 12px;
  min-height: 0;
}
.alert-form textarea {
  width: 100%;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 6px;
  resize: vertical;
  font-family: var(--mono);
  font-size: 12px;
}
.alert-controls {
  display: flex;
  gap: 5px;
  margin-top: 4px;
  flex-wrap: wrap;
}
.alert-controls input[type="text"] {
  flex: 1;
  min-width: 80px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 4px 6px;
}
.alert-controls select {
  flex: 1;
  min-width: 100px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 4px;
}
.alert-controls button {
  background: var(--accent);
  border: 0;
  border-radius: 5px;
  padding: 4px 10px;
  color: white;
  cursor: pointer;
}
.alert-controls button[id="run-test-btn"] {
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
}
.alert-controls button:hover { background: var(--accent-hover); }
.alert-controls button[id="run-test-btn"]:hover { background: var(--border); }

.history-wrap {
  overflow-y: auto;
  max-height: 180px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--panel-2);
}
.alert-history {
  list-style: none;
  padding: 0;
  margin: 0;
  font-family: var(--mono);
  font-size: 11px;
}
.alert-history li {
  padding: 4px 8px;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  color: var(--muted);
  display: flex;
  gap: 8px;
  align-items: baseline;
}
.alert-history li:hover { background: var(--panel); color: var(--text); }
.alert-history li.active {
  background: #163055;
  color: var(--text);
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.alert-history li.no-action {
  background: #2a1111;
  color: #ff9a9a;
  border-left: 3px solid var(--red);
}
.alert-history li.no-action:hover { background: #341818; }
.alert-history li.skipped { opacity: 0.55; }
.alert-history li.placed {
  background: #102418;
  color: #9ee5b7;
  border-left: 3px solid var(--green);
}
.alert-history li.placed:hover { background: #15301f; }
.alert-history .hist-tag {
  font-size: 10px;
  color: var(--red);
  flex-shrink: 0;
  text-transform: uppercase;
}
.alert-history li.skipped .hist-tag { color: var(--muted); }
.alert-history li.placed .hist-tag { color: var(--green); }
.alert-history .hist-fill {
  font-size: 10px;
  color: var(--green);
  flex-shrink: 0;
  min-width: 70px;
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.alert-history li:not(.placed) .hist-fill { color: var(--muted); }
.alert-history .hist-time {
  color: var(--muted);
  font-size: 10px;
  flex-shrink: 0;
  min-width: 130px;
  font-variant-numeric: tabular-nums;
}
.alert-history .hist-author {
  color: var(--accent);
  flex-shrink: 0;
}
.alert-history .hist-text {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.muted { color: var(--muted); }

/* =========================================================================
   Multi-account sub-tabs (Positions + History panels)
   ---
   Rendered above the table via #positions-acct-tabs / #history-acct-tabs.
   Buttons carry data-account="<name>" and toggle the .active class when
   selected. Kept small so they don't fight the section H2 for attention.
   ========================================================================= */
.acct-tabs {
  display: flex;
  gap: 4px;
  padding: 0 6px 8px;
  border-bottom: 1px solid #26343f;
  margin-bottom: 6px;
  flex-wrap: wrap;
}
.acct-tab {
  background: transparent;
  color: var(--muted);
  border: 1px solid transparent;
  padding: 3px 12px;
  border-radius: 6px 6px 0 0;
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  text-transform: capitalize;
  transition: background 60ms, color 60ms;
}
.acct-tab:hover { background: #1b2836; color: #d4e2ee; }
.acct-tab.active {
  background: #263749;
  color: #ffffff;
  border-color: #34506a #34506a transparent;
}
.acct-tab.disconnected {
  opacity: 0.55;
}
.acct-tab.disconnected::after {
  content: " •";
  color: #d97070;
}

/* Ticket account-target checkboxes — one per account, sits between
   the leg fields and the Place/Skip buttons. Selection persists via
   POST /ticket_targets. */
.ticket-targets {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 8px;
  border-top: 1px dashed #26343f;
  border-bottom: 1px dashed #26343f;
  margin: 6px 0;
  flex-wrap: wrap;
}
.ticket-targets-label {
  color: var(--muted);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.ticket-targets-list {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
}
.ticket-targets-list label {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: #d4e2ee;
  cursor: pointer;
  font-size: 13px;
  text-transform: capitalize;
}
.ticket-targets-list input[type="checkbox"] {
  cursor: pointer;
}

/* Archived trade groups — visible but visually deprioritized so the
   eye lands on active trades first. Excluded from aggregate Eff Cst
   in JS; this is only the visual cue. */
.leaf.archived-group td,
.trade-group-header.archived-group td {
  opacity: 0.55;
  font-style: italic;
}
.leaf.archived-group .group-id-pill,
.trade-group-header.archived-group .group-id-pill {
  background: #3a3a3a;
  color: #a0a0a0;
  text-decoration: line-through;
}

/* Trade-group header row — the row that carries the G-pill and per-
   group aggregate columns (PLO / PLC / Trd Prc / Cst / Eff Cst / NetLiq).
   Sits between the symbol row and the leg rows for that group. Lightly
   tinted so it's visually distinct from both without looking heavy. */
.trade-group-header td {
  background: rgba(56, 82, 108, 0.18);
  border-top: 1px solid #263749;
  padding-top: 3px;
  padding-bottom: 3px;
  font-weight: 500;
}
.trade-group-header {
  cursor: pointer;
}
.trade-group-header:hover td {
  background: rgba(56, 82, 108, 0.28);
}
.trade-group-header .group-header-pills {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
/* (Removed: `.group-open-cost` chip next to G-pill. Retired when Max
   Inv became the sole ROI denominator — the chip's value was a
   different concept and would have been confusing next to a %
   computed from a different number.) */
/* Reconciliation warning triangle next to the symbol ticker. Yellow
   so it reads as "caution — data mismatch worth looking at" rather
   than "error". Hover shows the tooltip with the failing OCCs and
   the reason. */
.reconcile-warn {
  color: #f5c542;
  font-size: 13px;
  /* margin-left: auto in the flex row pushes the triangle to the
     right end of the cell. Symbol + Price sit at their normal
     x-positions (aligned with the thead labels); the triangle
     lives in the leftover space at the far right, so its presence
     never shifts either column. */
  margin-left: auto;
  cursor: help;
  user-select: none;
}
.reconcile-warn:hover {
  color: #ffd76a;
}
/* Reconciliation-row description — muted, small, italic. Wraps
   inline after the "Reconciliation" label so the whole one-liner
   is visible without hovering. */
.recon-desc {
  color: var(--muted);
  font-size: 11px;
  font-style: italic;
  margin-left: 8px;
}
.group-caret {
  color: #7a94ad;
  font-size: 10px;
  transition: transform 100ms ease;
  display: inline-block;
  width: 10px;
  text-align: center;
}
.trade-group-header.collapsed .group-caret {
  transform: rotate(-90deg);
}

/* Symbol row is click-to-collapse too — cursor + hover tint indicate
   interactivity without extra decoration on the label itself. */
.positions-table tr.group-header {
  cursor: pointer;
}
.positions-table tr.group-header:hover td {
  filter: brightness(1.08);
}
/* thead Symbol / Price header — mirror the flex layout of the
   group-sym-grid cell below so "Price" sits directly above the
   underlying-mark number (both anchored via the same min-widths). */
.positions-table thead th[data-sort="symbol"] {
  padding-left: 8px;
  padding-right: 8px;
}
.positions-table thead th[data-sort="symbol"] .th-sym {
  display: inline-block;
  min-width: 56px;
  text-align: left;
}
.positions-table thead th[data-sort="symbol"] .th-price {
  display: inline-block;
  min-width: 80px;
  text-align: right;
  margin-left: 8px;              /* same gap as .group-sym-grid */
  color: var(--muted);
  font-weight: 600;
}

/* (Column widths are now driven by the shared <colgroup> in
   index.html + table-layout:fixed above; per-th min-widths are no
   longer needed.) */
/* Non-sortable columns (Trd Prc) get default cursor to distinguish. */
.positions-table th.no-sort {
  cursor: default;
}
/* Sort-vs-collapse split: pointer cursor lives on the LABEL only,
   not the whole cell. Hovering the padding shows the default arrow
   so the user can see that empty header space isn't a sort target
   (it toggles collapse instead). */
.positions-table th.sortable .th-label { cursor: pointer; }
.positions-table th.sortable .th-label:hover { color: var(--text); }
/* Any header hover — including empty area — shows pointer to hint
   at the collapse-all action. */
.positions-table thead th { cursor: pointer; }
/* Sort indicator — small caret next to the active sort column's
   header label. Set via .sort-asc / .sort-desc from JS after each
   render + sort click. */
.positions-table thead th.sort-asc::after,
.positions-table thead th.sort-desc::after {
  content: "";
  display: inline-block;
  width: 0;
  height: 0;
  margin-left: 6px;
  vertical-align: 2px;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
}
.positions-table thead th.sort-asc::after {
  border-bottom: 5px solid var(--text);
}
.positions-table thead th.sort-desc::after {
  border-top: 5px solid var(--text);
}
.positions-table thead th.sort-asc,
.positions-table thead th.sort-desc { color: var(--text); }

/* Net P/L (col 2) and PLC (col 5, since ROI got inserted at col 3) —
   never bold, on ANY row. The surrounding aggregate rows (symbol /
   TOTALS) carry font-weight: 600 by default; these two columns opt
   back to regular so the numbers read at the same weight as leaf
   rows. */
.positions-table td:nth-child(2),
.positions-table td:nth-child(5) {
  font-weight: 400;
}
.archived-tag {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 3px;
  background: #3a3a3a;
  color: #a0a0a0;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
}

