/* charts.css — Per-instance EA debug surface
   Reuses --bg-*, --text-*, --accent, --profit, --loss tokens from theme.css.
   Local chart-surface tokens flip in light mode so hairline backgrounds
   stay visible on white (0.02 white on white is invisible).
*/

/* Pause all infinite pulse animations when the tab is hidden — JS pollers
   already gate on visibilityState, but the CSS compositor keeps repainting
   dots/edges on a background tab. body.tab-hidden is toggled by rail.js. */
body.tab-hidden .charts-stream-dot.live,
body.tab-hidden .charts-stream-dot.live.stale,
body.tab-hidden .grp-live .dot,
body.tab-hidden .dot.hot,
body.tab-hidden .charts-overlay-svg .live-edge,
body.tab-hidden .charts-news-lock,
body.tab-hidden .charts-bg .particle {
  animation-play-state: paused !important;
}


.charts-shell {
  position: fixed;
  inset: 64px 0 0 0; /* below nav */
  display: grid;
  /* Widths are CSS variables so the resize handles can mutate them at runtime;
     rail.js persists user-chosen widths to localStorage. */
  --rail-left-w: 240px;
  --rail-right-w: 340px;
  grid-template-columns: var(--rail-left-w) 1fr var(--rail-right-w);
  /* Third track sizes to the drawer's intrinsic height — 28px collapsed
     (handle only) and 280px when `.charts-drawer.expanded` is toggled. */
  grid-template-rows: 56px 1fr auto;
  grid-template-areas:
    "topbar topbar topbar"
    "left   main   right"
    "left   drawer right";
  /* Outer padding mirrors dashboard .main-content (theme.css:5244-5249):
     clamp(16,3vw,32) + max-width 1600 centered. Charts now sits in the
     exact same gutter language as every other authenticated page so the
     nav→hero/topbar vertical gap matches. Background stays transparent so
     body::before radial backdrop reads through gutters. */
  gap: clamp(10px, 1.6vw, 16px);
  padding: clamp(16px, 3vw, 32px);
  max-width: 1600px;
  margin: 0 auto;
  background: transparent;
  color: var(--text-main);
  font: 13px/1.4 var(--font-sans);
  overflow: hidden;
  /* iOS notch + home indicator: viewport-fit=cover on base.html extends the
     page behind both. We HONOUR the env() inset on top of the design padding
     using max() so desktop keeps its clamp(16,3vw,32) gutter (matching
     dashboard's .main-content) AND iPhone X+ pads under the dynamic island
     and home indicator. Previously these individual padding-* declarations
     came AFTER the padding shorthand and clobbered the desktop gutter
     entirely (env resolves to 0 on desktop), so charts hugged the nav. */
  padding-top:    max(clamp(16px, 3vw, 32px), env(safe-area-inset-top, 0px));
  padding-bottom: max(clamp(16px, 3vw, 32px), env(safe-area-inset-bottom, 0px));
  padding-left:   max(clamp(16px, 3vw, 32px), env(safe-area-inset-left, 0px));
  padding-right:  max(clamp(16px, 3vw, 32px), env(safe-area-inset-right, 0px));
  box-sizing: border-box;
}

/* Topbar — floats as a glass card matching dashboard hero panel style:
   --glass-bg + --glass-border + --radius-lg + --glass-shadow. Same surface
   family as .dashboard-hero / .kpi-card.glass / .glass-card in theme.css. */
.charts-topbar {
  grid-area: topbar;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 18px;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--glass-shadow);
  gap: 12px;
  position: relative;
  overflow: hidden;
}
/* 3px accent gradient at the top edge — exact same accent→purple→teal
   sweep as .dashboard-hero::before (theme.css:23560). Sits inside the
   rounded top corners via matching border-radius. This is the signature
   "Project Green hero card" identity element. */
.charts-topbar::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--accent), var(--purple), var(--teal, #5ac8fa));
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  z-index: 2;
  /* Decorative only — must never intercept taps on the List/State toggles
     beneath it (real WebKit can route touches to a z-raised pseudo even when
     Chromium hit-tests cleanly). */
  pointer-events: none;
}
:root.light .charts-topbar {
  /* Light-mode glass-bg already resolves to near-white; tune the shadow
     so the card still floats visibly against the bright backdrop. */
  box-shadow: 0 4px 16px rgba(15, 15, 30, 0.06), 0 1px 3px rgba(15, 15, 30, 0.04);
}
.charts-topbar-left, .charts-topbar-right {
  display: flex; align-items: center; gap: 10px;
  flex-wrap: nowrap;
  min-width: 0;
}
.charts-topbar { flex-wrap: nowrap; }
.charts-topbar-left { flex: 1 1 auto; min-width: 0; }
.charts-topbar-right { flex: 0 0 auto; }
.charts-label {
  font-size: 11px; color: var(--text-sub); text-transform: uppercase; letter-spacing: 0.04em;
}
.charts-select, .charts-input {
  background: var(--bg-input);
  color: var(--text-main);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 5px 8px;
  font: inherit;
}
.charts-select { min-width: 220px; }
.charts-input { width: 100%; }
.charts-instance-title {
  font-weight: 500;
  color: var(--text-main);
  margin-left: 8px;
  /* Truncate instead of wrapping — without this, a long title at narrow
     widths (~900-1100px) pushes the right cluster (stream dot, meta, help,
     state toggle) past the viewport edge in the no-wrap topbar. */
  min-width: 0;
  flex: 0 1 auto;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.charts-meta {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-sub);
  /* Prevent the bars/last-close/marker string from wrapping into a second
     line at ~900-1100px — the 44px topbar can't grow and a 2-line meta
     visually collides with the right-cluster buttons. Truncate instead. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 260px;
  min-width: 0;
}
.charts-btn-help {
  width: 28px;
  padding: 0;
  font-weight: 700;
  font-size: 13px;
  opacity: 0.7;
}
.charts-btn-help:hover { opacity: 1; }
.charts-legend {
  position: fixed;
  top: 50px;
  right: 12px;
  z-index: 1200;
  width: 340px;
  max-width: calc(100vw - 24px);
  max-height: calc(100vh - 80px);
  overflow-y: auto;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: 14px 16px;
  font-size: 12px;
  box-shadow: var(--elev-card);
  color: var(--text-main, #e8e8ed);
  animation: legend-in 140ms ease-out;
}
@keyframes legend-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
.charts-legend h4 {
  margin: 0 0 10px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.3px;
}
.charts-legend-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 6px 0;
  line-height: 1.4;
  border-top: 1px solid var(--border-subtle, rgba(255,255,255,0.05));
}
.charts-legend-row:first-of-type { border-top: 0; }
.charts-legend-row b { font-weight: 600; color: var(--text-main, #f5f5f7); }
.charts-legend-row i { font-style: normal; color: var(--text-sub); }
.charts-legend .lg-swatch {
  width: 14px; height: 14px; flex: 0 0 14px;
  border-radius: 50%; margin-top: 2px;
}
.charts-legend .lg-place  { background: var(--yellow, #ffcc00); }
.charts-legend .lg-fill   { background: var(--profit, #52ca74); }
.charts-legend .lg-close  { background: var(--text-subtle, var(--text-dim)); }
.charts-legend .lg-veto   { background: var(--loss, #ed645f); }
.charts-legend .lg-modify { background: var(--accent, #0a84ff); }
.charts-legend .lg-ladder {
  width: 18px; height: 14px; flex: 0 0 18px;
  border-radius: 0; margin-top: 2px;
  background:
    repeating-linear-gradient(90deg, var(--profit, #52ca74) 0 3px, transparent 3px 6px) 0 3px / 18px 1px no-repeat,
    repeating-linear-gradient(90deg, var(--loss, #ed645f) 0 3px, transparent 3px 6px) 0 10px / 18px 1px no-repeat;
}
.charts-legend .lg-rangebox {
  width: 18px; height: 12px; flex: 0 0 18px;
  border-radius: 2px; margin-top: 3px;
  background: var(--ds-accent-tint);
  border: 1px dashed var(--ds-accent-border);
}
.charts-legend .lg-basket {
  width: 18px; height: 14px; flex: 0 0 18px;
  border-radius: 0; margin-top: 2px;
  background:
    repeating-linear-gradient(90deg, color-mix(in srgb, var(--accent) 90%, transparent) 0 4px, transparent 4px 8px) 0 5px / 18px 2px no-repeat,
    repeating-linear-gradient(90deg, color-mix(in srgb, var(--orange, #ff9500) 90%, transparent) 0 4px, transparent 4px 8px) 0 9px / 18px 2px no-repeat;
}
.charts-legend .lg-bidask {
  width: 14px; height: 4px; flex: 0 0 14px;
  border-radius: 2px; margin-top: 8px;
}
.charts-legend .lg-bid    { background: color-mix(in srgb, var(--loss) 70%, transparent); }
.charts-legend .lg-sess   { background: linear-gradient(90deg, var(--accent, #0a84ff), var(--purple, #bf5af2), var(--yellow, #ffcc00)); }
.charts-legend .lg-news {
  width: 22px; height: 14px; flex: 0 0 22px;
  background: color-mix(in srgb, var(--orange) 25%, transparent);
  border: 1px solid color-mix(in srgb, var(--orange) 55%, transparent);
  border-radius: 3px; margin-top: 2px;
  font-size: 8px; color: var(--orange); text-align: center; line-height: 12px;
}
.charts-legend .lg-news::before { content: 'T1'; }
.charts-legend-close {
  position: absolute;
  top: 8px; right: 10px;
  background: transparent; border: 0;
  color: var(--text-dim);
  font-size: 14px; cursor: pointer;
}
.charts-legend-close:hover { color: var(--text-main); }
.charts-legend-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Light-mode legend already inherits var(--text-main) (rgb 85,85,95) — no
   need to override to near-black; that looked harsh vs. the rest of the app. */
.charts-btn {
  background: transparent;
  color: var(--text-main);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  height: 28px;
  padding: 0 10px;
  min-width: 28px;
  white-space: nowrap;
  cursor: pointer;
  font-size: 12px;
}
.charts-btn:hover { background: var(--bg-hover); }
.charts-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.charts-btn-back {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  text-decoration: none;
  font-weight: 500;
}
.charts-btn-back:hover { color: var(--text-main); text-decoration: none; }
.charts-select-hidden { display: none !important; }

/* Brand link — mirrors dashboard .nav-brand identity so users recognise
   the charts page as part of the same app. Doubles as back-to-dashboard. */
.charts-brand {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  color: var(--text-main);
  padding: 0 6px;
  margin-right: 2px;
  height: 28px;
  border-radius: var(--radius);
  -webkit-tap-highlight-color: transparent;
}
.charts-brand:hover { background: var(--bg-hover); text-decoration: none; color: var(--text-main); }
.charts-brand:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.charts-nav-logo {
  width: 24px;
  height: 24px;
  background: linear-gradient(135deg, var(--accent), var(--purple));
  border-radius: 22%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 900;
  font-style: italic;
  font-family: var(--font-sans);
  -webkit-text-stroke: 0.4px white;
  color: white;
  letter-spacing: -0.4px;
  box-shadow: 0 2px 6px rgba(10, 132, 255, 0.25);
  flex-shrink: 0;
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.charts-brand:hover .charts-nav-logo { transform: scale(1.08) rotate(3deg); }

.charts-brand-label {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.2px;
  color: var(--text-main);
  white-space: nowrap;
}

/* Cross-page nav links inside the charts topbar — mirrors dashboard
   `.nav-link` behaviour (hover underline, accent active state) so users
   can move between Dashboard / Trades / Stats / Charts without an extra
   round-trip back to /dashboard. Compact 28px height to fit the 44px bar. */
.charts-nav-links {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  margin-left: 4px;
  padding: 0 4px;
  border-left: 1px solid var(--glass-border);
  height: 28px;
}
.charts-nav-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  height: 28px;
  padding: 0 10px;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-sub);
  text-decoration: none;
  white-space: nowrap;
  border-radius: var(--radius);
  transition: color var(--transition-fast), background-color var(--transition-fast);
}
.charts-nav-link:hover { color: var(--text-main); background: var(--bg-hover); text-decoration: none; }
.charts-nav-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.charts-nav-link::after {
  content: '';
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: 2px;
  height: 2px;
  background: currentColor;
  border-radius: 1px;
  opacity: 0;
  transition: opacity var(--transition);
  pointer-events: none;
}
.charts-nav-link:hover::after { opacity: 0.4; }
.charts-nav-link.active { color: var(--accent); font-weight: 600; }
.charts-nav-link.active::after { opacity: 1; }

/* Subtle accent hairline below the topbar — same gradient family as the
   PA logo (accent → purple) so the brand colour bleeds across the page
   horizon, echoing the dashboard's nav-container scrolled-shadow vibe. */
.charts-topbar {
  position: relative;
}
/* Hairline removed in wave 7: the topbar is now a rounded glass card so a
   bottom-edge gradient line clashed with the corner rounding. Identity now
   comes from the shared rounded surface family + accent bar in section
   headers, not a horizontal accent rule. */
:root.light .charts-topbar::after { opacity: 0.4; }

/* Live stream status dot */
.charts-stream-dot {
  display: inline-block;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--text-dim);
  box-shadow: 0 0 0 0 currentColor;
}
.charts-stream-dot.live {
  background: var(--profit);
  box-shadow: 0 0 6px color-mix(in srgb, var(--profit) 50%, transparent);
  animation: pulse 2s ease-in-out infinite;
}
.charts-stream-dot.live.stale {
  background: var(--yellow);
  box-shadow: 0 0 6px color-mix(in srgb, var(--yellow) 50%, transparent);
  animation: none;
}
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}

/* Long instance title — ellipsis instead of overflowing the bar */
.charts-instance-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 360px;
}

/* Left rail */
.charts-rail-left {
  grid-area: left;
  /* Glass-card matching topbar + dashboard hero panels. */
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--glass-shadow);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  container-type: inline-size;
  container-name: rail-left;
}
/* Drop the sparkline + secondary realized-chip when the rail is dragged
   narrow — keeps sym / tf / P-L legible instead of crushing the name column. */
@container rail-left (max-width: 230px) {
  .charts-instance-list .inst-spark { display: none; }
}
@container rail-left (max-width: 200px) {
  .charts-instance-list .pnl-today { display: none; }
}
@container rail-left (max-width: 175px) {
  .charts-instance-list .name .meta { display: none; }
}
.charts-rail-header { padding: 8px 10px; border-bottom: 1px solid var(--border-subtle); }
.charts-instance-list {
  list-style: none; margin: 0; padding: 4px 0 12px;
  overflow-y: auto;
  flex: 1;
}
.charts-instance-list li {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 7px 12px 7px 14px;
  cursor: pointer;
  /* Reserve the same 3px gutter as dashboard .section-title accent bar, so
     hover/active transitions don't shift the row contents horizontally. */
  border-left: 3px solid transparent;
  min-width: 0;
  transition: background 120ms ease, border-left-color 120ms ease;
}
.charts-instance-list li > .dot { flex: 0 0 8px; margin-top: 5px; }
.charts-instance-list li > .name { flex: 1 1 auto; min-width: 0; }
.charts-instance-list li > .rail-right {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  margin-left: auto;
}
.charts-instance-list li:hover { background: var(--surface-2); }
.charts-instance-list li.active {
  background: var(--surface-3);
  /* Single selection cue: the gradient accent→purple left bar (same identity
     as dashboard .section-title::before / hero markers) plus the raised
     surface-3 fill. The previous full inset 1px ring stacked a SECOND border
     on top of this bar — reading as a doubled "selector" — so it was removed
     in favour of one clear indicator. border-left-color can't gradient, so
     border-image paints the 3px bar. */
  border-left-color: var(--accent, #0a84ff);
  border-image: linear-gradient(180deg, var(--accent) 0%, var(--purple) 100%) 1 / 0 0 0 3px;
}
.charts-instance-list .dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--text-dim);
  position: relative;
}
.charts-instance-list .dot.armed   { background: var(--profit, #52ca74); }
/* Default "live" dot — overridden by .profit / .loss / .online below. Kept
   as a safe fallback so an instance that's live but lacks floating data
   still reads as alive rather than dead-grey. */
.charts-instance-list .dot.live    { background: var(--accent, #0a84ff); box-shadow: 0 0 0 2px var(--ds-accent-tint-strong, rgba(10,132,255,0.18)); }
.charts-instance-list .dot.live.profit { background: var(--profit, #52ca74); box-shadow: 0 0 0 2px var(--ds-profit-tint-strong, rgba(52,202,116,0.22)); }
.charts-instance-list .dot.live.loss   { background: var(--loss,   #ed645f); box-shadow: 0 0 0 2px var(--ds-loss-tint-strong,   rgba(237,100,95,0.22)); }
.charts-instance-list .dot.live.online { background: var(--accent, #0a84ff); box-shadow: 0 0 0 2px var(--ds-accent-tint-strong, rgba(10,132,255,0.18)); }
.charts-instance-list .dot.cooldown{ background: var(--yellow, #ffcc00); }
.charts-instance-list .dot.idle    { background: var(--text-dim); opacity: 0.5; }
.charts-instance-list .dot.stale   { background: var(--orange, #ff9500); }
.charts-instance-list .name {
  font-size: 12.5px;
  display: flex; flex-direction: column;
  gap: 1px;
  min-width: 0;
  overflow: hidden;
}
.charts-instance-list .name .top {
  display: flex; gap: 6px; align-items: baseline;
  white-space: nowrap;
  line-height: 1.25;
  min-width: 0;
  overflow: hidden;
}
.charts-instance-list .name .top .sym {
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.charts-instance-list .name .top .tf,
.charts-instance-list .name .top .tier-badge {
  flex: 0 0 auto;
}
.charts-instance-list .name .meta {
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  min-width: 0;
  font-size: 10.5px;
  color: var(--text-sub);
  line-height: 1.25;
}
.charts-instance-list .name .meta .inst-spark {
  flex: 0 0 44px;
  width: 44px; height: 12px;
  opacity: 0.92;
}
.charts-instance-list .name .meta .meta-text {
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  flex: 1 1 auto;
}
.charts-instance-list .name .ea  { color: var(--accent); font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; }
.charts-instance-list .name .sym { color: var(--text-main); font-weight: 600; letter-spacing: 0.01em; }
.charts-instance-list .name .tf  {
  color: var(--text-sub);
  font-family: var(--font-mono);
  font-size: 10px;
  background: var(--surface-2);
  padding: 1px 5px;
  border-radius: 3px;
  letter-spacing: 0.02em;
}
.charts-instance-list .pnl {
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--text-sub);
  text-align: right;
}
.charts-instance-list .pnl.up   { color: var(--profit); }
.charts-instance-list .pnl.down { color: var(--loss); }
.charts-instance-list .pnl-today {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 10px;
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  margin-left: 0;
  padding: 1px 5px;
  border-radius: 3px;
  background: var(--surface-3, rgba(255,255,255,0.04));
  color: var(--text-sub);
  opacity: 0.85;
}
.charts-instance-list .rail-right .pnl { text-align: right; }
.charts-instance-list .pnl-today.up   { color: var(--profit); }
.charts-instance-list .pnl-today.down { color: var(--loss); }
.charts-instance-empty {
  padding: 20px 14px !important;
  color: var(--text-sub);
  font-style: italic;
  cursor: default !important;
  border-left: 0 !important;
}
.charts-instance-more {
  padding: 6px 14px !important;
  margin: 2px 0 6px !important;
  color: var(--text-sub);
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  cursor: pointer;
  border-left: 2px solid transparent !important;
  background: var(--surface-1);
}
.charts-instance-more:hover {
  color: var(--text-main);
  background: var(--surface-3);
}
.charts-instance-more:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  color: var(--text-main);
}

/* Main pane */
.charts-main {
  grid-area: main;
  position: relative;
  /* Glass-card frame around the chart canvas — same surface family as the
     rails and topbar. The chart library draws its own pixels inside; this
     wrapper provides the rounded corners + elevation that make the chart
     read as a dashboard hero card instead of a flat tool panel. */
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--glass-shadow);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.charts-chart {
  flex: 1 1 auto; min-height: 0; position: relative;
  /* LWC chart background is transparent so a back-SVG layer (news ticks)
     paints THROUGH the canvas. This rule provides the visible bg in its
     place. --bg-main is the canonical theme token (white in light mode,
     near-black in dark) so the chart canvas tracks the shell theme. */
  background: var(--bg-main);
  /* Rounded corners + hairline border so the canvas reads as a distinct
     surface inside the shell — matches the landing preview .cp-frame .charts-chart. */
  border-radius: var(--radius-card);
  border: 1px solid var(--border-subtle);
  overflow: hidden;
}
:root.light .charts-chart {
  /* Off-white panel that gives the canvas enough contrast against the bright
     glass shell to read as a distinct surface — was #f7f7fa (~2% contrast,
     candles + grid washed out); #eef0f5 gives ~5% contrast so the chart
     interior reads clearly without going heavy. */
  background: #eef0f5;
}
.charts-chart-empty {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  justify-content: center; align-items: center;
  color: var(--text-sub);
  pointer-events: none;
}
.charts-chart-empty p { margin: 4px 0; }
.charts-chart-empty .charts-hint { color: var(--text-dim); font-size: 12px; max-width: 320px; text-align: center; }
.charts-chart-empty .empty-illustration { margin-bottom: 12px; opacity: 0.7; }
.charts-chart-empty .empty-frame { stroke: var(--border, rgb(124,124,128)); }
.charts-chart-empty .empty-spark { stroke: var(--profit, #52ca74); stroke-opacity: 0.55; }
.charts-chart-empty .empty-spark-dot { fill: var(--profit, #52ca74); }

/* Chart skeleton — shown while candles are being fetched. CSS-only horizontal
   shimmer; hidden by JS as soon as setData() runs. `.charts-chart` ID-target
   keeps specificity above the generic `.charts-chart` background so the
   skeleton renders on top during fetch. */
.charts-chart .charts-chart-skeleton {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  justify-content: center; align-items: stretch;
  gap: 18px;
  padding: 32px clamp(32px, 8%, 96px);
  background: var(--bg-card);
  border-radius: var(--radius-card);
  pointer-events: none;
  opacity: 1;
  transition: opacity 200ms ease-out;
  z-index: 2;
}
.charts-chart .charts-chart-skeleton[hidden] { display: none; }
.charts-chart .charts-chart-skeleton.is-fading { opacity: 0; }
.charts-chart .charts-chart-skeleton .ccs-bar {
  height: 10px;
  border-radius: 5px;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--text-dim) 14%, transparent) 0%,
    color-mix(in srgb, var(--text-dim) 22%, transparent) 50%,
    color-mix(in srgb, var(--text-dim) 14%, transparent) 100%);
  border: 1px solid var(--border-subtle);
  animation: chartsSkeletonPulse 1400ms ease-in-out infinite;
}
.charts-chart .charts-chart-skeleton .ccs-bar-1 { width: 72%; animation-delay: 0ms;   }
.charts-chart .charts-chart-skeleton .ccs-bar-2 { width: 88%; animation-delay: 160ms; }
.charts-chart .charts-chart-skeleton .ccs-bar-3 { width: 54%; animation-delay: 320ms; }
.charts-chart .charts-chart-skeleton .ccs-bar-4 { width: 78%; animation-delay: 480ms; }
@keyframes chartsSkeletonPulse {
  0%, 100% { opacity: 0.55; }
  50%      { opacity: 0.9;  }
}
@media (prefers-reduced-motion: reduce) {
  .charts-chart .charts-chart-skeleton .ccs-bar { animation: none; opacity: 0.7; }
  .charts-chart .charts-chart-skeleton { transition: none; }
}

/* Right rail */
.charts-rail-right {
  grid-area: right;
  /* Glass-card matching topbar + left rail. */
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--glass-shadow);
  overflow-y: auto;
  padding: 10px 10px 14px;
  container-type: inline-size;
  container-name: rail-right;
}
/* Tier histogram and basket-total full-text labels need to shed weight when
   the right rail is dragged below ~270px to keep the cluster header readable. */
@container rail-right (max-width: 270px) {
  .cluster-hdr .cluster-hist { display: none; }
}
.charts-section {
  /* The parent .charts-rail-right is itself a glass card now (wave 7) —
     stacking another translucent glass surface on top read as muddy /
     double-bordered. Sections inside the rail switch to a subtle inset
     surface (chart-surface-1 over the rail's translucent panel) plus a
     1px subtle border, which still reads as a separate sub-card. */
  background: var(--surface-1);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius);
  margin-bottom: 10px;
  overflow: hidden;
  box-shadow: 0 1px 0 rgba(0,0,0,0.04), 0 1px 2px rgba(0,0,0,0.06);
}
:root.light .charts-section {
  /* Light-mode glass-bg already resolves to ~white, just tune the shadow
     so the card still floats against the panel rail. */
  box-shadow: 0 1px 0 rgba(15, 15, 30, 0.03), 0 1px 3px rgba(15, 15, 30, 0.05);
}
.charts-section h3 {
  margin: 0;
  /* padding-left = bar left (8px) + bar width (4px) + 14px breathing room.
     Without this, the title text "OPEN POSITIONS" reads as glued to the
     gradient accent bar — same family as the dashboard's .section-title
     which gets 14px of flex-gap from its bar. */
  padding: 9px 12px 8px 26px;
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-sub);
  background: var(--surface-2);
  border-bottom: 1px solid var(--glass-border);
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
}
/* Signature accent→purple gradient bar — mirrors dashboard .section-title::before
   so rail sections read as the same family as the dashboard's KPI/section
   headers. Same gradient (180deg accent→purple), 4px wide / 14px tall so
   the bar still reads on the rail's smaller 10.5px header font. */
.charts-section h3::before {
  content: '';
  position: absolute;
  left: 8px;
  top: 50%;
  transform: translateY(-50%);
  width: 4px;
  height: 14px;
  background: linear-gradient(180deg, var(--accent) 0%, var(--purple) 100%);
  border-radius: 2px;
  opacity: 0.9;
  box-shadow: 0 0 8px rgba(10, 132, 255, 0.25);
}
/* Header gets a touch more contrast on white cards — surface-1 at 0.025
   black was nearly invisible inside the elevated section. */
:root.light .charts-section h3 {
  background: rgba(15, 15, 30, 0.035);
  border-bottom-color: rgba(15, 15, 30, 0.08);
}
.charts-section-body { padding: 10px 12px; }
.charts-section-body p { margin: 4px 0; }
.charts-section-body table {
  width: 100%; border-collapse: collapse;
  font-family: var(--font-mono);
  font-size: 11px;
}
.charts-section-body td { padding: 2px 0; }
.charts-section-body td.k { color: var(--text-sub); }
.charts-section-body td.v { color: var(--text-main); text-align: right; }
.charts-section-body .row-pos {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 8px;
  align-items: baseline;
  padding: 6px 8px;
  border-bottom: 1px solid var(--border-subtle);
  font-family: var(--font-mono);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  border-left: 2px solid transparent;
}
.charts-section-body .row-pos:last-child { border-bottom: 0; }
/* Side-tinted left edge — matches the basket-cluster card treatment so the
   same position reads the same way wherever it surfaces. */
.charts-section-body .row-pos-buy {
  border-left-color: color-mix(in oklab, var(--profit) 55%, transparent);
  background: color-mix(in oklab, var(--profit) 4%, transparent);
}
.charts-section-body .row-pos-sell {
  border-left-color: color-mix(in oklab, var(--loss) 55%, transparent);
  background: color-mix(in oklab, var(--loss) 4%, transparent);
}
.charts-section-body .row-pos .side {
  padding: 1px 6px;
  border-radius: 3px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
}
.charts-section-body .row-pos .side.buy  { background: var(--ds-profit-tint-strong); color: var(--profit); }
.charts-section-body .row-pos .side.sell { background: var(--ds-loss-tint-strong);   color: var(--loss); }
.charts-section-body .row-pos .pnl.up   { color: var(--profit); }
.charts-section-body .row-pos .pnl.down { color: var(--loss); }
/* Tier badge + lock flags — shared across .row-pos (orders panel) and
   .lvl-hdr (Levels panel) so buy/sell display stays consistent. */
.charts-orders-panel .row-pos .tier-badge,
.charts-section-body .lvl-hdr .tier-badge {
  display: inline-flex;
  align-items: center;
  height: 14px;
  padding: 0 5px;
  border-radius: 3px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.04em;
  background: var(--surface-2);
  color: var(--text-sub);
  border: 1px solid var(--border-subtle);
}
.charts-orders-panel .row-pos .tier-badge.t1,
.charts-section-body .lvl-hdr .tier-badge.t1 {
  background: color-mix(in oklab, var(--profit) 14%, var(--surface-2));
  border-color: color-mix(in oklab, var(--profit) 35%, transparent);
  color: var(--text-main);
}
.charts-orders-panel .row-pos .tier-badge.t2,
.charts-section-body .lvl-hdr .tier-badge.t2 {
  background: color-mix(in oklab, var(--yellow) 16%, var(--surface-2));
  border-color: color-mix(in oklab, var(--yellow) 40%, transparent);
  color: var(--text-main);
}
.charts-orders-panel .row-pos .tier-badge.t3,
.charts-orders-panel .row-pos .tier-badge.t4,
.charts-orders-panel .row-pos .tier-badge.t5,
.charts-section-body .lvl-hdr .tier-badge.t3,
.charts-section-body .lvl-hdr .tier-badge.t4,
.charts-section-body .lvl-hdr .tier-badge.t5 {
  background: color-mix(in oklab, var(--loss) 18%, var(--surface-2));
  border-color: color-mix(in oklab, var(--loss) 40%, transparent);
  color: var(--text-main);
}
.charts-orders-panel .row-pos .basket-leg-flags {
  display: inline-flex;
  gap: 3px;
}
.charts-orders-panel .row-pos .leg-flag {
  display: inline-flex;
  align-items: center;
  height: 14px;
  padding: 0 5px;
  border-radius: 3px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.04em;
}
.charts-orders-panel .row-pos .leg-flag.be {
  background: color-mix(in oklab, var(--yellow) 18%, transparent);
  color: var(--yellow);
}
.charts-orders-panel .row-pos .leg-flag.tr {
  background: color-mix(in oklab, var(--profit) 18%, transparent);
  color: var(--profit);
}
.charts-section-body .row-dec {
  display: grid;
  grid-template-columns: 56px 10px auto minmax(0, 1fr) 42px;
  gap: 6px;
  align-items: baseline;
  padding: 3px 0;
  font-family: var(--font-mono);
  font-size: 11px;
  border-bottom: 1px solid var(--border-subtle);
}
.charts-section-body .row-dec .dec-dir { font-weight: 700; text-align: center; }
.charts-section-body .row-dec .dec-dir.up { color: var(--profit, #52ca74); }
.charts-section-body .row-dec .dec-dir.down { color: var(--loss, #ed645f); }
.charts-section-body .row-dec .dec-pat { color: var(--text-main); font-weight: 500; }
.charts-section-body .row-dec .dec-when { text-align: right; font-size: 10px; cursor: pointer; }
.charts-section-body .row-dec .dec-when:hover {
  text-decoration: underline;
  color: var(--accent);
}
/* Keyboard focus needs a visible ring — relying on color-change alone fails
   WCAG 2.4.7 contrast requirements for the focus indicator. */
.charts-section-body .row-dec .dec-when:focus-visible {
  text-decoration: underline;
  color: var(--accent);
  outline: none;
  box-shadow: 0 0 0 2px var(--accent);
  border-radius: 2px;
}
/* Fresh decision pulse — fires for ~10s after a new decision arrives so the
   user catches "EA just acted" without staring at the rail. The animation
   fades the accent-tinted left border out over its lifetime. */
.charts-section-body .row-dec.fresh {
  animation: row-dec-fresh 10s ease-out forwards;
  border-left: 2px solid var(--accent);
  padding-left: 6px;
  margin-left: -8px;
}
@keyframes row-dec-fresh {
  0%   { background: color-mix(in srgb, var(--accent) 22%, transparent); }
  60%  { background: color-mix(in srgb, var(--accent) 12%, transparent); }
  100% { background: transparent; border-left-color: transparent; }
}
/* Brief flash when scrollToTime pans the chart — visual confirmation that
   the click landed (since the time scale jump itself can be subtle). */
.charts-chart-flash { box-shadow: inset 0 0 0 2px var(--accent); transition: box-shadow 240ms ease-out; }
/* "Back to live" pill — sits in the chart's bottom-right when the user has
   panned away from realtime. Click snaps the time scale back to now. */
.charts-back-to-live {
  position: absolute;
  bottom: 36px;
  right: 16px;
  z-index: 10;
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: var(--radius-pill);
  padding: 6px 14px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  cursor: pointer;
  opacity: 0;
  transform: translateY(8px);
  pointer-events: none;
  transition: opacity 160ms, transform 160ms;
  box-shadow: 0 4px 10px rgba(10, 132, 255, 0.30);
}
.charts-back-to-live.visible { opacity: 1; transform: translateY(0); pointer-events: auto; }
.charts-back-to-live:hover { filter: brightness(1.1); }
.charts-back-to-live:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.charts-section-body .row-dec:last-child { border-bottom: 0; }
.charts-section-body .row-dec .kind { font-weight: 600; }
.charts-section-body .row-dec .kind.PLACE { color: var(--profit, #52ca74); }
.charts-section-body .row-dec .kind.VETO  { color: var(--loss, #ed645f); }
.charts-section-body .row-dec .kind.SKIP  { color: var(--text-dim); }
.charts-section-body .row-dec .kind.CLOSE { color: var(--accent); }
.charts-section-body .row-dec .kind.TRAIL { color: var(--yellow, #ffcc00); }
.charts-section-body .row-dec .kind.BE_ARM,
.charts-section-body .row-dec .kind.PML_ARM,
.charts-section-body .row-dec .kind.DD_ENGAGE { color: var(--purple, #bf5af2); }
.charts-section-body .row-dec .reason { color: var(--text-sub); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.charts-dim { color: var(--text-sub); font-style: italic; }

/* News rail rows — tier-coloured strip mirrors the on-chart palette so the
   rail and the chart speak the same visual language. */
.charts-section-body .news-row {
  display: grid;
  grid-template-columns: 26px 10px minmax(0, 1fr) 56px;
  gap: 6px;
  align-items: baseline;
  padding: 3px 0 3px 7px;
  font-family: var(--font-mono);
  font-size: 11px;
  border-left: 2px solid transparent;
  border-bottom: 1px solid var(--border-subtle);
}
.charts-section-body .news-row:last-child { border-bottom: 0; }
.charts-section-body .news-row.tier-high { border-left-color: var(--loss, #ed645f); }
.charts-section-body .news-row.tier-mid  { border-left-color: var(--yellow, #ffcc00); }
.charts-section-body .news-row.tier-low  { border-left-color: var(--text-dim); }
.charts-section-body .news-row .news-tier {
  font-weight: 700; font-size: 10px; letter-spacing: 0.04em;
}
.charts-section-body .news-row.tier-high .news-tier { color: var(--loss, #ed645f); }
.charts-section-body .news-row.tier-mid  .news-tier { color: var(--yellow, #ffcc00); }
.charts-section-body .news-row.tier-low  .news-tier { color: var(--text-dim); }
.charts-section-body .news-row .news-headline {
  color: var(--text-main);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.charts-section-body .news-row .news-when { text-align: right; font-size: 10px; }
.charts-section-body .news-group-label {
  font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase;
  font-weight: 600; color: var(--text-sub);
  margin: 10px 0 4px;
  padding-top: 6px;
  border-top: 1px solid var(--border-subtle, rgba(127,127,127,0.18));
}
.charts-section-body .news-group-label:first-child {
  margin-top: 0; padding-top: 0; border-top: none;
}
.charts-section-body .news-lock-banner {
  display: flex; align-items: center; gap: 6px;
  padding: 6px 8px; margin-bottom: 6px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--loss, #ed645f) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--loss, #ed645f) 50%, transparent);
  font-size: 11px;
  min-width: 0;
}
.charts-section-body .news-lock-banner .news-lock-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--loss, #ed645f);
  animation: news-lock-pulse 1.6s ease-in-out infinite;
  flex: 0 0 auto;
}
.charts-section-body .news-lock-banner > span:not(.news-lock-dot):not(.news-lock-until) {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.charts-section-body .news-lock-banner .news-lock-until { margin-left: auto; font-size: 10px; flex: 0 0 auto; white-space: nowrap; }
@keyframes news-lock-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.35; }
}

/* MarketState / Armed / Levels rows */
.charts-section-body .ms-row {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 11px;
  padding: 2px 0;
}
.charts-section-body .ms-row > span:first-child {
  color: var(--text-sub);
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.charts-section-body .ms-row > span:last-child {
  flex: 0 0 auto;
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.charts-section-body .ms-row .up   { color: var(--profit, #52ca74); }
.charts-section-body .ms-row .down { color: var(--loss, #ed645f); }
.charts-section-body .ms-row .warn { color: var(--yellow, #ffcc00); }
/* Multiplier ring + value paired so the ring sits next to the value
   instead of floating in the middle of the row. */
.charts-section-body .ms-row .ms-mult {
  display: inline-flex; align-items: center; gap: 6px;
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
}
.charts-section-body .ms-row .ms-mult svg { display: block; }
.charts-section-body .ms-row .dim  { color: var(--text-dim); }

.charts-section-body .arm-on {
  color: var(--profit, #52ca74); font-weight: 600;
}
.charts-section-body .arm-off {
  color: var(--text-dim); opacity: 0.55;
}
/* --text-dim is already only AA-large on white; opacity 0.55 pushes it past
   illegible. Raise alpha in light mode so "off" still reads. */
:root.light .charts-section-body .arm-off { opacity: 0.85; }

.charts-section-body .ms-softs {
  display: flex; flex-wrap: wrap; gap: 4px; margin: 6px 0 2px;
}
.charts-section-body .ms-chip {
  display: inline-flex; align-items: center;
  font-family: var(--font-mono); font-size: 10px;
  padding: 2px 7px; border-radius: var(--radius-card);
  background: var(--surface-2);
  border: 1px solid var(--border-subtle);
  letter-spacing: 0.02em;
  transition: background 120ms ease;
}
.charts-section-body .ms-chip:hover { background: var(--surface-3); }
.charts-section-body .ms-chip.up   { color: var(--profit); border-color: var(--ds-profit-border); }
.charts-section-body .ms-chip.down { color: var(--loss);   border-color: var(--ds-loss-border); }
.charts-section-body .ms-chip.warn { color: var(--yellow); border-color: var(--ds-warn-border); }
.charts-section-body .ms-chip.dim  { color: var(--text-dim); opacity: 0.82; }
.charts-section-body .ms-chip.unused {
  opacity: 0.25;
  filter: grayscale(0.6);
}

.charts-section-body .ms-spark {
  display: block; width: 100%; height: 28px; margin: 6px 0 2px;
}

.charts-section-body .ms-gauge-wrap {
  margin: 4px 0 2px;
}
.charts-section-body .ms-gauge-labels {
  display: flex; justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-sub);
  margin-bottom: 2px;
}
.charts-section-body .ms-gauge-labels span:nth-child(2) {
  color: var(--text-main);
}
.charts-section-body .ms-gauge {
  display: block; width: 100%; height: 10px;
}

.charts-section-body .ms-ring {
  vertical-align: middle;
  margin-right: 4px;
}

/* Weekly cycle band */
.charts-section-body .cycle-band {
  display: flex; justify-content: center;
  margin: 6px 0 4px;
}
.charts-section-body .cycle-band svg {
  display: block;
}
/* Merged trading-window panel. Replaces the ad-hoc Weekly/Daily blocks. */
.charts-section-body .cycle-status {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 6px;
}
.charts-section-body .cycle-phase-pill {
  font-family: var(--font-mono);
  font-size: 10px; font-weight: 600;
  letter-spacing: 0.06em;
  padding: 2px 6px; border-radius: 4px;
  border: 1px solid currentColor;
  text-transform: uppercase;
}
.charts-section-body .cycle-phase-pill.up   { color: var(--profit, #52ca74); }
.charts-section-body .cycle-phase-pill.down { color: var(--loss,   #ed645f); }
.charts-section-body .cycle-phase-pill.warn { color: var(--yellow, #ffcc00); }
.charts-section-body .cycle-phase-pill.dim  { color: var(--text-dim); }
.charts-section-body .cycle-next {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-main, rgba(255,255,255,0.92));
  font-weight: 500;
}
.charts-section-body .cycle-band-label {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--text-dim, rgba(255,255,255,0.62));
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-top: 6px;
}
.charts-section-body .cycle-gates {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--border-subtle, rgba(255,255,255,0.06));
  display: flex; flex-direction: column; gap: 3px;
}
.charts-section-body .cycle-gate-row {
  display: grid;
  grid-template-columns: 10px minmax(0, 1fr) auto auto;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 10px;
  align-items: baseline;
}
.charts-section-body .cycle-gate-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; opacity: 0.7;
  margin-top: 4px;
}
.charts-section-body .cycle-gate-dot.up   { color: var(--profit, #52ca74); }
.charts-section-body .cycle-gate-dot.down { color: var(--loss,   #ed645f); }
.charts-section-body .cycle-gate-dot.warn { color: var(--yellow, #ffcc00); }
.charts-section-body .cycle-gate-name { color: var(--text-main); font-weight: 500; }
.charts-section-body .cycle-gate-when { color: var(--text-sub); }
.charts-section-body .cycle-gate-eta  { font-weight: 500; }
.charts-section-body .cycle-gate-eta.up   { color: var(--profit, #52ca74); }
.charts-section-body .cycle-gate-eta.down { color: var(--loss,   #ed645f); }
.charts-section-body .cycle-gate-eta.warn { color: var(--yellow, #ffcc00); }

/* MarketState header strip above the chart canvas. Surfaces regime,
   news, volatility, verdict, confidence, multiplier at a glance so the
   user doesn't have to scan the rail to know "what kind of market am I
   looking at right now". */
/* SVG overlay above the chart canvas (session boxes, range boxes). The
   text-shadow acts as a contrast halo against the chart bg — on dark bg we
   want a dark halo (sinks the text into shadow), on light bg we want a
   light halo (lifts the text off white). */
.charts-overlay-svg text {
  font-family: var(--font-mono);
  text-shadow: 0 0 3px rgba(0,0,0,0.75);
}
:root.light .charts-overlay-svg text {
  /* 0.95 (was 0.85) so on-chart session/range labels lift cleanly off the
     bright light-mode canvas. */
  text-shadow: 0 0 3px rgba(255,255,255,0.95);
}
.charts-overlay-svg text.news-label,
:root.light .charts-overlay-svg text.news-label {
  text-shadow: none;
}
/* Pulsing right edge of a live (developing) session box — makes the
   "this is still building" status visible at a glance. */
.charts-overlay-svg .live-edge {
  animation: charts-live-pulse 1.4s ease-in-out infinite;
}
@keyframes charts-live-pulse {
  0%, 100% { stroke-opacity: 0.4; stroke-width: 1.5; fill-opacity: 0.55; }
  50%      { stroke-opacity: 1;   stroke-width: 2.5; fill-opacity: 1;    }
}

/* Budget utilization bars */
.charts-section-body .bg-row {
  margin: 6px 0;
}
.charts-section-body .bg-label {
  display: flex; justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-main);
  margin-bottom: 3px;
}
.charts-section-body .bg-label span:first-child {
  color: var(--text-sub);
}
.charts-section-body .bg-track {
  background: var(--surface-3);
  border-radius: 3px;
  height: 6px;
  overflow: hidden;
}
.charts-section-body .bg-fill {
  height: 100%;
  border-radius: 3px;
  transition: width 0.3s ease, background 0.3s ease;
}
.charts-section-body .bg-sub {
  font-family: var(--font-mono);
  font-size: 10px;
  margin-top: 2px;
}

/* Session clock */
.charts-section-body .session-clock-wrap {
  display: flex; align-items: center; gap: 10px;
  margin: 4px 0 8px;
}
.charts-section-body .session-clock {
  flex: 0 0 auto;
  overflow: visible; /* hour labels (00/06/12/18) sit just outside r=38 */
}
.charts-section-body .session-clock-meta {
  flex: 1; min-width: 0;
}

.charts-section-body .lvl-block {
  padding: 4px 0;
  border-bottom: 1px solid var(--border-subtle);
}
.charts-section-body .lvl-block:last-child { border-bottom: 0; }
.charts-section-body .lvl-hdr {
  display: flex; align-items: center; gap: 6px;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 4px;
}
.charts-section-body .lvl-hdr .side {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 1px 5px; border-radius: 3px; font-size: 10px; font-weight: 600;
}
.charts-section-body .lvl-hdr .side.buy  { background: var(--ds-profit-tint-strong); color: var(--profit); }
.charts-section-body .lvl-hdr .side.sell { background: var(--ds-loss-tint-strong);   color: var(--loss); }
.charts-section-body .lvl-hdr .side .side-arrow { font-size: 10px; line-height: 1; }
.charts-section-body .lvl-hdr .lvl-ticket { color: var(--text-sub); font-family: var(--font-mono); }
.charts-section-body .lvl-bar-row {
  display: grid; grid-template-columns: 56px minmax(0, 1fr) 56px; gap: 6px;
  align-items: center; margin: 4px 0 2px;
  font-family: var(--font-mono); font-size: 10.5px;
}
.charts-section-body .lvl-bar-end { text-align: center; }
.charts-section-body .lvl-bar-end.up { color: var(--profit, #52ca74); }
.charts-section-body .lvl-bar-end.down { color: var(--loss, #ed645f); }
.charts-section-body .lvl-bar-tag {
  display: inline-block; margin-right: 4px; padding: 0 4px;
  font-size: 0.65rem; font-weight: 700; letter-spacing: 0.04em;
  opacity: 0.7; vertical-align: 1px;
}
.charts-section-body .lvl-bar {
  position: relative; height: 6px; border-radius: 3px;
  background: var(--surface-3);
  overflow: hidden;
}
.charts-section-body .lvl-bar-fill {
  position: absolute; top: 0; left: 0; height: 100%;
  border-radius: 3px;
  transition: width 200ms ease-out;
}
.charts-section-body .lvl-bar-fill.up   { background: color-mix(in srgb, var(--profit) 60%, transparent); }
.charts-section-body .lvl-bar-fill.down { background: color-mix(in srgb, var(--loss)   60%, transparent); }
.charts-section-body .lvl-bar-fill.warn { background: color-mix(in srgb, var(--yellow) 55%, transparent); }
.charts-section-body .lvl-bar-entry {
  position: absolute; top: -2px; width: 2px; height: 10px;
  background: var(--text-main);
  border-radius: 1px;
  transform: translateX(-50%);
}

/* Bottom drawer — interleaved EA log stream */
.charts-drawer {
  grid-area: drawer;
  /* Glass-card matching the other three panels — completes the four-card
     dashboard-style layout (topbar, left rail, main, right rail) +
     drawer/main share the middle column. */
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--glass-shadow);
  overflow: hidden;
  height: 28px;
  display: flex;
  flex-direction: column;
  transition: height 0.18s ease;
}
.charts-drawer.expanded { height: 280px; }
.charts-drawer-handle {
  padding: 6px 12px;
  font-size: 11px;
  color: var(--text-sub);
  cursor: pointer;
  user-select: none;
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 0 0 auto;
  flex-wrap: nowrap;
  min-width: 0;
  overflow: hidden;
}
.charts-drawer-handle .cdh-search { min-width: 0; flex: 0 1 160px; }
.charts-drawer-handle .cdh-filters { flex-wrap: wrap; }
.charts-drawer-handle:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.charts-drawer-handle .cdh-chev {
  display: inline-block;
  transition: transform 0.18s ease;
  color: var(--text-dim);
}
.charts-drawer.expanded .charts-drawer-handle .cdh-chev { transform: rotate(180deg); }
.charts-drawer-handle .cdh-label { font-weight: 600; color: var(--text-main); flex: 0 0 auto; }
.charts-drawer-handle .cdh-count {
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
  font-size: 10px;
}
.charts-drawer-handle .cdh-filters { margin-left: auto; display: flex; gap: 4px; }
.charts-drawer-handle .cdh-search {
  margin-left: 10px;
  background: var(--bg-input, transparent);
  border: 1px solid var(--border);
  color: var(--text-main);
  border-radius: 4px;
  font-size: 11px;
  padding: 3px 8px;
  width: 160px;
  outline: none;
}
.charts-drawer-handle .cdh-search:focus { border-color: var(--accent); }
.charts-drawer-handle .cdh-search::placeholder { color: var(--text-dim); }
.charts-drawer-body mark {
  background: rgba(255, 200, 0, 0.28);
  color: inherit;
  border-radius: 2px;
  padding: 0 2px;
}
:root.light .charts-drawer-body mark { background: rgba(255, 200, 0, 0.55); }
@media (max-width: 768px) {
  .charts-drawer-handle .cdh-search { width: 90px; }
}
.charts-drawer-handle .cdh-lvl {
  background: transparent;
  border: 1px solid var(--border-subtle);
  color: var(--text-dim);
  border-radius: 4px;
  font-size: 10px;
  padding: 2px 6px;
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.charts-drawer-handle .cdh-lvl:hover { color: var(--text-main); border-color: var(--border); }
.charts-drawer-handle .cdh-lvl:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.charts-drawer-handle .cdh-lvl.active {
  color: var(--text-main);
  background: var(--surface-3);
  border-color: var(--border);
}
.charts-drawer-body {
  flex: 1 1 auto;
  overflow-y: auto;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  padding: 6px 12px 10px;
  background: var(--surface-1);
}
.charts-log-line {
  display: grid;
  grid-template-columns: 70px 36px 90px minmax(0, 1fr);
  gap: 8px;
  padding: 1px 0;
  white-space: nowrap;
  cursor: text;
  transition: background-color 200ms ease-out;
}
.charts-log-line.copied {
  background: var(--ds-profit-tint-strong);
}
.charts-log-line.copied.copy-err {
  background: var(--ds-loss-tint-strong, rgba(232,93,107,0.18));
}
.charts-log-line .clg-ts { color: var(--text-dim); font-variant-numeric: tabular-nums; }
.charts-log-line .clg-lvl { font-weight: 700; text-transform: uppercase; }
.charts-log-line .clg-lvl.l-INF { color: var(--text-sub); }
.charts-log-line .clg-lvl.l-WRN { color: var(--yellow, #ffcc00); }
.charts-log-line .clg-lvl.l-ERR { color: var(--loss, #ed645f); }
.charts-log-line .clg-lvl.l-DBG { color: var(--text-dim); }
.charts-log-line .clg-lvl.l-CRT { color: var(--loss, #ed645f); }
.charts-log-line .clg-mod {
  color: var(--accent);
  overflow: hidden; text-overflow: ellipsis;
}
.charts-log-line .clg-msg {
  color: var(--text-main);
  overflow: hidden; text-overflow: ellipsis;
}
/* Rail subhead + egress panel.
   Subheads sit inside long sections (Egress, Levels, Decisions) to break
   them into scannable subsections. A thin top divider + a touch more top
   margin makes the boundary obvious without adding chrome — the eye finds
   the new group by edge contrast, not by typography weight alone. The
   `:first-child` variant drops both so the first subhead doesn't have a
   leading border that floats above nothing. */
.charts-section-body .charts-subhead {
  margin: 12px 0 2px;
  padding-top: 6px;
  border-top: 1px solid var(--border-subtle, rgba(127,127,127,0.18));
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
  font-weight: 600;
}
.charts-section-body .charts-subhead:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}
.egress-recent {
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.45;
  max-height: 140px;
  overflow-y: auto;
  border-top: 1px solid var(--border-subtle);
  padding-top: 4px;
  margin-top: 2px;
}
.egress-line {
  display: grid;
  grid-template-columns: 58px 32px minmax(0, 1fr) 44px;
  gap: 6px;
  white-space: nowrap;
}
.egress-line .eg-ts { color: var(--text-dim); }
.egress-line .eg-st { font-weight: 700; text-align: center; }
.egress-line .eg-pa { color: var(--text-sub); overflow: hidden; text-overflow: ellipsis; }
.egress-line .eg-la { color: var(--text-dim); text-align: right; }

/* Counters panel: trim long veto reasons cleanly. */
#rail-counters .ms-row .reason-trim {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 70%;
}

/* Gate chip — "is the EA currently refusing entries?". Sits at the top of
   the counters body. Loss-red wash when blocked (recent VETO), neutral
   when open. Pulses while blocked so the user notices a state change. */
#rail-counters .gate-chip {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 8px;
  margin: 0 0 8px;
  border-radius: 4px;
  font-size: 11px;
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  border: 1px solid var(--border);
  background: var(--surface-3);
  min-width: 0;
}
#rail-counters .gate-chip .gate-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--text-dim);
  flex: 0 0 auto;
}
#rail-counters .gate-chip .gate-label {
  font-weight: 700;
  letter-spacing: 0.08em;
}
#rail-counters .gate-chip .gate-reason {
  flex: 1 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#rail-counters .gate-chip .gate-age {
  flex: 0 0 auto;
  font-size: 10px;
}
#rail-counters .gate-chip.blocked {
  border-color: var(--loss);
  background: color-mix(in srgb, var(--loss) 12%, transparent);
}
/* 12% loss tint reads as near-white on the light canvas — lift to 18% so the
   "trading disabled" state is unmistakable in light mode. */
:root.light #rail-counters .gate-chip.blocked {
  background: color-mix(in srgb, var(--loss) 18%, transparent);
}
#rail-counters .gate-chip.blocked .gate-dot {
  background: var(--loss);
  box-shadow: 0 0 6px var(--loss);
  animation: gate-pulse 1.4s ease-in-out infinite;
}
#rail-counters .gate-chip.blocked .gate-label { color: var(--loss); }
#rail-counters .gate-chip.ok .gate-dot { background: var(--profit); }
#rail-counters .gate-chip.ok .gate-label { color: var(--text-sub); }
@keyframes gate-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.4; }
}
@media (prefers-reduced-motion: reduce) {
  #rail-counters .gate-chip.blocked .gate-dot { animation: none; }
}

/* In-rail close button: only visible when rail is in overlay mode */
.charts-rail-close {
  display: none;
  position: absolute;
  top: 8px; right: 8px;
  background: var(--surface-3);
  color: var(--text-main);
  border: 1px solid var(--border);
  border-radius: 50%;
  width: 26px; height: 26px;
  cursor: pointer;
  font-size: 13px;
  line-height: 1;
  z-index: 2;
}
.charts-rail-close:hover { background: var(--surface-hover); }
.charts-rail-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.charts-rail-left, .charts-rail-right { position: relative; }
.charts-rail-left.open .charts-rail-close,
.charts-rail-right.open .charts-rail-close { display: inline-flex; align-items: center; justify-content: center; }
@media (max-width: 1024px) {
  .charts-rail-right .charts-rail-close { display: inline-flex; align-items: center; justify-content: center; }
}
@media (max-width: 768px) {
  .charts-rail-left .charts-rail-close,
  .charts-rail-right .charts-rail-close { display: inline-flex; align-items: center; justify-content: center; }
}

/* Toggle buttons for rails (visible only on smaller screens) */
.charts-rail-toggle {
  display: none;
  background: transparent;
  color: var(--text-main);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 4px 8px;
  font-size: 11px;
  cursor: pointer;
  /* iOS Safari: remove the 300ms double-tap delay and stop the OS from
     hijacking the first tap as a potential double-tap-zoom gesture, which can
     make the List/State toggles feel unresponsive on real devices. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.charts-rail-toggle:hover { background: var(--bg-hover); }
.charts-rail-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Medium screens: shrink rails but keep both visible */
@media (max-width: 1280px) {
  .charts-shell {
    grid-template-columns: 200px 1fr 280px;
  }
  .charts-select { min-width: 160px; }
  /* Drop two cross-page links at narrower widths to keep the topbar
     single-row — brand link + Dashboard + Charts still cover navigation. */
  .charts-nav-link[href$="/trades"],
  .charts-nav-link[href$="/stats"] { display: none; }
}

@media (max-width: 1024px) {
  /* Collapse cross-page nav entirely on tablets — brand link covers the
     fallback. The right cluster (stream/meta/help/state) needs the space. */
  .charts-nav-links { display: none; }
}

/* Tablet: right rail becomes a slide-over panel (wider, no backdrop dimming) */
@media (max-width: 1024px) {
  .charts-shell {
    grid-template-columns: 180px 1fr;
    grid-template-areas:
      "topbar topbar"
      "left   main"
      "left   drawer";
  }
  .charts-rail-right {
    position: fixed;
    /* Charts now shares the 60px site nav with the rest of the app; the
       charts topbar is the second 56px row inside the shell. The right rail
       overlay anchors below both: 60 + 56 = 116px from viewport top. */
    top: 116px; right: 0; bottom: 0;
    width: 380px; max-width: 60vw;
    z-index: 50;
    transform: translateX(100%);
    transition: transform 0.2s ease;
    box-shadow: var(--elev-card);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    background: var(--bg-panel);
    border-left: 1px solid var(--border);
    /* leave room for the absolute-positioned close button + clear the iOS
       notch/dynamic-island and right safe-area on landscape rotation (mirrors
       the left rail's safe-area treatment). */
    padding-top: max(40px, env(safe-area-inset-top, 0px));
    padding-right: env(safe-area-inset-right, 0px);
  }
  .charts-rail-right.open { transform: translateX(0); }
  .charts-rail-toggle.toggle-right { display: inline-block; }
}

/* Mobile: left rail also becomes overlay; topbar stays single-row */
@media (max-width: 768px) {
  .charts-shell {
    grid-template-columns: 1fr;
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
      "topbar"
      "main"
      "drawer";
  }
  .charts-topbar {
    /* Single row + no-wrap is the difference between a clickable page and an
       unclickable one — when the instance-title or JS-injected balance pill
       force wrap, the topbar climbs to 3-4 rows and squeezes the chart out.
       Items that don't fit on phones are hidden below; List/Account/State/?
       always have room. */
    flex-wrap: nowrap;
    padding: 6px 8px;
    height: 48px;
    min-height: 48px;
  }
  .charts-topbar-left, .charts-topbar-right {
    gap: 6px;
    flex-wrap: nowrap;
    min-width: 0;
  }
  .charts-topbar-left { flex: 1 1 auto; min-width: 0; }
  .charts-topbar-right { flex: 0 0 auto; }
  /* Instance title stays visible at 481-768 so tablet portrait still shows
     EA · symbol · TF · acct-tail context once the right rail is closed.
     Phones (≤480) hide it via charts-mobile.css to reclaim row space. */
  /* JS-injected balance pill (Bal/Eq/Day) eats horizontal space and would
     force wrap. The dashboard already shows the same numbers. */
  .charts-account-balance { display: none; }
  .charts-select { min-width: 120px; font-size: 12px; height: 36px; flex: 0 1 auto; }
  .charts-meta { display: none; }
  /* Keep stream status visible on mobile so colorblind users still see LIVE/STALE/ERR
     signal — was display:none, but the aria-label alone wasn't perceivable visually. */
  .charts-stream-dot { width: 8px; height: 8px; flex: 0 0 8px; }
  /* 44px tap targets (Apple HIG / Material) — easy thumb reach. */
  .charts-rail-toggle, .charts-btn {
    height: 36px;
    min-width: 44px;
    padding: 0 10px;
    font-size: 12px;
  }
  .charts-btn-help { width: 36px; }
  .charts-btn-back-label { display: none; }
  .charts-btn-back { padding: 0 10px; }
  .charts-brand-label { display: none; }
  .charts-brand { padding: 0 4px; }
  /* The cross-page nav-links eat too much horizontal real-estate on phones.
     Brand link still acts as Dashboard fallback; rail toggles handle the rest. */
  .charts-nav-links { display: none; }
  .charts-legend {
    top: 56px;
    right: 8px;
    left: 8px;
    width: auto;
  }
  /* Both rails are full-height fixed overlays on phones. They MUST start
     below the shared 60px site nav — previously they slid over it, hiding
     the back/account picker the user expected to remain visible. The 56px
     charts topbar sits inside the shell on its own row, but on phones the
     overlay rails cover it intentionally so the rail content gets the full
     remaining viewport. */
  .charts-rail-left {
    position: fixed;
    top: var(--site-nav-h, 60px); left: 0; bottom: 0;
    width: 280px; max-width: 84vw;
    z-index: 50;
    transform: translateX(-100%);
    transition: transform 0.2s ease;
    box-shadow: var(--elev-card);
    padding-top: calc(40px + env(safe-area-inset-top, 0px));
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .charts-rail-left.open { transform: translateX(0); }
  .charts-rail-toggle.toggle-left { display: inline-block; }
  .charts-rail-right {
    top: var(--site-nav-h, 60px);
    width: 320px;
    max-width: 86vw;
    z-index: 51;
    padding-top: calc(40px + env(safe-area-inset-top, 0px));
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  /* Drawer handle must clear the iOS home indicator AND be tall enough to
     tap reliably. Was 28px collapsed (= ~half a fingertip) and sat on top of
     the home indicator on iPhone X+. */
  .charts-drawer { height: 44px; }
  .charts-drawer.expanded { height: min(60vh, 320px); }
  .charts-drawer-handle { padding: 10px 12px; }
  /* Search input was 90px — drop on phones, level pills are enough. Reduces
     the chance the handle row overflows and clips the count badge. */
  .charts-drawer-handle .cdh-search { display: none; }
}

/* Backdrop when a rail is open as overlay */
/* Backdrop: only used on mobile-width (≤768px) where rails fully overlay.
   On tablet (>768px) we skip it entirely so the chart stays visible while
   the rail is open and clickable elsewhere. */
.charts-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.25);
  z-index: 40;
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}
@media (max-width: 768px) {
  .charts-backdrop.visible { display: block; }
}

/* Phone-tight breakpoint — pack tap targets even tighter on narrow phones
   (iPhone SE, small Android). The ≤768 rule already removes everything that
   would force topbar wrap; this just shrinks widths so the remaining controls
   keep ≥36px reach without overflowing. */
@media (max-width: 480px) {
  .charts-topbar { padding: 6px 6px; gap: 4px; }
  .charts-topbar-left, .charts-topbar-right { gap: 4px; }
  .charts-select { min-width: 0; flex: 0 1 130px; max-width: 140px; font-size: 12px; }
  .charts-label { display: none; }
  /* Instance-title truncates instead of pushing the right-cluster off-screen.
     At 390px there's ~120px for it after List+Account select; ellipsis the
     rest so EA·SYM·TF still reads. */
  .charts-instance-title {
    flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-size: 12px;
  }
  .charts-rail-left { width: 88vw; }
  .charts-rail-right { width: 92vw; max-width: 360px; }
  .charts-legend { font-size: 11.5px; padding: 12px 14px; }
  .charts-legend h4 { font-size: 12.5px; }
  /* MarketState strip duplicates the right rail's MarketState section — hide
     on phones to give the chart ~50px more vertical space. */
  .charts-ms-strip { display: none !important; }
  /* Orders row: tighten padding + let h3/meta wrap, since stacked single
     column still puts a count badge next to a long header on 390px. */
  .charts-orders-row { padding: 0 2px 8px; gap: 8px; margin-top: 6px; }
  .charts-orders-panel h3 { flex-wrap: wrap; gap: 4px; }
  .charts-orders-meta { font-size: 9.5px; }
  /* Overlay bar: smaller chips + tighter gap so the 4 ov-groups fit ~2
     screens of scroll instead of 3, and the right-edge chevron isn't the
     only visible hint of overflow. */
  .charts-overlay-bar { gap: 4px; padding: 5px 8px; }
  .charts-overlay-bar .qf-chip { padding: 3px 7px; font-size: 10px; }
  .charts-overlay-bar .ov-group { padding-right: 6px; margin-right: 2px; }
}

/* (Narrow-desktop 1025-1280 rail/grid sizing is owned by charts-responsive.css
   which loads after this file and uses minmax() bounds — the duplicated rule
   here was dead. Keeping the empty media stub as a load-order anchor.) */

/* ── Trading Window: daily clock dial ────────────────────────────────── */
.day-clock-wrap {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 0 2px;
}
.day-clock { flex: 0 0 auto; overflow: visible; /* 00/06/12/18 hour labels sit just outside r=42 */ }
.day-clock-meta {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 11px;
}
.day-clock-meta .ms-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
.dim-dot,
.charts-section-body .ms-row > span.dim-dot:first-child {
  width: 8px; height: 8px; border-radius: 50%;
  display: inline-block; flex: 0 0 8px;
  overflow: visible;
}
.dot-open { background: var(--profit, #52ca74); }
.dot-soft { background: var(--yellow, #ffcc00); }
.dot-hard { background: var(--loss, #ed645f); }

/* ── Armed Systems: pattern detectors (24h fires/vetos) ──────────────── */
.pat-hdr {
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim, #8a8f99);
  margin: 6px 0 4px;
}
.pat-hdr:first-child { margin-top: 0; }
.pat-row {
  display: grid;
  grid-template-columns: 10px 64px minmax(0, 1fr) auto;
  grid-row-gap: 2px;
  align-items: center;
  gap: 6px;
  padding: 3px 2px;
  font-size: 12px;
  line-height: 1.3;
}
.pat-row .pat-strip { grid-column: 1 / -1; width: 100%; height: 10px; opacity: 0.9; }
.pat-row .pat-strip line { stroke: var(--border-subtle); }
.pat-dot {
  width: 8px; height: 8px; border-radius: 50%;
  display: inline-block;
}
.pat-dot.pat-hot    { background: var(--profit); box-shadow: 0 0 6px var(--ds-profit-glow); }
.pat-dot.pat-fired  { background: var(--profit); opacity: 0.55; }
.pat-dot.pat-vetoed { background: var(--orange, #ff9500); opacity: 0.85; }
.pat-dot.pat-dim    { background: var(--text-dim, #4a4f59); opacity: 0.4; }
.pat-code {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.pat-counts {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-main, #d8dde6);
}
.pat-fires { color: var(--profit, #52ca74); }
.pat-vetos { color: var(--orange, #ff9500); }
.pat-sep   { color: var(--text-dim, #4a4f59); margin: 0 3px; }
.pat-last  { font-size: 10px; text-align: right; }
.pat-state { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.04em; }
.pat-state.on  { color: var(--profit, #52ca74); font-weight: 600; }
.pat-state.off { color: var(--text-dim, #4a4f59); }
/* Protection rows reuse the .pat-row grid but never carry a timeline
   strip, so they don't need the row-2 gap reserved by the patterns layout. */
.pat-row.prot-row { padding: 2px 0; }

/* ── Basket cluster (buy/sell groups with tier badges + leg flags) ───── */
.cluster-hdr {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px;
  margin-top: 6px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 600;
  min-width: 0;
  flex-wrap: wrap;
}
.cluster-hdr .side,
.cluster-hdr .tier-badge,
.cluster-hdr .cluster-hist { flex: 0 0 auto; }
.cluster-hdr .cluster-lots {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cluster-hdr .pnl { flex: 0 0 auto; margin-left: auto; }
.cluster-hdr:first-child { margin-top: 0; }
.cluster-buy  { background: var(--ds-profit-tint); border-left: 2px solid var(--profit); }
.cluster-sell { background: var(--ds-loss-tint);   border-left: 2px solid var(--loss); }
.cluster-lots, .cluster-legs, .cluster-pnl {
  font-family: var(--font-mono);
  font-size: 11px;
}
.cluster-pnl { margin-left: auto; }
.cluster-pnl.up   { color: var(--profit, #52ca74); }
.cluster-pnl.down { color: var(--loss, #ed645f); }

.tier-badge {
  display: inline-block;
  padding: 1px 5px;
  border-radius: 3px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  background: var(--surface-3, #3a3f49);
  color: var(--text-main, #d8dde6);
}
/* Tier badges derive from theme tokens so they read correctly in light mode
   (the previous hardcoded hex left t1/t2 with #1a1a1a text on a yellow/orange
   pill regardless of theme, and t3/t4 forced white text). */
.tier-badge.t1 { background: var(--yellow,  #d4a017); color: var(--badge-ink-warm, #1a1a1a); }
.tier-badge.t2 { background: var(--orange,  #e67e22); color: var(--badge-ink-warm, #1a1a1a); }
.tier-badge.t3 { background: var(--loss,    #e74c3c); color: #fff; }
.tier-badge.t4 { background: var(--purple,  #8e44ad); color: #fff; }
:root.light .tier-badge:not(.t1):not(.t2):not(.t3):not(.t4) { background: rgba(0,0,0,0.08); color: var(--text-main); }
/* In light mode --yellow resolves to a dark olive (~#8c7300); the warm ink
   fallback (#1a1a1a) would be dark-on-dark. Pin t1/t2 ink to white like t3/t4. */
:root.light .tier-badge.t1, :root.light .tier-badge.t2 { color: #fff; }

.leg-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 2px 6px 2px 14px;
  font-size: 11px;
  font-family: var(--font-mono);
  min-width: 0;
}
.leg-row > span:nth-child(2) {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.leg-row .pnl { flex: 0 0 auto; margin-left: auto; }
.leg-ticket { color: var(--text-main, #d8dde6); flex: 0 0 auto; }
.leg-flag {
  display: inline-block;
  padding: 0 4px;
  border-radius: 2px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.04em;
}
.leg-flag.be  { background: var(--yellow, #d4a017); color: var(--badge-ink-warm, #1a1a1a); }
.leg-flag.tr  { background: var(--accent, #3498db); color: #fff; }
.leg-flag.pml { background: var(--purple, #8e44ad); color: #fff; }

.basket-total {
  display: flex;
  justify-content: space-between;
  margin-top: 8px;
  padding: 4px 6px;
  border-top: 1px solid var(--border-subtle, #2a2f39);
  font-size: 12px;
  font-weight: 600;
  font-family: var(--font-mono);
}
.basket-total .up   { color: var(--profit, #52ca74); }
.basket-total .down { color: var(--loss, #ed645f); }

/* ── Left rail: grouped instance list ────────────────────────────────── */
.charts-instance-group {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px 9px 14px;
  margin: 10px 0 1px;
  cursor: pointer;
  border-top: 1px solid var(--border-subtle);
  border-bottom: 1px solid var(--border-subtle);
  position: sticky;
  top: 0;
  background: var(--bg-panel);
  z-index: 3;
  user-select: none;
  text-transform: uppercase;
}
/* Colored left-edge accent per EA family — makes the section breaks scannable
   without relying on text alone. Falls back to neutral grey for unknown EAs. */
.charts-instance-group { box-shadow: inset 3px 0 0 rgba(255,255,255,0.12); }
.charts-instance-group[data-ea="PG_GS_Scalp_T"]  { box-shadow: inset 3px 0 0 var(--yellow, #ffcc00); }
.charts-instance-group[data-ea="PG_CFD_GL_T"]    { box-shadow: inset 3px 0 0 var(--accent, #0a84ff); }
.charts-instance-group[data-ea="PG_FX_RB_T"]     { box-shadow: inset 3px 0 0 var(--purple, #bf5af2); }
.charts-instance-group[data-ea="PG_MS_Utility"]  { box-shadow: inset 3px 0 0 rgba(255,255,255,0.25); }
:root.light .charts-instance-group {
  box-shadow: inset 3px 0 0 rgba(0,0,0,0.18);
}
:root.light .charts-instance-group[data-ea="PG_MS_Utility"] {
  box-shadow: inset 3px 0 0 rgba(0,0,0,0.32);
}
/* Light mode: keep the per-EA family accent distinct instead of collapsing
   every group to the same grey bar. Darkened tints of the dark-mode
   yellow/blue/purple stay visible on a white surface so users can still
   scan-identify Gold / Index / FX RB families by colour. */
:root.light .charts-instance-group[data-ea="PG_GS_Scalp_T"] { box-shadow: inset 3px 0 0 #8c7300; }
:root.light .charts-instance-group[data-ea="PG_CFD_GL_T"]   { box-shadow: inset 3px 0 0 #0051d5; }
:root.light .charts-instance-group[data-ea="PG_FX_RB_T"]    { box-shadow: inset 3px 0 0 #8b2fb0; }
.charts-instance-group:hover { background: var(--surface-2); }
.charts-instance-group .grp-caret {
  flex: 0 0 12px;
  font-size: 10px;
  color: var(--text-sub);
  text-align: center;
  transition: transform 0.15s;
}
.charts-instance-group .grp-name {
  flex: 1 1 auto;
  /* Guarantee enough space for the shortest group name ("Gold", "Index",
     "FX RB") so it isn't ellipsized to "G…" on narrow rails. */
  min-width: 3.5em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--text-main, #e8e8ed);
}
@container rail-left (max-width: 210px) {
  .charts-instance-group .grp-live { display: none; }
}
.charts-instance-group .grp-pnl { margin-left: auto; }
.charts-instance-group .grp-count {
  font-size: 10px;
  font-family: var(--font-mono);
}
.charts-instance-group .grp-live {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 10px;
  color: var(--profit, #52ca74);
}
.charts-instance-group .grp-live .dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--profit);
  box-shadow: 0 0 6px var(--ds-profit-glow);
  animation: cfin-pulse 1.6s ease-in-out infinite;
}
.charts-instance-group .grp-legs {
  font-size: 10px;
  background: var(--ds-accent-tint-strong);
  color: var(--accent);
  padding: 1px 5px;
  border-radius: 3px;
  font-family: var(--font-mono);
}
.charts-instance-group .grp-pnl {
  font-size: 11.5px;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0;
}
.charts-instance-group.collapsed .grp-caret { transform: none; }
.charts-instance-leaf {
  padding-left: 24px;
}
/* Rows whose (symbol, tf) has no bars in the spool — chart would be empty.
   Keep them in the rail (per spec — every cell stays visible) but dim them so
   the user knows clicking lands on a no-data state. */
.charts-instance-leaf.no-bars {
  opacity: 0.45;
}
.charts-instance-leaf.no-bars .name .top::after {
  content: 'no bars';
  font-size: 9px;
  font-family: var(--font-mono);
  color: var(--text-dim);
  margin-left: 4px;
  letter-spacing: 0.04em;
}
.charts-instance-leaf .dot.hot {
  animation: cfin-pulse 1.4s ease-in-out infinite;
  box-shadow: 0 0 8px var(--ds-profit-glow);
}
@keyframes cfin-pulse {
  0%, 100% { opacity: 1;   transform: scale(1);   }
  50%      { opacity: 0.55; transform: scale(1.18); }
}

/* Mini sparkline column in instance rows */
.inst-spark {
  width: 44px;
  height: 12px;
  opacity: 0.88;
  align-self: center;
}

/* Tier badge in instance rows (mirrors basket cluster badge) */
.charts-instance-leaf .tier-badge {
  font-size: 9px;
  padding: 0 4px;
  border-radius: 3px;
  font-family: var(--font-mono);
  font-weight: 700;
  background: var(--yellow, #ffcc00);
  color: #1a1a1a;
}
/* --yellow goes dark olive in light mode — flip text to white for legibility. */
:root.light .charts-instance-leaf .tier-badge { color: #fff; }

/* Tighter cycle band labels with brokerised text */
.cycle-band-label {
  font-size: 10.5px;
  color: var(--text-sub);
  letter-spacing: 0.02em;
}

/* ── Mobile tweaks: easier-to-view rail windows ──────────────────────── */
@media (max-width: 768px) {
  .charts-rail-left {
    width: 86vw;
    max-width: 320px;
  }
  .charts-rail-right {
    width: 92vw;
    max-width: 360px;
  }
  .charts-section {
    margin: 6px 8px;
    padding: 8px 10px;
  }
  .charts-section h3 {
    font-size: 11px;
  }
  /* Stacked cycle clock + meta on narrow */
  .day-clock-wrap {
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
  }
  .day-clock { margin: 0 auto; }
  /* Topbar account picker shrinks; titles get full-width second row */
  .charts-account-balance { display: none; }
}

/* Tighter top-bar layout on tablet so account picker doesn't crowd dots */
@media (max-width: 1024px) {
  .charts-instance-title {
    max-width: 220px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

/* ── 24h decision heatmap strip (Last Decisions section) ─────────────── */
.dec-heatmap-wrap {
  margin: 2px 0 8px;
  padding: 4px 0 2px;
  border-bottom: 1px dashed var(--border-subtle);
}
.dec-heatmap {
  width: 100%;
  height: 18px;
  display: block;
}
.dec-heatmap-axis {
  display: flex;
  justify-content: space-between;
  font-size: 9px;
  color: var(--text-dim);
  font-family: var(--font-mono);
  margin-top: 2px;
  padding: 0 2px;
}

/* News-line tooltip hit area — invisible, but receives hover so
   browser title tooltip surfaces reliably */
.charts-overlay-svg rect[fill="transparent"] { pointer-events: auto; }

/* ── Topbar balance/equity inline display ─────────────────────────────
   Wrapped in min-width:769 so the mobile @media display:none rules at
   lines 1540 / 1980 are the LAST matching declaration on phones —
   otherwise this base rule (source-order-later) clobbered them and the
   BAL/EQ/DAY chips overflowed the cramped 390px topbar past the State
   button on iPhone 14. Chips still show on tablet/desktop unchanged. */
@media (min-width: 769px) {
  .charts-account-balance {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: var(--font-mono);
    font-size: 11px;
    padding: 2px 8px;
    border-radius: 4px;
    background: var(--surface-2);
  }
}
.charts-account-balance .lbl {
  color: var(--text-sub);
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.charts-account-balance .val { color: var(--text-main, #e8e8ed); font-weight: 600; }
.charts-account-balance .val.up   { color: var(--profit, #52ca74); }
.charts-account-balance .val.down { color: var(--loss, #ed645f); }

/* ── Portfolio hero strip: DD bar + Vault + Effective Balance ────────── */
/* Mirrors dashboard hero-metric tiles using the shared theme tokens:
   --profit/--loss for live P/L, --series-vault/--series-effective for
   the named series, --warning for floating-DD share. */
.charts-hero {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  margin: 4px 0 8px;
}
@media (max-width: 480px) {
  .charts-hero { grid-template-columns: repeat(2, 1fr); }
  /* Days Active is the orphan 3rd narrow tile — span it so row 2 doesn't
     leave a dead cell next to it. */
  .charts-hero-tile:has(.swatch.days) { grid-column: 1 / -1; }
}
@container rail-right (max-width: 300px) {
  .charts-hero { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .charts-hero-tile.wide { grid-column: 1 / -1; }
  .charts-hero-tile:has(.swatch.days) { grid-column: 1 / -1; }
}
.charts-hero-tile {
  background: var(--surface-1);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-card);
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 6px;
  min-width: 0;
  min-height: 54px;
  transition: background 140ms ease, border-color 140ms ease;
}
.charts-hero-tile:hover {
  background: var(--surface-2);
  border-color: var(--border);
}
.charts-hero-tile.wide { grid-column: 1 / -1; }
.charts-hero-tile .lbl {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 9.5px;
  color: var(--text-sub);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  min-width: 0;
}
.charts-hero-tile .lbl > span:not(.swatch) {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* At narrow rail widths (< ~270px), shrink the label so EFFECTIVE / THE VAULT / DAYS ACTIVE
   fit without ellipsis. The hero is a 3-up grid so each tile ≈ rail/3 minus gutter. */
@container rail-right (max-width: 360px) {
  .charts-hero-tile { padding: 7px 6px; }
  .charts-hero-tile .lbl { font-size: 8.5px; letter-spacing: 0; }
}
@container rail-right (max-width: 290px) {
  .charts-hero-tile { padding: 6px 7px; }
  .charts-hero-tile .lbl {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
  }
  .charts-hero-tile .lbl > span:not(.swatch) {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
    font-size: 8px;
    letter-spacing: 0;
  }
}
.charts-hero-tile .lbl .swatch {
  display: inline-block;
  width: 7px; height: 7px;
  flex: 0 0 7px;
  border-radius: 50%;
  box-shadow: 0 0 4px currentColor;
}
.charts-hero-tile .lbl .swatch.eff   { background: var(--series-effective, #40c8e0); color: var(--series-effective, #40c8e0); }
.charts-hero-tile .lbl .swatch.vault { background: var(--series-vault, var(--accent)); color: var(--series-vault, var(--accent)); }
.charts-hero-tile .lbl .swatch.dd    { background: var(--loss, #ed645f); color: var(--loss, #ed645f); }
.charts-hero-tile .lbl .swatch.daily { background: var(--yellow, #ffcc00); color: var(--yellow, #ffcc00); }
.charts-hero-tile .lbl .swatch.days  { background: var(--accent, #0a84ff); color: var(--accent, #0a84ff); }
.charts-hero-tile .val.up   { color: var(--profit, #52ca74); }
.charts-hero-tile .val.down { color: var(--loss, #ed645f); }
.charts-hero-tile .val.dim  { color: var(--text-main, #e8e8ed); }
.charts-hero-tile .val {
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  color: var(--text-main, #e8e8ed);
  line-height: 1.1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
@container rail-right (max-width: 360px) {
  .charts-hero-tile .val { font-size: 13px; }
}
@container rail-right (max-width: 280px) {
  .charts-hero-tile .val { font-size: 12px; }
}
/* The wide DD-Budget tile bundles a secondary "remaining of …" dim span inside .val.
   Allow that secondary text to wrap to the next line instead of getting ellipsed off. */
.charts-hero-tile.wide .val {
  white-space: normal;
  line-height: 1.25;
}
.charts-hero-tile.wide .val .charts-dim {
  display: inline-block;
  white-space: normal;
}
.charts-hero-tile .sub {
  font-size: 10px;
  color: var(--text-sub);
  font-family: var(--font-mono);
  display: flex;
  justify-content: space-between;
}
.charts-hero-dd-bar {
  position: relative;
  height: 5px;
  border-radius: 3px;
  background: var(--surface-3);
  overflow: hidden;
  margin-top: 6px;
}
.charts-hero-dd-bar .seg-realized {
  position: absolute; top: 0; left: 0; bottom: 0;
  background: var(--loss, #ed645f);
}
.charts-hero-dd-bar .seg-floating {
  position: absolute; top: 0; bottom: 0;
  background: var(--yellow, #ffcc00);
}

/* ── Section header status swatch ────────────────────────────────────── */
.charts-section h3 .hdr-swatch {
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  margin-left: 2px;
  vertical-align: middle;
  background: var(--text-dim);
  box-shadow: 0 0 0 2px var(--surface-1);
}
.charts-section h3 .hdr-swatch.up   { background: var(--profit); box-shadow: 0 0 0 2px var(--ds-profit-tint-strong); }
.charts-section h3 .hdr-swatch.down { background: var(--loss);   box-shadow: 0 0 0 2px var(--ds-loss-tint-strong); }
.charts-section h3 .hdr-swatch.warn { background: var(--yellow); box-shadow: 0 0 0 2px var(--ds-warn-tint); }

/* Tier histogram in basket cluster header */
.cluster-hdr .cluster-hist { width: 60px; height: 16px; opacity: 0.85; margin: 0 4px; }

/* Intraday DD consumption sparkline below daily DD bar */
.bg-row .dd-spark { display: block; width: 100%; height: 24px; margin-top: 3px; opacity: 0.92; }

/* Collapsible right-rail sections (click h3 to collapse, state persisted) */
.charts-section h3.collapsible { cursor: pointer; user-select: none; position: relative; padding-right: 18px; }
.charts-section h3.collapsible::after {
  content: '▾';
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%) rotate(0deg);
  transition: transform 120ms ease;
  font-size: 10px;
  color: var(--text-dim);
}
.charts-section.collapsed h3.collapsible::after { transform: translateY(-50%) rotate(-90deg); }
.charts-section.collapsed .charts-section-body { display: none; }
.charts-section h3.collapsible:hover { color: var(--text-main); }

/* MarketState strip — segmented panel above chart. Each segment is a fixed
   1fr column inside a flex container so all six (verdict/conf/news/vol/mult/regime)
   are visually identical-width regardless of value length. */
.charts-ms-strip { display: flex; gap: 0; padding: 0; margin: 0; background: transparent; border: none; border-bottom: 1px solid var(--border-subtle); border-radius: 0; overflow: hidden; }

/* Per-EA narrative strip — sits between MS strip and the chart canvas.
   Two rows: (1) headline + EA badge, (2) status chips as uniform label/value
   cells matching the MS strip's segment grid so the page reads as one
   consistent dashboard rather than two unrelated bars. */
.charts-explainer {
  display: flex;
  flex-direction: column;
  row-gap: 6px;
  margin: 0;
  padding: 6px 10px;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border-subtle);
  border-radius: 0;
  font-size: 11.5px;
  min-width: 0;
}
.charts-explainer .exp-row-head {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
/* Status chip row — CSS grid with `auto-fill, minmax(86px, 1fr)` so chips
   take equal-width cells that wrap to a new row cleanly. No more inline-flex
   chip lengths varying by content; each chip occupies the same column. */
.charts-explainer .exp-row-chips {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 4px;
  min-width: 0;
  color: var(--text-sub);
  line-height: 1.25;
}
.charts-explainer .exp-tag {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  padding: 4px 8px;
  background: var(--surface-2, rgba(255,255,255,0.02));
  border: 1px solid var(--border-subtle, var(--border));
  border-radius: var(--radius-sm);
  color: var(--text-main);
  font-weight: 600;
  font-size: 12px;
  white-space: normal;
  overflow-wrap: anywhere;
  min-width: 0;
}
.charts-explainer .exp-tag.ok    { color: var(--profit); border-color: var(--ds-profit-tint-strong, var(--border-subtle)); }
.charts-explainer .exp-tag.warn  { color: var(--yellow);  border-color: var(--ds-warn-tint-strong,   var(--border-subtle)); }
.charts-explainer .exp-tag.veto  { color: var(--loss);    border-color: var(--ds-loss-tint-strong,   var(--border-subtle)); }
.charts-explainer .exp-tag.muted { color: var(--text-sub); }
.charts-explainer .exp-label {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-sub);
  opacity: 0.9;
  display: block;
  width: 100%;
}
.charts-explainer .exp-headline {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-main);
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.charts-explainer .exp-ea-badge {
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.08em;
  padding: 2px 7px;
  border-radius: 4px;
  text-transform: uppercase;
  color: #1a1a1a;
  flex: 0 0 auto;
}
/* Dark text reads on bright dark-mode yellow (rgb 255,204,0). In light mode
   --yellow shifts to rgb(140,115,0) — dark olive — so swap to white text.
   Accent blue / purple use white in both modes. */
.charts-explainer .exp-ea-badge.gs  { background: var(--yellow); }
:root.light .charts-explainer .exp-ea-badge.gs { color: #fff; }
.charts-explainer .exp-ea-badge.cfd { background: var(--accent); color: #fff; }
.charts-explainer .exp-ea-badge.fx  { background: var(--purple); color: #fff; }
.charts-explainer .exp-ea-badge.msu { background: var(--text-sub); color: var(--bg-main); }
@media (max-width: 480px) {
  .charts-explainer { font-size: 10.5px; padding: 6px 8px; row-gap: 3px; }
  .charts-explainer .exp-headline { font-size: 12px; }
  .charts-explainer .exp-row-chips { gap: 2px 10px; }
}
.ms-seg { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 1px; padding: 5px 8px; border-right: 1px solid var(--border-subtle); position: relative; }
.ms-seg:last-child { border-right: none; }
.ms-seg .ms-seg-lbl { font-size: 9px; font-weight: 700; letter-spacing: 0.6px; color: var(--text-sub); text-transform: uppercase; }
.ms-seg .ms-seg-val { font-size: 13px; font-weight: 700; color: var(--text-main); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.ms-seg.up   .ms-seg-val { color: var(--profit, #52ca74); }
.ms-seg.down .ms-seg-val { color: var(--loss, #ed645f); }
.ms-seg.warn .ms-seg-val { color: var(--yellow, #ffcc00); }
.ms-seg.dim  .ms-seg-val { color: var(--text-main); }
/* Light-mode .ms-seg inherits var(--text-sub/main) cleanly — no override
   needed. Earlier hardcoded near-black overrides were inconsistent with the
   theme's softer rgb(85,85,95) ink. */
.ms-seg .ms-seg-bar { display: block; align-self: stretch; width: auto; height: 3px; background: var(--surface-3); border-radius: 1px; margin-top: 3px; overflow: hidden; }
.ms-seg .ms-seg-bar-fill { display: block; height: 100%; background: var(--text-sub); transition: width 200ms ease; }
.ms-seg .ms-seg-bar-fill.pos { background: var(--profit, #52ca74); }
.ms-seg .ms-seg-bar-fill.warn { background: var(--yellow, #ffcc00); }
.ms-seg .ms-seg-bar-fill.neg { background: var(--loss, #ed645f); }
@media (max-width: 768px) {
  .ms-seg .ms-seg-lbl { font-size: 8px; }
  .ms-seg .ms-seg-val { font-size: 11px; }
  .ms-seg { padding: 4px 6px; }
}

/* Rail resize handles (desktop only — overlay drawers on mobile don't need it) */
.rail-resize {
  position: absolute;
  top: 0;
  width: 6px;
  height: 100%;
  cursor: col-resize;
  z-index: 50;
  background: transparent;
  transition: background 120ms ease;
}
.rail-resize:hover, .rail-resize.dragging { background: var(--ds-accent-border); }
.rail-resize-left  { right: -3px; }
.rail-resize-right { left: -3px; }
@media (max-width: 1024px) { .rail-resize { display: none; } }

/* PML lifespan ring next to leg ticket */
.pml-ring { vertical-align: middle; margin-right: 3px; }
.leg-ticket { display: inline-flex; align-items: center; gap: 2px; }

/* Decision filter chip + clear */
.dec-filter-bar { display: flex; align-items: center; gap: 6px; margin: 6px 0; padding: 4px 8px; background: var(--ds-accent-tint); border: 1px solid var(--ds-accent-border); border-radius: 4px; font-size: 11px; }
.dec-filter-name { font-family: var(--font-mono); color: var(--accent, #0a84ff); font-weight: 600; }
.dec-filter-clear { margin-left: auto; background: transparent; border: 0; color: var(--text-dim); cursor: pointer; font-size: 12px; padding: 0 4px; }
.dec-filter-clear:hover { color: var(--text-main, #fff); }

/* Decision pattern column ellipsis */
.row-dec .dec-pat { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; }
.row-dec .dec-pat:hover { color: var(--accent, #0a84ff); }
/* Direction-aware pattern chip: same pattern reads green/red depending on
   whether the EA is calling a long or a short. Keeps the user from having to
   decode the arrow + pattern name together. */
.row-dec .dec-pat.dir-buy  { color: var(--profit, #52ca74); font-weight: 600; }
.row-dec .dec-pat.dir-sell { color: var(--loss, #ed645f); font-weight: 600; }

/* Last-decision-ago label on instance leaf (when fresher than last_seen) */
.charts-instance-leaf .name .dec-ago { color: var(--profit, #52ca74); font-weight: 500; opacity: 0.85; }
.charts-instance-leaf .name .last-seen,
.charts-instance-leaf .name .dec-ago {
  font-size: 10px;
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  display: block;
  color: var(--text-subtle, var(--text-sub));
  letter-spacing: 0.02em;
}

/* Ticket copy feedback */
.leg-ticket .copied, .lvl-ticket .copied { color: var(--profit, #52ca74); font-family: inherit; }
.leg-ticket .copied.copy-err, .lvl-ticket .copied.copy-err { color: var(--loss, #e85d6b); }

/* Inline retry button for failed loads (instances list, etc). */
.charts-retry-btn {
  margin-left: 8px;
  padding: 2px 8px;
  font-size: 11px;
  background: var(--accent, #4a8eff);
  color: #fff;
  border: none;
  border-radius: 3px;
  cursor: pointer;
}
.charts-retry-btn:hover { filter: brightness(1.1); }
.charts-retry-btn:focus-visible { outline: 2px solid var(--accent, #4a8eff); outline-offset: 2px; }

/* Stream status caption next to the dot. nowrap keeps "Live · 5s" on a
   single line so it can't push the meta string onto a second row inside
   the 44px topbar. */
.charts-stream-caption {
  font-size: 10px;
  margin-left: 2px;
  min-width: 56px;
  display: inline-block;
  font-family: var(--font-mono);
  white-space: nowrap;
  flex: 0 0 auto;
}

/* Tick flash on stream dot — quick scale pulse when a tick lands */
@keyframes cfin-tickflash {
  0%   { transform: scale(1);   filter: brightness(1); }
  35%  { transform: scale(1.6); filter: brightness(1.6); }
  100% { transform: scale(1);   filter: brightness(1); }
}
.charts-stream-dot.tick-flash { animation: cfin-tickflash 350ms ease-out; }

/* Cluster header next-tier ETA line */
.cluster-next { font-size: 10px; padding: 2px 0 4px 4px; font-family: var(--font-mono); }
.cluster-next.cluster-locked { color: var(--purple, #bf5af2); font-weight: 600; }

/* Levels: breakeven tick on the SL→TP bar */
.lvl-bar-be {
  position: absolute;
  top: -2px;
  width: 2px;
  height: calc(100% + 4px);
  background: var(--purple, #bf5af2);
  border-radius: 1px;
  box-shadow: 0 0 4px rgba(191,90,250,0.7);
  transform: translateX(-50%);
}
.lvl-bar { position: relative; }

/* ---------- Quick filter chips ---------- */
.charts-quickfilters {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
  margin-top: 6px;
}
.qf-chip {
  font: 10px/1 var(--font-sans);
  padding: 3px 7px;
  border-radius: 999px;
  background: var(--surface-3);
  color: var(--text-sub);
  border: 1px solid var(--border);
  cursor: pointer;
  user-select: none;
  transition: background 0.12s, color 0.12s;
}
.qf-chip:hover { background: var(--surface-hover); color: var(--text-main); }
.qf-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.qf-chip.active {
  background: var(--ds-accent-tint-strong);
  border-color: var(--ds-accent-border);
  color: var(--accent);
}
/* Live count badge appended by rail.js#updateQuickFilterCounts so the
   user can see the size of each slice without clicking through. */
.charts-quickfilters .qf-chip .qf-count {
  display: inline-block;
  margin-left: 5px;
  padding: 1px 5px;
  font: 9px/1 var(--font-mono);
  background: var(--surface-2);
  border-radius: 999px;
  color: var(--text-sub);
  vertical-align: 1px;
  min-width: 14px;
  text-align: center;
}
.charts-quickfilters .qf-chip.active .qf-count {
  background: var(--bg-base);
  color: var(--accent);
}
.charts-quickfilters .qf-chip .qf-count.qf-count-zero {
  opacity: 0.45;
}

/* Auth-failure messaging now uses the standard .charts-notice stack via
   rail.js#showAuthBanner — see .cn-action below for the inline CTA style. */

/* ---------- Decision heatmap legend ---------- */
.dec-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 10px;
  margin-top: 4px;
  font: 9.5px/1.2 var(--font-mono);
  color: var(--text-sub);
}
.dec-legend-chip { display: inline-flex; align-items: center; gap: 4px; }
.dec-legend-dot {
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
}

/* ---------- Stream paused / reconnecting visuals ---------- */
.charts-stream-dot.paused {
  background: var(--text-dim);
  box-shadow: none;
  animation: none;
}
.charts-stream-dot.error {
  background: var(--loss);
  box-shadow: 0 0 6px var(--ds-loss-glow);
  animation: cfin-stream-pulse 1.2s ease-in-out infinite;
}
.charts-stream-dot.idle {
  background: var(--text-subtle, var(--text-dim));
  box-shadow: none;
  animation: none;
  opacity: 0.6;
}
@keyframes cfin-stream-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}

/* ---------- Market-closed banner (overlaid over chart pane) ---------- */
/* Legacy chart-pane banner replaced by bottom-up notice stack (showNotice). */
/* ---------- Notification stack (top-right) ----------
   Lightweight, queue-driven notices for transient conditions like
   "week soft-close in 1h", "T1 news in 10m", "bar closes in 30s".
   Distinct from the bottom error toast: those are JS exceptions; these
   are scheduled UX cues. */
/* Match the dashboard's .notif-banner xbox-pill: a single-line, bottom-centered
   pill (height 36, radius 100, blurred) that stacks vertically when several
   notices coexist. Reuses --banner-* and --notif-banner-icon-* tokens so the
   charts page is visually identical to the rest of the app. */
.charts-notice-stack {
  position: fixed;
  /* The charts page has a fixed bottom drawer (~28px collapsed, 280px
     expanded). Sit just above the collapsed handle so notices never hide
     under it. The expanded-state stack still rides at 40px which is fine —
     the drawer body is opaque and the user has dismissed focus from the
     top half of the screen anyway. */
  bottom: 40px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column-reverse;
  gap: var(--banner-stack-gap, 10px);
  z-index: 1001;
  pointer-events: none;
  align-items: center;
  max-width: min(94vw, 680px);
}
.charts-notice-bulk {
  pointer-events: auto;
  background: var(--bg-elev, var(--bg-panel));
  color: var(--text-dim);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 4px 12px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.04em;
  cursor: pointer;
  opacity: 0.85;
  transition: opacity 120ms;
}
.charts-notice-bulk:hover,
.charts-notice-bulk:focus-visible {
  opacity: 1;
  color: var(--text-main);
  outline: 1px solid var(--border-strong, var(--border));
  outline-offset: 1px;
}
.charts-notice {
  position: relative;
  background: var(--card-bg, var(--bg-panel));
  color: var(--text-main);
  border: 1px solid var(--border);
  height: var(--banner-height, 36px);
  padding: 0 12px 0 16px;
  font-size: var(--banner-font-size, 12px);
  font-weight: var(--banner-font-weight, 500);
  line-height: var(--banner-line-height, 1);
  letter-spacing: var(--banner-letter-spacing, 0.02em);
  border-radius: var(--banner-radius, 100px);
  box-shadow: var(--elev-float);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--banner-gap, 8px);
  pointer-events: auto;
  max-width: 100%;
  box-sizing: border-box;
  opacity: 0;
  animation: notifBallExpand 0.5s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
.charts-notice.leaving {
  animation: notifBallCollapse 0.45s cubic-bezier(0.55, 0, 1, 0.45) forwards;
}
.charts-notice .cn-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--ds-accent-tint);
  color: var(--accent);
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
}
.charts-notice.info .cn-icon { background: var(--ds-accent-tint); color: var(--accent); }
.charts-notice.ok   .cn-icon { background: var(--ds-profit-tint); color: var(--profit); }
.charts-notice.warn .cn-icon { background: color-mix(in srgb, var(--orange) 14%, transparent); color: var(--orange); }
.charts-notice.crit .cn-icon { background: var(--ds-loss-tint);   color: var(--loss); }
.charts-notice.info { border-left: 3px solid var(--accent); }
.charts-notice.ok   { border-left: 3px solid var(--profit); }
.charts-notice.warn { border-left: 3px solid var(--orange); }
.charts-notice.crit { border-left: 3px solid var(--loss); }
/* Persistent banners need user attention — bolden the border and lift slightly
   so they don't get visually lost in a stack of transient toasts. */
.charts-notice.persistent { border-left-width: 4px; box-shadow: var(--elev-float); }
.charts-notice .cn-body {
  display: flex;
  align-items: baseline;
  gap: 6px;
  min-width: 0;
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.charts-notice .cn-title { font-weight: 600; overflow: hidden; text-overflow: ellipsis; }
.charts-notice .cn-sub   { color: var(--text-sub); font-weight: 400; overflow: hidden; text-overflow: ellipsis; }
.charts-notice .cn-sub::before { content: '·'; margin-right: 6px; opacity: 0.6; }
.charts-notice .cn-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 0;
  background: transparent;
  color: var(--text-sub);
  cursor: pointer;
  padding: 0;
  transition: background var(--transition, 0.15s ease), color var(--transition, 0.15s ease);
  font-size: 14px;
  line-height: 1;
  flex-shrink: 0;
}
.charts-notice .cn-close:hover {
  background: var(--ds-loss-tint);
  color: var(--loss);
}
.charts-notice .cn-close:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.charts-notice .cn-action {
  display: inline-flex;
  align-items: center;
  height: 22px;
  padding: 0 10px;
  margin-left: 4px;
  border-radius: var(--radius-pill);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-decoration: none;
  color: var(--text-main);
  background: var(--ds-accent-tint);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  transition: background var(--transition, 0.15s ease), color var(--transition, 0.15s ease);
  flex-shrink: 0;
  pointer-events: auto;
}
.charts-notice .cn-action:hover { background: var(--accent); color: #fff; }
.charts-notice .cn-action:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.charts-notice.crit .cn-action {
  background: var(--ds-loss-tint);
  border-color: color-mix(in srgb, var(--loss) 40%, transparent);
  color: var(--loss);
}
.charts-notice.crit .cn-action:hover { background: var(--loss); color: #fff; }
@media (max-width: 640px) {
  .charts-notice { padding: 0 10px 0 12px; }
}

/* When any .charts-notice is on screen, push the alpha banner above the
   notice stack so they don't overlap at the bottom of the viewport. Mirrors
   the body.notif-banner-active pattern used by the dashboard's notif-banner.
   Stack bottom (40px) + banner-height (36px) + stack-gap (10px) = 86px. */
.beta-banner { transition: bottom 0.4s cubic-bezier(0.16, 1, 0.3, 1); }
body.charts-notice-active .beta-banner {
  bottom: calc(40px + var(--banner-height) + var(--banner-stack-gap)) !important;
}

/* ---------- Error toast (transient surface for JS exceptions) ---------- */
.charts-error-toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translate(-50%, 20px);
  background: color-mix(in srgb, var(--loss) 95%, transparent);
  color: #fff;
  font: 12px/1.4 var(--font-sans);
  padding: 8px 14px;
  border-radius: var(--radius-card);
  box-shadow: var(--elev-float);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s, transform 0.2s;
  max-width: min(560px, calc(100vw - 32px));
  z-index: 9999;
  text-align: center;
}
.charts-error-toast.visible {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* WCAG 2.3.3 — respect prefers-reduced-motion. Indefinite-loop pulses
   (live stream dot, hot instance leaf, overlay live-edge) can trigger
   vestibular discomfort. Disable them but keep the colors so status is
   still conveyed (green = live, red = error). Brief one-shot feedback
   (tick flash, row-dec-fresh, legend-in, notifBall*) is left alone —
   <500ms transitions are below WCAG's animation threshold. */
@media (prefers-reduced-motion: reduce) {
  .charts-stream-dot.live,
  .charts-stream-dot.error,
  .charts-stream-dot.live.stale,
  .charts-instance-leaf .dot.hot,
  .charts-overlay-svg .live-edge {
    animation: none;
  }
}

/* ─────────────────────────────────────────────────────────────────────
   Overlay toggle bar (chart canvas decluttering)
   ───────────────────────────────────────────────────────────────────── */
/* Overlay toggle bar — sits between the MS strip and the chart canvas.
   Uses the same .qf-chip base style as the left-rail quick filters, with
   a small "Overlays:" label so users see at a glance what these chips do.
   Container is a hairline glass strip rather than a full card so it sits
   flush against the chart without adding visual weight. */
.charts-overlay-bar {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  margin: 0;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border-subtle, var(--border));
  border-radius: 0;
}
/* Narrow viewports: allow horizontal scroll instead of wrap, and surface a
   right-edge fade + chevron hint so users don't miss off-screen chips. */
@media (max-width: 900px) {
  .charts-overlay-bar {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .charts-overlay-bar::-webkit-scrollbar { display: none; }
  .charts-overlay-bar::after {
    content: '\203A';
    position: absolute;
    top: 0;
    right: 0;
    width: 28px;
    height: 100%;
    pointer-events: none;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding-right: 6px;
    color: var(--text-sub);
    font-family: var(--font-sans);
    font-size: 14px;
    background: linear-gradient(to right, transparent, var(--bg-card) 70%);
  }
}
/* Per-group labels render via .ov-group::before so each cluster reads as
   a distinct functional group (News / Protection / Markers / Context)
   rather than one long blur of chips. */
.charts-overlay-bar .ov-group {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding-right: 8px;
  margin-right: 4px;
  border-right: 1px solid var(--border-subtle, var(--border));
}
.charts-overlay-bar .ov-group:last-child { border-right: none; margin-right: 0; padding-right: 0; }
.charts-overlay-bar .ov-group::before {
  content: attr(aria-label);
  font: 9px/1 var(--font-sans);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-sub);
  opacity: 0.75;
  white-space: nowrap;
  margin-right: 4px;
}
/* Inherit the rail's .qf-chip look — only override the toggle state so
   aria-pressed="true" gives the same affordance as .qf-chip.active does
   for the rail quick-filters. */
.charts-overlay-bar .qf-chip {
  padding: 3px 9px;
  font-size: 10.5px;
}
.charts-overlay-bar .qf-chip[aria-pressed="true"] {
  background: var(--ds-accent-tint-strong, rgba(10, 132, 255, 0.18));
  border-color: var(--ds-accent-border, var(--accent));
  color: var(--accent);
  font-weight: 600;
}
.charts-overlay-bar .qf-chip[aria-pressed="false"] {
  /* Dim the off-state slightly so on/off is unambiguous at a glance. */
  opacity: 0.78;
}
.charts-overlay-bar .qf-chip[aria-pressed="false"]:hover { opacity: 1; }
.charts-overlay-bar .qf-chip.kb-flash {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  transition: outline-color 200ms ease;
}

/* Tier-gated news visibility — line + label + top blackout cap.
   News tier mapping: 1=high, 2=medium, 3=low. */
.charts-shell[data-ov-news-h="off"] .news-tick.tier-1,
.charts-shell[data-ov-news-h="off"] .news-label.tier-1,
.charts-shell[data-ov-news-h="off"] .news-cap.tier-1 { display: none; }
.charts-shell[data-ov-news-m="off"] .news-tick.tier-2,
.charts-shell[data-ov-news-m="off"] .news-label.tier-2,
.charts-shell[data-ov-news-m="off"] .news-cap.tier-2 { display: none; }
.charts-shell[data-ov-news-l="off"] .news-tick.tier-3,
.charts-shell[data-ov-news-l="off"] .news-label.tier-3,
.charts-shell[data-ov-news-l="off"] .news-cap.tier-3 { display: none; }

/* ─────────────────────────────────────────────────────────────────────
   Typography + density polish lifted from the landing .cp-frame overrides
   so the real /charts surface matches the website-themed preview.
   Source of truth for these tweaks lives in landing.css under .cp-frame —
   when changing density tokens, update both.
   ───────────────────────────────────────────────────────────────────── */
.charts-topbar { min-height: 52px; padding: 0 14px; }
.charts-instance-title { font-size: 13.5px; }
.charts-topbar .charts-meta { font-size: 11.5px; opacity: 0.9; }
.charts-label { font-size: 11px; }
.charts-select { font-size: 12px; min-width: 200px; }
.cdh-count { color: var(--accent); font-feature-settings: 'tnum' 1; font-weight: 600; margin-left: 4px; }
.cdh-filters { margin-left: auto; display: flex; gap: 4px; }

/* Drawer handle reads better with the preview's letter-spacing + chip-style
   level filters. cdh-* tokens already exist in charts.css; this just lifts
   the polish styling. */
.cdh-chev  { color: var(--text-sub); font-size: 14px; }
.cdh-label { color: var(--text-main); font-weight: 600; letter-spacing: 0.04em; }

/* MS strip header band — flush inside .charts-main glass card, separated
   from siblings by a single bottom hairline. */
.charts-ms-strip { margin: 0; display: flex; }

/* Right-rail section bodies — denser inside the website-themed shell.
   padding-left preserves the 26px gap that keeps title text clear of the
   accent gradient bar (.charts-section h3::before). Earlier `padding: 6px 10px`
   shorthand wiped that left-padding and made every rail/orders-row title read
   as glued to the bar. */
.charts-rail-right { overflow-y: auto; }
.charts-section { margin-bottom: 8px; }
.charts-section h3 { font-size: 10.5px; padding: 6px 10px 6px 26px; }
.charts-section-body { padding: 8px 10px; font-size: 11.5px; }

/* Instance list — readability tuning to match preview. */
.charts-instance-list { padding: 4px; gap: 2px; }
.charts-instance-list li { padding: 7px 8px; font-size: 11.5px; gap: 8px; }
.charts-instance-list .name .top { gap: 6px; font-size: 11.5px; }
.charts-instance-list .name .meta { font-size: 10.5px; opacity: 0.85; }
.charts-instance-list .pnl { font-size: 11.5px; font-weight: 600; }
.charts-instance-list .inst-spark { color: var(--text-dim); opacity: 0.6; }
.charts-instance-list li.active .inst-spark { color: var(--accent); opacity: 1; }

/* Quick filters — chip sizing parity with preview. */
.charts-quickfilters { gap: 4px; padding: 4px; flex-wrap: wrap; }
.qf-chip { padding: 3px 8px; font-size: 10.5px; }

/* ─── Below-chart Open Positions + Pending Orders panel ─────────────────
   Lives inside <main class="charts-main"> below #charts-chart. Two
   .charts-section panels side-by-side on desktop, stacked on narrow
   viewports. Mirrors the right-rail .charts-section visual family so the
   new surface reads as part of the same chart-page UI. */
.charts-orders-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 10px;
  padding: 0 4px 10px;
  margin-top: 8px;
}
.charts-orders-row[hidden] { display: none; }
.charts-orders-panel { margin-bottom: 0; }
.charts-orders-panel h3 {
  /* Stretch the inner span pair so the orders-meta count sits flush-right
     against the header bar — mirrors basket header's swatch placement. */
  justify-content: space-between;
}
.charts-orders-meta {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--text-sub);
  text-transform: none;
}
.charts-orders-meta .pnl.up   { color: var(--profit); }
.charts-orders-meta .pnl.down { color: var(--loss); }
/* Middle column of row-pos: lots + entry + pills. Row-pos already grids
   into [side | flex | pnl]; we just need pill styling for the middle. */
.charts-orders-panel .row-pos-mid {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: baseline;
  min-width: 0;
}
.charts-orders-panel .row-pos-mid .lots { font-weight: 600; }
.charts-orders-panel .tier-pill,
.charts-orders-panel .lock-pill,
.charts-orders-panel .kind-pill {
  font-size: 9px;
  font-weight: 700;
  padding: 1px 4px;
  border-radius: 3px;
  letter-spacing: 0.04em;
}
.charts-orders-panel .tier-pill {
  background: var(--surface-2);
  color: var(--text-sub);
  border: 1px solid var(--border-subtle);
}
.charts-orders-panel .lock-pill.be {
  background: var(--ds-warn-tint, rgba(255, 196, 0, 0.18));
  color: var(--yellow, #f5c64a);
}
.charts-orders-panel .lock-pill.trail {
  background: var(--ds-profit-tint, rgba(82, 202, 116, 0.18));
  color: var(--profit);
}
.charts-orders-panel .kind-pill {
  background: var(--surface-2);
  color: var(--text-sub);
  border: 1px solid var(--border-subtle);
}
/* Narrow viewports — stack vertically. Below the rail-toggle breakpoint
   the side rails collapse, so the main pane gets the full width and a
   2-column orders row would crush the row-pos line into wrap. */
@media (max-width: 900px) {
  .charts-orders-row {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ------------------------------------------------------------------
   Left-rail visual polish (2026-05-20 — unified leaf-row look)
   ------------------------------------------------------------------ */

/* Group headers — slightly bigger, more breathing, gradient accent strip
   replaces the dimmer inset shadow for a clearer EA-family identity. */
.charts-instance-list .charts-instance-group {
  padding: 9px 12px 8px 16px;
  font-size: 10.5px;
  letter-spacing: 0.08em;
  background: linear-gradient(180deg, var(--surface-2) 0%, var(--bg-panel) 100%);
}
.charts-instance-list .charts-instance-group .grp-name {
  font-weight: 800;
  font-size: 11px;
}
.charts-instance-list .charts-instance-group .grp-legs,
.charts-instance-list .charts-instance-group .grp-count {
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--surface-3);
  color: var(--text-sub);
  font-weight: 600;
}
.charts-instance-list .charts-instance-group .grp-legs {
  background: var(--ds-accent-tint-strong);
  color: var(--accent);
}

/* Leaf rows — 2-line layout. Row 1: dot · EA · SYM · TF · tier | pnl pill.
   Row 2: sparkline · meta-text  |  realized chip. */
.charts-instance-list .charts-instance-leaf {
  padding: 8px 12px 8px 20px;
  align-items: stretch;
  gap: 10px;
}
.charts-instance-list .charts-instance-leaf > .dot {
  margin-top: 6px;
}
.charts-instance-list .charts-instance-leaf .name {
  gap: 3px;
  justify-content: center;
}
.charts-instance-list .charts-instance-leaf .name .top {
  align-items: center;
  gap: 7px;
  font-size: 12.5px;
}
/* EA code pill (GS / CFD / RB / UT) — uniform tinted pill instead of
   the old underlined accent text. Reads as a peer to the TF pill. */
.charts-instance-list .charts-instance-leaf .name .ea {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 4px;
  background: var(--ds-accent-tint-strong, rgba(10,132,255,0.18));
  color: var(--accent, #0a84ff);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  line-height: 1.45;
  flex: 0 0 auto;
}
.charts-instance-list .charts-instance-leaf .name .sym {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.charts-instance-list .charts-instance-leaf .name .tf {
  font-size: 9.5px;
  padding: 1px 6px;
  border-radius: 4px;
  background: var(--surface-3);
  color: var(--text-sub);
  font-weight: 600;
  letter-spacing: 0.04em;
  line-height: 1.45;
  flex: 0 0 auto;
}
/* TF chips on the collapsed (one-row-per-symbol) leaf. The EA exposes
   multiple TFs per symbol — render each as a compact chip. The chip with
   live PML data gets an accent ring so it stands out. */
.charts-instance-list .charts-instance-leaf .name .tf-chips {
  display: inline-flex;
  gap: 3px;
  flex: 0 0 auto;
  flex-wrap: nowrap;
  align-items: center;
}
.charts-instance-list .charts-instance-leaf .name .tf-chip {
  font-size: 9.5px;
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--surface-3);
  color: var(--text-sub);
  font-weight: 700;
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  line-height: 1.3;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background 100ms ease, color 100ms ease, border-color 100ms ease, transform 80ms ease;
}
.charts-instance-list .charts-instance-leaf .name .tf-chip:hover {
  background: color-mix(in srgb, var(--accent) 8%, var(--surface-3));
  color: var(--text-main);
  border-color: color-mix(in srgb, var(--accent) 25%, transparent);
}
.charts-instance-list .charts-instance-leaf .name .tf-chip:active {
  transform: translateY(0.5px);
}
.charts-instance-list .charts-instance-leaf .name .tf-chip.has-pml {
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 35%, transparent);
}
.charts-instance-list .charts-instance-leaf .name .tf-chip.selected {
  background: var(--accent);
  color: var(--surface-1);
  border-color: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 28%, transparent);
}
/* Meta line — sparkline left, text right. Both compact. */
.charts-instance-list .charts-instance-leaf .name .meta {
  font-size: 10.5px;
  color: var(--text-sub);
  gap: 7px;
  line-height: 1.3;
}
.charts-instance-list .charts-instance-leaf .name .meta .inst-spark {
  flex: 0 0 48px;
  width: 48px;
  height: 13px;
  opacity: 0.95;
  border-radius: 2px;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--surface-3) 60%, transparent) 0%,
    transparent 100%);
}
.charts-instance-list .charts-instance-leaf .name .meta .meta-text {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Right column — pnl + realized stack tightly, aligned to right edge. */
.charts-instance-list .charts-instance-leaf .rail-right {
  gap: 3px;
  justify-content: center;
  min-width: 50px;
}
.charts-instance-list .charts-instance-leaf .rail-right .pnl {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.01em;
}
.charts-instance-list .charts-instance-leaf .rail-right .pnl-today {
  font-size: 9.5px;
  padding: 1px 6px;
  border-radius: 4px;
  font-weight: 600;
}

/* Tier badge — match other pill chips, no more flat yellow square. */
.charts-instance-list .charts-instance-leaf .tier-badge {
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.04em;
  background: var(--ds-warn-tint-strong, rgba(255,204,0,0.22));
  color: var(--yellow, #ffcc00);
}

/* Hover + active feedback — soft accent tint + 1px-shift removed (was jumpy). */
.charts-instance-list .charts-instance-leaf:hover {
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--accent) 4%, transparent) 0%,
    transparent 100%);
}
.charts-instance-list .charts-instance-leaf.active {
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--accent) 10%, transparent) 0%,
    color-mix(in srgb, var(--accent) 2%, transparent) 100%);
}

/* No-bars rows — keep the dim but apply it to the whole row, not just the
   ::after hint. Reads as "tap-disabled" without grey-flat-fill. */
.charts-instance-list .charts-instance-leaf.no-bars {
  opacity: 0.55;
}
.charts-instance-list .charts-instance-leaf.no-bars:hover {
  opacity: 0.75;
}

/* SL/TP/now chips on open-positions rows + basket legs (Batch 17) — surface
   server-provided p.sl/p.tp/p.current that were previously hidden. Three
   muted inline chips with hairline borders; render `—` when null. */
.charts-orders-panel .row-pos .row-pos-chips {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-left: 4px;
}
.charts-orders-panel .row-pos .row-pos-chip {
  display: inline-flex;
  align-items: center;
  height: 14px;
  padding: 0 5px;
  border-radius: 3px;
  border: 1px solid var(--border-soft, rgba(255,255,255,0.08));
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.basket-leg .basket-leg-row3 {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 2px;
  font-size: 10px;
}
.basket-leg .basket-leg-chip {
  display: inline-flex;
  align-items: center;
  padding: 0 5px;
  height: 14px;
  border-radius: 3px;
  border: 1px solid var(--border-soft, rgba(255,255,255,0.08));
  white-space: nowrap;
}
