/* Onism AI Trading Platform — light theme, Vodafone red accent */
:root {
  --bg: #f2f3f5;
  --bg-elev: #ffffff;
  --bg-elev-2: #f6f7f9;
  --line: #e3e4e9;
  --line-strong: #d3d5dd;
  --text: #25282b;            /* Vodafone grey */
  --text-dim: #666c74;
  --muted: #9aa0a8;
  --accent: #e60000;          /* Vodafone red - brand/CTA only */
  --accent-strong: #bd0000;
  --danger: #c62828;          /* dedicated loss/negative-value red - distinct
                                  from the brand accent so gains vs. losses
                                  never compete visually with primary CTAs */
  --danger-strong: #8e1c1c;
  --go: #007c92;              /* aqua blue */
  --warn: #eb6100;            /* fresh orange */
  --ok: #2f8132;
  --radius: 12px;
  --shadow: 0 1px 2px rgba(37, 40, 43, .06), 0 10px 30px rgba(37, 40, 43, .07);
  --mono: "SF Mono", "JetBrains Mono", "Consolas", ui-monospace, monospace;
  color-scheme: light;
}

/* Dark mode theme */
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #1a1a1f;
    --bg-elev: #242429;
    --bg-elev-2: #2d2d34;
    --line: #3d3d44;
    --line-strong: #4d4d56;
    --text: #e4e4e8;
    --text-dim: #a8aab0;
    --muted: #7a7e86;
    --accent: #ff4444;
    --accent-strong: #ff2222;
    --danger: #ff6b6b;
    --danger-strong: #e04848;
    --go: #00d4ff;
    --warn: #ffaa44;
    --ok: #44dd44;
    color-scheme: dark;
  }
}

html.dark-mode {
  color-scheme: dark;
}

html.dark-mode,
html.dark-mode body {
  --bg: #0f0f12;
  --bg-elev: #1a1a1f;
  --bg-elev-2: #252530;
  --line: #3a3a42;
  --line-strong: #4a4a54;
  --text: #e8e8ec;
  --text-dim: #a0a0aa;
  --muted: #707078;
  --accent: #ff3333;
  --accent-strong: #ff1111;
  --danger: #ff6b6b;
  --danger-strong: #e04848;
  --go: #00d9ff;
  --warn: #ffb84d;
  --ok: #4dd94d;
}

/* Dark mode overrides for specific elements */
html.dark-mode .btn {
  background: #2a2a32;
  border-color: #4a4a54;
  color: #e8e8ec;
}

html.dark-mode .btn:hover:not(:disabled) {
  background: #35353f;
  border-color: #5a5a64;
}

html.dark-mode .btn-primary {
  background: #ff3333;
  border-color: #ff1111;
  color: #fff;
}

html.dark-mode .btn-primary:hover:not(:disabled) {
  background: #ff1111;
  border-color: #ff0000;
}

html.dark-mode .btn-mini {
  background: #2a2a32;
  border-color: #4a4a54;
  color: #e8e8ec;
}

html.dark-mode .btn-go {
  background: transparent;
  border-color: #4a7a7f;
  color: #00d9ff;
}

html.dark-mode .btn-go:hover:not(:disabled) {
  background: #003a3f;
}

html.dark-mode .btn-stop {
  background: transparent;
  border-color: #7a4a4f;
  color: #ff6666;
}

html.dark-mode .btn-stop:hover:not(:disabled) {
  background: #3a1a1f;
}

html.dark-mode .btn-warn {
  background: transparent;
  border-color: #7a6a3a;
  color: #ffb84d;
}

html.dark-mode .btn-warn:hover:not(:disabled) {
  background: #3a2a0a;
}

html.dark-mode .btn-logout {
  background: transparent;
  border-color: #7a4a4f;
  color: #ff6666;
}

html.dark-mode .btn-logout:hover:not(:disabled) {
  background: #3a1a1f;
}

html.dark-mode .btn-icon {
  background: transparent;
  border-color: #4a4a54;
  color: #a0a0aa;
}

html.dark-mode .btn-icon:hover:not(:disabled) {
  background: #2a2a32;
  color: #e8e8ec;
}

html.dark-mode .btn-icon.active {
  background: #ff3333;
  color: #fff;
  border-color: #ff1111;
}

html.dark-mode input[type="text"],
html.dark-mode input[type="password"],
html.dark-mode input[type="number"],
html.dark-mode textarea,
html.dark-mode select {
  background: #1a1a1f;
  color: #e8e8ec;
  border-color: #4a4a54;
}

html.dark-mode input:focus,
html.dark-mode textarea:focus,
html.dark-mode select:focus {
  border-color: #ff3333;
  outline-color: #ff3333;
}

html.dark-mode .card {
  background: #1a1a1f;
  border-color: #3a3a42;
}

html.dark-mode .card:hover {
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3), 0 12px 40px rgba(0, 0, 0, 0.2);
}

html.dark-mode table tr:hover td {
  background: #252530;
}

html.dark-mode th {
  background: #252530;
  border-color: #3a3a42;
}

html.dark-mode .pill-flat {
  background: #2a2a32;
  color: #b0b0ba;
}

html.dark-mode .pill-pending {
  background: #3a2a0a;
  color: #ffb84d;
}

html.dark-mode .pill-long {
  background: #0a2a0a;
  color: #4dd94d;
}

html.dark-mode .pill-blocked {
  background: #3a1a1f;
  color: #ff6666;
}

html.dark-mode .pbadge.b-managed {
  background: #1a2a4a;
  color: #6daaff;
}

html.dark-mode .pbadge.b-protected {
  background: #0a2a0a;
  color: #4dd94d;
}

html.dark-mode .pbadge.b-naked {
  background: #3a1a1f;
  color: #ff6666;
}

html.dark-mode .pbadge.b-ignored {
  background: #2a2a32;
  color: #8a8a94;
}

html.dark-mode .pos-badge.b-managed {
  background: #1a2a4a;
  color: #6daaff;
}

html.dark-mode .pos-badge.b-protected {
  background: #0a2a0a;
  color: #4dd94d;
}

html.dark-mode .pos-badge.b-naked {
  background: #3a1a1f;
  color: #ff6666;
}

html.dark-mode .pos-badge.b-ignored {
  background: #2a2a32;
  color: #8a8a94;
}

html.dark-mode .section-tag.tag-ai {
  background: #1a2a4a;
  color: #6daaff;
  border-color: #6daaff;
}

html.dark-mode .section-tag.tag-api {
  background: #3a2a0a;
  color: #ffb84d;
  border-color: #ffb84d;
}

html.dark-mode .section-tag.tag-ext {
  background: #0f3a1a;
  color: #4dd97a;
  border-color: #4dd97a;
}

html.dark-mode .log-view {
  background: #0f0f12;
  color: #a0a0aa;
}

html.dark-mode .log-view .lvl-INFO {
  color: #a0a0aa;
}

html.dark-mode .log-view .lvl-WARNING {
  color: #ffb84d;
}

html.dark-mode .log-view .lvl-ERROR {
  color: #ff6666;
  font-weight: 600;
}

html.dark-mode .log-view .lvl-DEBUG {
  color: #707078;
}

html.dark-mode .filter-col {
  background: #252530;
  border-color: #3a3a42;
}

html.dark-mode .filters-dropdown {
  background: #1a1a1f;
  border-color: #4a4a54;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);
}

html.dark-mode .track {
  background: #3a3a42;
  border-color: #4a4a54;
}

html.dark-mode .arm-toggle input:checked + .track {
  background: #ff3333;
  border-color: #ff1111;
}

html.dark-mode .autonomy-toggle input:checked + .track {
  background: #ffb84d;
  border-color: #ff8800;
}

html.dark-mode .modal {
  background: #1a1a1f;
  border-color: #4a4a54;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}

html.dark-mode .modal code {
  background: #3a1a1f;
  color: #ff8888;
}

html.dark-mode .badge {
  background: transparent;
  border-color: #4a4a54;
  color: #a0a0aa;
}

html.dark-mode .badge-neutral {
  color: #a0a0aa;
}

html.dark-mode .badge-live {
  color: #fff;
  background: #ff3333;
  border-color: #ff1111;
}

html.dark-mode .badge-paper {
  color: #a0d9ff;
  background: #0a2a3a;
  border-color: #4a7a8f;
}

html.dark-mode .mode-select {
  background: #2a2a32;
  border-color: #4a4a54;
  color: #e8e8ec;
}

html.dark-mode .mode-select.badge-live {
  background-color: #ff3333;
  border-color: #ff1111;
  color: #fff;
}

html.dark-mode .mode-select.badge-paper {
  background-color: #0a2a3a;
  border-color: #4a7a8f;
  color: #a0d9ff;
}

html.dark-mode .arm-dry {
  background: #0a2a0a;
  color: #4dd94d;
  border-color: #2a5a2a;
}

html.dark-mode .arm-paper {
  background: #3a2a0a;
  color: #ffb84d;
  border-color: #5a4a1a;
}

html.dark-mode .arm-live {
  background: #ff3333;
  color: #fff;
  border-color: #ff1111;
  animation: armglow 1.5s ease-in-out infinite;
}

html.dark-mode .mode-suggest {
  background: #0a2a3a;
  color: #a0d9ff;
  border-color: #4a7a8f;
}

html.dark-mode .mode-autonomous {
  background: #3a2a0a;
  color: #ffb84d;
  border-color: #5a4a1a;
}

html.dark-mode .sidebar {
  background: #1a1a1f;
  border-right-color: #3a3a42;
}

html.dark-mode .nav-item {
  color: #e8e8ec;
  border-left-color: transparent;
}

html.dark-mode .nav-item:hover {
  background: #252530;
  color: #ff3333;
}

html.dark-mode .nav-item.active {
  background: #252530;
  color: #ff3333;
  border-left-color: #ff3333;
}

html.dark-mode .nav-divider {
  background: #3a3a42;
}

html.dark-mode .suggestion-item {
  background: #252530;
  border-left-color: #00d9ff;
  color: #e8e8ec;
}

html.dark-mode .suggestion-item strong {
  color: #e8e8ec;
}

html.dark-mode .login-card {
  background: #1a1a1f;
  border-color: #4a4a54;
}

html.dark-mode .login-field input {
  background: #252530;
  color: #e8e8ec;
  border-color: #4a4a54;
}

html.dark-mode .login-field input:focus {
  outline-color: #ff3333;
  border-color: #ff3333;
}

html.dark-mode .login-error {
  background: #3a1a1f;
  color: #ff8888;
  border-color: #5a3a3f;
}

html.dark-mode .login-mode-opt {
  border-color: #4a4a54;
  background: #252530;
  color: #a0a0aa;
}

html.dark-mode .login-mode-opt:has(input:checked) {
  border-color: #4a7a8f;
  background: #0a2a3a;
  color: #a0d9ff;
}

html.dark-mode .login-mode-opt:last-child:has(input:checked) {
  border-color: #ff1111;
  background: #3a1a1f;
  color: #ff8888;
}

/* Additional dark mode fixes for all text and elements */
html.dark-mode h1,
html.dark-mode h2,
html.dark-mode h3,
html.dark-mode h4,
html.dark-mode h5,
html.dark-mode h6 {
  color: #e8e8ec;
}

html.dark-mode dt,
html.dark-mode dd {
  color: #e8e8ec;
}

html.dark-mode dd {
  color: #e8e8ec;
}

html.dark-mode .kv dt {
  color: #a0a0aa;
}

html.dark-mode .kv dd {
  color: #e8e8ec;
}

html.dark-mode .muted {
  color: #707078;
}

html.dark-mode p {
  color: #e8e8ec;
}

html.dark-mode .pos-card-sym {
  color: #e8e8ec;
}

html.dark-mode .pos-card-value {
  color: #e8e8ec;
}

html.dark-mode .pos-card-row .label {
  color: #a0a0aa;
}

html.dark-mode .pos-card-row .value {
  color: #e8e8ec;
}

html.dark-mode .pos-card-value-pct {
  color: #a0a0aa;
}

html.dark-mode .pos-card-value-small {
  color: #a0a0aa;
}

html.dark-mode .sess-info {
  color: #a0a0aa;
}

html.dark-mode .conn-text {
  color: #a0a0aa;
}

html.dark-mode .sub {
  color: #a0a0aa;
}

html.dark-mode .arm-label {
  color: #a0a0aa;
}

html.dark-mode .filter-toggle {
  color: #e8e8ec;
}

html.dark-mode .filter-param {
  color: #a0a0aa;
}

html.dark-mode .filter-select {
  background: #1a1a1f;
  color: #e8e8ec;
  border-color: #4a4a54;
}

html.dark-mode .suggest-reason {
  color: #a0a0aa;
}

html.dark-mode .strategy-card h4 {
  color: #e8e8ec;
}

html.dark-mode .strategy-desc {
  color: #a0a0aa;
}

html.dark-mode .form-group label {
  color: #e8e8ec;
}

html.dark-mode .control-group label {
  color: #e8e8ec;
}

html.dark-mode .result-label {
  color: #a0a0aa;
}

html.dark-mode .result-value {
  color: #e8e8ec;
}

html.dark-mode .results-chart {
  background: #252530;
  border-color: #3a3a42;
}

html.dark-mode .result-card {
  background: #252530;
  border-color: #3a3a42;
}

html.dark-mode .time-period {
  color: #a0a0aa;
}

html.dark-mode table td {
  color: #e8e8ec;
}

html.dark-mode table th {
  color: #a0a0aa;
}

html.dark-mode tr.empty td {
  color: #707078;
}

html.dark-mode .total-pnl:not(.pnl-up):not(.pnl-down) {
  color: #a0a0aa;
}

html.dark-mode .foot {
  color: #707078;
}

html.dark-mode .settings-status {
  background: #2a2a32;
  color: #b0b0ba;
}

html.dark-mode .settings-status.ok {
  background: #0a2a0a;
  color: #4dd94d;
}

html.dark-mode .settings-status.err {
  background: #3a1a1f;
  color: #ff6666;
}

/* Fix button text and styles for better visibility */
html.dark-mode button {
  color: #e8e8ec;
}

html.dark-mode .login-field > span {
  color: #a0a0aa;
}

html.dark-mode .login-status {
  color: #a0a0aa;
}

html.dark-mode .login-history summary {
  color: #a0a0aa;
}

html.dark-mode .login-history-row {
  color: #a0a0aa;
}

html.dark-mode .login-history-row.fail {
  color: #ff6666;
}

html.dark-mode .filter-toggle input {
  accent-color: #ff3333;
}

html.dark-mode .login-mode-opt input {
  accent-color: #00d9ff;
}

html.dark-mode .login-mode-opt:last-child input {
  accent-color: #ff3333;
}

html.dark-mode .arm-toggle input {
  accent-color: #ff3333;
}

html.dark-mode .autonomy-toggle input {
  accent-color: #ffb84d;
}

* { box-sizing: border-box; }
html { background: var(--bg); }
body {
  margin: 0; min-height: 100vh;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
}

/* Distinctive display font for headings only - body text stays on the
   system stack above for performance/familiarity. Falls back to the same
   system stack if the Google Fonts request is ever blocked (offline dev,
   restrictive network), so nothing breaks without it. */
h1, h2, h3, h4 {
  font-family: "Space Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

.shell { width: 95%; max-width: none; margin: 0 auto; padding: 20px 16px 46px; }

/* ---------- login gate ---------- */
.login-gate {
  min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px;
  /* Subtle brand-colored ambient glow instead of a flat fill - built from the
     same accent/go tokens used everywhere else, so it adapts with the theme
     instead of needing a separate dark-mode override or an image asset. */
  background:
    radial-gradient(1100px 550px at 12% -10%, rgba(230, 0, 0, .10), transparent 58%),
    radial-gradient(850px 480px at 108% 112%, rgba(0, 124, 146, .10), transparent 55%),
    var(--bg);
}
.login-gate[hidden] { display: none; }
.login-card {
  width: 100%; max-width: 420px;
  background: var(--bg-elev); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 32px 28px;
  position: relative; overflow: hidden;
}
.login-card::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 4px;
  background: linear-gradient(90deg, var(--accent), var(--go));
}
.login-brand { margin-bottom: 26px; }
.login-brand .logo { width: 52px; height: 52px; font-size: 24px; border-radius: 14px; }

.login-mode-row { display: flex; gap: 10px; }
.login-mode-opt {
  flex: 1; display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 10px; border: 1px solid var(--line-strong); border-radius: 10px;
  cursor: pointer; font-weight: 650; font-size: 13.5px; color: var(--text-dim);
  transition: border-color .15s ease, background .15s ease, color .15s ease;
}
.login-mode-opt input { accent-color: var(--go); margin: 0; }
.login-mode-opt:has(input:checked) { border-color: #9fd3dc; background: #e2f3f6; color: #05606f; }
.login-mode-opt:last-child:has(input:checked) {
  border-color: var(--accent-strong); background: #fdeaea; color: var(--accent-strong);
}
.login-mode-opt:last-child input { accent-color: var(--accent); }
.login-mode-opt:has(input:disabled) { opacity: .5; cursor: not-allowed; }
.login-live-note { margin: 8px 0 0; font-size: 11.5px; }

.login-field { display: block; margin: 18px 0 0; }
.login-field > span { display: block; font-size: 12px; color: var(--text-dim); margin-bottom: 5px; }
.login-field input {
  width: 100%; padding: 10px 12px; border-radius: 10px;
  border: 1px solid var(--line-strong); background: #fff; color: var(--text); font-size: 14px;
}
.login-field input:focus { outline: 2px solid rgba(230, 0, 0, .35); border-color: var(--accent); }

.login-btn { width: 100%; margin-top: 20px; padding: 11px; font-size: 14px; }

.login-error {
  margin: 14px 0 0; padding: 10px 12px; border-radius: 8px; font-size: 12.5px;
  background: #fdeaea; color: var(--accent-strong); border: 1px solid #f3b0b0;
}
.login-status { margin: 12px 0 0; text-align: center; font-size: 12px; }

.login-history { margin-top: 20px; border-top: 1px solid var(--line); padding-top: 12px; }
.login-history summary { cursor: pointer; font-size: 12.5px; color: var(--text-dim); font-weight: 600; }
.login-history-list { margin-top: 10px; max-height: 160px; overflow-y: auto; }
.login-history-row {
  display: flex; justify-content: space-between; gap: 8px; font-size: 11.5px;
  padding: 5px 0; border-bottom: 1px solid var(--line); color: var(--text-dim);
}
.login-history-row:last-child { border-bottom: none; }
.login-history-row.fail { color: var(--accent-strong); }

/* ---------- top bar ---------- */
.topbar {
  display: flex; align-items: flex-start; justify-content: space-between;
  padding-bottom: 16px; border-bottom: 2px solid var(--accent); margin-bottom: 22px;
  /* Sticky: Live, Budget, Net Liq, Buying Power and Logout are the figures you
     check before every decision, and they used to scroll away with the page. */
  position: sticky;
  top: 0;
  z-index: 350;                /* under modals (500+), over the page */
  background: var(--bg);
  padding-top: 10px;
}
/* ---------- OnismAI brand ----------
   The emblem is capped at 30px so the header stays one row alongside the
   financial summary strip; the wordmark is sized from it rather than set
   independently, so the two cannot drift apart. */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: inherit;
  flex: 0 0 auto;
}
.brand:hover .brand-mark { transform: translateY(-1px); }
.brand:focus-visible { outline: 2px solid var(--go); outline-offset: 3px; border-radius: 10px; }

.brand-mark {
  width: 30px; height: 30px;          /* inside the 28-32px brief */
  flex: 0 0 auto;
  transition: transform .18s ease;
  /* A whisper of glow so the mark holds its own on a light header too. */
  filter: drop-shadow(0 0 6px color-mix(in srgb, #10B981 28%, transparent));
}
.brand-mark-lg { width: 42px; height: 42px; }

.brand-word {
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-size: 20px;
  line-height: 1;
  letter-spacing: -0.03em;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin: 0;
}
.brand-onism { font-weight: 800; color: var(--text); }

/* "AI" as a gradient pill. background-clip:text would vanish against a dark
   header at this size, so the gradient is the BADGE and the glyphs sit on it -
   higher contrast, and it survives a theme flip without a second rule. */
.brand-ai {
  font-weight: 800;
  font-size: .72em;
  letter-spacing: .01em;
  color: #fff;
  padding: 3px 7px 4px;
  border-radius: 7px;
  background: linear-gradient(135deg, #3B82F6, #10B981);
  box-shadow: 0 0 12px color-mix(in srgb, #10B981 45%, transparent),
              0 1px 2px rgba(0, 0, 0, .25);
}

.brand-lg .brand-word { font-size: 26px; }
.brand-lg .brand-mark { width: 38px; height: 38px; }

.login-brand { display: flex; flex-direction: column; align-items: center; gap: 8px; }

/* The old single-letter tile, kept for any markup still referencing it. */
.logo {
  display: grid; place-items: center; width: 42px; height: 42px; border-radius: 10px;
  background: linear-gradient(135deg, var(--accent), var(--accent-strong));
  color: #fff; font-size: 21px; font-weight: 800;
  box-shadow: 0 4px 14px rgba(230, 0, 0, .28), 0 0 0 5px rgba(230, 0, 0, .07);
}
.topbar h1 { font-size: 19px; margin: 0; letter-spacing: .2px; font-weight: 750; }
/* login.html reuses .brand-word on an <h1>; strip the heading's own metrics. */
h1.brand-word { font-size: 24px; font-weight: 800; }
.sub { margin: 2px 0 0; font-size: 12.5px; color: var(--text-dim); }

.session { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; justify-content: flex-end; }
.sess-info { font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.conn-text { font-size: 13px; color: var(--text-dim); }
.dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.dot-off { background: var(--muted); box-shadow: 0 0 0 3px rgba(154, 160, 168, .18); }
.dot-on { background: var(--ok); box-shadow: 0 0 0 3px rgba(47, 129, 50, .18); animation: pulse 2s infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .5; } }

.badge {
  font-size: 11px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase;
  padding: 4px 10px; border-radius: 999px; border: 1px solid var(--line-strong);
}
.badge-neutral { color: var(--text-dim); }
.badge-live { color: #fff; background: var(--accent); border-color: var(--accent-strong); }
.badge-paper { color: #05606f; background: #e2f3f6; border-color: #b7e0e6; }

/* mode selector: a <select> styled to sit where the mode badge does - only
   shown (and only editable) while disconnected; picking LIVE prompts for
   confirmation before it's applied (see app.js) */
.mode-select {
  font-size: 11px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase;
  padding: 4px 22px 4px 10px; border-radius: 999px; border: 1px solid var(--line-strong);
  cursor: pointer; appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' fill='none' stroke='%23666c74' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat; background-position: right 8px center; background-size: 8px 5px;
}
.mode-select:disabled { cursor: not-allowed; opacity: .7; }
.mode-select.badge-live { background-color: var(--accent); border-color: var(--accent-strong); }
.mode-select.badge-paper { background-color: #e2f3f6; border-color: #b7e0e6; }

/* ---------- status bar: arm + mode banners merged onto one line ---------- */
.status-bar { display: flex; gap: 10px; margin-bottom: 20px; }
.status-bar .arm-banner, .status-bar .mode-banner { flex: 1 1 0; margin-bottom: 0; }

.arm-banner {
  border-radius: var(--radius); padding: 12px 18px; margin-bottom: 20px;
  font-weight: 650; font-size: 13.5px; letter-spacing: .2px; text-align: center;
  border: 1px solid transparent;
}
.arm-dry { background: #ecf6ec; color: #226626; border-color: #cfe6d0; }
.arm-paper { background: #fff3e7; color: #9a4a0c; border-color: #ffd9b8; }
.arm-live {
  background: var(--accent); color: #fff; border-color: var(--accent-strong);
  animation: armglow 1.5s ease-in-out infinite;
}
@keyframes armglow {
  0%, 100% { box-shadow: 0 0 0 0 rgba(230, 0, 0, 0); }
  50% { box-shadow: 0 0 24px 2px rgba(230, 0, 0, .4); }
}

/* ---------- controls ---------- */
.controls {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: var(--bg-elev); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 14px; margin-bottom: 20px; box-shadow: var(--shadow);
}
.spacer { flex: 1 1 12px; }
.btn {
  appearance: none; border: 1px solid var(--line-strong); background: #fff;
  color: var(--text); font-size: 13px; font-weight: 600; padding: 9px 15px;
  border-radius: 9px; cursor: pointer;
  transition: transform .06s ease, background .15s ease, border-color .15s ease, box-shadow .15s ease;
}
.btn:hover:not(:disabled) { background: var(--bg-elev-2); border-color: var(--muted); }
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn-primary { background: var(--accent); border-color: var(--accent-strong); color: #fff; }
.btn-primary:hover:not(:disabled) { background: var(--accent-strong); border-color: var(--accent-strong); }
.btn-go { border-color: #9fd3dc; color: #05606f; }
.btn-go:hover:not(:disabled) { background: #e2f3f6; }
.btn-stop { border-color: #f3b0b0; color: var(--accent-strong); }
.btn-stop:hover:not(:disabled) { background: #fdeaea; }
.btn-warn { border-color: #f6c79a; color: #9a4a0c; }
.btn-warn:hover:not(:disabled) { background: #fff3e7; }
.btn-mini { padding: 6px 11px; font-size: 12px; }

/* Scan-in-progress state: a small spinning ring before the "Scanning…"
   label, so it's clear something is happening rather than the button just
   looking disabled. */
.btn-scanning { position: relative; padding-left: 28px !important; }
.btn-scanning::before {
  content: ""; position: absolute; left: 10px; top: 50%; width: 12px; height: 12px;
  margin-top: -6px; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent; opacity: .7;
  animation: btn-spin .7s linear infinite;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }
.btn-logout { padding: 6px 12px; font-size: 12px; margin-left: 4px; border-color: #f3b0b0; color: var(--accent-strong); }
.btn-logout:hover:not(:disabled) { background: #fdeaea; }

/* Arm orders and the connection switch are the same control in two places,
   so they are now the same size and the same label style - 34x18 with a 14px
   knob, matching .nav-conn-switch. .track/.thumb are shared with the "Fully
   autonomous" toggle in Settings, which follows suit. */
.arm-toggle { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; user-select: none; }
.arm-toggle input { display: none; }
.track {
  width: 34px; height: 18px; border-radius: 999px; background: var(--line-strong);
  position: relative; transition: background .18s ease; border: 0;
}
.thumb {
  position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, .25); transition: left .18s ease;
}
.arm-toggle input:checked + .track { background: var(--accent); }
.arm-toggle input:checked + .track .thumb { left: 18px; }
.arm-toggle input:disabled + .track { opacity: .55; }
.arm-label {
  font-size: 11px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-dim);
}

/* the autonomy toggle uses warn-orange (not red) - a different kind of caution than live money */
.autonomy-toggle input:checked + .track { background: var(--warn); border-color: #c94f00; }

/* ---------- mode banner (suggest vs autonomous) ---------- */
.mode-banner {
  border-radius: var(--radius); padding: 10px 18px; margin-bottom: 20px;
  font-weight: 650; font-size: 13px; letter-spacing: .2px; text-align: center;
  border: 1px solid transparent;
}
.mode-suggest { background: #e2f3f6; color: #05606f; border-color: #b7e0e6; }
.mode-autonomous { background: #fff3e7; color: #9a4a0c; border-color: #ffd9b8; }

/* ---------- trade suggestions ---------- */
.suggest-reason { color: var(--text-dim); font-size: 12px; max-width: 260px; }
.btn-execute { border-color: #9fd3dc; color: #05606f; background: #e2f3f6; white-space: nowrap; }
.btn-execute:hover:not(:disabled) { background: #cdeaf0; }

/* ---------- grid + cards ---------- */
/* default align-items:stretch - Account/Strategy stay equal height. */
.grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; margin-bottom: 18px; }
.card {
  background: var(--bg-elev); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 22px; box-shadow: var(--shadow); transition: box-shadow 0.2s ease;
  min-width: 0; width: 100%;
}
.card:hover { box-shadow: 0 1px 3px rgba(37, 40, 43, .08), 0 12px 40px rgba(37, 40, 43, .1); }
.card h2 { margin: 0 0 14px; font-size: 12px; text-transform: uppercase; letter-spacing: .8px; color: var(--text-dim); }
.card-wide { grid-column: 1 / -1; width: 100%; }

/* ---------- dashboard ----------
   Was a 3-column grid: Holdings | center | Trade History. Holdings now lives
   in its own left rail outside .page-area and the right side-panel is gone
   (Account and Risk moved to Intraday), so the centre column is the only
   child left - with three tracks still declared it was being squeezed into
   the first 1fr and the chart rendered about a hundred pixels wide. */
.dashboard {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
  align-items: start;
  width: 100%;
  position: relative;
}
/* Pre-existing gap: .dashboard's own `display: grid` (same specificity as
   the UA [hidden] rule, but author styles win the tie) silently overrode
   the hidden attribute, so switching to Strategy/History/etc. rendered the
   dashboard grid stacked underneath the page instead of replacing it.
   Mirrors the .strategy-page[hidden] override below. */
.dashboard[hidden] {
  display: none !important;
}
.dashboard.grid-stack {
  display: block !important;
  position: relative;
  width: 100%;
  min-height: 600px;
  background: transparent;
  padding: 0;
  margin: 0;
}
.dashboard.grid-stack .gs-item {
  position: absolute !important;
  box-sizing: border-box;
  padding: 16px !important;
  margin: 0 !important;
  left: auto;
  right: auto;
  top: auto;
}
.dashboard.grid-stack .gs-item > .card {
  margin: 0;
  padding: 22px;
}
.dashboard:not(.grid-stack) .gs-item {
  position: relative;
  padding: 0;
  margin: 0;
}
.dashboard.gs-animating { z-index: 100; }
body.edit-mode .dashboard.gs-animating { pointer-events: auto; }
.side-panel { min-width: 0; width: 100%; }
.side-panel .card { position: sticky; top: 16px; }
.center-col { min-width: 0; display: flex; flex-direction: column; gap: 16px; width: 100%; }
.gs-item { touch-action: none; }
body:not(.edit-mode) .gs-item { user-select: auto; cursor: auto; }
body.edit-mode .gs-item { user-select: none; -webkit-user-select: none; cursor: grab; }
body.edit-mode .gs-item.ui-draggable-dragging { cursor: grabbing; }
.center-col .grid { margin-bottom: 0; }

.pos-actions-stack { display: flex; flex-direction: column; gap: 6px; margin: 0 0 14px; }
.pos-actions-stack .btn { width: 100%; }

.kv { display: grid; grid-template-columns: auto 1fr; gap: 10px 16px; margin: 0; align-items: center; }
.kv dt { color: var(--text-dim); font-size: 13px; }
.kv dd { margin: 0; text-align: right; font-size: 13.5px; font-variant-numeric: tabular-nums; }
.muted { color: var(--muted); font-size: 12px; }

/* A bare "—" while data hasn't loaded yet can read as an error rather than
   "loading" - pulse it instead of leaving it static. Opacity-based (not a
   background-gradient shimmer) so it works regardless of the element's
   width or content length. */
.skeleton-loading {
  color: var(--muted) !important;
  animation: skeleton-pulse 1.4s ease-in-out infinite;
}
@keyframes skeleton-pulse {
  0%, 100% { opacity: .35; }
  50% { opacity: .85; }
}

.budget-cell { display: flex; gap: 6px; justify-content: flex-end; align-items: center; }
.budget-cell input {
  width: 96px; padding: 6px 8px; border: 1px solid var(--line-strong); border-radius: 8px;
  background: #fff; color: var(--text); font-size: 13px; text-align: right; font-variant-numeric: tabular-nums;
}
.budget-cell input:focus { outline: 2px solid rgba(230, 0, 0, .35); outline-offset: 0; border-color: var(--accent); }
.budget-cell-header { gap: 6px; }
.budget-cell-header input { width: 64px; padding: 4px 6px; font-size: 12px; border-radius: 6px; }
.budget-cell-header .btn-mini { padding: 4px 9px; }

/* ---------- entry filters: its own full-width card, one column per filter
   so each has room for its checkbox, description and controls ---------- */
.filters-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 20px 24px;
}
.filter-col {
  display: flex; flex-direction: column; gap: 8px; min-width: 0;
  padding: 14px 16px; background: var(--bg-elev-2); border: 1px solid var(--line);
  border-radius: 10px;
}
.filter-toggle {
  display: flex; align-items: center; gap: 8px; font-size: 13.5px; font-weight: 650; color: var(--text);
  cursor: pointer; user-select: none;
}
.filter-toggle span { white-space: nowrap; }
.filter-toggle input { accent-color: var(--accent); width: 16px; height: 16px; cursor: pointer; margin: 0; flex: none; }
.filter-toggle input:disabled { cursor: not-allowed; }
.filter-toggle input:disabled + * { opacity: .6; }
.filter-desc { margin: -4px 0 0 24px; font-size: 11.5px; line-height: 1.4; }
.filter-params { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-left: 24px; }

.filter-param { display: flex; align-items: center; gap: 5px; font-size: 12px; color: var(--text-dim); }
.filter-select {
  border: 1px solid var(--line-strong); border-radius: 6px; background: #fff; color: var(--text);
  font-size: 12.5px; padding: 4px 6px; cursor: pointer; font-variant-numeric: tabular-nums;
}
.filter-select:disabled { cursor: not-allowed; opacity: .6; }

/* Filters trigger lives as a row in the Strategy card; the panel itself
   floats above the page (position:absolute) so opening/closing it never
   reflows the Account card beside it or the Trade Suggestions card below -
   same reasoning as .status-bar above. */
#strategyCard { position: relative; }
.filters-summary-wrap { display: flex; align-items: center; gap: 8px; justify-content: flex-end; }
.filters-dropdown {
  position: absolute; top: calc(100% + 8px); left: 0; z-index: 30;
  width: min(560px, 85vw); max-height: 70vh; overflow-y: auto;
  background: var(--bg-elev); border: 1px solid var(--line-strong); border-radius: 12px;
  padding: 18px 20px; box-shadow: 0 16px 48px rgba(37, 40, 43, .22);
}
.filters-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }

.pill {
  display: inline-block; font-size: 11px; font-weight: 700; padding: 3px 9px;
  border-radius: 999px; letter-spacing: .4px; text-transform: uppercase;
}
.pill-flat { background: #ebedf0; color: #5c636c; }
.pill-pending { background: #fff0e0; color: #9a4a0c; }
.pill-long { background: #e6f4e7; color: #226626; }
.pill-blocked { background: #fde7e7; color: var(--accent-strong); }

/* ---------- table ---------- */
.table-wrap { overflow-x: auto; margin: -4px -22px 0; }
/* Market News already caps at 420px via .news-table-wrap; Trade Suggestions
   had no such cap, so a very active scan cycle could grow the page tall. */
#suggestTableWrap { max-height: 380px; overflow-y: auto; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th, td { text-align: left; padding: 12px 22px; border-bottom: 1px solid var(--line); }
th {
  color: var(--text-dim); font-weight: 700; font-size: 11px; text-transform: uppercase;
  letter-spacing: .5px; background: var(--bg-elev-2); border-top: 1px solid var(--line);
}
table tr:hover td { background: #fafbfc; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
tr.empty td { color: var(--muted); text-align: center; padding: 28px 22px; }
th.tk, td.tk { width: 44px; text-align: center; }

/* ---------- holdings / position console (Phase 8) ---------- */
.pos-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.pos-head h2 { margin: 0; }
.pos-actions { display: flex; gap: 6px; flex-wrap: wrap; }
.pos-hint { margin: 10px 2px 0; line-height: 1.5; }
.suggest-collapsed { text-align: center; padding: 20px 4px; margin: 0; }
#suggestCard.collapsed { padding: 0; }
#suggestCard.collapsed .pos-head { padding: 12px 22px; border-bottom: 1px solid var(--line); }
#suggestCard.collapsed .pos-actions { display: none; }
#suggestCard.collapsed #suggestModeNote { display: none; }
#suggestCard.collapsed .autoscroll { display: none; }
#suggestCard.collapsed #whatsappNote { display: none; }
#suggestCard.collapsed #suggestCollapsedNote { display: none; }
#suggestCard.collapsed #suggestTableWrap { display: none; }
#suggestCard.collapsed #btnToggleSuggest { display: inline-block !important; }
#btnToggleSuggest.expanded::before { content: "−"; }
#btnToggleSuggest.collapsed::before { content: "+"; }
/* var(--ok), not a literal: html.dark-mode redefines that token, and a
   hardcoded #226626 stayed near-invisible on a dark card while the
   matching .pnl-down (which does read var(--danger)) brightened. */
.pnl-up { color: var(--ok); }
.pnl-down { color: var(--danger); }
.pbadge {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 600; text-transform: capitalize;
}
.b-managed   { background: #e6f0ff; color: #1b4b8f; }
.b-protected { background: #e6f4e7; color: #226626; }
.b-naked     { background: #fde7e7; color: var(--accent-strong); }
.b-ignored   { background: #ececf0; color: #63636d; }

/* Small status badge abbreviations for holdings rows */
.pos-badge {
  display: inline-block; padding: 2px 6px; border-radius: 4px;
  font-size: 10px; font-weight: 700; letter-spacing: 0.5px;
  margin-left: 8px; cursor: help; text-transform: uppercase;
}
.pos-badge.b-managed { background: #e6f0ff; color: #1b4b8f; }
.pos-badge.b-protected { background: #e6f4e7; color: #226626; }
.pos-badge.b-naked { background: #fde7e7; color: var(--accent-strong); }
.pos-badge.b-ignored { background: #ececf0; color: #63636d; }

/* font-weight/size only here - color must come solely from .pnl-up/.pnl-down
   (set in render()) so it's never shadowed by a same-specificity fallback;
   the :not() below only supplies a color when neither is present. */
.total-pnl { font-size: 13px; font-weight: 750; font-variant-numeric: tabular-nums; }
.total-pnl:not(.pnl-up):not(.pnl-down) { color: var(--text-dim); }
.total-pnl-row { display: flex; align-items: center; gap: 6px; }
/* Icon sprite usage: <svg class="icon"><use href="#icon-name"></use></svg> -
   sized off font-size and colored via currentColor, so it inherits whatever
   text color the surrounding element already has (nav-item, btn-icon, etc.)
   instead of needing per-context color rules. */
.icon {
  width: 1em; height: 1em; display: inline-block; vertical-align: -2px;
  flex-shrink: 0;
}
.icon-lg { width: 18px; height: 18px; }

.btn-icon {
  appearance: none; border: 1px solid var(--line-strong); background: transparent; color: var(--text-dim);
  width: 22px; height: 22px; border-radius: 6px; cursor: pointer; font-size: 13px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center; padding: 0;
  transition: transform .15s ease, background .15s ease;
}
.btn-icon .icon { width: 14px; height: 14px; }
.btn-icon:hover:not(:disabled) { background: var(--bg-elev-2); color: var(--text); }
.btn-icon:disabled { opacity: .45; cursor: not-allowed; }
.btn-icon.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent-strong);
}
.btn-icon.spinning { animation: spin 0.6s linear; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- holdings: compact row-style cards ---------- */
.pos-filter-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 0 0 12px; }
.pos-list { display: flex; flex-direction: column; gap: 0; max-height: 460px; overflow-y: auto; padding-right: 12px; }
.pos-list.pos-list-modal { max-height: 65vh; display: flex; flex-direction: column; gap: 0; }
.pos-list .empty { text-align: center; padding: 24px 4px; margin: 0; }
.pos-card-header {
  /* No padding-right: the rows below are NOT inset, so adding any here slides
     every header label 12px left of the numbers it labels. The narrower
     columns alone are what make this fit the rail. */
  display: flex; align-items: center; gap: 10px; padding: 8px 0 12px 0; border-bottom: 2px solid var(--line);
  font-size: 12px; font-weight: 600; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.3px;
}
.pos-card-symbol-col { flex: 0 0 auto; min-width: 60px; display: flex; align-items: center; gap: 8px; }
.pos-card-grid-header { display: flex; gap: 10px; flex: 1 1 auto; justify-content: flex-end; align-items: center; }
.pos-card-col-header { flex: 0 0 52px; text-align: right; }
.pos-card-col-header-small { flex: 0 0 auto; text-align: right; font-size: 10px; color: var(--text-dim); }

.pos-card {
  border: none; border-bottom: 1px solid var(--line); border-radius: 0; background: transparent;
  padding: 12px 0; transition: all 0.15s ease; cursor: pointer;
  display: flex; flex-direction: column; gap: 0; min-width: 0;
  border-left: 3px solid transparent;
}
.pos-card:last-child { border-bottom: none; }
.pos-card:hover { background: var(--bg-elev-2); padding-left: 8px; padding-right: 8px; margin: 0 -8px; }
.pos-card-row-main {
  display: flex; align-items: center; gap: 12px; width: 100%;
}
.pos-card.selected { border-left-color: var(--accent); background: #fdeaea; }
.pos-card.pos-card-disabled { cursor: not-allowed; opacity: 0.6; }
.pos-card-top { display: flex; align-items: center; gap: 12px; flex: 1 1 auto; min-width: 0; }
.pos-card-top-left { display: flex; align-items: center; gap: 12px; flex: 1 1 auto; min-width: 0; }
.pos-card-top input[type="radio"] { display: none; }
.pos-card-sym { font-size: 15px; font-weight: 700; flex: 0 0 auto; letter-spacing: -0.3px; white-space: nowrap; }
.pos-card-sym-label { font-size: 12px; color: var(--text-dim); font-weight: 500; }
.pos-card-grid {
  display: flex; gap: 10px; font-size: 13px; flex: 1 1 auto; align-items: flex-start; min-width: 0; justify-content: flex-end;
}
.pos-card-value {
  flex: 0 0 52px; text-align: right; color: var(--text); font-weight: 700; font-size: 14px;
  font-variant-numeric: tabular-nums; display: flex; flex-direction: column; gap: 2px;
}
.pos-card-value.pnl-up { color: var(--ok); }
.pos-card-value.pnl-down { color: var(--danger); }
.pos-card-row { display: flex; flex-direction: column; gap: 3px; flex: 0 0 auto; text-align: right; }
.pos-card-row .label { color: var(--muted); font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.3px; }
.pos-card-row .value { color: var(--text); font-weight: 700; font-size: 16px; font-variant-numeric: tabular-nums; display: flex; flex-direction: column; gap: 2px; }
.pos-card-row .value.pnl-up { color: var(--ok); }
.pos-card-row .value.pnl-down { color: var(--danger); }
.pnl-pct { font-size: 11px; font-weight: 500; opacity: 0.8; }
.pos-card-value-pct {
  flex: 0 0 auto; text-align: right; color: var(--text-dim); font-weight: 500; font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.pos-card-details {
  display: flex; gap: 0; padding: 4px 0 0 0; width: 100%; align-items: center;
}
.pos-card-value-small {
  flex: 0 0 auto; text-align: right; color: var(--text-dim); font-weight: 500; font-size: 11px;
  font-variant-numeric: tabular-nums;
}
.section-tag {
  display: inline-block; margin-left: 8px; padding: 3px 6px; font-size: 9px;
  border-radius: 3px; font-weight: 700; white-space: nowrap;
}
.tag-ai {
  background: #e6f4ff; color: #1b4b8f; border: 1px solid #1b4b8f;
}
.tag-api {
  background: #fff4e6; color: #8f5d1b; border: 1px solid #8f5d1b;
}
/* Third tag color for third-party data sources (e.g. CoinGecko) that are
   neither the IBKR API nor a pure AI-generated suggestion. */
.tag-ext {
  background: #eafbe7; color: #1b6e2b; border: 1px solid #1b6e2b;
}
.pbadge { display: none; white-space: nowrap; }

/* ---------- entry filters: collapsible dropdown ---------- */
/* ---------- log ---------- */
.log-card { padding: 0; overflow: hidden; }
.log-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 13px 18px; border-bottom: 1px solid var(--line);
}
.log-head h2 { margin: 0; }
.autoscroll { font-size: 12px; color: var(--text-dim); display: flex; align-items: center; gap: 6px; }
.log-view {
  margin: 0; padding: 14px 18px; height: 320px; overflow-y: auto;
  background: #fbfbfc; font-family: var(--mono);
  font-size: 12px; line-height: 1.55; white-space: pre-wrap; word-break: break-word; color: #3b4046;
}
.log-view .lvl-INFO { color: #3b4046; }
.log-view .lvl-WARNING { color: #a5490b; }
.log-view .lvl-ERROR { color: var(--accent); font-weight: 600; }
.log-view .lvl-DEBUG { color: var(--muted); }

.foot { margin-top: 22px; text-align: center; font-size: 11.5px; color: var(--muted); }

/* ---------- modal ---------- */
.modal-backdrop {
  position: fixed; inset: 0; background: rgba(37, 40, 43, .45); backdrop-filter: blur(2px);
  display: grid; place-items: center; z-index: 50;
}
.modal-backdrop[hidden] { display: none; }

/* The confirmation dialog is always raised ABOVE any modal that opened it.
   Every backdrop shares z-index 50, so stacking fell to DOM order - and
   #swingTicketModal is created at runtime and appended to <body>, which put
   it after the static #confirmModal and therefore on top of it. The order
   ticket then hid its own "Buy 14 AFRM at limit 68.43 - OK / Cancel"
   confirmation: the click did nothing because the dialog was behind the
   thing that asked for it. A confirmation must never be able to fall behind
   its caller. */
#confirmModal { z-index: 120; }
.modal {
  width: min(440px, 92vw); background: #fff; border: 1px solid var(--line-strong);
  border-radius: 14px; padding: 24px; box-shadow: 0 20px 60px rgba(37, 40, 43, .25);
}
.modal h3 { margin: 0 0 10px; font-size: 17px; }
.modal p { font-size: 13.5px; color: var(--text-dim); line-height: 1.5; margin: 8px 0; }
.modal code { background: #fdeaea; padding: 2px 6px; border-radius: 6px; color: var(--accent-strong); font-weight: 600; }
.live-env-list { margin: 4px 0 10px; padding-left: 20px; font-size: 13px; color: var(--text-dim); }
.live-env-list li { margin: 4px 0; }
/* Scoped to text-like inputs only - a bare ".modal input" also matched the
   Entry Filters checkboxes once that section moved into this modal,
   stretching each to fill the row (width:100%) and shoving its label
   outside the column. Number/checkbox controls inside the modal (filter
   toggles, period selects) keep their own purpose-built sizing instead. */
.modal input[type="text"], .modal input[type="password"] {
  width: 100%; margin-top: 6px; padding: 10px 12px; border-radius: 10px;
  border: 1px solid var(--line-strong); background: #fff; color: var(--text); font-size: 14px;
}
.modal input[type="text"]:focus, .modal input[type="password"]:focus {
  outline: 2px solid rgba(230, 0, 0, .35); border-color: var(--accent);
}
.modal-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }
.modal-wide { width: min(720px, 92vw); max-height: 85vh; overflow-y: auto; }
.settings-section h4 { margin: 0 0 6px; font-size: 13px; text-transform: uppercase; letter-spacing: .6px; color: var(--text-dim); }
.settings-status {
  display: inline-block; font-size: 12px; font-weight: 650; padding: 3px 10px; border-radius: 999px;
  background: #ececf0; color: #63636d; margin: 4px 0 14px;
}
.settings-status.ok { background: #e6f4e7; color: #226626; }
.settings-status.err { background: #fde7e7; color: var(--accent-strong); }
.modal-wide .pos-head { margin-bottom: 14px; }
.modal-wide .pos-filter-row { margin: 0; }
.modal-wide .pos-list-modal { grid-template-columns: repeat(2, 1fr); display: grid; align-content: start; gap: 10px; }

/* ---------- form validation feedback ---------- */
.input-error {
  border-color: var(--accent-strong) !important;
  background-color: rgba(230, 0, 0, 0.05);
  box-shadow: 0 0 0 2px rgba(230, 0, 0, 0.1);
}

.input-error:focus {
  outline: 2px solid var(--accent-strong) !important;
  border-color: var(--accent-strong) !important;
}

.field-error-msg {
  display: block;
  font-size: 12px;
  color: var(--accent-strong);
  margin-top: 4px;
  margin-bottom: 8px;
  font-weight: 500;
  animation: slideInRight 0.2s ease;
}

html.dark-mode .input-error {
  background-color: rgba(255, 51, 51, 0.08);
  border-color: #ff5555 !important;
  box-shadow: 0 0 0 2px rgba(255, 51, 51, 0.15);
}

html.dark-mode .field-error-msg {
  color: #ff6666;
}

input:valid:not([value=""]) {
  border-color: var(--ok);
}

/* ---------- dashboard customization ---------- */
.dashboard-card-toggles {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
  margin: 12px 0;
}

.card-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-radius: 6px;
  background: var(--bg-elev-2);
  cursor: pointer;
  transition: all 0.15s ease;
  font-size: 13px;
}

.card-toggle:hover {
  background: var(--line);
}

.card-toggle input[type="checkbox"] {
  cursor: pointer;
  margin: 0;
}

.card-toggle span {
  flex: 1;
  color: var(--text);
}

html.dark-mode .card-toggle {
  background: #252530;
}

html.dark-mode .card-toggle:hover {
  background: #2a2a35;
}

input:valid:not([value=""]):focus {
  outline: 2px solid var(--ok);
  border-color: var(--ok);
}

@media (max-width: 1100px) {
  .side-panel .card { position: static; }
}

@media (max-width: 768px) {
  /* The 3-column dashboard (Holdings | center | Platform Suggestions) never
     had a mobile rule of its own - only the nested Account/Strategy .grid
     did, so phones still got 3 cramped columns squeezed into one screen. */
  .dashboard { grid-template-columns: 1fr; }
  .grid { grid-template-columns: 1fr; }
  .spacer { flex-basis: 100%; height: 0; }
  .shell { width: 100%; padding: 14px 10px 32px; }
  .card { padding: 16px 14px; }
}

/* ---------- edit mode styling ---------- */
body.edit-mode .card {
  border: 2px dashed var(--accent);
  cursor: grab;
  position: relative;
}
body.edit-mode .card:hover {
  box-shadow: 0 0 0 2px var(--accent), 0 4px 16px rgba(37, 40, 43, .15);
  border-color: var(--accent-strong);
}
body.edit-mode .card::before {
  content: "⋮⋮";
  position: absolute;
  top: 8px;
  left: 12px;
  color: var(--accent);
  font-size: 12px;
  opacity: 0.6;
  user-select: none;
  cursor: grab;
}
body.edit-mode .card::after {
  content: "↗";
  position: absolute;
  bottom: 8px;
  right: 12px;
  color: var(--accent);
  font-size: 16px;
  opacity: 0.6;
  user-select: none;
  cursor: nwse-resize;
}
#btnEditMode.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent-strong);
}

/* ---------- notification system ---------- */
.notification-container {
  position: fixed;
  top: 80px;
  right: 20px;
  z-index: 2000;
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 400px;
}

.notification {
  background: var(--bg-elev);
  border: 1px solid var(--line-strong);
  border-left: 4px solid var(--accent);
  border-radius: 8px;
  padding: 16px;
  box-shadow: 0 4px 12px rgba(37, 40, 43, 0.15);
  animation: slideInRight 0.3s ease;
  display: flex;
  align-items: flex-start;
  gap: 12px;
}

.notification-icon {
  font-size: 20px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
}

.notification-content {
  flex: 1;
  min-width: 0;
}

.notification-title {
  font-weight: 600;
  font-size: 14px;
  color: var(--text);
  margin: 0 0 4px 0;
}

.notification-message {
  font-size: 13px;
  color: var(--text-dim);
  margin: 0;
  line-height: 1.4;
}

.notification-close {
  flex-shrink: 0;
  background: none;
  border: none;
  color: var(--text-dim);
  cursor: pointer;
  font-size: 18px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color 0.2s ease;
}

.notification-close:hover {
  color: var(--text);
}

.notification.info {
  border-left-color: #007c92;
}

.notification.info .notification-icon {
  color: #007c92;
}

.notification.success {
  border-left-color: #2f8132;
}

.notification.success .notification-icon {
  color: #2f8132;
}

.notification.warning {
  border-left-color: #eb6100;
}

.notification.warning .notification-icon {
  color: #eb6100;
}

.notification.error {
  border-left-color: #e60000;
  background: rgba(230, 0, 0, 0.05);
}

.notification.error .notification-icon {
  color: #e60000;
}

@keyframes slideInRight {
  from {
    transform: translateX(420px);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

@keyframes slideOutRight {
  from {
    transform: translateX(0);
    opacity: 1;
  }
  to {
    transform: translateX(420px);
    opacity: 0;
  }
}

.notification.removing {
  animation: slideOutRight 0.3s ease forwards;
}

html.dark-mode .notification {
  background: #1a1a1f;
  border-color: #4a4a54;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}

html.dark-mode .notification-title {
  color: #e8e8ec;
}

html.dark-mode .notification-message {
  color: #a0a0aa;
}

html.dark-mode .notification-close {
  color: #a0a0aa;
}

html.dark-mode .notification-close:hover {
  color: #e8e8ec;
}

/* ---------- sidebar menu ---------- */
.sidebar {
  position: fixed;
  left: -280px;
  top: 0;
  width: 280px;
  height: 100vh;
  background: var(--bg-elev);
  border-right: 1px solid var(--line);
  transition: left 0.3s ease;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}
.sidebar.open {
  left: 0;
}
.sidebar-header {
  padding: 16px;
  border-bottom: 1px solid var(--line);
  display: flex;
  justify-content: flex-end;
}
.sidebar-close {
  font-size: 20px;
  color: var(--text-dim);
}
.sidebar-nav {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 8px 0;
  overflow-y: auto;
}
.nav-item {
  padding: 12px 20px;
  color: var(--text);
  text-decoration: none;
  transition: background 0.15s ease, color 0.15s ease;
  border-left: 3px solid transparent;
  font-size: 14px;
}
.nav-item .icon { margin-right: 9px; vertical-align: -3px; }

/* Groups the flat nav-item list under small labels (Trading/Tools/Account)
   so it scales better as more pages get added. */
.nav-section-label {
  padding: 16px 20px 6px;
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.7px;
  color: var(--muted);
}
.nav-section-label:first-child { padding-top: 8px; }
.nav-item:hover {
  background: var(--bg-elev-2);
  color: var(--accent);
}
.nav-item.active {
  background: var(--bg-elev-2);
  color: var(--accent);
  border-left-color: var(--accent);
  font-weight: 600;
}

.nav-shortcut {
  float: right;
  background: var(--line-strong);
  color: var(--text-dim);
  padding: 2px 6px;
  border-radius: 3px;
  font-size: 11px;
  font-weight: 600;
  font-family: monospace;
  margin-right: 0;
}

.nav-item:hover .nav-shortcut {
  background: var(--accent);
  color: #fff;
}

.nav-divider {
  height: 1px;
  background: var(--line);
  margin: 8px 0;
}

.menu-toggle {
  position: relative;
  z-index: 999;
  font-size: 20px;
  margin-right: 10px;
}

.shell.sidebar-open .sidebar {
  left: 0;
}

/* ---------- strategy page ---------- */
.strategy-page {
  padding: 0;
  margin: 0;
}
.strategy-page[hidden] {
  display: none !important;
}
.strategy-container {
  padding: 20px 16px;
}
.strategy-header {
  margin-bottom: 24px;
}
.strategy-header h2 {
  font-size: 24px;
  margin: 0;
  color: var(--text);
}

/* Reuses .nav-item for its click wiring (setupSidebarMenu already binds
   every ".nav-item[data-page]" to switchPage()) but overrides the sidebar
   row look with a compact breadcrumb-style back link instead. */
.back-to-dashboard {
  display: inline-flex; align-items: center; gap: 6px;
  width: auto; padding: 0; margin: 0 0 10px; border-left: none;
  font-size: 13px; font-weight: 600; color: var(--text-dim); text-decoration: none;
}
.back-to-dashboard:hover { color: var(--accent); background: none; }
.back-to-dashboard .icon { width: 14px; height: 14px; }

.strategy-tabs {
  display: flex;
  gap: 8px;
  margin-bottom: 24px;
  border-bottom: 1px solid var(--line);
}
.tab-btn {
  padding: 12px 16px;
  border: none;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  font-weight: 600;
  font-size: 14px;
  border-bottom: 2px solid transparent;
  transition: all 0.15s ease;
  position: relative;
  bottom: -1px;
}
.tab-btn:hover {
  color: var(--text);
}
.tab-btn.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.tab-content {
  display: none;
}
.tab-content.active {
  display: block;
}

/* Existing Strategies */
.strategies-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 16px;
}
.strategy-card {
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 20px;
  box-shadow: var(--shadow);
  transition: all 0.15s ease;
  max-width: 360px;
}
.strategy-card:hover {
  border-color: var(--accent);
  box-shadow: 0 1px 3px rgba(37, 40, 43, .08), 0 8px 24px rgba(37, 40, 43, .12);
}
.strategy-card h4 {
  margin: 0 0 8px;
  font-size: 16px;
  color: var(--text);
}
.strategy-desc {
  font-size: 13px;
  color: var(--text-dim);
  margin: 0 0 12px;
  line-height: 1.5;
}
.strategy-info {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
  flex-wrap: wrap;
}
.badge {
  display: inline-block;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 600;
  background: #e2f3f6;
  color: #05606f;
}
.badge-inactive {
  background: #ececf0;
  color: #63636d;
}
.time-period {
  font-size: 12px;
  color: var(--muted);
}

/* New Strategy Form */
.new-strategy-form {
  max-width: 600px;
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 24px;
}
.form-group {
  margin-bottom: 20px;
}
.form-group label {
  display: block;
  margin-bottom: 8px;
  font-weight: 600;
  font-size: 14px;
  color: var(--text);
}
.form-group input,
.form-group textarea,
.form-group select {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  font-family: inherit;
  font-size: 14px;
  color: var(--text);
  background: #fff;
  transition: border-color 0.15s ease;
}
.form-group input:focus,
.form-group textarea:focus,
.form-group select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(230, 0, 0, 0.1);
}
.form-group textarea {
  resize: vertical;
  min-height: 100px;
  font-family: inherit;
}

/* Backtest Panel */
.backtest-panel {
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 24px;
}
.backtest-controls {
  margin-bottom: 32px;
}
.control-group {
  margin-bottom: 20px;
}
.control-group label {
  display: block;
  margin-bottom: 12px;
  font-weight: 600;
  font-size: 14px;
  color: var(--text);
}
.control-group select {
  width: 100%;
  max-width: 300px;
  padding: 10px 12px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  font-size: 14px;
  color: var(--text);
}

.period-buttons {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(80px, 1fr));
  gap: 8px;
}
.period-btn {
  padding: 10px 12px;
  border: 1px solid var(--line-strong);
  background: #fff;
  color: var(--text);
  border-radius: 8px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  transition: all 0.15s ease;
}
.period-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.period-btn.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent-strong);
}

.backtest-results {
  margin-top: 32px;
}
.results-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
  margin-bottom: 24px;
}
.result-card {
  background: var(--bg-elev-2);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 16px;
  text-align: center;
}
.result-label {
  font-size: 12px;
  color: var(--text-dim);
  font-weight: 600;
  text-transform: uppercase;
  margin-bottom: 8px;
  letter-spacing: 0.5px;
}
.result-value {
  font-size: 28px;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
/* Higher specificity than the bare .pnl-up/.pnl-down rules elsewhere (which
   would otherwise lose to .result-value's own color on declaration order),
   so Portfolio Analytics' stat tiles actually go green/red. */
.result-value.pnl-up { color: var(--ok); }
.result-value.pnl-down { color: var(--danger); }

.results-chart {
  background: var(--bg-elev-2);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 40px;
  text-align: center;
  min-height: 300px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.suggestions-list {
  display: flex;
  flex-direction: column;
  gap: 16px;
  max-height: 450px;
  overflow-y: auto;
  padding-right: 8px;
}

.suggestions-category {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.suggestions-category-title {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-dim);
  margin: 0 0 6px 0;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line);
}

.suggestion-item {
  background: var(--bg-elev-2);
  border-left: 3px solid #007c92;
  border-radius: 4px;
  padding: 11px 13px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--text);
  transition: all 0.15s ease;
}

.suggestion-item:hover {
  background: var(--line);
  border-left-color: var(--accent);
}

.suggestion-item p {
  margin: 0;
  word-wrap: break-word;
}

.suggestion-item strong {
  color: var(--text);
  font-weight: 600;
}

.suggestion-item .muted {
  color: var(--muted);
  font-size: 11px;
}

.suggestion-dismissible {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  position: relative;
}

.suggestion-dismissible p {
  flex: 1;
  padding-top: 2px;
}

.suggestion-dismiss {
  flex-shrink: 0;
  background: transparent;
  border: 1px solid var(--line-strong);
  border-radius: 3px;
  width: 24px;
  height: 24px;
  padding: 0;
  cursor: pointer;
  color: var(--text-dim);
  font-size: 12px;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.15s ease;
  margin-top: 1px;
}

.suggestion-dismiss:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--bg-elev);
}

.suggestion-dismiss:active {
  transform: scale(0.95);
}

.suggestion-dismiss:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

html.dark-mode .suggestion-dismiss {
  border-color: #4a4a54;
}

html.dark-mode .suggestion-dismiss:hover {
  border-color: #ff3333;
  background: #2a2a35;
}

html.dark-mode .suggestions-category-title {
  color: #a0a0aa;
  border-bottom-color: #3a3a42;
}

html.dark-mode .suggestion-item {
  background: #252530;
  border-left-color: #00d9ff;
}

html.dark-mode .suggestion-item:hover {
  background: #2a2a35;
  border-left-color: #ff3333;
}

html.dark-mode .suggestion-item p {
  color: #e8e8ec;
}

.history-page {
  padding: 0;
  margin: 0;
}
.history-page[hidden] {
  display: none !important;
}
.history-container {
  padding: 20px 16px;
}
.history-header {
  margin-bottom: 24px;
}
.history-header h2 {
  font-size: 24px;
  margin: 0;
  color: var(--text);
}
.history-filters {
  display: flex;
  gap: 8px;
  margin-bottom: 24px;
}

/* ============================================================
   Market News Card
   ============================================================ */
.news-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.news-controls {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}
.news-sentiment {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  padding: 3px 10px;
}
.news-sentiment.positive { background: #226626; color: #fff; }
.news-sentiment.negative { background: var(--danger); color: #fff; }
.news-sentiment.neutral { background: var(--muted); color: #fff; }
.news-table-wrap {
  max-height: 420px;
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: 10px;
}
.news-table-wrap .table-wrap { margin: 0; }
table.news-table { font-size: 12px; }
table.news-table th, table.news-table td { padding: 10px 12px; vertical-align: top; }
table.news-table td.news-datetime {
  white-space: nowrap;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
table.news-table th.news-sortable {
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
table.news-table th.news-sortable:hover { color: var(--text); }
table.news-table th.news-sortable .sort-arrow {
  display: inline-block;
  width: 10px;
  margin-left: 2px;
  color: var(--accent);
}
table.news-table th.news-sortable.sort-active { color: var(--text); }

.ticker-badge {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  background: var(--bg-elev-2);
  color: var(--text);
  border: 1px solid var(--line-strong);
  white-space: nowrap;
}

.news-headline-link {
  color: var(--text);
  text-decoration: none;
  font-weight: 600;
  line-height: 1.45;
}
.news-headline-link:hover { color: var(--accent); text-decoration: underline; }
.news-headline-hinglish {
  font-weight: 500;
  font-style: italic;
  display: block;
}
.hinglish-bullets {
  margin: 0;
  padding-left: 16px;
  list-style: disc;
}
.hinglish-bullets li {
  margin-bottom: 3px;
}
.hinglish-bullets li:last-child {
  margin-bottom: 0;
}

.impact-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
}
.impact-badge.bullish { background: #e6f4e7; color: #226626; }
.impact-badge.bearish { background: #fde7e7; color: var(--danger); }
.impact-badge.neutral { background: #ebedf0; color: #5c636c; }
html.dark-mode .impact-badge.bullish { background: rgba(34, 102, 38, 0.35); color: #7fd88a; }
html.dark-mode .impact-badge.bearish { background: rgba(189, 0, 0, 0.3); color: #ff8a8a; }
html.dark-mode .impact-badge.neutral { background: var(--bg-elev-2); color: var(--text-dim); }

.news-lang-toggle-btn {
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 600;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: var(--bg-elev-2);
  color: var(--text-dim);
  cursor: pointer;
  white-space: nowrap;
  transition: all 0.15s ease;
}
.news-lang-toggle-btn:hover { border-color: var(--accent); color: var(--accent); }

/* ============================================================
   Trade Journal
   ============================================================ */
.journal-btn {
  padding: 3px 10px;
  font-size: 11px;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: var(--bg-elev-2);
  color: var(--text-dim);
  cursor: pointer;
  transition: all 0.15s ease;
}
.journal-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.journal-btn.has-entry {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.journal-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 4px 0 16px;
}
.journal-form label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-dim);
}
.journal-form textarea {
  font-family: inherit;
  font-size: 13px;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--bg-elev-2);
  color: var(--text);
  resize: vertical;
}
.journal-stats-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line);
}
.journal-rating {
  display: flex;
  gap: 2px;
}
.star-btn {
  background: none;
  border: none;
  font-size: 20px;
  color: var(--line-strong);
  cursor: pointer;
  padding: 0 2px;
  transition: color 0.1s ease;
}
.star-btn.active,
.star-btn:hover {
  color: #f5a623;
}

.news-focus-note {
  font-size: 11px;
  margin: -4px 0 2px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 5px;
}
.news-symbol-chip {
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  border: 1px solid var(--line-strong);
  background: var(--bg-elev-2);
  color: var(--text-dim);
  cursor: pointer;
  transition: all 0.15s ease;
}
.news-symbol-chip:hover { border-color: var(--accent); color: var(--accent); }
.news-symbol-chip.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}

/* ============================================================
   Account Card - hero net liquidation + P&L
   ============================================================ */
/* .grid's default align-items:stretch keeps Account/Strategy matched to each
   other, but a shared floor keeps the row from looking cramped when either
   card's content is sparse (e.g. before connecting, or filters collapsed). */
.account-card, #strategyCard { min-height: 320px; display: flex; flex-direction: column; gap: 14px; }
/* Net Liquidation is the single most important number on the dashboard -
   every other card here shares the same border/shadow/radius regardless of
   importance, so give this one a touch more visual weight instead. */
.account-card {
  position: relative;
  border-color: var(--line-strong);
  box-shadow: var(--shadow), 0 0 0 1px rgba(230, 0, 0, .06);
}
.account-card::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px;
  border-radius: var(--radius) var(--radius) 0 0;
  background: linear-gradient(90deg, var(--accent), var(--go));
}

.account-hero {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 14px 16px;
  border-radius: 12px;
  background: linear-gradient(135deg, var(--bg-elev-2), var(--bg-elev));
  border: 1px solid var(--line);
}
.account-hero-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .4px;
  color: var(--text-dim);
}
.account-hero-value {
  font-size: 28px;
  font-weight: 800;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}
.account-hero-pnl-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-top: 4px;
  flex-wrap: wrap;
}
.account-hero-pnl-row .total-pnl { font-size: 15px; }
.account-pnl-pct {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-dim);
}
.account-pnl-pct.pnl-up { color: var(--ok); }
.account-pnl-pct.pnl-down { color: var(--danger); }

.account-stats-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: auto auto;
  grid-auto-flow: column;
  gap: 4px 10px;
  text-align: center;
}
.account-stats-grid dt {
  font-size: 11px;
  color: var(--text-dim);
  white-space: nowrap;
  justify-self: center;
}
.account-stats-grid dd {
  text-align: center;
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
  margin-top: 2px;
}

/* ============================================================
   Strategy Card - name + state badge + icon labels
   ============================================================ */
.strategy-state-badge {
  font-size: 12px;
  font-weight: 700;
  padding: 4px 12px;
}
#stState.pill-flat::before { content: "⏸ "; }
#stState.pill-pending::before { content: "⏳ "; }
#stState.pill-long::before { content: "📈 "; }
#stState.pill-blocked::before { content: "🚫 "; }

.strategy-name-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 2px 0 12px;
}
.strategy-name {
  font-size: 18px;
  font-weight: 800;
  color: var(--accent);
}
.strategy-active-symbol {
  font-size: 12px;
  font-weight: 700;
}

.strategy-kv dt { white-space: nowrap; }

/* Strategy Performance Table */
.strategy-table-header {
  display: grid;
  grid-template-columns: 1fr 0.9fr 0.7fr 0.9fr 1.1fr 1.1fr 0.9fr;
  gap: 6px;
  padding: 8px 10px;
  margin-bottom: 8px;
  border-bottom: 2px solid var(--line-strong);
  background: var(--bg-elev-2);
  border-radius: 6px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  color: var(--text-dim);
  letter-spacing: 0.4px;
}

.strategy-table-header .col {
  display: flex;
  align-items: center;
  height: 20px;
  min-width: 0;
}

.strategy-table-body {
  display: flex;
  flex-direction: column;
  gap: 5px;
  max-height: 320px;
  overflow-y: auto;
  padding-right: 8px;
}

.strategy-table-body .empty {
  text-align: center;
  padding: 20px 4px;
  margin: 0;
}

.strategy-row {
  display: grid;
  grid-template-columns: 1fr 0.9fr 0.7fr 0.9fr 1.1fr 1.1fr 0.9fr;
  gap: 6px;
  padding: 8px 10px;
  align-items: center;
  border-radius: 5px;
  background: var(--bg-elev);
  border: 1px solid var(--line);
  transition: background 0.15s ease, border-color 0.15s ease;
  font-size: 12px;
}

.strategy-row:hover {
  background: var(--bg-elev-2);
  border-color: var(--line-strong);
}

.strategy-row .col {
  display: flex;
  align-items: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.strategy-row .col-strategy {
  font-weight: 700;
  color: var(--text);
}

.strategy-row .col-state {
  font-size: 11px;
  font-weight: 700;
  padding: 4px 8px;
  border-radius: 4px;
  text-align: center;
  background: var(--bg);
}

.strategy-row .col-state.state-flat {
  background: #fff9c4;
  color: #f57f17;
}

.strategy-row .col-state.state-long {
  background: #c8e6c9;
  color: #2e7d32;
}

.strategy-row .col-state.state-pending {
  background: #e0e0e0;
  color: #424242;
}

.strategy-row .col-qty,
.strategy-row .col-price {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text-dim);
  text-align: right;
  padding-right: 6px;
}

.strategy-row .col-unrealized {
  font-weight: 600;
  font-family: var(--mono);
  font-size: 12px;
  text-align: right;
  padding-right: 6px;
}

.strategy-row .col-unrealized.pnl-positive {
  color: var(--ok);
}

.strategy-row .col-unrealized.pnl-negative {
  color: var(--danger);
}

.strategy-row .col-unrealized.pnl-neutral {
  color: var(--text-dim);
}

.strategy-row .col-realized {
  font-weight: 600;
  font-family: var(--mono);
  font-size: 12px;
  text-align: right;
  padding-right: 6px;
}

.strategy-row .col-realized.pnl-positive {
  color: var(--ok);
}

.strategy-row .col-realized.pnl-negative {
  color: var(--danger);
}

.strategy-row .col-winrate {
  font-family: var(--mono);
  font-size: 12px;
  text-align: center;
  color: var(--text-dim);
}

/* Phase 4: Pre-Market Batch Optimize panel */
.batch-optimize {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}

.batch-optimize-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
}

.batch-optimize-title {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--text-dim);
}

.batch-optimize-status {
  font-size: 11px;
  font-family: var(--mono);
}
.batch-optimize-status.running { color: var(--go); font-weight: 700; }
.batch-optimize-status.done { color: var(--ok); font-weight: 700; }
.batch-optimize-status.error,
.batch-optimize-status.cancelled { color: var(--danger); font-weight: 700; }

.batch-optimize-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 8px;
}

.batch-field {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: 11px;
}
.batch-field > span { font-size: 10px; text-transform: uppercase; letter-spacing: 0.3px; }
.batch-field input[type="number"] {
  width: 64px;
  padding: 5px 7px;
  font-size: 12px;
  font-family: var(--mono);
  border: 1px solid var(--line-strong);
  border-radius: 5px;
  background: var(--bg-elev);
  color: var(--text);
}
.batch-field select { padding: 5px 7px; font-size: 12px; }

.batch-field-check {
  flex-direction: row;
  align-items: center;
  gap: 5px;
  padding-bottom: 6px;
  font-size: 12px;
  cursor: pointer;
}

.batch-optimize-progress { margin-top: 10px; }

.batch-bar {
  height: 6px;
  border-radius: 3px;
  background: var(--bg-elev-2);
  overflow: hidden;
  border: 1px solid var(--line);
}
.batch-bar-fill {
  height: 100%;
  width: 0%;
  background: var(--go);
  transition: width 0.3s ease;
}

.batch-optimize-detail {
  margin: 6px 0 0;
  font-size: 11px;
  font-family: var(--mono);
}

.batch-optimize-hint {
  margin: 8px 0 0;
  font-size: 11px;
  line-height: 1.45;
}

/* Sidebar Strategy Table (Compact Version) */
.strategy-sidebar-widget {
  padding: 0 20px 12px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 12px;
}

.strategy-table-header-sidebar {
  display: grid;
  grid-template-columns: 0.9fr 0.8fr 0.6fr 0.8fr 0.95fr 0.95fr 0.8fr;
  gap: 4px;
  padding: 6px 8px;
  margin-bottom: 6px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-elev-2);
  border-radius: 4px;
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
  color: var(--text-dim);
  letter-spacing: 0.3px;
}

.strategy-table-header-sidebar .col {
  display: flex;
  align-items: center;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.strategy-table-body-sidebar {
  display: flex;
  flex-direction: column;
  gap: 3px;
  max-height: 200px;
  overflow-y: auto;
}

.strategy-table-body-sidebar .empty {
  text-align: center;
  padding: 12px 4px;
  margin: 0;
  font-size: 11px;
}

.strategy-sidebar-widget .strategy-row {
  display: grid;
  grid-template-columns: 0.9fr 0.8fr 0.6fr 0.8fr 0.95fr 0.95fr 0.8fr;
  gap: 4px;
  padding: 6px 8px;
  border-radius: 4px;
  background: var(--bg-elev);
  border: 1px solid var(--line);
  font-size: 11px;
  align-items: center;
  transition: background 0.15s ease;
}

.strategy-sidebar-widget .strategy-row:hover {
  background: var(--bg-elev-2);
}

/* ---------- Swing Desk (dashboard sub-page) ---------- */
/* Uses the console's own tokens so it reads as part of the same product.
   --sw-ok / --sw-warn are the EVIDENCE colours: backtested vs unproven. */
#swingCard { --sw-ok: var(--go); --sw-warn: var(--warn); }

.swing-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
  gap: .6rem;
  margin: .9rem 0 1rem;
}
.swing-tile {
  display: flex; flex-direction: column; gap: .18rem;
  padding: .75rem .9rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-strong);
  border-radius: var(--radius);
}
.swing-tile.is-ok   { border-left-color: var(--sw-ok); }
.swing-tile.is-warn { border-left-color: var(--sw-warn); }
.swing-tile.is-bad  { border-left-color: var(--danger); }
.swing-tile-v { font-size: 1.5rem; font-weight: 650; line-height: 1; font-variant-numeric: tabular-nums; }
.swing-tile-l { font-size: .7rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: .06em; }

.swing-legend {
  font-size: .81rem; color: var(--text-dim);
  background: var(--bg-elev-2); border-radius: var(--radius);
  padding: .55rem .85rem; margin: 0 0 .9rem;
}
.swing-key { display: inline-block; width: .7rem; height: .7rem; border-radius: 2px; vertical-align: -1px; margin-right: .15rem; }
.swing-key-ok { background: var(--sw-ok); }
.swing-key-warn { background: var(--sw-warn); }

.swing-controls {
  display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
  margin-bottom: .8rem; font-size: .83rem; color: var(--text-dim);
}
.swing-ctl { display: inline-flex; align-items: center; gap: .4rem; }
.swing-ctl input[type="number"] { width: 4.4rem; }
.swing-search { min-width: 150px; }
.swing-count { margin-left: auto; font-size: .78rem; }

/* No nowrap: with twelve fixed-width columns a sortable header that cannot
   wrap ("Total Score" plus its info button) overflows into its neighbour. */
#swingTable th.swing-sortable { cursor: pointer; user-select: none; }
#swingTable th.swing-sortable:hover { color: var(--text); }
#swingTable th.swing-sorted-asc::after  { content: " \2191"; color: var(--accent); }
#swingTable th.swing-sorted-desc::after { content: " \2193"; color: var(--accent); }

#swingTable tr.swing-row { cursor: pointer; }
#swingTable tr.swing-row:hover { background: var(--bg-elev-2); }
#swingTable tr.swing-row.is-open { background: var(--bg-elev-2); box-shadow: inset 3px 0 0 var(--accent); }
#swingTable tr.is-blocked { opacity: .55; }
.swing-sym { font-weight: 650; }

/* The score bar is the point of this view: segments are sized by points and
   coloured by EVIDENCE CLASS, so "most of this score is unproven" registers
   before the number does. */
/* min-width was sized for the old, wider Score column. In the merged
   twelve-column table 116px is more than the column holds, so the bar
   pushed past its cell on every row. The bar flexes; it does not need a
   floor to stay legible. */
.swing-score { display: flex; align-items: center; gap: .4rem; min-width: 0; }
.swing-score-n { font-weight: 650; font-variant-numeric: tabular-nums; min-width: 1.6rem; }
.swing-bar { flex: 1; display: flex; height: 7px; border-radius: 4px; overflow: hidden; background: var(--line); }
.swing-bar i { display: block; height: 100%; }
.swing-seg-ok { background: var(--sw-ok); }
.swing-seg-warn { background: var(--sw-warn); }

.swing-chips { display: flex; gap: .3rem; flex-wrap: wrap; }
.swing-chip {
  font-size: .69rem; font-weight: 600; letter-spacing: .02em;
  padding: .13rem .48rem; border-radius: 999px; white-space: nowrap;
  border: 1px solid transparent;
}
.swing-chip-ok {
  background: color-mix(in srgb, var(--sw-ok) 14%, transparent);
  color: var(--sw-ok); border-color: color-mix(in srgb, var(--sw-ok) 34%, transparent);
}
/* Dashed on purpose - an unproven signal must not look as settled as a tested one. */
.swing-chip-warn {
  background: transparent; color: var(--sw-warn);
  border: 1px dashed color-mix(in srgb, var(--sw-warn) 55%, transparent);
}
.swing-chip-bad {
  background: color-mix(in srgb, var(--danger) 13%, transparent);
  color: var(--danger); border-color: color-mix(in srgb, var(--danger) 34%, transparent);
}
.swing-earn-near { color: var(--danger); font-weight: 650; }
.swing-earn-soon { color: var(--warn); }

.swing-detail {
  margin-top: 1rem; padding: 1rem 1.1rem;
  background: var(--bg-elev-2); border: 1px solid var(--line);
  border-radius: var(--radius);
}
.swing-detail-head { display: flex; align-items: baseline; gap: .6rem; }
.swing-detail-head h3 { margin: 0; font-size: 1.05rem; }
.swing-detail-sub { font-size: .81rem; color: var(--text-dim); margin: .15rem 0 .85rem; }
.swing-factors { list-style: none; margin: 0; padding: 0; display: grid; gap: .45rem; }
.swing-frow {
  display: grid; grid-template-columns: 6.5rem 3.4rem 5.5rem 1fr;
  align-items: center; gap: .7rem; font-size: .82rem; opacity: .45;
}
.swing-frow.fired { opacity: 1; }
.swing-fname { font-weight: 650; }
.swing-fpts { font-variant-numeric: tabular-nums; color: var(--text-dim); }
.swing-fbar { height: 6px; border-radius: 3px; background: var(--line); overflow: hidden; }
.swing-fbar span { display: block; height: 100%; }
.swing-fdetail { color: var(--text-dim); }

.swing-caveat {
  margin-top: 1rem; padding: .8rem 1rem;
  border-left: 3px solid var(--warn);
  background: var(--bg-elev-2); border-radius: var(--radius);
  font-size: .79rem; line-height: 1.55;
}

@media (max-width: 760px) {
  .swing-frow { grid-template-columns: 5.5rem 3rem 1fr; }
  .swing-frow .swing-fbar { display: none; }
  .swing-count { margin-left: 0; }
}

/* Swing execution status + button */
.swing-exec-note {
  font-size: .8rem;
  padding: .5rem .8rem;
  margin: 0 0 .8rem;
  border-radius: var(--radius);
  border-left: 3px solid var(--warn);
  background: var(--bg-elev-2);
  color: var(--text-dim);
}
.swing-exec-note.is-ready { border-left-color: var(--ok); }
.swing-exec-cell { text-align: right; white-space: nowrap; }

/* ---------- horizontal menubar (replaced the off-canvas sidebar) ---------- */
.menubar {
  display: flex;
  align-items: stretch;
  gap: .15rem;
  padding: 0 .5rem;
  margin-bottom: 14px;
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow-x: auto;
  /* horizontal scroll on narrow screens beats wrapping into two rows, which
     would shift every dashboard card down by a variable amount */
  scrollbar-width: thin;
}
.menubar::-webkit-scrollbar { height: 4px; }
.menubar::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 2px; }

.menubar .nav-item {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  padding: .7rem .85rem;
  white-space: nowrap;
  font-size: .86rem;
  font-weight: 550;
  color: var(--text-dim);
  text-decoration: none;
  border: 0;
  background: none;
  border-bottom: 2px solid transparent;
  transition: color .12s ease, border-color .12s ease, background .12s ease;
}
.menubar .nav-item:hover { color: var(--text); background: var(--bg-elev-2); }
.menubar .nav-item.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}
.menubar .nav-item .icon { width: 16px; height: 16px; flex: none; }

@media (max-width: 640px) {
  .menubar .nav-item { padding: .65rem .6rem; font-size: .8rem; }
  .menubar .nav-item .icon { display: none; }
}

/* ---------- explain layer: (i) buttons + language ---------- */
.lang-select {
  font: inherit;
  font-size: .76rem;
  padding: .2rem .35rem;
  border-radius: 6px;
  border: 1px solid var(--line-strong);
  background: var(--bg-elev);
  color: var(--text);
  cursor: pointer;
}

/* Deliberately quiet: an (i) sits beside almost every panel, so at full
   contrast they would compete with the data. They lift on hover. */
.explain-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  margin-left: .4rem;
  padding: 0;
  flex: none;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: transparent;
  color: var(--text-dim);
  font-size: 10px;
  font-style: italic;
  font-weight: 700;
  font-family: Georgia, "Times New Roman", serif;
  line-height: 1;
  cursor: help;
  vertical-align: middle;
  opacity: .55;
  transition: opacity .12s ease, color .12s ease, border-color .12s ease;
}
.explain-btn:hover,
.explain-btn:focus-visible {
  opacity: 1;
  color: var(--go);
  border-color: var(--go);
}

.explain-modal { max-width: 560px; }
.explain-body { margin-top: .4rem; }
.explain-body p {
  margin: 0 0 .75rem;
  font-size: .88rem;
  line-height: 1.62;
  color: var(--text-dim);
  white-space: pre-line;   /* the entries use single newlines inside a para */
}
.explain-body p:last-child { margin-bottom: 0; }

/* Tiles double as filters: clicking one narrows the table to that bucket. */
.swing-tile {
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
  transition: background .12s ease, border-color .12s ease, transform .08s ease;
}
.swing-tile:hover { background: var(--bg-elev); border-color: var(--line-strong); }
.swing-tile:active { transform: translateY(1px); }
.swing-tile:focus-visible { outline: 2px solid var(--go); outline-offset: 2px; }

/* The active tile is filled with its own accent rather than merely outlined,
   so which bucket you are looking at survives a glance. */
.swing-tile.is-active {
  background: color-mix(in srgb, var(--line-strong) 22%, transparent);
  border-color: var(--line-strong);
}
.swing-tile.is-ok.is-active {
  background: color-mix(in srgb, var(--sw-ok, var(--go)) 16%, transparent);
  border-color: var(--sw-ok, var(--go));
}
.swing-tile.is-warn.is-active {
  background: color-mix(in srgb, var(--warn) 16%, transparent);
  border-color: var(--warn);
}
.swing-tile.is-bad.is-active {
  background: color-mix(in srgb, var(--danger) 15%, transparent);
  border-color: var(--danger);
}
.swing-clear { margin-left: .5rem; }

/* Inline detail: expands under the row you clicked, instead of a panel at
   the bottom of a 100-row table that was usually off-screen. */
.swing-caret {
  display: inline-block;
  width: .7rem;
  color: var(--muted);
  transition: transform .15s ease;
}
.swing-caret.is-open { transform: rotate(90deg); color: var(--accent); }

.swing-detail-row > td { padding: 0 !important; background: var(--bg-elev-2); }
.swing-detail-inner {
  padding: 1rem 1.2rem 1.1rem 2rem;
  border-left: 3px solid var(--accent);
}
.swing-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(122px, 1fr));
  gap: .55rem;
  margin: .5rem 0 .9rem;
}
.swing-stat {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  padding: .5rem .65rem;
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-radius: 8px;
}
.swing-stat-l {
  font-size: .66rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-dim);
}
.swing-stat-v { font-size: .95rem; font-weight: 650; font-variant-numeric: tabular-nums; }

/* ---------- swing order ticket ---------- */
.ticket-modal { max-width: 430px; }
.ticket-sub { font-size: .8rem; margin: .1rem 0 .9rem; }
.ticket-grid { display: grid; grid-template-columns: 1fr 1fr; gap: .7rem; }
.ticket-f { display: flex; flex-direction: column; gap: .25rem; font-size: .76rem;
            text-transform: uppercase; letter-spacing: .05em; color: var(--text-dim); }
.ticket-f input { font-size: 1rem; padding: .45rem .55rem; font-variant-numeric: tabular-nums; }

.ticket-calc {
  display: grid; gap: .35rem;
  margin: .9rem 0 .2rem; padding: .7rem .8rem;
  background: var(--bg-elev-2); border-radius: var(--radius);
  font-size: .82rem;
}
.ticket-calc > div { display: flex; justify-content: space-between; gap: 1rem; }
.ticket-calc span { color: var(--text-dim); }
.ticket-calc strong { font-variant-numeric: tabular-nums; }

/* Loud on purpose: this is the last thing between a typo and an order. */
.ticket-warn {
  margin: .7rem 0 0; padding: .55rem .7rem;
  border-left: 3px solid var(--danger);
  background: color-mix(in srgb, var(--danger) 10%, transparent);
  color: var(--danger);
  font-size: .8rem; line-height: 1.45;
}
.swing-unaffordable { font-size: .72rem; font-style: italic; }

/* A position the strategy wants out of should be the first thing you see. */
#swingPosTable tr.swing-pos-exit { background: color-mix(in srgb, var(--danger) 7%, transparent); }
#swingPosTable tr.swing-pos-exit .swing-sym { color: var(--danger); }

/* ticket v2: sizer row, four-field grid, risk maths */
.ticket-sizer { display: flex; align-items: center; gap: .35rem; margin: .2rem 0 .7rem; }
.ticket-sizer-l {
  font-size: .7rem; text-transform: uppercase; letter-spacing: .05em;
  color: var(--text-dim); margin-right: .25rem;
}
.ticket-grid { grid-template-columns: 1fr 1fr; }
.ticket-hint { text-transform: none; letter-spacing: 0; color: var(--muted); font-size: .68rem; }
.ticket-note { font-size: .72rem; color: var(--muted); margin: .5rem 0 0; }
.ticket-calc > div:nth-child(4) { border-top: 1px solid var(--line); padding-top: .35rem; }

/* Ticket inputs were overflowing the dialog: a number input does not shrink
   below its intrinsic width inside a grid track unless min-width is reset. */
.ticket-grid { min-width: 0; }
.ticket-f { min-width: 0; }
.ticket-f input { width: 100%; min-width: 0; box-sizing: border-box; }

/* order-type switch */
.ticket-type { display: inline-flex; gap: 0; margin: .1rem 0 .6rem;
               border: 1px solid var(--line-strong); border-radius: 8px; overflow: hidden; }
.ticket-ot {
  font: inherit; font-size: .78rem; padding: .3rem .8rem;
  border: 0; background: var(--bg-elev); color: var(--text-dim); cursor: pointer;
  transition: background .12s ease, color .12s ease;
}
.ticket-ot + .ticket-ot { border-left: 1px solid var(--line-strong); }
.ticket-ot:hover { color: var(--text); }
.ticket-ot.is-active { background: var(--accent); color: #fff; font-weight: 600; }

/* a market order's price field is an estimate, not an instruction */
.ticket-f.is-muted { opacity: .65; }
.ticket-f.is-muted input { background: var(--bg-elev-2); cursor: not-allowed; }

/* ---------- persistent Holdings rail ---------- */
/* Holdings left the dashboard grid so it can sit in the same place on every
   page: what you hold is context for whatever else you are looking at. */
.workspace { display: flex; align-items: flex-start; gap: 14px; }
.page-area { flex: 1; min-width: 0; }

.holdings-rail {
  /* 260px was narrower than the card's own content: .pos-list needs 328px for
     the QTY / AVG / LAST / P&L columns, so every holding overflowed its rail
     and ran into the page beside it. 328 of content plus 46 of card padding
     and border, rounded up. */
  flex: 0 0 380px;
  position: sticky;
  top: 14px;
  max-height: calc(100vh - 28px);
  overflow-y: auto;
}
.holdings-rail-inner { display: block; }

@media (max-width: 1250px) {
  /* below this the rail squeezes the tables, so it goes back to stacking */
  .workspace { display: block; }
  .holdings-rail { position: static; max-height: none; margin-bottom: 14px; }
}

/* The holdings columns may shrink, but never below what the numbers need. */
.pos-list, .pos-card-header { min-width: 0; }

/* ---------- topbar account figures ---------- */
.topbar-acct {
  display: inline-flex;
  align-items: baseline;
  gap: .4rem;
  padding: .15rem .5rem;
  border-radius: 7px;
  background: var(--bg-elev-2);
  white-space: nowrap;
}
.topbar-acct-l {
  font-size: .64rem; text-transform: uppercase; letter-spacing: .05em;
  color: var(--text-dim);
}
.topbar-acct-v { font-size: .84rem; font-weight: 650; font-variant-numeric: tabular-nums; }
.topbar-acct-pnl { font-size: .78rem; font-variant-numeric: tabular-nums; }

/* The three account figures as a label/value column. A grid rather than three
   inline pills so the values share one right edge and read as a column of
   money - tabular-nums keeps the digits in the same place as they tick. */
.topbar-acct-stack {
  display: grid;
  /* label | figure | P&L. Three columns, and every row supplies all three
     (the P&L cell is empty on the rows that have none) so the dollar amounts
     share one right edge instead of the P&L shunting Net Liq out of line. */
  grid-template-columns: auto auto auto;
  gap: 1px .55rem;
  align-items: baseline;
  padding: .2rem .55rem;
  border-radius: 8px;
  background: var(--bg-elev-2);
  white-space: nowrap;
}
.topbar-acct-row { display: contents; }
.topbar-acct-row[hidden] { display: none; }
.topbar-acct-stack .topbar-acct-l { justify-self: start; }
.topbar-acct-stack .topbar-acct-v { justify-self: end; text-align: right; }
.topbar-acct-stack .topbar-acct-pnl { justify-self: start; }

@media (max-width: 900px) {
  .topbar-acct-l { display: none; }
  /* Without labels the stack is just numbers, so put them back on one line. */
  .topbar-acct-stack { display: inline-flex; gap: .5rem; }
  .topbar-acct-row { display: inline-flex; }
  .topbar-acct-stack .topbar-acct-l { display: none; }
}
.swing-sector { font-size: .78rem; color: var(--text); margin: 0 0 .8rem; font-weight: 600; }
#swingFwdTable tr.swing-fwd-base td { border-top: 1px solid var(--line-strong); font-size: .78rem; }

/* ---------------------------------------------------- Wall Street Desk ---
   Snapshot-only institutional data. Uses the existing tokens throughout so
   it inherits both themes without a second palette to keep in sync. */

.ws-caveat { margin: 0 0 12px; }

.ws-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
}

.ws-col h3 {
  margin: 0 0 8px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.ws-list { list-style: none; margin: 0; padding: 0; }

.ws-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  padding: 7px 0;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
}

.ws-list li:last-child { border-bottom: 0; }

.ws-sym { font-weight: 600; font-family: var(--mono); }

.ws-val { font-size: 12px; font-weight: 600; }
.ws-val.is-ok { color: var(--ok); }
.ws-val.is-bad { color: var(--danger); }

/* The muted third column is a name or a summary and can run long - let it
   take the remaining width and ellipsize rather than wrapping the row. */
.ws-list li .muted {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ws-regime {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  color: var(--text-dim);
}

.ws-regime.is-on { color: var(--ok); border-color: var(--ok); }
.ws-regime.is-off { color: var(--warn); border-color: var(--warn); }
.ws-regime.is-idle { color: var(--muted); }

/* ------------------------------------------- Master Confluence Signals ---
   Top card on the Swing Desk. Verdict colours are deliberately the same
   three the rest of the app uses for good / caution / bad, so a green here
   means what green means everywhere else. */

.conf-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 12px;
}

.conf-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: var(--bg-elev-2);
  color: var(--text-dim);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}

.conf-chip:hover { border-color: var(--muted); }
.conf-chip.is-active { color: var(--text); border-color: var(--text-dim); }
.conf-chip span { font-family: var(--mono); }

#confTable { width: 100%; }
#confTable td { vertical-align: middle; }
.conf-sym { font-family: var(--mono); font-weight: 600; }

.conf-verdict {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .03em;
  white-space: nowrap;
}

.conf-verdict.is-super { color: var(--ok); }
.conf-verdict.is-buy { color: var(--warn); }
.conf-verdict.is-none { color: var(--muted); }
.conf-verdict.is-avoid { color: var(--danger); }

.conf-action { white-space: nowrap; }

.conf-blocked {
  font-size: 12px;
  color: var(--muted);
  border: 1px dashed var(--line-strong);
  border-radius: 6px;
  padding: 3px 9px;
}

/* An unmatured horizon is not a neutral reading, so it is styled as absent
   information rather than as a zero. */
.conf-edge-none { font-style: italic; }

/* The merged table carries both tables' columns. It is laid out to FIT the
   card rather than to scroll: fixed layout with percentage widths, and long
   text wraps inside its cell instead of being cut off. Truncating was the
   wrong trade - "2+ upgrades in 72h · 63% he…" hides the part that matters. */

#swingTable {
  width: 100%;
  table-layout: fixed;
}

/* Percentages, summing to 100. The two prose columns get the most room; the
   numeric ones need only their few characters. */
#swingTable th:nth-child(1),  #swingTable td:nth-child(1)  { width: 5%; }   /* Symbol */
#swingTable th:nth-child(2),  #swingTable td:nth-child(2)  { width: 5%; }   /* Price */
#swingTable th:nth-child(3),  #swingTable td:nth-child(3)  { width: 6%; }   /* Total Score */
#swingTable th:nth-child(4),  #swingTable td:nth-child(4)  { width: 16%; }  /* Swing Engine Status */
#swingTable th:nth-child(5),  #swingTable td:nth-child(5)  { width: 16%; }  /* Wall Street Confluence */
#swingTable th:nth-child(6),  #swingTable td:nth-child(6)  { width: 9%; }   /* Forward Matrix Edge */
#swingTable th:nth-child(7),  #swingTable td:nth-child(7)  { width: 5%; }   /* Upside */
#swingTable th:nth-child(8),  #swingTable td:nth-child(8)  { width: 5%; }   /* Analysts */
#swingTable th:nth-child(9),  #swingTable td:nth-child(9)  { width: 5%; }   /* Earnings */
#swingTable th:nth-child(10), #swingTable td:nth-child(10) { width: 12%; }  /* Signals */
#swingTable th:nth-child(11), #swingTable td:nth-child(11) { width: 10%; }  /* Master Signal */
#swingTable th:nth-child(12), #swingTable td:nth-child(12) { width: 6%; }  /* Action */

/* Wrap rather than overflow. */
#swingTable th, #swingTable td {
  white-space: normal;
  vertical-align: top;
  /* The app-wide 22px horizontal padding costs 528px across twelve columns -
     nearly half the card - and every pixel of it comes out of the text, which
     then wraps into tall rows. */
  padding-left: 8px;
  padding-right: 8px;
}

/* `anywhere` only on the PROSE columns, which can carry an unbroken token no
   space-based wrap can split. Applying it table-wide broke words mid-letter
   inside the buttons and chips - "Execute Ticket" became a 214px column of
   single characters in a 66px cell. */
#swingTable td.col-wide, #swingTable td.col-mid { overflow-wrap: anywhere; }

/* Labels and chips break at spaces only, never inside a word. */
#swingTable .swing-exec-cell, #swingTable .conf-verdict,
#swingTable .swing-chip, #swingTable .conf-blocked {
  overflow-wrap: normal;
  word-break: keep-all;
}
/* The verdict wraps between its icon and its label rather than spilling
   into the Action column - "NO-TRADE" is wider than the cell once the
   window narrows. */
#swingTable .conf-verdict { white-space: normal; }

/* The detail row spans everything, so it must not inherit a column width. */
#swingTable tr.swing-detail-row > td { width: auto; }

#swingTable .col-wide, #swingTable .col-mid { line-height: 1.35; }

/* Headers wrap across lines rather than spilling into the next column. The
   column widths above are chosen so each one fits its longest UNBREAKABLE
   word ("Analysts", "Earnings") - wrapping cannot save a single word that is
   wider than its column. */
#swingTable thead th { line-height: 1.25; }

/* The action button has to shrink with its column rather than force the
   table wider than the card. */
#swingTable .swing-exec-cell .btn-secondary {
  width: 100%;
  padding-left: 6px;
  padding-right: 6px;
  white-space: normal;
  overflow-wrap: normal;
  word-break: keep-all;
  line-height: 1.25;
}

/* Container query, not a media query. The table sits beside a 344px holdings
   rail, so its width is the window minus the rail minus the padding - and a
   viewport rule was dropping columns that still fitted while keeping ones
   that did not. This measures the space the table actually has. */
#swingCard .table-wrap { container-type: inline-size; }

@container (max-width: 1080px) {
  /* Below this the two prose columns squeeze the rest hard enough that the
     verdict and the price start overflowing their own cells. The narrative is
     still in the pop-down, so nothing is lost by dropping them. */
  #swingTable th.col-wide, #swingTable td.col-wide,
  #swingTable th.col-mid, #swingTable td.col-mid { display: none; }
}

@supports not (container-type: inline-size) {
  @media (max-width: 1430px) {
    #swingTable th.col-wide, #swingTable td.col-wide,
    #swingTable th.col-mid, #swingTable td.col-mid { display: none; }
  }
}

/* ------------------------------------- menubar connection switch ---------
   Replaces the full-width Connect / Disconnect bar. That bar spent an entire
   horizontal strip of the console on two buttons whose whole job is to show
   and toggle one boolean. */

.nav-conn {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;          /* pins it to the right end of the menubar */
  padding-left: 14px;
  white-space: nowrap;
}

.nav-conn-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--muted);
  box-shadow: 0 0 0 3px rgba(154, 160, 168, .18);
}
.nav-conn-dot.is-on {
  background: var(--ok);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ok) 22%, transparent);
}

.nav-conn-label {
  font-size: 11px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-dim);
}

.nav-conn-switch { position: relative; display: inline-block; width: 34px; height: 18px; }
.nav-conn-switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.nav-conn-slider {
  position: absolute; inset: 0; border-radius: 999px;
  background: var(--line-strong); transition: background .18s ease;
  pointer-events: none;
}
.nav-conn-slider::before {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 14px; height: 14px; border-radius: 50%;
  background: #fff; transition: transform .18s ease;
}
.nav-conn-switch input:checked + .nav-conn-slider { background: var(--ok); }
.nav-conn-switch input:checked + .nav-conn-slider::before { transform: translateX(16px); }
.nav-conn-switch input:disabled + .nav-conn-slider { opacity: .55; }
.nav-conn-switch input:focus-visible + .nav-conn-slider { outline: 2px solid var(--go); outline-offset: 2px; }

/* ------------------------------------------------ symbol search bar ------ */

/* Centred and capped rather than stretched edge to edge: a search field as
   wide as the window reads as a form to fill in, not a box to type a ticker
   into. The width cap is what makes it look like a search box at all. */
.controls-search { display: flex; justify-content: center; }

.symsearch {
  position: relative;
  display: flex;
  flex-direction: column;      /* field on top, results underneath */
  align-items: stretch;
  width: min(520px, 100%);
}
.symsearch-field {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
}

.symsearch-icon {
  position: absolute; left: 13px; width: 15px; height: 15px;
  color: var(--muted); pointer-events: none;
}

.symsearch input {
  width: 100%;
  padding: 8px 14px 8px 36px;      /* was 11px tall top and bottom */
  font-size: 13px;
  line-height: 1.35;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: var(--bg-elev);
  color: var(--text);
  box-shadow: 0 1px 3px rgba(37, 40, 43, .05);
  transition: box-shadow .16s ease, border-color .16s ease;
}
/* Lifts on hover and focus the way a search box does, instead of only
   changing colour. */
.symsearch input:hover { box-shadow: 0 1px 8px rgba(37, 40, 43, .12); }
.symsearch input:focus {
  outline: none;
  border-color: var(--go);
  box-shadow: 0 1px 10px rgba(37, 40, 43, .14),
              0 0 0 3px color-mix(in srgb, var(--go) 16%, transparent);
}
.symsearch input::placeholder { color: var(--muted); }

.symsearch-list {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0;
  z-index: 60;                /* above the cards, below any modal (120) */
  margin: 0; padding: 6px; list-style: none;
  background: var(--bg-elev);
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  box-shadow: var(--shadow);
  max-height: 320px; overflow-y: auto;
}

.symsearch-item {
  display: flex; align-items: baseline; gap: 10px;
  padding: 8px 12px; border-radius: 8px; cursor: pointer; font-size: 13px;
}
.symsearch-item:hover, .symsearch-item.is-active { background: var(--bg-elev-2); }
.symsearch-sym { font-family: var(--mono); font-weight: 700; min-width: 56px; }
.symsearch-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.symsearch-tag { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.symsearch-item.is-held .symsearch-tag { color: var(--ok); }
.symsearch-empty { padding: 10px 12px; font-size: 13px; color: var(--muted); }

.symsearch-status { font-size: 12px; white-space: nowrap; }
.symsearch-status.is-ok { color: var(--ok); }
.symsearch-status.is-err { color: var(--danger); }
.symsearch-status.is-busy { color: var(--text-dim); }

/* ------------------------------------ a row that is still being added ---- */

.swing-row.is-pending { opacity: .85; }
.swing-pending-cell { color: var(--text-dim); font-size: 12.5px; }

.swing-spinner {
  display: inline-block; width: 12px; height: 12px; margin-right: 8px;
  vertical-align: -2px; border-radius: 50%;
  border: 2px solid var(--line-strong); border-top-color: var(--go);
  animation: swing-spin .7s linear infinite;
}
@keyframes swing-spin { to { transform: rotate(360deg); } }

/* A freshly added row is easy to lose in two hundred. */
.swing-row.is-new { animation: swing-flash 2.4s ease-out; }
@keyframes swing-flash {
  0%, 30% { background: color-mix(in srgb, var(--go) 20%, transparent); }
  100% { background: transparent; }
}

@media (prefers-reduced-motion: reduce) {
  .swing-spinner { animation: none; }
  .swing-row.is-new { animation: none; outline: 2px solid var(--go); }
}

/* ------------------------------------------------------- table pager ----- */

.swing-pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 14px;
}

.swing-page-btn {
  min-width: 34px;
  padding: 5px 10px;
  border-radius: 8px;
  border: 1px solid var(--line-strong);
  background: var(--bg-elev-2);
  color: var(--text-dim);
  font-size: 12.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
.swing-page-btn:hover:not(:disabled) { border-color: var(--muted); color: var(--text); }
.swing-page-btn.is-active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.swing-page-btn:disabled { opacity: .45; cursor: default; }

.swing-page-gap { color: var(--muted); padding: 0 2px; }
.swing-page-of { margin-left: auto; font-size: 12px; color: var(--muted); }

#swingPageSize {
  padding: 3px 6px;
  border-radius: 6px;
  border: 1px solid var(--line-strong);
  background: var(--bg-elev);
  color: var(--text);
  font-size: 12.5px;
}

/* ------------------------------------------- expanded company detail ----- */

.dt-panel {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
  gap: 14px;
  margin-top: 16px;
}

.dt-card {
  background: var(--bg-elev-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 12px 14px;
}
.dt-card-wide { grid-column: span 2; }
@media (max-width: 900px) { .dt-card-wide { grid-column: span 1; } }

.dt-card h4 {
  margin: 0 0 10px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.dt-grid { display: flex; flex-direction: column; gap: 1px; }

.dt-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 5px 0;
  border-bottom: 1px solid var(--line);
  font-size: 12.5px;
}
.dt-row:last-child { border-bottom: 0; }
.dt-k { color: var(--text-dim); }
.dt-v { font-weight: 600; font-variant-numeric: tabular-nums; text-align: right; }

.dt-why { margin: 10px 0 0; font-size: 11.5px; line-height: 1.45; }

.dt-loading {
  display: flex; align-items: center; gap: 8px;
  margin-top: 16px; font-size: 12.5px; color: var(--text-dim);
}

/* --- analyst donut ------------------------------------------------------- */

.donut-wrap { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.donut { width: 132px; height: 132px; flex: 0 0 auto; }
.donut-seg { transition: opacity .15s ease; }
.donut-seg:hover { opacity: .78; }

.donut-mid {
  text-anchor: middle; font-size: 19px; font-weight: 700;
  fill: var(--text); font-variant-numeric: tabular-nums;
}
.donut-sub { text-anchor: middle; font-size: 8.5px; fill: var(--muted);
  letter-spacing: .08em; text-transform: uppercase; }

.donut-legend { list-style: none; margin: 0; padding: 0; flex: 1 1 150px; min-width: 0; }
.donut-legend li {
  display: flex; align-items: center; gap: 8px;
  padding: 3px 0; font-size: 12px;
}
.donut-legend li strong { margin-left: auto; font-variant-numeric: tabular-nums; }
.donut-legend li .muted { min-width: 34px; text-align: right; }
.donut-key { width: 10px; height: 10px; border-radius: 2px; flex: 0 0 auto; }
.donut-total { margin-top: 6px; border-top: 1px solid var(--line); padding-top: 6px; }

/* -------------------------------- small add box above the table --------- */

.swing-add { position: relative; display: inline-flex; align-items: center; gap: 6px; }

.swing-add input {
  width: 150px;
  padding: 4px 9px;
  font-size: 12.5px;
  border-radius: 6px;
  border: 1px solid var(--line-strong);
  background: var(--bg-elev);
  color: var(--text);
}
.swing-add input:focus {
  outline: none;
  border-color: var(--go);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--go) 18%, transparent);
}
.swing-add .symsearch-list {
  top: calc(100% + 4px);
  left: 0;
  right: auto;
  width: 320px;
}

/* ------------------------------------------------ research drawer ------- */
/* A slide-over, not an inline panel: looking a stock up is a detour, and the
   page you were on should be exactly where you left it when you close. */

.research-scrim {
  position: fixed; inset: 0; z-index: 110;
  background: rgba(37, 40, 43, .45);
  backdrop-filter: blur(2px);
}
.research-scrim[hidden] { display: none; }

.research-drawer {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  z-index: 115;                 /* above the scrim, below confirmModal (120) */
  width: min(860px, 94vw);
  display: flex;
  flex-direction: column;
  background: var(--bg-elev);
  border-left: 1px solid var(--line-strong);
  box-shadow: -18px 0 48px rgba(37, 40, 43, .22);
  transform: translateX(100%);
  transition: transform .22s ease;
}
.research-drawer[hidden] { display: none; }
.research-drawer.is-open { transform: translateX(0); }

@media (prefers-reduced-motion: reduce) {
  .research-drawer { transition: none; }
}

body.drawer-open { overflow: hidden; }

.research-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  padding: 14px 18px;
  border-bottom: 1px solid var(--line);
}
.research-head h2 { margin: 0; font-size: 17px; }
.research-actions { display: flex; gap: 8px; }

.research-scroll { flex: 1 1 auto; overflow-y: auto; padding: 16px 18px 24px; }

.research-chart { margin-bottom: 4px; }
.tv-wrap {
  height: 400px;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--line);
}
.tv-wrap > div { width: 100%; height: 100%; }
@media (max-width: 900px) { .tv-wrap { height: 280px; } }

/* --- 52-week range ------------------------------------------------------ */

.w52 { margin-top: 12px; }
.w52-bar {
  position: relative;
  height: 6px;
  border-radius: 999px;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--danger) 45%, transparent),
    var(--line-strong),
    color-mix(in srgb, var(--ok) 45%, transparent));
}
.w52-dot {
  position: absolute; top: 50%;
  width: 12px; height: 12px; margin-left: -6px;
  transform: translateY(-50%);
  border-radius: 50%;
  background: var(--text);
  border: 2px solid var(--bg-elev);
}
.w52-ends {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-top: 6px; font-size: 12px; font-variant-numeric: tabular-nums;
}
.w52-ends em { display: block; font-style: normal; font-size: 10px;
  color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
.w52-hi { text-align: right; }
.w52-pos { color: var(--text-dim); font-weight: 600; }

/* The research panel reuses the pop-down's cards, so it inherits the same
   grid without a second set of rules. */
.research-body .dt-panel { margin-top: 12px; }

/* ---------------------------------------- the evidence conclusion ------- */

.op-card { border-color: var(--line-strong); }

.op-head {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  padding: 8px 12px; border-radius: 8px; margin-bottom: 12px;
  border-left: 4px solid var(--muted);
  background: var(--bg-elev);
}
.op-verdict { font-weight: 700; font-size: 13.5px; }

.op-head.is-for        { border-left-color: var(--ok); }
.op-head.is-mixfor     { border-left-color: color-mix(in srgb, var(--ok) 60%, var(--muted)); }
.op-head.is-mixed      { border-left-color: var(--warn); }
.op-head.is-mixagainst { border-left-color: color-mix(in srgb, var(--danger) 60%, var(--muted)); }
.op-head.is-against    { border-left-color: var(--danger); }
.op-head.is-unknown    { border-left-color: var(--muted); }

.op-head.is-for .op-verdict { color: var(--ok); }
.op-head.is-against .op-verdict { color: var(--danger); }
.op-head.is-mixed .op-verdict { color: var(--warn); }

/* --- the for/against balance bar --- */
.op-bar {
  display: flex; height: 10px; border-radius: 999px; overflow: hidden;
  background: var(--line);
}
.op-bar-for { background: var(--ok); }
.op-bar-against { background: var(--danger); }
.op-bar-ends {
  display: flex; justify-content: space-between;
  margin: 5px 0 14px; font-size: 11.5px; font-weight: 600;
}
.op-for-n { color: var(--ok); }
.op-against-n { color: var(--danger); }

.op-cols {
  display: grid; grid-template-columns: 1fr 1fr; gap: 16px;
}
@media (max-width: 760px) { .op-cols { grid-template-columns: 1fr; } }

.op-h {
  margin: 0 0 6px; font-size: 11px; font-weight: 700;
  letter-spacing: .05em; text-transform: uppercase; color: var(--text-dim);
}

.op-list { list-style: none; margin: 0 0 10px; padding: 0; }
.op-list li {
  display: flex; gap: 7px; align-items: baseline;
  padding: 4px 0; font-size: 12.5px; line-height: 1.45;
}
.op-list li.is-strong { font-weight: 600; }
.op-mark { flex: 0 0 auto; font-weight: 700; }
.op-for .op-mark { color: var(--ok); }
.op-against .op-mark { color: var(--danger); }
.op-neutral .op-mark { color: var(--muted); }

.op-intraday {
  margin-top: 6px; padding: 9px 12px; border-radius: 8px;
  background: var(--bg-elev); border-left: 4px solid var(--muted);
  font-size: 12.5px;
}
.op-intraday.is-for { border-left-color: var(--ok); }
.op-intraday.is-mixed { border-left-color: var(--warn); }
.op-intraday.is-against { border-left-color: var(--danger); }
.op-intra-note { margin-top: 5px; font-size: 11.5px; color: var(--text-dim); }
.op-intra-note.is-bad { color: var(--danger); }

.op-caveat { border-top: 1px solid var(--line); padding-top: 9px; margin-top: 12px; }

/* ------------------------------------------------- trend column --------- */
/* Market direction on top, this stock's underneath. The market line repeats
   on every row on purpose: it is context, and repeating it is what makes a
   red stock inside a green market jump out. */

.trend-cell { display: flex; flex-direction: column; gap: 2px; line-height: 1.25; }

.trend-mkt {
  font-size: 10px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase;
}
.trend-stock { font-size: 12px; font-weight: 600; white-space: nowrap; }

.trend-mkt.is-up, .trend-stock.is-up { color: var(--ok); }
.trend-mkt.is-down, .trend-stock.is-down { color: var(--danger); }
.trend-mkt.is-flat, .trend-stock.is-flat { color: var(--warn); }

.swing-fwd-edge { margin-top: 10px; }

/* Cash now lives inside .topbar-acct-stack, which owns its own spacing. */

/* controls rehomed from the top bar into Settings */
.settings-row {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 9px 0; border-bottom: 1px solid var(--line);
}
.settings-row:last-child { border-bottom: 0; }
.settings-row .btn { flex: 0 0 auto; }
.settings-hint { flex: 1 1 220px; min-width: 0; }

/* ---------------------------------------------- trend glyphs ------------ */
/* Shaped by the CLASSIFICATION, not the raw price path - see trendGlyph().
   Plotting the real 24-day closes drew a falling line on a row labelled
   "MKT up", because SPY sits above its 200-day while having drifted down
   over the last month. Both facts true; together they looked broken. */

.spark { width: 38px; height: 13px; margin-left: 5px; flex: 0 0 auto; overflow: visible; }
.spark path { fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; }
.spark-dot { fill: currentColor; }

@keyframes spark-draw { to { stroke-dashoffset: 0; } }

/* The market line repeats on every row, so it is quieter than the stock's
   own - otherwise 200 identical glyphs dominate the column. */
.trend-mkt .spark { opacity: .5; width: 30px; height: 10px; }

.trend-stock, .trend-mkt { display: inline-flex; align-items: center; }

/* One width for every label, so the glyphs start on the same x in every row
   and the column reads as a column rather than ragged text. */
/* Sized to the longest label ("sideways") and no wider - the word plus the
   glyph together set this column's minimum, and 5.4em pushed it 7px past
   what the column holds. */
.trend-word { display: inline-block; min-width: 4.6em; font-size: 11.5px; }
.trend-mkt .trend-word { font-size: 9.5px; min-width: 5.2em; }

@media (prefers-reduced-motion: reduce) {
  .spark path { animation: none !important; stroke-dashoffset: 0 !important; }
}

/* The symbol IS the control - click it to trade that holding. Styled as a
   link rather than a button so it stays a symbol first and an action second;
   the confirmation dialog is what actually guards the order. */
.pos-card-sym.pos-card-trade {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-weight: 700;
  color: var(--text);
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 3px;
  transition: color .12s ease, text-decoration-color .12s ease;
}
.pos-card-sym.pos-card-trade:hover,
.pos-card-sym.pos-card-trade:focus-visible {
  color: var(--go);
  text-decoration-color: currentColor;
}

#holdingTicketModal .ticket-sizer { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }
#holdingTicketModal .ht-size { display: inline-flex; gap: 5px; align-items: baseline; }

/* The Action button opens a dialog, so it only has to name the action - the
   detail lives in the ticket. "Execute Ticket ⚡" needed a column three times
   this wide for no extra information. */
#swingTable .swing-exec-cell .btn-secondary {
  font-size: 11px; padding: 2px 4px; width: 100%; min-width: 0;
}
#swingTable .conf-blocked { font-size: 10.5px; padding: 2px 5px; }

/* Signals: a 2x2 grid, not a ragged wrap. Four chips flowing freely gave
   three stacked on one side and one adrift on the other, which forced the
   column wide to hold a shape nothing needed. */
#swingTable .swing-chips {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2px 3px;
  align-items: start;
}
#swingTable .swing-chip {
  font-size: .6rem; padding: .08rem .3rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Score: the number ABOVE the bar rather than beside it. Side by side, the
   two together set the column's minimum width; stacked, the column only has
   to be as wide as the wider of them. */
#swingTable .swing-score {
  flex-direction: column;
  align-items: stretch;
  gap: 2px;
}
#swingTable .swing-score-n { min-width: 0; font-size: 12.5px; line-height: 1.1; }

/* flex: 0 0 6px, NOT the inherited flex: 1. In a row that meant "take the
   leftover width"; in this column layout it means flex-basis 0 on the HEIGHT,
   which collapsed the bar to nothing. The green/amber split vanished while
   the markup was still there. */
#swingTable .swing-bar {
  flex: 0 0 6px;
  height: 6px;
  width: 100%;
  max-width: none;
}

/* ================================= dashboard front page ================= */
/* Account and Risk & Portfolio Heat moved to Intraday. The account figures
   already sit in the top bar, and portfolio heat describes what the intraday
   engine is doing with its budget - neither earned a slot on the page you
   look at first. What is left: a chart, and the news. */

.chart-card { display: flex; flex-direction: column; }

.dash-chart {
  /* The custom property is only set once the user has resized, so an
     untouched chart keeps the responsive default rather than being pinned to
     whatever height the window happened to be the first time. */
  height: var(--dash-chart-h, clamp(340px, 46vh, 560px));
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--bg-elev-2);
}
.tv-mount { width: 100%; height: 100%; }

/* ---------- chart resize grip ---------- */
.dash-chart-grip {
  height: 14px;
  margin: 2px 0 -4px;
  display: flex; align-items: center; justify-content: center;
  cursor: ns-resize;
  border-radius: 6px;
  touch-action: none;          /* or a touch drag scrolls the page instead */
}
.dash-chart-grip span {
  display: block; width: 46px; height: 4px; border-radius: 999px;
  background: var(--line-strong);
  transition: background .15s ease, width .15s ease;
}
.dash-chart-grip:hover span,
.dash-chart-grip:focus-visible span,
.dash-chart-grip.is-dragging span { background: var(--accent); width: 72px; }
.dash-chart-grip:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* While dragging, the pointer leaves the grip and crosses the TradingView
   iframe, which would swallow the move events. */
body.chart-resizing { cursor: ns-resize; user-select: none; }
body.chart-resizing iframe { pointer-events: none; }

/* "Already on the Swing Desk" - a statement, not a dead button. */
.chart-ondesk {
  display: inline-flex; align-items: center; gap: 5px;
  background: color-mix(in srgb, var(--ok) 14%, transparent); color: var(--ok);
  text-transform: none; letter-spacing: 0;
}
.chart-ondesk .icon { width: 12px; height: 12px; }
/* display: inline-flex above outranks the UA's [hidden] rule, so without this
   the pill stays on screen next to the Add button it is meant to replace. */
.chart-ondesk[hidden] { display: none; }

/* ---------- chart full screen ----------
   Fills the viewport whether or not the browser granted native fullscreen,
   so the expand button behaves the same either way. position: fixed against
   the viewport works in both cases: outside native fullscreen the viewport is
   the window, inside it the card IS the fullscreen element and the fixed box
   resolves to the same rectangle. */
#dashChartCard.is-full {
  position: fixed;
  inset: 0;
  z-index: 300;
  margin: 0;
  padding: 0;
  border-radius: 0;
  max-width: none;
  display: flex;
  flex-direction: column;
  background: var(--bg-elev);
  overflow: hidden;            /* nothing scrolls behind a full-screen chart */
}
/* The header shrinks to a thin strip - in full screen the title and the exit
   control are all that is needed, and every row of chrome is a row of chart. */
#dashChartCard.is-full .pos-head {
  flex: 0 0 auto;
  margin: 0;
  padding: 6px 12px;
  border-bottom: 1px solid var(--line);
}
#dashChartCard.is-full .pos-head h2 { margin: 0; font-size: 12px; }
#dashChartCard.is-full .dash-chart {
  /* Full screen means the CHART is full screen. It takes everything the thin
     header leaves, rather than sharing the space with a detail panel you did
     not expand the chart to read. */
  flex: 1 1 auto;
  height: auto;
  min-height: 0;
  border: 0;
  border-radius: 0;
}
#dashChartCard.is-full .dash-chart-grip { display: none; }
/* The fundamentals are still one Esc away on the normal card. */
#dashChartCard.is-full .dash-chart-detail { display: none; }
/* The page behind a fullscreen chart must not scroll under it. */
body.has-chart-full { overflow: hidden; }

/* ---------- collapsible Holdings rail ----------
   Collapsed, the rail keeps a narrow strip so there is always something to
   click to bring it back - a rail that vanishes completely leaves no way in. */
.rail-expand { display: none; }

body.rail-collapsed .holdings-rail {
  flex: 0 0 34px;
  overflow: visible;
}
body.rail-collapsed .holdings-rail-inner { display: none; }
body.rail-collapsed .rail-expand {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 34px;
  padding: 12px 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg-elev);
  color: var(--text-dim);
  cursor: pointer;
  /* Reads bottom-to-top up the strip, the usual convention for a vertical
     tab label, so the word is not one letter per line. */
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  justify-content: flex-end;
}
body.rail-collapsed .rail-expand:hover {
  color: var(--text);
  border-color: var(--line-strong);
}
.rail-expand-label {
  font-size: 11px; font-weight: 700; letter-spacing: .6px; text-transform: uppercase;
}
.rail-expand .icon { width: 14px; height: 14px; transform: rotate(90deg); }

/* The collapse control sits in the card header next to the title. */
#btnRailCollapse { margin-left: auto; }

@media (max-width: 1250px) {
  /* The rail already stacks above the page at this width, so there is no
     horizontal space to win back - collapsing it would just hide Holdings. */
  body.rail-collapsed .holdings-rail { flex: none; }
  body.rail-collapsed .holdings-rail-inner { display: block; }
  body.rail-collapsed .rail-expand { display: none; }
}


.dash-chart-msg {
  display: grid;
  place-items: center;
  height: 100%;
  margin: 0;
  padding: 0 24px;
  text-align: center;
  max-width: 46ch;
  margin-inline: auto;
  line-height: 1.5;
}

.dash-chart-detail:not(:empty) { margin-top: 16px; }
.dash-chart-detail .dt-panel { margin-top: 0; }

/* The search hint fades once a real symbol is loaded - it has done its job. */
#dashChartHint:empty { display: none; }

/* --- the two cards in their new home on Intraday --- */
.intraday-top {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 14px;
  margin-bottom: 14px;
}
.intraday-top > .card { margin: 0; }

/* The dashboard is now a single column, so the grid does not need to reserve
   a second track for a side panel that no longer exists. */
.dashboard .center-col { width: 100%; }


/* ---------- arm + connection switches, stacked ----------
   Moved out of the menubar so the two controls that gate real orders sit
   together. Column layout keeps the top bar's height rather than widening it
   with a second full-width control. */
.switch-stack {
  display: flex;
  flex-direction: column;
  gap: 3px;
  align-items: flex-start;
}
/* padding-left came from the menubar this block used to live in; left in
   place it indented the LIVE switch relative to Arm orders. */
.switch-stack .nav-conn { margin: 0; padding-left: 0; gap: 8px; }

/* ---------- unfilled orders: one line each ----------
   These rows had no styling at all, so each span stacked and a single order
   took three lines of a 380px rail. */
.oo-row {
  display: flex;
  align-items: baseline;
  gap: 5px;
  padding: 4px 2px;
  font-size: 11.5px;
  line-height: 1.5;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.oo-row:last-child { border-bottom: 0; }
.oo-sym { font-weight: 700; font-family: var(--mono); }
.oo-act { font-weight: 700; font-size: 10px; letter-spacing: .03em; }
.oo-act.is-buy { color: var(--ok); }
.oo-act.is-sell { color: var(--danger); }
.oo-qty { font-variant-numeric: tabular-nums; }
/* The only part allowed to shrink: everything else is short and fixed, and a
   truncated price is less use than a truncated order type. */
.oo-px { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.oo-status {
  font-size: 9.5px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-dim); flex: 0 0 auto;
}
.oo-cancel {
  flex: 0 0 auto;
  padding: 1px 6px;
  font-size: 10px;
  line-height: 1.5;
}

/* ---------- chart toolbar ---------- */
.chart-toolbar {
  display: flex; align-items: center; gap: 8px;
  margin: 0 0 8px; flex-wrap: wrap;
}
.chart-ivs { display: inline-flex; gap: 2px; }
.chart-iv {
  padding: 2px 8px; font-size: 11px; font-weight: 600;
  border: 1px solid var(--line); border-radius: 6px;
  background: transparent; color: var(--text-dim); cursor: pointer;
}
.chart-iv:hover { color: var(--text); border-color: var(--line-strong); }
.chart-iv.is-active {
  background: var(--go); border-color: var(--go); color: #fff;
}
.chart-sel {
  padding: 2px 6px; font-size: 11px;
  border: 1px solid var(--line); border-radius: 6px;
  background: var(--bg-elev); color: var(--text);
}
.chart-ind-wrap { position: relative; display: inline-block; }
.chart-ind-count { font-variant-numeric: tabular-nums; }
.chart-ind-menu {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 70;
  min-width: 190px; padding: 6px;
  background: var(--bg-elev);
  border: 1px solid var(--line-strong); border-radius: 10px;
  box-shadow: var(--shadow);
  max-height: 280px; overflow-y: auto;
}
.chart-ind-opt {
  display: flex; align-items: center; gap: 7px;
  padding: 4px 7px; font-size: 12px; border-radius: 6px; cursor: pointer;
  white-space: nowrap;
}
.chart-ind-opt:hover { background: var(--bg-elev-2); }
/* In full screen the toolbar would eat a row of chart; the settings are
   already applied, so it has nothing left to say there. */
#dashChartCard.is-full .chart-toolbar { display: none; }

/* ---------- budget cell: amount, then P&L underneath ---------- */
.budget-cell-header {
  display: inline-grid;
  grid-template-columns: auto auto;
  gap: 2px 6px;
  align-items: center;
  justify-items: start;
}
.budget-lbl { justify-self: start; }
.budget-val { display: inline-flex; align-items: center; gap: 6px; }
.budget-cell-header .total-pnl {
  font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums;
}

.session-end { display: inline-flex; align-items: center; gap: 8px; }

.budget-flash {
  font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .05em; color: var(--ok);
}
.budget-flash[hidden] { display: none; }

/* ---------- Trade dropdown in the menubar ---------- */
.nav-menu { position: relative; display: inline-flex; }
.nav-menu-btn {
  background: none;
  border: 0;
  font: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.nav-menu-caret { transform: rotate(90deg); width: 12px; height: 12px; opacity: .7; }
.nav-menu-list {
  position: fixed; z-index: 400;          /* above the menubar's overflow clip */
  min-width: 178px; padding: 5px;
  background: var(--bg-elev);
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  box-shadow: var(--shadow);
  display: flex; flex-direction: column; gap: 2px;
}
.nav-menu-list[hidden] { display: none; }
.nav-menu-item { white-space: nowrap; border-radius: 7px; }

/* ---------- news inside the pop-down ---------- */
.dt-news-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.dt-news-item { display: flex; align-items: flex-start; gap: 8px; font-size: 12px; line-height: 1.4; }
.dt-news-dot {
  flex: 0 0 auto; width: 7px; height: 7px; border-radius: 50%; margin-top: 5px;
  background: var(--muted);
}
.dt-news-dot.is-pos { background: var(--ok); }
.dt-news-dot.is-neg { background: var(--danger); }
.dt-news-text { min-width: 0; }
.dt-news-text a { color: var(--text); text-decoration: none; }
.dt-news-text a:hover { text-decoration: underline; }
.dt-news-meta { display: block; font-size: 10.5px; color: var(--text-dim); margin-top: 1px; }

.sess-acct { font-family: var(--mono); font-size: 11px; }
#connDot[hidden], #connText[hidden] { display: none; }

/* Auto-loop status, rehomed from the top bar to the page that controls it. */
.intraday-loop {
  margin: 0 0 12px;
  font-size: 12px; font-weight: 600;
  letter-spacing: .03em;
  color: var(--text-dim);
}
.intraday-loop.is-on { color: var(--ok); }

/* ---------- header label-over-detail stacks ---------- */
.hdr-stack {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  flex: 0 0 auto;            /* a stack keeps its width rather than crushing */
}
.hdr-sub {
  font-size: 10px;
  line-height: 1.2;
  color: var(--text-dim);
  white-space: nowrap;
  max-width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.hdr-sub .icon { width: 11px; height: 11px; vertical-align: -1px; }

/* Nothing in the header is hidden on a narrow screen - it WRAPS onto more
   rows instead. A nowrap + overflow-x strip was worse than the problem: the
   cells crushed into each other and the figures overlapped. */
@media (max-width: 900px) {
  .session { flex-wrap: wrap; justify-content: flex-end; gap: 8px 10px; }
  .topbar { align-items: flex-start; flex-wrap: wrap; gap: 8px; }
  .topbar .brand { flex: 1 1 100%; }
  .session > * { flex: 0 0 auto; }      /* nothing shrinks into its neighbour */
}

/* The Sign in link sits with the chart's other controls. */
#btnChartSignIn { text-decoration: none; }

/* ---------- centred search overlay ---------- */
.symsearch-overlay {
  position: fixed; inset: 0; z-index: 600;
  background: rgba(15, 16, 20, .55);
  backdrop-filter: blur(2px);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 14vh 16px 16px;
}
.symsearch-overlay[hidden] { display: none; }
.symsearch-panel {
  width: min(620px, 100%);
  background: var(--bg-elev);
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  box-shadow: 0 24px 70px rgba(0, 0, 0, .35);
  padding: 14px;
}
/* Inside the panel the field fills it; the list is in flow, not floating. */
.symsearch-panel .symsearch { width: 100%; }
/* Results sit under the field and span the panel, never beside it. */
.symsearch-panel .symsearch-list { width: 100%; }
.symsearch-panel .symsearch input { font-size: 15px; padding: 11px 14px 11px 40px; }
.symsearch-panel .symsearch-icon { left: 15px; width: 17px; height: 17px; }
.symsearch-panel .symsearch-list {
  position: static; margin-top: 8px; box-shadow: none; border: 0;
  max-height: 46vh; padding: 4px 0;
}
.symsearch-hint { margin: 10px 2px 0; font-size: 11px; }
.symsearch-hint kbd {
  background: var(--bg-elev-2); border: 1px solid var(--line);
  border-radius: 4px; padding: 1px 5px; font-family: var(--mono);
  font-size: 10px; margin: 0 1px;
}
body.has-search-overlay { overflow: hidden; }

.nav-search-btn {
  background: none; border: 0; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  margin-left: auto;            /* sits at the far end of the menubar */
}

/* ---------- the hidden attribute, meant globally ----------
   Any rule that sets `display` on a class outranks the UA's [hidden] rule, so
   `el.hidden = true` silently did nothing and the element stayed on screen.
   This file already carried sixteen one-off `.thing[hidden] { display: none }`
   patches for exactly that, and the next new component would have needed a
   seventeenth.

   Last in the file and deliberately NOT !important: it beats the
   single-class rules that caused the problem, while an id-based rule or an
   inline style.display can still override it where that is intended. */
[hidden] { display: none; }

/* ---------- title row: name, toolbar and actions on ONE line ---------- */
.chart-head {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;            /* narrow screens drop to a second row rather
                                 than squeezing the controls out of reach */
}
.chart-head h2 { margin: 0; flex: 0 0 auto; }
.chart-head .chart-toolbar { margin: 0; flex: 1 1 auto; }
.chart-head .pos-actions { margin-left: auto; flex: 0 0 auto; }

/* ---------- the header while the chart is maximised ----------
   The maximised card is a fixed overlay, and the sticky top bar sat ON TOP of
   it - logo, brand, budget, language and all - covering the chart. While the
   chart is up the bar keeps only the three figures worth watching a position
   with, over a transparent ground so the candles show through. */
body.has-chart-full .topbar {
  background: transparent;
  border-bottom: 0;
  z-index: 320;               /* above the card (300), below any modal */
  pointer-events: none;       /* the chart underneath stays draggable */
  margin: 0;
  padding: 5px 0 0;
  /* Centred: the card's own header already owns the left (symbol name) and
     the right (Sign in / exit), so the middle is the only strip free of it. */
  justify-content: center;
  gap: 8px;
}
body.has-chart-full .session { justify-content: center; gap: 8px; flex-wrap: nowrap; }
body.has-chart-full .topbar .brand,
body.has-chart-full .budget-cell-header .budget-lbl,
body.has-chart-full .budget-cell-header .budget-val,
body.has-chart-full #btnRefresh,
body.has-chart-full #btnSettings,
body.has-chart-full #btnLogout,
body.has-chart-full #sessAccount,
body.has-chart-full #langSelect,
body.has-chart-full #sessGateway,
body.has-chart-full .switch-stack,
body.has-chart-full #modeBadge,
body.has-chart-full #timezoneDisplay,
body.has-chart-full #connDot,
body.has-chart-full #connText {
  display: none;
}
/* What survives: Net Liq (with its P&L), Cash if it disagrees, Buying Power. */
body.has-chart-full .topbar-acct-stack {
  background: color-mix(in srgb, var(--bg-elev) 72%, transparent);
  backdrop-filter: blur(6px);
  border: 1px solid color-mix(in srgb, var(--line) 60%, transparent);
  pointer-events: auto;
  border-radius: 9px;
}
/* The P&L moved under Budget, which is hidden here - bring it along so the
   figure is not lost with the field it happens to sit beside. */
body.has-chart-full .budget-cell-header { display: inline-flex; }
body.has-chart-full .budget-cell-header .budget-lbl:last-of-type,
body.has-chart-full .budget-cell-header .budget-val:last-of-type {
  display: inline-flex;
  pointer-events: auto;
}
body.has-chart-full .budget-cell-header {
  background: color-mix(in srgb, var(--bg-elev) 72%, transparent);
  backdrop-filter: blur(6px);
  border: 1px solid color-mix(in srgb, var(--line) 60%, transparent);
  border-radius: 9px;
  padding: 3px 9px;
  align-items: center;
  gap: 6px;
}

/* Maximised, the card header keeps only what a chart needs: the symbol on
   the left, Sign in and the exit control on the right. The desk status and
   the search hint are for the dashboard, not for this. */
#dashChartCard.is-full #dashChartOnDesk,
#dashChartCard.is-full #btnDashChartAdd,
#dashChartCard.is-full #dashChartHint { display: none; }

/* The sign-in link, once it has been used. */
#btnChartSignIn.is-known {
  color: var(--ok);
  border-color: color-mix(in srgb, var(--ok) 45%, transparent);
}

/* ---------- account menu (avatar + dropdown) ---------- */
.acct-menu { position: relative; }
.acct-avatar {
  position: relative;
  display: inline-grid; place-items: center;
  width: 34px; height: 34px; border-radius: 50%;
  border: 0; cursor: pointer;
  background: linear-gradient(135deg, var(--go), #0a5f6e);
  color: #fff; font-weight: 700; font-size: 14px;
}
.acct-avatar:hover { filter: brightness(1.08); }
.acct-avatar-lg { width: 40px; height: 40px; font-size: 16px; cursor: default; }
.acct-dot {
  position: absolute; right: -1px; top: -1px;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--muted); border: 2px solid var(--bg);
}
.acct-dot.is-on { background: var(--ok); }

.acct-menu-list {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 420;
  min-width: 288px;
  background: var(--bg-elev);
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, .3);
  padding: 6px;
  text-align: left;
}
.acct-menu-head { display: flex; align-items: center; gap: 11px; padding: 10px 10px 12px; }
.acct-menu-who { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.acct-menu-who strong { font-size: 14px; font-family: var(--mono); }
.acct-menu-who .muted { font-size: 11px; }
.acct-menu-sep { height: 1px; background: var(--line); margin: 5px 2px; }

.acct-menu-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 9px 10px;
  background: none; border: 0; border-radius: 8px;
  color: var(--text); font: inherit; font-size: 13px;
  cursor: pointer; text-align: left;
}
.acct-menu-item:hover { background: var(--bg-elev-2); }
.acct-menu-item .icon { width: 15px; height: 15px; color: var(--text-dim); }
.acct-menu-row { justify-content: space-between; }
.acct-menu-row > span:first-child { display: inline-flex; align-items: center; gap: 10px; }
.acct-menu-static { cursor: default; }
.acct-menu-static:hover { background: none; }
.acct-menu-val { font-family: var(--mono); font-size: 11px; }
.acct-menu-danger { color: var(--accent); }
.acct-menu-danger .icon { color: var(--accent); }
.acct-menu-danger:hover { background: color-mix(in srgb, var(--accent) 12%, transparent); }

.acct-lang {
  background: var(--bg-elev-2); color: var(--text);
  border: 1px solid var(--line); border-radius: 6px;
  font-size: 12px; padding: 2px 6px;
}

/* The theme switch inside the menu, matching the header toggles. */
.acct-switch {
  position: relative; width: 34px; height: 18px; border-radius: 999px;
  background: var(--line-strong); transition: background .18s ease; flex: 0 0 auto;
}
.acct-switch-knob {
  position: absolute; top: 2px; left: 2px; width: 14px; height: 14px;
  border-radius: 50%; background: #fff; transition: left .18s ease;
}
.acct-switch.is-on { background: var(--ok); }
.acct-switch.is-on .acct-switch-knob { left: 18px; }

/* Hidden while the chart is maximised, with the rest of the header. */
body.has-chart-full .acct-menu { display: none; }

/* ---------- maximised chart: the header row goes entirely ----------
   The symbol name, the desk pill and the toolbar cost a full line of chart
   for information the chart itself already shows. What is left - the
   TradingView state and the exit control - floats over the top-right corner
   of the chart instead, on the same translucent treatment as the figures. */
#dashChartCard.is-full .pos-head {
  position: absolute;
  top: 6px;
  right: 10px;
  left: auto;
  width: auto;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  z-index: 330;
  pointer-events: none;       /* the chart under it stays draggable */
}
#dashChartCard.is-full .pos-head h2,
#dashChartCard.is-full .chart-toolbar { display: none; }
#dashChartCard.is-full .pos-actions {
  margin: 0;
  pointer-events: auto;
  gap: 6px;
  background: color-mix(in srgb, var(--bg-elev) 72%, transparent);
  backdrop-filter: blur(6px);
  border: 1px solid color-mix(in srgb, var(--line) 60%, transparent);
  border-radius: 9px;
  padding: 3px 6px;
}
/* With the header out of the flow the chart starts at the very top. */
#dashChartCard.is-full .dash-chart { margin-top: 0; }

/* ---------- role-based gating ---------- */
.rbac-badge {
  display: inline-flex; align-items: center;
  padding: 4px 10px; border-radius: 999px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  background: color-mix(in srgb, var(--warn) 16%, transparent);
  color: var(--warn);
  border: 1px solid color-mix(in srgb, var(--warn) 40%, transparent);
  white-space: nowrap;
}
.rbac-badge[hidden] { display: none; }

/* A blocked control reads as unavailable rather than merely inert. */
.rbac-blocked {
  opacity: .45 !important;
  cursor: not-allowed !important;
  filter: grayscale(.6);
}

/* Maximised chart: the brand goes with the rest of the header chrome. */
body.has-chart-full .brand { display: none; }

/* ---------- PAPER / LIVE switch ---------- */
.mode-switch {
  display: inline-flex;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  overflow: hidden;
  flex: 0 0 auto;
}
.mode-switch[hidden] { display: none; }
.mode-opt {
  padding: 4px 11px;
  font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  background: transparent; border: 0; cursor: pointer; color: var(--text-dim);
}
.mode-opt:hover:not(.is-active) { color: var(--text); }
.mode-opt.is-active { background: var(--go); color: #fff; }
/* LIVE reads red when it is the one in force - the colour IS the warning. */
.mode-opt[data-mode="LIVE"].is-active { background: var(--accent); }
.mode-opt:disabled { opacity: .4; cursor: not-allowed; }

.profile-kv { margin-bottom: 14px; }
.profile-hint { font-size: 11.5px; margin: -4px 0 12px; }

/* ---------- options flow / volatility badge ---------- */
/* Colour carries the meaning here, so both halves must read at a glance in
   either theme - every value below is a token, never a literal. A hardcoded
   green went invisible in dark mode once already (.pnl-up). */
.opt-cell { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }

.opt-vol, .opt-flow, .opt-unusual {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 1px 6px; border-radius: 999px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .02em;
  white-space: nowrap;
}

/* Volatility rank. Calm is not "good" and hot is not "bad" - they are cheap
   and expensive entry. Muted rather than green/red so the column does not
   compete with the Master Signal beside it. */
.opt-vol.is-calm { background: var(--ok-bg, rgba(34,102,38,.10)); color: var(--ok); }
.opt-vol.is-hot  { background: var(--warn-bg, rgba(180,120,0,.12)); color: var(--warn, #b47800); }

.opt-flow.is-bullish { background: var(--ok-bg, rgba(34,102,38,.10)); color: var(--ok); }
.opt-flow.is-bearish { background: var(--danger-bg, rgba(200,40,40,.10)); color: var(--danger); }
.opt-flow.is-neutral { background: var(--chip-bg, rgba(128,128,128,.12)); color: var(--text-dim); }

.opt-unusual {
  background: var(--accent-bg, rgba(80,120,220,.12));
  color: var(--accent);
  text-transform: uppercase; font-size: 9.5px;
}

.opt-none { font-size: 11px; }


/* ---------- circuit breaker banner ---------- */
/* Full-bleed and above the fold. While this is showing the desk will not
   accept a new entry, so it must not read as one more status chip. */
.cb-banner {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 16px;
  background: var(--danger); color: #fff;
  border-bottom: 1px solid rgba(0, 0, 0, .25);
}
.cb-banner[hidden] { display: none; }
.cb-banner-main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1 1 auto; }
.cb-banner-title { font-size: 12px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; }
.cb-banner-detail { font-size: 12px; line-height: 1.35; }
.cb-banner-sub { font-size: 11px; opacity: .85; }
.cb-banner .btn { flex: 0 0 auto; background: rgba(255, 255, 255, .16); color: #fff; border-color: rgba(255, 255, 255, .4); }
.cb-banner .btn:hover { background: rgba(255, 255, 255, .28); }


/* ---------- websocket status ---------- */
.ws-status {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px; border-radius: 999px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .02em;
  background: var(--warn-bg, rgba(180,120,0,.12)); color: var(--warn);
  white-space: nowrap;
}
.ws-status[hidden] { display: none; }
.ws-status-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: currentColor;
}
/* Pulsing while it is retrying, solid once it has given up - a moving dot
   reads as "working on it", a still one as "this is the state now". */
.ws-status[data-state="connecting"] .ws-status-dot { animation: wsPulse 1.1s ease-in-out infinite; }
.ws-status[data-state="offline"] { background: var(--danger-bg, rgba(200,40,40,.10)); color: var(--danger); }
@keyframes wsPulse { 0%,100% { opacity: 1; } 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) {
  .ws-status[data-state="connecting"] .ws-status-dot { animation: none; }
}

/* ---------- execution history ---------- */
.exec-head { margin: 26px 0 10px; font-size: 14px; display: flex; align-items: center; gap: 8px; }
.exec-filters {
  display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end;
  margin-bottom: 10px;
}
.exec-f { display: flex; flex-direction: column; gap: 3px; font-size: 10.5px;
          color: var(--text-dim); text-transform: uppercase; letter-spacing: .04em; font-weight: 700; }
.exec-f input, .exec-f select {
  padding: 4px 7px; font-size: 12px; text-transform: none; letter-spacing: 0;
  font-weight: 400; color: var(--text);
  border: 1px solid var(--line-strong); border-radius: 6px; background: var(--card);
  min-width: 108px;
}
.exec-summary { font-size: 12px; color: var(--text-dim); margin-bottom: 10px; }
.exec-sym { font-weight: 700; }
#execTable { font-size: 12px; }
#execTable td, #execTable th { white-space: nowrap; }

/* ---------- guest experience ---------- */
/* Every colour is a token so the lock reads correctly in BOTH themes. A
   hardcoded overlay went invisible in dark mode once already (.pnl-up). */

.btn-signin {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--go); color: #fff; border-color: var(--go);
  font-weight: 700;
}
.btn-signin:hover { filter: brightness(1.08); }
.btn-signin[hidden] { display: none; }

/* The locked panel. Kept in the LAYOUT rather than removed, so the guest
   dashboard has the same shape as the member one - a visitor can see what
   they would get, and signing in does not rearrange the page under them. */
[data-private].is-locked { position: relative; }
[data-private].is-locked > *:not(.lock-veil) {
  filter: blur(3px);
  opacity: .45;
  pointer-events: none;
  user-select: none;
}

.lock-veil {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  /* Semi-opaque rather than solid: the shape of the panel stays legible
     underneath, which is what makes it read as "locked" rather than "broken". */
  background: color-mix(in srgb, var(--card) 70%, transparent);
  border-radius: inherit;
  z-index: 2;
}
@supports not (background: color-mix(in srgb, red 50%, transparent)) {
  .lock-veil { background: var(--card); opacity: .82; }
}

.lock-cta {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 13px; border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: var(--card); color: var(--text);
  font-size: 11.5px; font-weight: 700; cursor: pointer;
  box-shadow: 0 1px 6px rgba(0, 0, 0, .12);
}
.lock-cta:hover { border-color: var(--go); color: var(--go); }
.lock-ico { width: 13px; height: 13px; }

/* The topbar figures are a strip, not a card - a blur there looks like a
   rendering fault, so they are simply replaced by the lock. */
.topbar-acct-stack.is-locked > *:not(.lock-veil) { filter: none; opacity: 0; }
.topbar-acct-stack .lock-veil { background: transparent; }
.topbar-acct-stack .lock-cta { padding: 3px 9px; font-size: 10.5px; box-shadow: none; }

.modal-narrow { max-width: 380px; }

/* A guest has no account menu; hide the controls that only make sense with
   one, rather than showing them disabled. */
body.is-guest #acctMenu,
body.is-guest #modeSwitch { display: none; }

/* ---------- sign-in: other methods ---------- */
.signin-alt { margin-top: 16px; }
.signin-or {
  display: flex; align-items: center; gap: 10px;
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-dim); margin-bottom: 10px;
}
.signin-or::before, .signin-or::after {
  content: ""; flex: 1 1 auto; height: 1px; background: var(--line-strong); opacity: .5;
}
.signin-providers { display: flex; flex-direction: column; gap: 7px; }
.signin-provider {
  display: flex; align-items: center; gap: 9px;
  width: 100%; padding: 8px 12px;
  border: 1px solid var(--line-strong); border-radius: 8px;
  background: var(--card); color: var(--text);
  font-size: 12.5px; font-weight: 600; cursor: pointer; text-align: left;
}
.signin-provider:hover:not(:disabled) { border-color: var(--go); color: var(--go); }
.signin-provider-ico { font-size: 14px; line-height: 1; }
/* An unconfigured method is shown, not hidden: a missing button reads as a
   bug, whereas a greyed one with the reason on it is an instruction. */
.signin-provider.is-off { opacity: .5; cursor: not-allowed; }
.signin-provider-why {
  margin-left: auto; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em; color: var(--text-dim);
}
