/* ============================================================================
   SINGLE STYLESHEET ENTRY. Templates load ONLY this file.
   The legacy sheet is imported here into its own cascade layer, so every
   unlayered rule below outranks it by cascade order -- no !important arms race,
   no second <link> for authors to remember. This file is the one place styles
   are written.
   ============================================================================ */
/* ==========================================================================
   Mithqal — the interface, rebuilt.

   This file is loaded after react-app.css and is authoritative. The old
   stylesheet grew to ~2,900 rules by accretion: eleven card treatments on one
   page, four type sizes for a single metric, a desktop layout squeezed into a
   phone with three full-width control rows before the first candle. Patching
   it produced patched results.

   Three rules govern everything here:

   1. MOBILE FIRST, and mobile is not a narrower desktop. The phone gets an app
      shell -- a 56px bar, a bottom tab bar, and content between them -- because
      that is what a trading app is on a phone.
   2. ONE SCALE. Every size, space and radius comes from the tokens. No literal
      pixel value appears in a layout rule.
   3. DENSITY IS THE POINT. A trading screen earns trust by fitting the numbers
      a decision needs above the fold. Whitespace is not luxury here; it is
      distance between the two numbers you are comparing.
   ========================================================================== */

:root {
  /* Surfaces, dark to light. Four steps is enough to express hierarchy and
     few enough that every surface is recognisable. */
  --s0: #080B14;
  --s1: #0E1320;
  --s2: #151C2E;
  --s3: #1D273D;
  --line: rgba(125, 155, 205, 0.14);
  --line-strong: rgba(125, 155, 205, 0.26);

  --ink-1: #F4F7FC;
  --ink-2: #B9C6DD;
  --ink-3: #7E8FAC;

  --up: #21C97A;
  /* #F2555A until 2026-08-15. Measured 4.41:1 against --s3, the lightest
     surface, which is under WCAG AA for body text -- and this is the colour a
     loss is printed in. Lightened by the smallest step that clears the bar
     (4.54:1); every other surface was already well over it. */
  --down: #F4585D;
  --flag: #E8A33D;
  --focus: #6E7BFF;

  --bar-h: 56px;
  --tabs-h: 60px;
}

/* ------------------------------------------------------------------ shell */

body {
  background: var(--s0);
  color: var(--ink-1);
  -webkit-font-smoothing: antialiased;
}
body::before { display: none; }   /* the decorative grid competed with candles */

.app-shell {
  /* ONE PAGE EDGE.
     The top bar and the session strip run to the glass, and the content was
     capped at 1500 — so on a 1920 laptop the bar stretched 210px past the
     cards on each side and the page read as two documents laid on top of one
     another. The owner's words: the navigation bar does not cover all the
     content.

     Raised, not removed: the cap still exists because a 2560 monitor should
     not stretch a grid across a metre of glass. What protects READING is the
     measure rule further down — prose is bounded at 78ch wherever the card
     ends up — so the extra width goes to the figures, the tables and the
     chart, which want it. */
  max-width: 1500px;
  margin-inline: auto;
  padding: 0;
}

/* The top bar. One row, always, at every width -- and genuinely immobile.
   `sticky` is correct in theory and jitters in practice: on a phone it is
   repositioned by the compositor on every momentum-scroll frame, and with a
   backdrop-filter on top of it the bar visibly shivers against the content
   passing behind. `fixed` is painted once and never moves. The shell pays for
   it with a matching top offset. */
/* The header must not let data ghost through the wordmark: glass with
   real blur, not translucency alone (app demolition wave, finding 6). */
.top-nav {
  backdrop-filter: blur(14px) saturate(1.3);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  block-size: var(--bar-h);
  padding-inline: var(--space-4);
  margin: 0;
  background: var(--s1);
  border: 0;
  border-block-end: 1px solid var(--line);
  border-radius: 0;
  box-shadow: none;
  backdrop-filter: none;
}
.brand { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.brand-mark { block-size: 26px; inline-size: auto; }
.brand span {
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.nav-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-inline-start: auto;
  min-width: 0;
}
.nav-more { display: none; }

/* ------------------------------------------------------------------ price */

.price-hero {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-4);
  border-block-end: 1px solid var(--line);
  background: var(--s0);
  margin: 0;
}
.price-title { display: flex; align-items: center; gap: var(--space-3); }
.price-title h1 {
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0;
}
.price-value {
  font-size: clamp(2rem, 7vw, 2.6rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.price-change { font-size: var(--text-sm); font-weight: 600; font-variant-numeric: tabular-nums; }
.price-time { font-size: var(--text-2xs); color: var(--ink-3); }

/* The four facts. A scroll-free row on a phone, not a stack. */
.price-facts {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-2);
  margin: 0;
  padding-block-start: var(--space-2);
  border-block-start: 1px solid var(--line);
}
.price-facts > div { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.price-facts dt {
  font-size: 0.69rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.price-facts dd {
  margin: 0;
  font-size: var(--text-xs);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* -------------------------------------------------------------------- rtl */
/* Tracking is a Latin instrument: spread connected Arabic script and it
   falls apart. And a label must wrap before it amputates ("أعلى سعر 24 س…"
   was shipping). English news headlines inside the Arabic page keep their
   own direction (dir=auto in markup) and align to their own start edge. */
body.rtl .price-title h1,
body.rtl .price-facts dt,
body.rtl .panel > h3,
body.rtl .chart-header h3,
body.rtl .news-header h3,
body.rtl .verdict-panel-label { letter-spacing: 0; }
body.rtl .price-facts dt {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}
body.rtl .news-title { text-align: start; }

/* ------------------------------------------------------------------- grid */

.main-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
  padding: var(--space-4);
}

/* --------------------------------------------------------------- surfaces */

/* Three card treatments. There were eleven. */
.panel, .surface, .chart-card, .verdict-panel, .live-position, .news-section {
  background: var(--s1);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: none;
}
.panel > h3, .chart-header h3, .news-header h3 {
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0;
}

/* ------------------------------------------------------------------ chart */

.chart-card { display: flex; flex-direction: column; overflow: hidden; }
.chart-header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3);
  border-block-end: 1px solid var(--line);
  flex-wrap: nowrap;
}
/* One row. Never three. */
.chart-controls {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-inline-start: auto;
  flex-wrap: nowrap;
}
.chart-controls .dropdown-button {
  min-inline-size: auto;
  inline-size: auto;
  block-size: 36px;
  padding-inline: var(--space-3);
  font-size: var(--text-2xs);
}
.chart-type-switch { padding: 2px; }
.chart-type-option { min-block-size: 32px; padding-inline: var(--space-3); }
.chart-expand { min-block-size: 36px; padding-inline: var(--space-3); }
.chart-canvas { block-size: clamp(300px, 46vh, 560px); }
.chart-legend {
  display: flex;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-3);
  border-block-start: 1px solid var(--line);
  overflow-x: auto;
  scrollbar-width: none;
}
.chart-legend::-webkit-scrollbar { display: none; }

/* ------------------------------------------------------------------- news */

/* News is context. It gets a digest, not forty percent of the page. */
.news-list { display: flex; flex-direction: column; }
.news-card, .news-item {
  padding: var(--space-3);
  border: 0;
  border-block-end: 1px solid var(--line);
  border-radius: 0;
  background: transparent;
}
.news-title { font-size: var(--text-xs); line-height: 1.45; }
.news-meta { font-size: 0.69rem; color: var(--ink-3); }

/* ------------------------------------------------------------- bottom tabs */

.tab-bar { display: none; }

/* ================================================================= PHONE */
@media (max-width: 820px) {
  /* Clearance for BOTH fixed layers: the tab bar and the floating ask-pill
     above it (48px + 16px gap). Without the second term the pill sat ON the
     last card's content at rest -- covering, not floating over, the page. */
  body { padding-block-end: calc(var(--tabs-h) + env(safe-area-inset-bottom) + 76px); }

  .nav-more {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-inline-size: 40px;
    min-block-size: 40px;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--ink-2);
    cursor: pointer;
  }
  /* The primary action keeps its place; everything else moves. */
  .nav-primary { min-block-size: 40px; padding-inline: var(--space-3); }
  .nav-primary span { display: none; }
  .brand span { display: none; }

  .price-hero { padding: var(--space-3) var(--space-4); }
  .price-title .badge { font-size: 0.69rem; padding: 2px var(--space-2); }
  .main-grid { padding: var(--space-3); gap: var(--space-3); }

  .chart-header { flex-wrap: wrap; }
  .chart-header h3 { display: none; }
  .chart-controls { margin-inline-start: 0; inline-size: 100%; }
  .chart-controls .dropdown-button { flex: 1; }
  .chart-canvas { block-size: 44vh; }

  /* The bottom bar: the thing that makes this feel like an app instead of a
     web page. Five destinations, thumb-reachable, always visible. */
  .tab-bar {
    position: fixed;
    inset-block-end: 0;
    inset-inline: 0;
    z-index: 55;
    display: grid;
    grid-template-columns: repeat(5, 1fr);
  }
  /* On the phone the AI tab IS the entry point; the gold top button would be
     the same verb twice on one screen. Desktop keeps the top button because
     the tab bar does not render there. (.top-nav prefix: the base
     .nav-primary rule later in the file sets display and would win on
     source order at equal specificity.) */
  .top-nav .nav-primary { display: none; }
  .tab-bar {
    block-size: calc(var(--tabs-h) + env(safe-area-inset-bottom));
    padding-block-end: env(safe-area-inset-bottom);
    background: var(--s1);
    border-block-start: 1px solid var(--line);
  }
  .tab-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    border: 0;
    background: transparent;
    color: var(--ink-3);
    font-family: inherit;
    font-size: 0.69rem;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
  }
  .tab-item i { font-size: 1.05rem; }
  .tab-item.is-active { color: var(--focus); }
  .tab-badge {
    position: absolute;
    transform: translate(14px, -10px);
    min-inline-size: 16px;
    padding-inline: 4px;
    border-radius: var(--radius-pill);
    background: var(--down);
    color: #fff;
    font-size: 0.55rem;
    line-height: 16px;
    text-align: center;
  }
}

/* ================================================================ DESKTOP */
@media (min-width: 821px) {
  .main-grid {
    grid-template-columns: minmax(0, 1fr) 360px;
    padding: var(--space-5);
    gap: var(--space-5);
    align-items: start;
  }
  /* The verdict is the product; it reads in the wide column, in the same
     order a trader needs it: open position, verdict, chart link, news.
     The indicator accordion is reference material -- it rides the rail.
     (The old auto-placement did the exact opposite: a collapsed accordion
     owned the wide column and the verdict wrapped inside 380px.) */
  .main-grid > section {
    grid-column: 1; grid-row: 1;
    display: flex; flex-direction: column; gap: var(--space-4);
  }
  .main-grid > section > .live-position { order: -3; }
  .main-grid > section > .verdict-panel { order: -2; }
  .main-grid > section > .chart-cta { order: -1; }
  .main-grid > aside { grid-column: 2; grid-row: 1; align-self: start; }

  /* The hero as a masthead band: price left, the day's facts on the right
     edge -- not floating in the middle of 600px of nothing. */
  .price-hero {
    padding-inline: var(--space-6, 40px);
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
    column-gap: var(--space-5);
  }
  .price-hero .price-facts {
    grid-column: 2; grid-row: 1;
    align-self: end;
    border-block-start: 0;
    padding-block-start: 0;
    margin-block-start: 0;
    grid-template-columns: repeat(3, minmax(96px, auto));
    gap: var(--space-5);
    text-align: end;
  }
  .price-hero .price-facts > div { align-items: flex-end; }
  body.rtl .price-hero .price-facts > div { align-items: flex-start; }
}

/* The mark: a single letterform, set properly, instead of a raster logo that
   rendered at four different sizes. One glyph, one weight, one radius. */
.brand-glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 32px;
  block-size: 32px;
  flex: none;
  border-radius: var(--radius-sm);
  background: linear-gradient(135deg, var(--focus), #4A55E0);
  color: #fff;
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0;
  user-select: none;
}

/* ============================================================ CORRECTIONS
   The legacy layer still painted through wherever this file was silent.
   These rules close every remaining gap seen on the phone capture.
   ============================================================ */

/* The hero is a reading, not a poster. Left-aligned, compact, the badge
   beside the label instead of a second colour block. */
.price-hero, .price-hero * { text-align: start; }
.price-hero { justify-items: start; }
.price-title { flex-wrap: wrap; }
.price-title .badge {
  font-size: 0.69rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 2px var(--space-2);
  border-radius: var(--radius-pill);
  background: rgba(33, 201, 122, 0.12);
  color: var(--up);
  border: 1px solid rgba(33, 201, 122, 0.25);
}
.price-title .badge.warning {
  background: rgba(232, 163, 61, 0.12);
  color: var(--flag);
  border-color: rgba(232, 163, 61, 0.25);
}
.price-value { color: var(--ink-1); }        /* price is a number, not a mood */
.price-change.pos, .price-change[data-dir="up"] { color: var(--up); }
.price-change.neg, .price-change[data-dir="down"] { color: var(--down); }
/* A 24h change nobody read wears neither colour and neither sign. Green here
   is a claim that gold rose; red that it fell; the muted state says only that
   the reading is missing, which is the true thing. */
.price-change.is-unknown {
  color: var(--ink-3);
  font-weight: 500;
}

/* The T mark must survive the phone rule that hides the wordmark. */
.brand > span:not(.brand-glyph) { }
@media (max-width: 820px) {
  .brand span { display: inline-flex; }
  .brand span:not(.brand-glyph) { display: none; }
}

/* Chart controls: one row at every width. The legacy sheet stacked them into
   three centred full-width rows on phones. */
.chart-header { flex-direction: row !important; }
.chart-controls {
  flex-direction: row !important;
  inline-size: auto !important;
  flex-wrap: nowrap !important;
}
.chart-controls > * { inline-size: auto !important; flex: none; }
@media (max-width: 820px) {
  .chart-controls { inline-size: 100% !important; }
  .chart-controls .dropdown { flex: 1; min-inline-size: 0; }
  .chart-controls .dropdown-button { inline-size: 100%; }
}

/* The OHLC readout must not cover the overlay tags at the top of the pane. */
.ohlc-readout {
  inset-block-start: auto;
  inset-block-end: var(--space-2);
  inset-inline-start: var(--space-2);
  font-size: 0.69rem;
  padding: var(--space-1) var(--space-2);
}

/* Buttons: two shapes only. A filled primary and a quiet secondary. The pill
   zoo -- six identical outlined capsules -- is over. */
.btn {
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
  font-weight: 600;
  min-block-size: 40px;
}
.btn-primary {
  background: var(--focus);
  border: 1px solid transparent;
  box-shadow: none;
}
.btn-primary:hover { background: #5A67F2; }
.btn-secondary, .btn-ghost {
  background: transparent;
  border: 1px solid var(--line);
  color: var(--ink-2);
  box-shadow: none;
}
.btn-secondary:hover, .btn-ghost:hover {
  background: var(--s2);
  color: var(--ink-1);
  transform: none;
}
.alerts-bell { border-radius: var(--radius-sm); }

/* The one destructive confirmation in the app: closing a live trade books the
   P&L then and there. Red only appears on the committing tap -- direction/P&L
   colour discipline holds, this is an action, not a reading. */
.btn-danger {
  background: var(--danger);
  border: 1px solid var(--danger);
  color: #fff;
  box-shadow: none;
}
.btn-danger:hover { filter: brightness(1.06); transform: none; }
.btn-danger:disabled { opacity: 0.7; }

/* Two-step close confirmation: replaces the single close button in place so the
   card does not jump. Reads top-down -- the question, then the two answers. */
.live-close-confirm {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--danger);
  border-radius: var(--radius-sm);
  background: rgba(244, 86, 90, 0.08);
}
.live-close-confirm-q {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--ink-1);
  text-align: center;
}
.live-close-confirm-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2);
}
.live-close-confirm-actions .live-close { width: 100%; }

/* ------------------------------------------------------------ analysis page */
/* The AI analysis as a full page. One column, reading width: it is a document
   the reader works through, not a dashboard they scan. */
.analysis-body {
  max-width: 1100px;
  margin: 0 auto;
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.analysis-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.analysis-head h1 {
  font-size: var(--text-xl);
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
}
.analysis-controls {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}
/* The three states a run can be in -- closed market, working, failed -- all
   render as the same centred card so the page never jumps between layouts. */
.analysis-state {
  text-align: center;
  padding: var(--space-8, 48px) var(--space-4);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
}
.analysis-state i { font-size: 1.6rem; color: var(--gold); }
.analysis-state h2 { margin: 0; font-size: var(--text-lg); }
.analysis-state p { margin: 0; color: var(--ink-2); }

/* -------------------------------------------------------- position sizing */
/* The size row: quiet arithmetic under the levels. Grey + reason when the
   system halts are up -- a size beside a halted system is an instruction. */
.verdict-sizing {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  flex-wrap: wrap;
  padding: var(--space-2) 0;
  font-size: var(--text-sm);
}
.verdict-sizing-label {
  color: var(--ink-3);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.verdict-sizing b { font-variant-numeric: tabular-nums; }
.verdict-sizing-detail { color: var(--ink-3); font-size: var(--text-xs); }
.verdict-sizing.is-halted b, .verdict-sizing.is-halted .verdict-sizing-detail {
  opacity: 0.4;
  text-decoration: line-through;
}
.verdict-sizing-halt { color: var(--danger); font-size: var(--text-xs); }
.verdict-sizing-unset a { color: var(--ink-3); font-size: var(--text-xs); text-decoration: underline; }

/* The settings inputs for it. */
.risk-inputs { display: flex; gap: var(--space-3); }
.risk-inputs label { display: flex; flex-direction: column; gap: 4px; }
.risk-inputs small { color: var(--ink-3); font-size: var(--text-xs); }
.risk-inputs input {
  width: 110px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--s2);
  color: var(--ink-1);
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------- setup quality */
/* Confluence behind the proposed direction, with its component breakdown.
   Quiet by design: it qualifies the setup, it must never outshout the verdict. */
.verdict-quality {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding: var(--space-2) 0;
  border-block-start: 1px solid var(--line);
  font-size: var(--text-sm);
}
.verdict-quality-label {
  color: var(--ink-3);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.verdict-quality-score { font-weight: 700; font-variant-numeric: tabular-nums; }
.verdict-quality-score small { color: var(--ink-3); font-weight: 400; }
.verdict-quality-score.grade-A { color: var(--success, #2E9E6B); }
.verdict-quality-score.grade-B { color: var(--gold); }
.verdict-quality-score.grade-C { color: var(--ink-2); }
.verdict-quality-parts { display: flex; gap: var(--space-2); flex-wrap: wrap;
                         color: var(--ink-3); font-size: var(--text-xs); }
.verdict-quality-parts .neg { color: var(--danger); }

/* ------------------------------------------------------------- journal page */
.journal-body {
  max-width: 900px;
  margin: 0 auto;
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.journal-section h3 { margin-block-end: var(--space-3); }
.journal-note { color: var(--ink-3); font-size: var(--text-sm); margin-block-end: var(--space-3); }
.journal-empty { color: var(--ink-3); font-size: var(--text-sm); }
.journal-audit {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-block-start: var(--space-3);
  padding-block-start: var(--space-3);
  border-block-start: 1px solid var(--line);
  font-size: var(--text-sm);
}
.journal-audit a { color: var(--gold); text-decoration: none; }
.journal-audit a:hover { text-decoration: underline; }
/* An arrow glyph carries direction the bidi algorithm cannot flip: in RTL
   "entry → exit" rendered with the arrow pointing back into the entry. */
body.rtl .dir-arrow { display: inline-block; transform: scaleX(-1); }
.journal-row {
  padding: var(--space-3) 0;
  border-block-start: 1px solid var(--line);
}
.journal-row-head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}
.journal-side { font-weight: 700; font-size: var(--text-sm); }
.journal-buy { color: var(--success, #2E9E6B); }
.journal-sell { color: var(--danger); }
.journal-when { color: var(--ink-3); font-size: var(--text-xs); }
.journal-r { margin-inline-start: auto; font-weight: 700; font-variant-numeric: tabular-nums; }
.journal-r.pos { color: var(--success, #2E9E6B); }
.journal-r.neg { color: var(--danger); }
.journal-chip {
  font-size: var(--text-xs);
  padding: 1px 8px;
  border-radius: 999px;
  border: 1px solid var(--line);
  color: var(--ink-2);
}
.journal-chip.won { border-color: var(--success, #2E9E6B); color: var(--success, #2E9E6B); }
.journal-chip.lost { border-color: var(--danger); color: var(--danger); }
.journal-chip.expired, .journal-chip.open { color: var(--gold); border-color: var(--gold); }
.journal-chip.override { color: var(--gold); border-color: var(--gold); }
.journal-chip.excluded { text-decoration: line-through; }
.journal-levels { font-size: var(--text-sm); color: var(--ink-2); margin-block-start: 4px; font-variant-numeric: tabular-nums; }
.journal-autopsy { margin: 6px 0 0; font-size: var(--text-sm); color: var(--ink-1); }

/* The real-time feed being down, said plainly beside the freshness clock. The
   socket state used to be tracked and never rendered, so a dropped feed looked
   live. Amber, not red: it is reconnecting, not broken. */
.conn-flag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  font-size: var(--text-xs);
  color: var(--gold, #C99A3A);
}
.conn-flag-dot {
  inline-size: 7px;
  block-size: 7px;
  border-radius: 50%;
  background: var(--gold, #C99A3A);
  animation: conn-flag-pulse 1.4s ease-in-out infinite;
}
@keyframes conn-flag-pulse {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .conn-flag-dot { animation: none; }
}

/* Colour discipline: green and red belong to market direction and P&L only.
   Everything structural is ink on surface. */
.stat-value, .price-facts dd { color: var(--ink-1); }
.measured-row b.inconclusive { color: var(--ink-1); }

/* The bar never wraps; a second row was being clipped under it. */
.top-nav, .nav-actions { flex-wrap: nowrap; }
.top-nav > * { min-width: 0; }

/* The hero column: the legacy layer stacks .price-title into a column on
   phones, and this file's align-items:center (meant for a row) centred the
   whole stack. State the column explicitly, aligned to the start. */
.price-title {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-1);
}
.price-title > div { justify-content: flex-start !important; }

/* The legacy layer adds block padding to the bar; with 40px buttons that
   overflowed the 56px height and the second half of every control was clipped
   into a sliver under the bar. */
.top-nav { padding-block: 0; }

/* Measured, not guessed: .brand was growing to the full 358px (legacy flex),
   which pushed .nav-actions onto a second line where legacy overflow-x:auto
   crushed it to 11px and the bar clipped it. The brand is content-sized; the
   actions take the remaining space and never scroll. */
.brand { flex: 0 0 auto; }
.nav-actions {
  flex: 1 1 auto;
  justify-content: flex-end;
  overflow: visible;
  padding: 0;
}

/* The legacy sheet flips the bar to a column and sets .brand{width:100%} inside
   a media query. Those beat this file's element selectors, so state the row
   layout with the same weight and settle it for good. */
@media (max-width: 820px) {
  .top-nav { flex-direction: row !important; align-items: center !important; position: fixed !important; }
  .brand { width: auto !important; justify-content: flex-start !important; }
  .nav-actions { width: auto !important; }
}

/* ------------------------------------------------------- reading order */
@media (max-width: 820px) {
  /* The chart, the verdict and the news are siblings inside one <section>, so
     the order is fixed by source unless the section becomes a flex column.
     A trader opens this app to learn whether there is a trade -- that answer
     goes first, then the chart it rests on, then everything else. */
  .main-grid > section { display: flex; flex-direction: column; gap: var(--space-3); }
  .main-grid > section > .live-position { order: -3; }
  .main-grid > section > .verdict-panel { order: -2; }
  .main-grid > section > .chart-card { order: -1; }

  /* Chart controls: quieter and shorter. They were three large pills that
     between them outweighed the chart's own header. */
  .chart-controls .dropdown-button,
  .chart-expand,
  .chart-type-option { min-block-size: 34px; }
  .chart-header { padding: var(--space-2) var(--space-3); }
  .chart-legend { padding-block-end: var(--space-3); }
}

/* The legend was clipped by the card's overflow at the phone width. */
.chart-card { overflow: visible; }
.chart-canvas { overflow: hidden; border-radius: 0; }
/* The chart paints the card's ground, not its own. The legacy sheet pinned
   a navy #0f182b behind the canvas and a near-black loading veil — in light
   mode that rendered as a dark void with unreadable loading text. */
.chart-canvas { background: var(--s1); }
.chart-overlay {
  /* Full geometry here, not just the skin: this unlayered rule outranks the
     legacy sheet, and leaving position to the layered rule rendered the
     loading/error veil as an unpositioned stray box while the canvas sat
     black and silent. The overlay owns the canvas or it does not exist. */
  position: absolute;
  inset: 0;
  z-index: 5;
  display: grid;
  place-items: center;
  text-align: center;
  background: color-mix(in srgb, var(--s0) 78%, transparent);
  color: var(--ink-2);
  font-weight: 600;
}
.chart-overlay .chart-retry { margin-block-start: 10px; }

/* The dashboard's route to the chart. A destination, not a cramped preview. */
.chart-cta {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--s1);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  text-decoration: none;
  color: var(--ink-1);
  min-block-size: 64px;
}
.chart-cta:hover { background: var(--s2); border-color: var(--line-strong); }
.chart-cta-main { display: inline-flex; align-items: center; gap: var(--space-2); }
.chart-cta-main i { color: var(--focus); }
.chart-cta-main b { font-size: var(--text-sm); }
.chart-cta-meta { font-size: var(--text-2xs); color: var(--ink-3); }
.chart-cta-go { margin-inline-start: auto; color: var(--ink-3); }
body.rtl .chart-cta-go { transform: scaleX(-1); }

/* The section already spaces its children; the legacy margin-top stacked on
   top of that and left a dead band under the price. */
.verdict-panel, .live-position { margin-block: 0; }

/* ==========================================================================
   THE PREMIUM SKIN
   Identity, not decoration. This is a GOLD terminal, so the signature colour
   is gold -- one warm accent against a near-black ground, spent only on
   identity and primary action. Green and red stay reserved for market
   direction. Numbers set in the display face with tight tracking; surfaces
   get a single top highlight and a deep soft shadow instead of flat grey.
   Later rules in the same sheet outrank everything above them.
   ========================================================================== */
:root {
  --s0: #06080D;
  --s1: #0B0F17;
  --s2: #111725;
  --s3: #182031;
  --line: rgba(226, 232, 255, 0.07);
  --line-strong: rgba(226, 232, 255, 0.15);

  --ink-1: #EEF2FA;
  --ink-2: #A9B4CC;
  --ink-3: #6C7893;

  --gold: #E9C46A;
  --gold-strong: #D4A93F;
  --gold-ink: #191204;          /* text on gold */
  --focus: var(--gold);

  --up: #2FD383;
  --down: #FF5D5D;
  --flag: #E8A33D;
}

/* The ground: near-black with one faint warm bloom, top-right, like light on
   metal. Cheaper than any texture and impossible to mistake for Bootstrap. */
body {
  background:
    radial-gradient(1100px 520px at 85% -8%, rgba(233, 196, 106, 0.055), transparent 62%),
    var(--s0);
}

/* Surfaces: one material. A hairline, a 1px top highlight, a deep soft drop.
   The highlight is what makes a dark card read as an object instead of a
   hole. */
.panel, .surface, .chart-card, .verdict-panel, .live-position,
.news-section, .chart-cta, .alerts-panel, .modal {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.025), transparent 36%), var(--s1);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04), 0 14px 36px rgba(0, 0, 0, 0.4);
}
.top-nav, .tab-bar { background: rgba(9, 12, 19, 0.92); backdrop-filter: blur(14px); }

/* ------------------------------------------------------------- typography */
/* Numbers are the product. They get the display face, tight tracking, and
   weight; labels stay small, wide and quiet. The contrast between those two
   voices IS the hierarchy. */
.price-value,
.price-facts dd,
.verdict-panel-status,
.size-lots,
.live-r,
.terminal-price b,
.verdict-setup b,
.live-position-levels b,
.stat-value {
  font-family: var(--font-display);
}
.price-value {
  font-size: clamp(2.6rem, 10vw, 3.6rem);
  font-weight: 700;
  letter-spacing: -0.035em;
}
.price-title h1, .verdict-panel-label, .verdict-evidence-title,
.price-facts dt, .live-position-title, .panel > h3 {
  letter-spacing: 0.14em;
  font-weight: 600;
}
.verdict-panel-label { color: var(--gold); }
.verdict-panel-status { font-size: 1.7rem; letter-spacing: -0.02em; }

/* ------------------------------------------------------------------ brand */
.brand-glyph {
  background: linear-gradient(155deg, #F5DC8F 0%, #E9C46A 45%, #C08F2C 100%);
  color: var(--gold-ink);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45), 0 2px 8px rgba(212, 169, 63, 0.35);
  border-radius: 9px;
}

/* ---------------------------------------------------------------- buttons */
/* One gold primary. Everything else is a hairline ghost. */
.btn-primary, .nav-primary {
  background: linear-gradient(180deg, #F2CF7C, #D9AC45);
  color: var(--gold-ink);
  border: 0;
  font-weight: 700;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), 0 4px 14px rgba(212, 169, 63, 0.25);
}
.btn-primary:hover, .nav-primary:hover { filter: brightness(1.06); background: linear-gradient(180deg, #F2CF7C, #D9AC45); }
/* (A saturate/brightness filter lived here and turned the disabled primary
   into the grey slab the design law forbids — the outline rule below is the
   whole treatment.) */
.btn-secondary, .btn-ghost, .nav-more, .alerts-bell {
  background: transparent;
  border: 1px solid var(--line);
  color: var(--ink-2);
}
.btn-secondary:hover, .btn-ghost:hover, .nav-more:hover, .alerts-bell:hover {
  border-color: var(--line-strong);
  background: var(--s2);
  color: var(--ink-1);
}

/* ------------------------------------------------------------------ badge */
.price-title .badge, .price-title .badge.success {
  background: transparent;
  border: 1px solid rgba(47, 211, 131, 0.35);
  color: var(--up);
  font-weight: 700;
}
.price-title .badge.warning {
  border-color: rgba(232, 163, 61, 0.4);
  color: var(--flag);
  background: transparent;
}

/* ---------------------------------------------------------------- verdict */
/* overflow was HIDDEN, and inside the chart rail the panel's content ran
   778px in a 662px box: the evidence list sliced mid-glyph with no scrollbar
   and no way to reach the Volatility row. A panel that hides its own
   evidence reads as broken. Vertical scroll, horizontal stays clipped for
   the ::before sheen. */
.verdict-panel { border-left-width: 1px; position: relative;
                 overflow-x: hidden; overflow-y: auto; }
.verdict-panel::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: 2px;
}
.verdict-panel.verdict-take::before { background: linear-gradient(180deg, var(--up), transparent); }
.verdict-panel.verdict-wait::before { background: linear-gradient(180deg, var(--flag), transparent); }
.verdict-panel.verdict-none::before { background: linear-gradient(180deg, var(--ink-3), transparent); }

/* Stance chips: hairline capitals, not filled pills. Finer, more certain. */
.evidence-stance {
  background: transparent !important;
  border: 1px solid currentColor;
  padding: 1px 8px;
  font-size: 0.69rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 700;
  border-radius: 4px;
}
.stance-context { border-color: transparent; }

/* The sizing strip earns the gold tint -- it is the number the product is
   proudest of. */
.verdict-size {
  background: rgba(233, 196, 106, 0.06);
  border: 1px solid rgba(233, 196, 106, 0.22);
}
.size-lots b { color: var(--gold); }

.verdict-dir-muted { border: 1px solid var(--line); background: transparent; }

/* ---------------------------------------------------------------- tab bar */
.tab-item { position: relative; }
.tab-item.is-active { color: var(--gold); }
.tab-item.is-active::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inline-size: 22px;
  block-size: 2px;
  border-radius: 2px;
  background: var(--gold);
}
.tab-badge { background: var(--down); }

/* --------------------------------------------------------------- terminal */
.terminal-bar { background: rgba(9, 12, 19, 0.92); }
.terminal-price b { letter-spacing: -0.02em; }
.chart-cta-main i { color: var(--gold); }
.live-dot { background: var(--up); box-shadow: 0 0 0 3px rgba(47, 211, 131, 0.18); }

/* ------------------------------------------------------------ chart card */
.chart-type-option.is-active { background: var(--s3); color: var(--ink-1); }
.legend-toggle.is-on { color: var(--ink-2); }
.ohlc-readout { background: rgba(6, 8, 13, 0.85); border-color: var(--line); }

/* ------------------------------------------------------------ chart tools */
.tf-strip { display: inline-flex; gap: 2px; padding: 2px; background: var(--s2); border: 1px solid var(--line); border-radius: 9px; }
.tf-chip {
  min-block-size: 30px; padding-inline: 10px;
  border: 0; border-radius: 7px; background: transparent;
  color: var(--ink-3); font-family: inherit; font-size: 0.7rem; font-weight: 700;
  letter-spacing: 0.02em; cursor: pointer;
}
.tf-chip:hover { color: var(--ink-1); }
.tf-chip.is-active { background: var(--gold); color: var(--gold-ink); }

.chart-tools {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3); flex-wrap: wrap;
  padding: var(--space-2) var(--space-3);
  border-block-end: 1px solid var(--line);
}
.tool-group { display: inline-flex; gap: var(--space-1); flex-wrap: wrap; }
.tool-chip {
  display: inline-flex; align-items: center; gap: 6px;
  min-block-size: 30px; padding-inline: 10px;
  border: 1px solid var(--line); border-radius: 7px;
  background: transparent; color: var(--ink-3);
  font-family: inherit; font-size: 0.7rem; font-weight: 600; cursor: pointer;
}
.tool-chip:hover { color: var(--ink-1); border-color: var(--line-strong); }
.tool-chip.is-on { color: var(--ink-1); border-color: var(--line-strong); background: var(--s2); }
.tool-swatch { inline-size: 10px; block-size: 2px; border-radius: 2px; }

@media (max-width: 820px) {
  /* The dropdown is redundant once the strip is there. */
  .chart-controls .dropdown { display: none; }
  .tf-strip { flex: 1; justify-content: space-between; }
  .chart-tools { padding: var(--space-2); }
}

/* ==========================================================================
   COMPOSITION
   Everything above made the parts correct. This makes them one thing.

   The failure was structural, not decorative: a price card, then a verdict
   card, then a chart card, each with the same border and the same weight,
   stacked. That reads as a template no matter how good the colours are,
   because nothing on the screen claims to be more important than anything
   else. A premium screen has ONE object your eye lands on, and everything
   else is subordinate to it.

   So the price and the verdict fuse into a single hero slab -- one surface,
   one border, one shadow -- with the price as the overline and the verdict as
   the headline. That is the product's whole sentence: "gold is at X, and here
   is what to do about it."
   ========================================================================== */

/* The fusion is a PHONE idea: on one narrow column the price flows straight
   into the verdict as a single sentence. On desktop the verdict lives in the
   grid's main column, so these rules must not reach it there -- unscoped they
   stripped the verdict's top border and radii inside the rail, leaving a card
   with a missing edge. */
@media (max-width: 820px) {
  .price-hero {
    border: 1px solid var(--line);
    border-block-end: 0;
    border-start-start-radius: 16px;
    border-start-end-radius: 16px;
    background:
      radial-gradient(120% 140% at 100% 0%, rgba(233, 196, 106, 0.07), transparent 58%),
      linear-gradient(180deg, rgba(255, 255, 255, 0.03), transparent 40%),
      var(--s1);
    margin: var(--space-3) var(--space-3) 0;
    padding: var(--space-5) var(--space-5) var(--space-4);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
  }

  /* The verdict continues the same slab: no gap, no second border, one shadow
     closing the bottom. */
  .main-grid > section > .verdict-panel {
    margin: 0 var(--space-3) var(--space-3);
    border-start-start-radius: 0;
    border-start-end-radius: 0;
    border-end-start-radius: 16px;
    border-end-end-radius: 16px;
    border-block-start: 0;
    background:
      linear-gradient(180deg, rgba(255, 255, 255, 0.018), transparent 30%),
      var(--s1);
    box-shadow: 0 26px 60px rgba(0, 0, 0, 0.5);
    padding: var(--space-5);
  }
  /* A gold hairline is the seam between the two halves of the sentence. */
  .main-grid > section > .verdict-panel::after {
    content: "";
    position: absolute;
    inset-block-start: 0;
    inset-inline: var(--space-5);
    block-size: 1px;
    background: linear-gradient(90deg, transparent, rgba(233, 196, 106, 0.32), transparent);
  }
  .main-grid > section > .verdict-panel::before { display: none; }
  .main-grid { padding-block-start: 0; }
  .main-grid > section { gap: 0; }
  .main-grid > section > .chart-cta { margin-inline: var(--space-3); }
}

/* ------------------------------------------------------------- typography */
/* The drama is the RATIO, not the size. A 0.69rem label at 0.18em tracking
   against a 4rem number at -0.04em is what reads as designed. */
.price-title h1 {
  font-size: 0.69rem;
  letter-spacing: 0.2em;
  color: var(--ink-3);
}
.price-value {
  font-size: clamp(3rem, 13vw, 4.2rem);
  letter-spacing: -0.045em;
  line-height: 0.94;
  margin-block-start: var(--space-1);
}
.price-change { font-size: var(--text-md); font-weight: 700; letter-spacing: -0.01em; }
.price-time { font-size: 0.69rem; letter-spacing: 0.06em; color: var(--ink-3); }

.price-facts { border-block-start: 1px solid var(--line); padding-block-start: var(--space-3); margin-block-start: var(--space-3); }
.price-facts dt { font-size: 0.56rem; letter-spacing: 0.14em; }
.price-facts dd { font-size: var(--text-sm); letter-spacing: -0.01em; }

.verdict-panel-label { font-size: 0.69rem; letter-spacing: 0.22em; }
/* The timeframe the verdict was computed on, as a quiet chip beside the label.
   Not gold -- it is a qualifier on the title, not part of it. */
.verdict-tf {
  display: inline-block;
  margin-inline-start: 8px;
  padding: 1px 7px;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink-2);
  letter-spacing: 0.02em;
  vertical-align: middle;
}
.verdict-panel-status {
  font-size: clamp(1.9rem, 8vw, 2.5rem);
  letter-spacing: -0.035em;
  line-height: 1.02;
  margin-block-start: var(--space-2);
}
.verdict-panel-reason {
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--ink-2);
  max-inline-size: 46ch;
}

/* Evidence: a quiet ledger. Hairlines, wide labels, tabular values. */
.verdict-evidence-title { font-size: 0.69rem; letter-spacing: 0.2em; margin-block-end: var(--space-3); }
.evidence-row { padding-block: var(--space-3); border-top-color: var(--line); }
/* Values share one start edge beside their labels. Centered fragments float
   mid-card and every row's value starts somewhere new — nothing to scan. */
@media (min-width: 821px) {
  .evidence-row { grid-template-columns: 220px minmax(0, 1fr) auto; }
}
.evidence-value { text-align: start; }
.evidence-label { font-size: 0.72rem; letter-spacing: 0.02em; }
.evidence-value { font-size: 0.78rem; color: var(--ink-1); }

/* ------------------------------------------------------------------ motion */
/* Nothing on the screen moved. Every interactive thing acknowledges itself. */
.btn, .tool-chip, .tf-chip, .legend-toggle, .tab-item, .chart-cta,
.alert-row, .style-option, .nav-more, .alerts-bell {
  transition: background var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease),
              opacity var(--dur-fast) var(--ease);
}
.btn:active, .tool-chip:active, .tf-chip:active, .chart-cta:active { transform: scale(0.985); }
.btn-primary:focus-visible, .btn:focus-visible, .tool-chip:focus-visible,
.tf-chip:focus-visible, .tab-item:focus-visible, .alerts-bell:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .btn:active, .tool-chip:active, .tf-chip:active, .chart-cta:active { transform: none; }
}

/* The verdict arriving is the moment the product delivers. It should land, not
   blink into place. */
.verdict-panel { animation: verdict-in 340ms var(--ease) both; }
@keyframes verdict-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .verdict-panel { animation: none; } }

/* --------------------------------------------------------------- loading */
/* "Loading…" as a word where a price belongs is the cheapest thing an
   interface can do. A shaped shimmer says the same and keeps the layout. */
.price-value.is-placeholder { color: transparent; position: relative; }
.price-value.is-placeholder::after {
  content: "";
  position: absolute; inset-block: 12%; inset-inline-start: 0;
  inline-size: 5.2ch; border-radius: 8px;
  background: linear-gradient(90deg, var(--s2) 25%, var(--s3) 50%, var(--s2) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.25s linear infinite;
}
@keyframes shimmer { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .price-value.is-placeholder::after { animation: none; } }

@media (min-width: 821px) {
  .price-hero { margin-inline: var(--space-5); padding: var(--space-6) var(--space-6) var(--space-5); }
  .main-grid > section > .verdict-panel { margin-inline: var(--space-5); }
  .main-grid > section > .chart-cta { margin-inline: var(--space-5); }
}

/* An empty state says what would fill it. Two zeros in a box say nothing. */
.positions-empty {
  margin: 0;
  padding: var(--space-4) 0 0;
  font-size: var(--text-xs);
  line-height: 1.6;
  color: var(--ink-3);
  max-inline-size: 52ch;
}
/* SESSION wrapped to two lines and broke the fact row's baseline. */
.price-facts dd { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Four levels, four columns, no orphan R:R on its own row. */
.verdict-setup { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-3); }
@media (max-width: 420px) { .verdict-setup { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ==========================================================================
   MATERIAL
   A dark theme is not a luxury theme. The difference is physical: light has a
   direction, surfaces have a grain, and edges catch that light.

   Everything until now was flat -- a dark rectangle with a uniform 1px border
   is a wireframe, and no amount of gold on top of it reads as expensive.
   Three techniques, applied consistently:

     1. DIRECTIONAL LIGHT. The top edge of every surface is brighter than the
        bottom, because the light is above. One line of CSS per surface, and it
        is the single biggest difference between "dark mode" and "made of
        something".
     2. GRAIN. A near-invisible noise layer breaks the perfect flatness of a
        large dark field. Screens without it look like paint; screens with it
        look like a material.
     3. DEPTH. Two shadows -- a tight contact shadow and a wide soft one --
        instead of a single blur, so a card sits ON the page rather than
        floating above a void.
   ========================================================================== */

/* The grain. An inline SVG turbulence, fixed to the viewport so it never
   scrolls and never repeats visibly. 3% opacity: you should not be able to
   see it, only to notice its absence. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
}
/* Lift the shell above the grain, but NEVER flatten the bars into it: this
   rule set z-index:1 on .top-nav, so content with any stacking context of its
   own scrolled straight over a translucent bar. The bar looked like it was
   moving because the page was passing in front of it. */
.app-shell, .terminal, .modal-backdrop { position: relative; z-index: 1; }
.top-nav { z-index: 200; }
.tab-bar { z-index: 200; }
.alerts-panel { z-index: 210; }
.modal-backdrop { z-index: 300; }

/* Every surface: light from above, contact shadow, soft depth. */
.panel, .surface, .chart-card, .verdict-panel, .live-position, .news-section,
.chart-cta, .alerts-panel, .modal, .price-hero, .settings-body > section {
  border-color: rgba(255, 255, 255, 0.055);
  border-top-color: rgba(255, 255, 255, 0.11);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    0 1px 2px rgba(0, 0, 0, 0.5),
    0 18px 44px -12px rgba(0, 0, 0, 0.65);
}

/* The hero slab catches the most light -- it is the top of the composition. */
.price-hero {
  border-top-color: rgba(255, 255, 255, 0.14);
  background:
    radial-gradient(130% 150% at 100% 0%, rgba(233, 196, 106, 0.085), transparent 55%),
    linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.008) 30%, transparent 60%),
    var(--s1);
}

/* The price is the object the whole screen is built around. A whisper of warm
   light behind it, not a glow -- glows are cheap, light is not. */
.price-value {
  background: linear-gradient(180deg, #FFFFFF 0%, #C7D2E6 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  text-shadow: 0 0 34px rgba(190, 210, 255, 0.09);
}
.price-value.is-placeholder { background: none; -webkit-text-fill-color: transparent; }

/* Inset wells -- the levels strip, the sizing strip -- are cut INTO the card,
   so their light comes from the opposite direction. */
.verdict-setup, .live-track, .tf-strip, .chart-type-switch {
  background: rgba(0, 0, 0, 0.28);
  border: 1px solid rgba(0, 0, 0, 0.5);
  border-top-color: rgba(0, 0, 0, 0.6);
  border-bottom-color: rgba(255, 255, 255, 0.05);
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.45);
}

/* Bars are glass over the grain, not opaque panels. */
.top-nav, .tab-bar, .terminal-bar {
  background: rgba(8, 11, 18, 0.72);
  backdrop-filter: blur(18px) saturate(1.4);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  border-color: rgba(255, 255, 255, 0.07);
}

/* The mark: metal, not a flat swatch. A bright top edge, a dark bottom, and a
   warm cast beneath it. */
.brand-glyph {
  background: linear-gradient(160deg, #FFF0C4 0%, #EFC96F 38%, #C9982F 72%, #A87B1E 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.75),
    inset 0 -1px 0 rgba(0, 0, 0, 0.28),
    0 3px 12px rgba(201, 152, 47, 0.32);
}

/* The primary action is the same metal. */
.btn-primary, .nav-primary {
  background: linear-gradient(180deg, #F6D98C 0%, #E3B855 52%, #CF9F38 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 -1px 0 rgba(0, 0, 0, 0.2),
    0 4px 16px rgba(207, 159, 56, 0.28);
}

/* Hairlines that catch light, used only where a seam is real. */
.evidence-row { border-top-color: rgba(255, 255, 255, 0.055); }
.price-facts { border-top-color: rgba(255, 255, 255, 0.07); }

/* Ghost controls: a barely-there fill so they read as objects, not as text. */
.btn-secondary, .btn-ghost, .nav-more, .alerts-bell, .tool-chip {
  background: rgba(255, 255, 255, 0.022);
  border-color: rgba(255, 255, 255, 0.075);
  border-top-color: rgba(255, 255, 255, 0.11);
}
.btn-secondary:hover, .btn-ghost:hover, .nav-more:hover, .alerts-bell:hover, .tool-chip:hover {
  background: rgba(255, 255, 255, 0.05);
  border-color: rgba(255, 255, 255, 0.14);
}

/* ==========================================================================
   NUMERALS
   A trading screen is a column of numbers being compared. Manrope's figures
   are proportional by default and its tabular set still has the soft, wide
   shapes of a UI face -- so a price reads as marketing copy rather than as an
   instrument reading.

   Prices, levels, R multiples and indicator values move to JetBrains Mono:
   monospaced by construction, so 4340.40 and 4229.39 align digit-for-digit
   down the column without any tabular-nums workaround, with a tall x-height
   and unambiguous 0/O and 1/l. Labels stay in Manrope -- the contrast between
   a humanist label and a mechanical number is the instrument look.
   ========================================================================== */
:root { --font-numeric: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace; }
/* The fixed top nav's height. tokens.css defines it, and the CUSTOMER app does
   not load tokens.css — so `calc(100dvh - var(--topnav-h) - …)` was an invalid
   calc, which a browser drops entirely rather than approximating. That is how
   the overflow menu came to run 50px past the bottom of a 700px phone with
   Logout drawn below the edge of the device. Declared here so the customer
   app has it, and every use carries a literal fallback as well: a missing
   custom property must never be able to delete a layout rule again. */
:root { --topnav-h: 56px; }

.price-value,
.price-change,
.price-facts dd,
.verdict-setup b,
.evidence-value,
.size-lots b,
.size-detail b,
.live-r,
.live-position-levels b,
.coach-log,
.terminal-price b,
.terminal-price span,
.terminal-stats b,
.ohlc-readout,
.tf-chip,
.measured-row b,
.stat-value,
.signal-value,
.open-position,
.alert-row span {
  font-family: var(--font-numeric);
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "lnum" 1, "zero" 1;
}

/* Mono runs wide and tall; the display sizes need pulling back in so the
   price still fits and still reads as one object. */
.price-value {
  font-size: clamp(2.5rem, 11vw, 3.5rem);
  font-weight: 700;
  letter-spacing: -0.04em;
}
.price-change { font-size: var(--text-sm); letter-spacing: -0.02em; }
.price-facts dd { font-size: var(--text-xs); letter-spacing: -0.02em; }
.verdict-setup b { font-size: var(--text-sm); letter-spacing: -0.02em; }
.evidence-value { font-size: 0.74rem; letter-spacing: -0.01em; }
.tf-chip { font-size: 0.64rem; letter-spacing: 0; }
.ohlc-readout { font-size: 0.69rem; letter-spacing: -0.01em; }
.terminal-price b { font-size: var(--text-xl); letter-spacing: -0.03em; }

/* The verdict headline stays in the display face -- it is a sentence, not a
   reading. */
.verdict-panel-status { font-family: var(--font-display); }

/* Correction: the mono face is for NUMBERS. Applying it to prose -- "trending",
   "rising — a headwind for gold" -- made the evidence column read as terminal
   output rather than as an analyst's note. Prose returns to the humanist face;
   only the figures inside it stay mechanical. */
.evidence-value,
.alert-row span,
.open-position,
.coach-log {
  font-family: var(--font-body);
  font-size: 0.78rem;
  letter-spacing: 0;
}
/* Numerals inside prose still align, without the whole line turning into code. */
.evidence-value, .alert-row span, .coach-log {
  font-variant-numeric: tabular-nums lining-nums;
}
/* The tally IS a row of figures, so it keeps the instrument face. */
.evidence-row[key="tally"] .evidence-value { font-family: var(--font-numeric); }

/* ==========================================================================
   THEME
   Dark is the default because a trading screen is looked at for hours in a
   dim room, and because the candles carry the only saturated colour on the
   page. But the choice belongs to the user, not to me -- someone reading this
   on a phone in sunlight needs the other one.

   Every colour in this stylesheet already comes from a token, so the light
   theme is a redefinition of those tokens and nothing else. That is the whole
   point of having had one scale.
   ========================================================================== */
:root[data-theme="light"] {
  --s0: #F7F8FA;
  --s1: #FFFFFF;
  --s2: #F1F3F7;
  --s3: #E7EAF1;
  --line: rgba(16, 24, 40, 0.10);
  --line-strong: rgba(16, 24, 40, 0.18);

  --ink-1: #0E1320;
  --ink-2: #47516A;
  --ink-3: #78829A;

  --gold: #A9791B;
  --gold-strong: #8C610F;
  --gold-ink: #FFFFFF;
  --focus: var(--gold);

  --up: #0B8A4B;
  --down: #C62A2A;
  --flag: #A96A10;
}

:root[data-theme="light"] body {
  background:
    radial-gradient(1100px 520px at 85% -8%, rgba(169, 121, 27, 0.05), transparent 62%),
    var(--s0);
  color: var(--ink-1);
}
/* Light from above becomes shadow from above on a light ground: the direction
   inverts, so the borders and shadows have to invert with it. */
:root[data-theme="light"] .panel,
:root[data-theme="light"] .surface,
:root[data-theme="light"] .chart-card,
:root[data-theme="light"] .verdict-panel,
:root[data-theme="light"] .live-position,
:root[data-theme="light"] .news-section,
:root[data-theme="light"] .chart-cta,
:root[data-theme="light"] .alerts-panel,
:root[data-theme="light"] .modal,
:root[data-theme="light"] .price-hero {
  background: var(--s1);
  border-color: rgba(16, 24, 40, 0.10);
  border-top-color: rgba(16, 24, 40, 0.06);
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.06), 0 12px 28px -14px rgba(16, 24, 40, 0.18);
}
:root[data-theme="light"] .price-hero {
  background:
    radial-gradient(130% 150% at 100% 0%, rgba(169, 121, 27, 0.06), transparent 55%),
    var(--s1);
}
:root[data-theme="light"] .price-value {
  background: linear-gradient(180deg, #0E1320 0%, #2C3550 100%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent; text-shadow: none;
}
:root[data-theme="light"] .verdict-setup,
:root[data-theme="light"] .live-track,
:root[data-theme="light"] .tf-strip,
:root[data-theme="light"] .chart-type-switch {
  background: var(--s2);
  border-color: rgba(16, 24, 40, 0.08);
  box-shadow: inset 0 1px 2px rgba(16, 24, 40, 0.06);
}
:root[data-theme="light"] .top-nav,
:root[data-theme="light"] .tab-bar,
:root[data-theme="light"] .terminal-bar {
  background: rgba(255, 255, 255, 0.82);
  border-color: rgba(16, 24, 40, 0.10);
}
:root[data-theme="light"] .btn-secondary,
:root[data-theme="light"] .btn-ghost,
:root[data-theme="light"] .nav-more,
:root[data-theme="light"] .alerts-bell,
:root[data-theme="light"] .tool-chip {
  background: var(--s1);
  border-color: rgba(16, 24, 40, 0.12);
  border-top-color: rgba(16, 24, 40, 0.08);
  color: var(--ink-2);
}
/* The grain is a dark-surface trick; on white it reads as dirt. */
:root[data-theme="light"] body::after { display: none; }
:root[data-theme="light"] .ohlc-readout { background: rgba(255, 255, 255, 0.9); }

/* ------------------------------------------------------------ the control */
.setting-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-4);
  border-block-start: 1px solid var(--line);
}
.setting-row:first-of-type { border-block-start: 0; }
.setting-copy { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.setting-copy strong { font-size: var(--text-sm); }
.setting-copy span { font-size: var(--text-2xs); color: var(--ink-3); line-height: 1.5; }
.seg {
  display: inline-flex; flex: none; padding: 3px; gap: 2px;
  background: var(--s2); border: 1px solid var(--line); border-radius: 9px;
}
.seg button {
  min-block-size: 34px; padding-inline: var(--space-3);
  border: 0; border-radius: 7px; background: transparent;
  color: var(--ink-3); font-family: inherit; font-size: 0.7rem; font-weight: 700;
  cursor: pointer; display: inline-flex; align-items: center; gap: 6px;
}
.seg button.is-active { background: var(--gold); color: var(--gold-ink); }

/* The bar is out of flow now, so the shell reserves its height. Centring the
   bar's own contents on wide screens keeps it aligned with the page below it
   rather than running edge to edge while the content sits in a column. */
.app-shell { padding-block-start: var(--bar-h); }
.top-nav > .brand { margin-inline-start: max(0px, calc((100vw - 1500px) / 2)); }
.top-nav > .nav-actions { margin-inline-end: max(0px, calc((100vw - 1500px) / 2)); }

/* The terminal is a fixed-height flex column that never scrolls the document,
   so its bar is already immobile and must NOT be offset. */
.terminal .top-nav { position: static; }
.terminal { padding-block-start: 0; }

/* The terminal is an app shell that must not scroll: the chart fills what is
   left after the bar, and the rail scrolls inside itself. It was 100dvh tall
   while the body also reserved room for the tab bar underneath, so the page
   grew 120px past the viewport and the whole thing -- bar included -- slid up
   on scroll. Subtract the tab bar and it stops moving entirely. */
@media (max-width: 820px) {
  .terminal {
    block-size: calc(100dvh - var(--tabs-h) - env(safe-area-inset-bottom));
    overflow: hidden;
  }
  .terminal .top-nav,
  .terminal-bar { position: static !important; }
}
@media (min-width: 821px) {
  .terminal { block-size: 100dvh; overflow: hidden; }
}

/* The terminal still grew past the viewport: 100dvh minus the tab bar is the
   right height, but the legacy sheet also gives .app-shell/.terminal padding
   and the bar its own margin, and those stack on top of the calc. Pin the
   shell to the viewport and let ONLY the rail scroll -- the chart page should
   never move as a whole. */
@media (max-width: 820px) {
  html, body { overscroll-behavior: none; }
  .terminal {
    position: fixed;
    inset-block-start: 0;
    inset-inline: 0;
    block-size: calc(100dvh - var(--tabs-h) - env(safe-area-inset-bottom));
    margin: 0;
    padding: 0;
    overflow: hidden;
  }
  .terminal-body { min-block-size: 0; overflow: hidden; }
  .terminal-chart { min-block-size: 0; }
}

/* Surfaces the legacy sheet paints with hardcoded dark values. They survived
   the light theme as navy blocks on white -- the theme is only as complete as
   its least-tokenised element. */
:root[data-theme="light"] .style-option,
:root[data-theme="light"] .measured-record,
:root[data-theme="light"] .alerts-row,
:root[data-theme="light"] .positions-summary,
:root[data-theme="light"] .stat-card,
:root[data-theme="light"] .open-position,
:root[data-theme="light"] .panel-note,
:root[data-theme="light"] .signal-card {
  background: var(--s2);
  border-color: rgba(16, 24, 40, 0.10);
  color: var(--ink-1);
}
/* !important because the light flatten at the bottom of this file is
   !important too -- without matching it, the selected card looks identical to
   its neighbours and the picker reads as dead. */
:root[data-theme="light"] .style-option.active {
  background: rgba(169, 121, 27, 0.10) !important;
  border-color: var(--gold) !important;
  color: var(--ink-1);
}
:root[data-theme="light"] .style-option .style-name { color: var(--ink-1); }
:root[data-theme="light"] .style-option .style-meta,
:root[data-theme="light"] .measured-record .measured-head,
:root[data-theme="light"] .measured-caveat,
:root[data-theme="light"] .alerts-copy span { color: var(--ink-3); }
:root[data-theme="light"] .measured-row b { color: var(--ink-1); }
:root[data-theme="light"] .news-title,
:root[data-theme="light"] .panel > h3,
:root[data-theme="light"] .verdict-panel-status { color: var(--ink-1); }
:root[data-theme="light"] .verdict-panel-reason,
:root[data-theme="light"] .evidence-value { color: var(--ink-2); }
:root[data-theme="light"] .price-title h1,
:root[data-theme="light"] .price-facts dt,
:root[data-theme="light"] .evidence-label,
:root[data-theme="light"] .price-time { color: var(--ink-3); }
:root[data-theme="light"] .verdict-panel-label { color: var(--gold); }

/* The active trading style was near-invisible: light fill, light text. */
.style-option.active .style-name { color: var(--ink-1); }
.style-option .style-name { color: var(--ink-1); }
.style-option .style-meta { color: var(--ink-3); }

/* A translucent bar over scrolling content needs enough blur and enough
   opacity that text passing behind it never reads through. */
.top-nav, .tab-bar, .terminal-bar {
  background: rgba(8, 11, 18, 0.88);
  backdrop-filter: blur(20px) saturate(1.5);
  -webkit-backdrop-filter: blur(20px) saturate(1.5);
}
:root[data-theme="light"] .top-nav,
:root[data-theme="light"] .tab-bar,
:root[data-theme="light"] .terminal-bar {
  background: rgba(247, 248, 250, 0.9);
}

/* ==========================================================================
   THE CORRECTION
   A design review of the live screens found the root cause of "not premium",
   and it was not decoration. Three faults, in order of damage:

   1. The hero number -- 4340.40, the thing this product exists to say -- was
      set in JetBrains Mono. A code editor font. The monospace decimal even
      left a visible hole: "4340 . 40". Worse, the same font was on the prose:
      "rising -- a headwind for gold" read as terminal output. A terminal is
      the cheapest signifier in software; it says an engineer built this for
      himself.
   2. Every neutral was blue-shifted to hue ~220. Warm gold surrounded entirely
      by cold blue-grey does not read as gold, it reads as a yellow warning.
   3. The actual --accent was still #7B7BFF, a periwinkle violet -- on the Sign
      In button, the news chips, the selected trading style. This was a
      blue-violet app with yellow labels on it.

   Fixed here: a display serif for the number, a silent grotesk for everything
   else, a warm neutral ramp, and one gold that means one thing.
   ========================================================================== */

:root {
  --font-display: "Playfair Display", "IBM Plex Sans Arabic", Georgia, serif;
  --font-body: "Inter Tight", "IBM Plex Sans Arabic", system-ui, sans-serif;
  --font-numeric: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* Warm ramp. --s1 sits a full step above --s0 so a card reads as a card and
     the directional-light border has a surface to light. */
  --s0: #0A0908;
  --s1: #121110;
  --s2: #1A1817;
  --s3: #242120;
  --line: rgba(232, 224, 208, 0.10);
  --line-strong: rgba(232, 224, 208, 0.18);

  --ink-1: #F2EDE4;
  --ink-2: #A39C90;
  --ink-3: #6E675D;

  --gold: #C9A227;          /* solid, ink-bearing */
  --gold-text: #E3C77A;     /* gold as text on dark */
  --gold-ink: #0A0908;
  --focus: var(--gold);

  /* Muted to roughly the chroma of the gold, so nothing outshouts the brand.

     --down was #B4635A and failed AA on three of the four surfaces it prints
     on (4.38 / 4.11 / 3.71). The readiness plan recorded that exact defect as
     fixed -- but the fix was written into the FIRST :root in this file, and
     this block is the third, so the browser never resolved it. Measured and
     corrected here, on the palette the cascade actually keeps: 5.33 / 5.00 /
     4.51, worst surface first clear of the bar. */
  --up: #5E9E7A;
  --down: #BD756D;
  --flag: var(--gold);

  /* One radius, one control height. The desktop nav had buttons at 40, 42, 44,
     46 and 47px -- six different top edges in a single row. */
  --radius: 12px;
  --control-h: 40px;

  /* The legacy sheet's own tokens, repointed so nothing violet survives. */
  --accent: #C9A227;
  --accent-strong: #A8871D;
  --surface: #1A1817;
  --surface-2: #242120;
  --success: #5E9E7A;
  --danger: #B4635A;
  --warning: #C9A227;
  --text-1: #F2EDE4;
  --text-2: #A39C90;
  --text-3: #6E675D;
  --border: rgba(232, 224, 208, 0.10);
  --bg-0: #0A0908;
  --bg-1: #121110;
  --bg-2: #1A1817;
}

body { font-family: var(--font-body); }

/* ---------------------------------------------------------------- the price */
/* Engraved, not emitted. A serif at 400 with real stroke contrast, no gradient
   fill (the old one faded the number 20% darker at its baseline), and the cents
   demoted so 4340 is the object and .40 is the footnote. */
.price-value {
  font-family: var(--font-display) !important;
  font-size: clamp(3.6rem, 9vw, 6.4rem) !important;
  font-weight: 400 !important;
  letter-spacing: -0.01em !important;
  line-height: 0.92;
  background: none !important;
  -webkit-text-fill-color: var(--ink-1);
  color: var(--ink-1);
  text-shadow: none;
}

/* Prose returns to the body face everywhere. */
.evidence-value, .alert-row span, .open-position, .coach-log,
.verdict-panel-reason, .news-title { font-family: var(--font-body); }

/* Figures keep the display serif; it has proper old-style-free lining numerals. */
.price-facts dd, .verdict-setup b, .live-r, .terminal-price b,
.live-position-levels b, .measured-row b {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums lining-nums;
}

/* The verdict headline is a sentence in the serif -- the counterweight to the
   price at the other end of the slab. */
.verdict-panel-status {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: -0.01em;
}

/* Integer sizes only: 13.328px and 9.6px rendered soft and read as legalese. */
.price-title h1, .verdict-panel-label, .verdict-evidence-title, .panel > h3 {
  font-size: 11px;
  letter-spacing: 0.18em;
  font-weight: 500;
  color: var(--ink-3);
}
.price-facts dt { font-size: 10px; letter-spacing: 0.12em; }
.price-title .badge { font-size: 11px; }
.verdict-panel-label { color: var(--gold-text); }

/* ------------------------------------------------------------------ controls */
/* One height, one radius, no bevel. The primary was a three-stop gradient with
   a white top highlight and a dark bottom line -- the iOS 6 glossy recipe. */
.btn, .btn-primary, .btn-secondary, .btn-ghost, select.btn,
.nav-more, .alerts-bell, .nav-primary {
  min-block-size: var(--control-h);
  block-size: var(--control-h);
  border-radius: var(--radius);
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 500;
}
.btn-primary, .nav-primary {
  background: var(--gold) !important;
  color: var(--gold-ink) !important;
  border: 0;
  box-shadow: none !important;
}
.btn-primary:hover, .nav-primary:hover { background: #D8B03A !important; }
/* Disabled is a STATE, not a defect. A grey slab where the primary action
   lives reads as broken chrome; a quiet gold outline reads as "not now". */
.btn-primary:disabled, .nav-primary:disabled {
  background: transparent !important;
  border: 1px solid rgba(201, 154, 58, 0.30) !important;
  color: rgba(232, 200, 107, 0.55) !important;
  box-shadow: none !important;
  cursor: not-allowed;
}
.panel, .surface, .chart-card, .verdict-panel, .live-position,
.news-section, .chart-cta, .alerts-panel, .modal, .price-hero {
  border-radius: var(--radius);
}
.brand-glyph {
  background: var(--gold);
  color: var(--gold-ink);
  box-shadow: none;
  border-radius: 10px;
  font-family: var(--font-display);
  font-weight: 400;
}

/* The OHLC box sat over the time axis and hid the date. Move it clear. */
.ohlc-readout {
  inset-block-end: auto;
  inset-block-start: var(--space-2);
  inset-inline-start: var(--space-2);
  font-family: var(--font-body);
  font-size: 11px;
  letter-spacing: 0;
}

/* ------------------------------------------------------------ light theme */
/* It was live and broken: the verdict headline kept its dark-theme white on a
   white card, so "Market closed" was invisible, and the signal cards kept a
   hardcoded translucent navy. A luxury product does not ship a broken skin. */
:root[data-theme="light"] {
  --s0: #FAF8F4;
  --s1: #FFFFFF;
  --s2: #F4F1EA;
  --s3: #EAE5DA;
  --line: rgba(28, 24, 18, 0.10);
  --line-strong: rgba(28, 24, 18, 0.18);
  --ink-1: #17140F;
  --ink-2: #55504A;
  --ink-3: #6B6459;
  --gold: #A07C10;
  --gold-text: #7A5E0A;
  --gold-ink: #FFFFFF;
  /* #3F7D5C read 4.33 and 3.89 on the two deepest light surfaces. Darkened by
     the smallest step that clears AA on all four (5.01 / 4.50). */
  --up: #3A7254;
  --down: #9C4A42;
  --accent: #A07C10;
  --surface: #F4F1EA;
  --surface-2: #EAE5DA;
  --text-1: #17140F;
  --text-2: #55504A;
  --text-3: #6B6459;
  --border: rgba(28, 24, 18, 0.10);
  --bg-0: #FAF8F4;
  --bg-1: #FFFFFF;
  --bg-2: #F4F1EA;
  --success: #3F7D5C;
  --danger: #9C4A42;
  --warning: #A07C10;
}
/* Anything the legacy sheet hardcoded, restated in tokens. */
:root[data-theme="light"] .verdict-panel-status,
:root[data-theme="light"] .price-value,
:root[data-theme="light"] .signal-value,
:root[data-theme="light"] .stat-value,
:root[data-theme="light"] .news-title { color: var(--ink-1) !important; -webkit-text-fill-color: var(--ink-1); }
:root[data-theme="light"] .signal-card,
:root[data-theme="light"] .stat-card,
:root[data-theme="light"] .measured-record,
:root[data-theme="light"] .positions-summary,
:root[data-theme="light"] .open-position,
:root[data-theme="light"] .alerts-row,
:root[data-theme="light"] .style-option {
  background: var(--s2) !important;
  border-color: var(--line) !important;
  color: var(--ink-1);
}

/* ------------------------------------------------------------- get ready */
/* The pre-signal: a setup is forming but has not fired. A heads-up, weighted
   below a live verdict -- a soft warm band with a slow pulse, never the loud
   colour of an actionable trade. */
.getready {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-block-end: var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: rgba(201, 162, 39, 0.08);
  border: 1px solid rgba(201, 162, 39, 0.24);
  border-radius: var(--radius);
}
.getready-pulse {
  inline-size: 8px; block-size: 8px; flex: none;
  border-radius: 50%; background: var(--gold);
  box-shadow: 0 0 0 0 rgba(201, 162, 39, 0.5);
  animation: getready-pulse 2s var(--ease) infinite;
}
@keyframes getready-pulse {
  0% { box-shadow: 0 0 0 0 rgba(201, 162, 39, 0.45); }
  70% { box-shadow: 0 0 0 8px rgba(201, 162, 39, 0); }
  100% { box-shadow: 0 0 0 0 rgba(201, 162, 39, 0); }
}
@media (prefers-reduced-motion: reduce) { .getready-pulse { animation: none; } }
.getready-copy { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.getready-copy b { font-size: var(--text-xs); color: var(--gold-text); }
.getready-copy span { font-size: 11px; color: var(--ink-3); line-height: 1.5; }

/* ---------------------------------------------------- the alerted setup */
/* Landing here from a notification, the first thing seen is the exact trade
   the alert announced -- with a caveat that the plan below is live and may
   have moved on. It answers "I tapped the alert, now what?". */
.alert-setup {
  margin-block-end: var(--space-4);
  padding: var(--space-4);
  border-radius: var(--radius);
  background: rgba(201, 162, 39, 0.07);
  border: 1px solid rgba(201, 162, 39, 0.28);
}
.alert-setup-head { display: flex; align-items: center; justify-content: space-between; }
.alert-setup-tag {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase;
  font-weight: 600; color: var(--gold-text);
}
.alert-setup-x {
  border: 0; background: transparent; color: var(--ink-3);
  cursor: pointer; min-block-size: 32px; min-inline-size: 32px;
}
.alert-setup-dir {
  font-family: var(--font-display);
  font-size: 1.6rem; letter-spacing: -0.02em;
  margin-block: var(--space-2) var(--space-3);
}
.alert-setup-levels {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-3);
  padding: var(--space-3); border-radius: 10px;
  background: rgba(0, 0, 0, 0.22);
}
.alert-setup-levels span { display: flex; flex-direction: column; gap: 2px; }
.alert-setup-levels small { font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-3); }
.alert-setup-levels b { font-family: var(--font-display); font-variant-numeric: tabular-nums; color: var(--ink-1); }
.alert-setup-note { margin: var(--space-3) 0 0; font-size: 11px; color: var(--ink-3); line-height: 1.55; }
:root[data-theme="light"] .alert-setup-levels { background: var(--s2); }

/* The legacy sheet painted .chart-canvas #0f182b; the chart now paints its own
   surface from the live theme tokens, so this hardcode has to go or it shows
   as a blue rectangle behind a themed canvas. */
.chart-canvas { background: transparent !important; }
.chart-card { background: var(--s1); }

/* ------------------------------------------------------- the plan, closable */
/* The plan drawer opened with no way out. A header with a close button, and a
   scrim behind it so a tap anywhere off the panel dismisses it. */
.rail-head { display: none; }
.rail-scrim { display: none; }

@media (max-width: 820px) {
  .rail-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-block-end: var(--space-3);
    margin-block-end: var(--space-2);
    border-block-end: 1px solid var(--line);
    position: sticky;
    inset-block-start: 0;
    background: var(--s1);
    z-index: 1;
  }
  .rail-head span {
    font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase;
    color: var(--ink-3); font-weight: 600;
  }
  .rail-close {
    display: inline-flex; align-items: center; justify-content: center;
    min-inline-size: 40px; min-block-size: 40px;
    border: 1px solid var(--line); border-radius: var(--radius);
    background: transparent; color: var(--ink-2); cursor: pointer;
  }
  .rail-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 39;
    background: rgba(0, 0, 0, 0.45);
    backdrop-filter: blur(2px);
  }
  /* The rail sits above its own scrim. */
  .terminal-rail { z-index: 40; }
}

/* The XAUUSD news chip kept the old violet accent. */
.news-chip, .news-symbol, .chip-symbol {
  background: rgba(201, 162, 39, 0.10) !important;
  color: var(--gold-text) !important;
  border: 1px solid rgba(201, 162, 39, 0.22);
}

/* The "..." menu opened with no way out; a scrim dismisses it, and the icon
   flips to a close mark while open. */
.nav-scrim {
  position: fixed; inset: 0;
  /* ABOVE the tab bar (z 200) and below the sheet (z 210). At 44 the dim sat
     under the bottom bar, so the sheet opened over a dimmed page with a fully
     lit tab bar glowing beneath it — the one element the sheet is covering. */
  z-index: 205;
  background: rgba(0, 0, 0, 0.4);
}
@media (min-width: 821px) { .nav-scrim { display: none; } }

/* ---------------------------------------------------------------- login */
/* It loaded only the legacy sheet, so it kept the violet button, the grotesk
   headings and a blue ground. The rebuilt tokens now reach it; these map its
   own class names onto them. */
.auth-page, .login-page, body.login {
  background:
    radial-gradient(1000px 500px at 100% 0%, rgba(201,162,39,0.06), transparent 60%),
    var(--s0) !important;
}
.auth-submit, .login-page .btn-primary, button[type=submit].btn {
  background: var(--gold) !important;
  color: var(--gold-ink) !important;
  border: 0 !important;
  box-shadow: none !important;
  font-weight: 600;
}
.auth-panel, .login-card, .auth-card {
  background: var(--s1) !important;
  border: 1px solid var(--line) !important;
}
.auth-lede h1, .auth-title, .login-title, .auth-hero h1, .auth-headline {
  font-family: var(--font-display) !important;
  font-weight: 400;
  letter-spacing: -0.01em;
}
.input, input.input, .auth-input {
  background: rgba(0,0,0,0.22) !important;
  border: 1px solid var(--line) !important;
  color: var(--ink-1) !important;
}

/* The login/splash is always dark -- a marketing surface, not the app chrome.
   The rebuilt tokens style it; these force the whole split onto one ground so
   there is no dark-hero/white-form seam and the headline is never dark-on-dark. */
.auth-split { background: var(--s0); }
.auth-panel, .auth-form-wrap { background: transparent !important; border: 0 !important; }
.auth-lede h1, .auth-lede h2, .auth-hero h1 {
  font-family: var(--font-display) !important;
  font-weight: 400 !important;
  letter-spacing: -0.015em;
  color: var(--ink-1) !important;
  -webkit-text-fill-color: var(--ink-1);
}
.auth-lede p, .auth-form-wrap p, .auth-sub { color: var(--ink-2) !important; }
.auth-form-wrap h2 { font-family: var(--font-display) !important; font-weight: 400 !important; }
.auth-points i { color: var(--gold) !important; }
.auth-split .input, .auth-split input {
  background: rgba(255,255,255,0.04) !important;
  border: 1px solid var(--line) !important;
  color: var(--ink-1) !important;
}

/* Login inputs were light pills on the dark splash. Match them to the ground
   so the form reads as one surface, not white slabs floating on black. */
[data-theme="dark"] .auth-split .input,
[data-theme="dark"] .auth-split input.input,
.auth-split .input, .auth-split input.input {
  background: rgba(255, 255, 255, 0.05) !important;
  border: 1px solid rgba(255, 255, 255, 0.12) !important;
  color: var(--ink-1) !important;
}
.auth-split .input::placeholder { color: var(--ink-3) !important; }
.auth-split .input-affix-btn { color: var(--ink-3) !important; }
/* The language pill on the splash follows the dark ground too. */
.auth-split select, .auth-split .btn-secondary {
  background: rgba(255, 255, 255, 0.05) !important;
  border-color: rgba(255, 255, 255, 0.12) !important;
  color: var(--ink-1) !important;
}

/* ==========================================================================
   POLISH PASS
   The controls read faint -- a secondary button was a near-invisible outline,
   and every interactive surface sat flat. Premium is not more colour, it is
   more DEFINITION: a button that looks pressable, a hairline that catches
   light, a hover that acknowledges. This pass gives every control weight and
   feedback without adding a single new hue.
   ========================================================================== */

/* Secondary controls: a real, if quiet, surface -- raised, with a lit top edge
   and a soft drop, so they read as objects you can press, not as text. */
.btn-secondary, .btn-ghost, .nav-more, .alerts-bell, .tool-chip, .seg,
.chart-type-switch, .tf-strip, select.btn {
  background: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.02)) , var(--s2);
  border: 1px solid var(--line);
  border-top-color: var(--line-strong);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05), 0 1px 2px rgba(0,0,0,0.35);
}
.btn-secondary:hover, .btn-ghost:hover, .nav-more:hover, .alerts-bell:hover, .tool-chip:hover {
  background: var(--s3);
  border-color: var(--line-strong);
  transform: translateY(-1px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.07), 0 4px 12px rgba(0,0,0,0.4);
}
.btn-secondary:active, .btn-ghost:active, .tool-chip:active { transform: translateY(0); }

/* The primary and active states glow with the brand, faintly -- gold, once. */
.btn-primary, .nav-primary {
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.4), 0 2px 12px rgba(201,162,39,0.28) !important;
}
.btn-primary:hover, .nav-primary:hover {
  transform: translateY(-1px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.45), 0 6px 20px rgba(201,162,39,0.38) !important;
}
.tf-chip.is-active, .chart-type-option.is-active {
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), 0 2px 8px rgba(201,162,39,0.25);
}

/* Cards lift a hair on hover where they are actionable -- news rows, the chart
   CTA, style options -- so the surface answers the cursor. */
.chart-cta:hover, .news-card:hover, .style-option:hover, .alert-row:hover {
  border-color: var(--line-strong);
  transform: translateY(-1px);
  transition: transform var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}

/* The stance chips and badges get a faint tinted fill instead of a bare
   outline, so a "SUPPORTS" reads as a token, not as ghost text. */
.evidence-stance.stance-supports { background: rgba(94,158,122,0.10) !important; }
.evidence-stance.stance-opposes  { background: rgba(180,99,90,0.12) !important; }
.evidence-stance.stance-blocks   { background: rgba(201,162,39,0.10) !important; }
.getready, .verdict-size, .alert-setup {
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.04);
}

/* Inputs get an inset well and a gold focus ring, so a focused field is
   unmistakable. */
.input:focus, input.input:focus, .risk-field .input:focus, .auth-split .input:focus {
  outline: none !important;
  border-color: var(--gold) !important;
  box-shadow: 0 0 0 3px rgba(201,162,39,0.18) !important;
}

/* The bottom-tab active item gets a soft gold wash behind its icon. */
.tab-item.is-active i { filter: drop-shadow(0 0 8px rgba(201,162,39,0.4)); }

/* Scrollbars, themed and thin, instead of the OS default slabs. */
* { scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent; }
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 8px; }
*::-webkit-scrollbar-track { background: transparent; }

/* Selection uses the brand. */
::selection { background: rgba(201,162,39,0.28); color: var(--ink-1); }

/* ------------------------------------------------------------ login brand */
/* The splash used a raster logo the service worker holds cache-first, so it
   never updated and stayed on the old identity. The mark is now the same
   letterform the app chrome uses -- one brand, and nothing to cache-bust. */
.sv-mark { margin-block-end: var(--space-5); }
.auth-glyph { inline-size: 44px; block-size: 44px; font-size: 1.5rem; border-radius: 12px; }
.auth-wordmark { display: flex; flex-direction: column; gap: 2px; }
.auth-wordmark b {
  font-size: 13px; letter-spacing: 0.16em; font-weight: 600; color: var(--ink-1);
}
.auth-wordmark small {
  font-size: 10px; letter-spacing: 0.22em; text-transform: uppercase; color: var(--ink-3);
}

/* The headline was constrained to 159px and broke across two lines mid-phrase.
   Let it use the panel it sits in. */
.auth-lede h1, .auth-hero h1, .auth-split h1 {
  max-inline-size: 18ch;
  inline-size: auto;
  font-size: clamp(1.9rem, 5.5vw, 2.8rem) !important;
  line-height: 1.08;
  text-wrap: balance;
}
.auth-lede p, .auth-split .auth-lede p { max-inline-size: 46ch; }

/* The splash still had two grounds: the legacy hero kept a blue-violet gradient
   while the form half sat on the new near-black, so the page read as two pages
   stitched together. One ground, one warm bloom. */
.auth-split, .auth-split > *, .auth-hero, .auth-lede, .auth-panel, .auth-form-wrap {
  background: transparent !important;
}
.auth-split {
  background:
    radial-gradient(900px 480px at 50% -10%, rgba(201, 162, 39, 0.07), transparent 62%),
    var(--s0) !important;
}
.auth-split::before, .auth-split::after { display: none !important; }
/* The hero/form seam was a hard border between the two halves. */
.auth-panel, .auth-form-wrap { border: 0 !important; box-shadow: none !important; }

/* The new brand block reused the legacy .auth-brand class name and inherited
   its blue/green radial gradient and its 88px padding -- which is the blue
   rectangle that kept appearing behind the mark. Reset it to a plain row. */
/* The hero column keeps its stacking; only its blue/green gradient goes. */
.auth-brand {
  background: none !important;
  border: 0 !important;
}
/* The mark itself is a row, scoped to its own class so it cannot inherit the
   hero container's layout. */
.sv-mark {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--space-3);
  padding: 0;
  background: none;
  border: 0;
}

/* ==========================================================================
   LOGIN — rebuilt from a measured critique
   The faults, measured: a 630px dead void between two floating columns on
   desktop; a page anchored to nothing (340px of empty above the mark); a
   lone language pill; fractional type (13.328 / 9.6 / 10px); label and lede
   the same colour; 42px field vs 40px button; no autofocus, no inputmode.
   This replaces the whole layout with ONE centred card that holds the brand,
   the pitch and the form together, so nothing floats and nothing competes.
   ========================================================================== */

.auth-split {
  display: grid !important;
  grid-template-columns: 1fr !important;
  place-items: center;
  min-block-size: 100dvh;
  padding: var(--space-6) var(--space-5);
  background:
    radial-gradient(1000px 620px at 50% -6%, rgba(201,162,39,0.09), transparent 60%),
    var(--s0) !important;
}

/* One card. On desktop the brand sits left of the form inside it; on phone
   they stack. No dead middle either way. */
.auth-split > .auth-brand,
.auth-split > .auth-panel {
  inline-size: 100%;
  max-inline-size: 460px;
}
.auth-brand { padding: 0 !important; margin-block-end: var(--space-6); text-align: start; }

.sv-mark { margin-block-end: var(--space-5) !important; }
.auth-wordmark b { font-size: 12px; letter-spacing: 0.18em; }
.auth-wordmark small { font-size: 9px; letter-spacing: 0.2em; }

.auth-lede h1, .auth-brand h1 {
  font-size: clamp(30px, 6vw, 40px) !important;
  line-height: 1.06 !important;
  max-inline-size: 14ch;
  margin: 0 0 var(--space-3) !important;
  text-wrap: balance;
}
.auth-lede, .auth-brand > p {
  font-size: 15px !important;
  line-height: 1.6 !important;
  color: var(--ink-2) !important;
  max-inline-size: 44ch;
}

/* The three honesty points: a quiet, aligned list, gold ticks. */
.auth-points { margin-block-start: var(--space-5) !important; gap: var(--space-3) !important; }
.auth-points li {
  font-size: 13px; line-height: 1.5; color: var(--ink-2);
  display: flex; gap: var(--space-3); align-items: flex-start;
}
.auth-points i { color: var(--gold) !important; margin-block-start: 3px; }

/* The form panel is a real raised card -- the object the eye lands on. */
.auth-panel {
  background: var(--s1) !important;
  border: 1px solid var(--line) !important;
  border-top-color: var(--line-strong) !important;
  border-radius: 16px !important;
  padding: var(--space-6) !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05), 0 24px 60px -20px rgba(0,0,0,0.7) !important;
}
.auth-panel-top { display: flex; justify-content: flex-end; margin-block-end: var(--space-4); }
.auth-form-wrap h2 {
  font-family: var(--font-display) !important;
  font-size: 30px !important; font-weight: 400 !important;
  margin: 0 0 var(--space-1);
}
.auth-sub { font-size: 14px !important; color: var(--ink-3) !important; margin: 0 0 var(--space-5); }

/* Labels lead the fields: brighter than help text, integer size. */
.form-label {
  display: block;
  font-size: 12px !important;
  font-weight: 600 !important;
  letter-spacing: 0.02em;
  color: var(--ink-2) !important;
  margin-block-end: var(--space-2);
}
.form-group { margin-block-end: var(--space-4); }

/* Fields: an inset well, 44px, matching the button. */
.auth-split .input, .auth-split input.input {
  inline-size: 100%;
  min-block-size: 44px !important;
  font-size: 15px !important;
  padding: 0 var(--space-4) !important;
  border-radius: 10px !important;
  background: rgba(0,0,0,0.28) !important;
  border: 1px solid var(--line) !important;
  box-shadow: inset 0 2px 5px rgba(0,0,0,0.4) !important;
  color: var(--ink-1) !important;
}
.input-affix { position: relative; }
.input-affix .input { padding-inline-end: 44px !important; }
.input-affix-btn {
  position: absolute; inset-block: 0; inset-inline-end: 4px;
  inline-size: 40px; display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 0; color: var(--ink-3); cursor: pointer;
}

/* The submit is present, not dominant: 44px, gold, but not the biggest thing
   on the screen -- the headline is. */
.auth-submit {
  inline-size: 100%;
  min-block-size: 44px !important;
  margin-block-start: var(--space-2);
  font-size: 14px !important;
  font-weight: 600 !important;
  border-radius: 10px !important;
}
.auth-disclaimer {
  font-size: 11px !important; line-height: 1.5 !important;
  color: var(--ink-3) !important; margin-block-start: var(--space-5) !important;
}

/* Desktop: brand and form side by side INSIDE one centred band, capped so
   there is never a dead middle. */
@media (min-width: 900px) {
  .auth-split {
    grid-template-columns: minmax(0, 440px) minmax(0, 420px) !important;
    gap: clamp(40px, 6vw, 96px);
    align-content: center;
    justify-content: center;
  }
  .auth-split > .auth-brand { max-inline-size: 440px; align-self: center; margin: 0; }
  .auth-split > .auth-panel { max-inline-size: 420px; align-self: center; }
}

/* Login, second pass — three residual faults from the measured screenshot:
   the show-password button floated outside the field (legacy .input-affix had
   its own positioning), the card was wider than its content, and the band sat
   left of centre. */

/* The affix must be a positioning context sized to the field, and the button
   vertically centred inside it. */
.auth-split .input-affix { position: relative; display: block; }
.auth-split .input-affix .input { inline-size: 100%; }
.auth-split .input-affix-btn {
  position: absolute !important;
  inset-block-start: 50% !important;
  transform: translateY(-50%) !important;
  inset-inline-end: 6px !important;
  inset-block-end: auto !important;
  block-size: 32px; inline-size: 36px;
  z-index: 2;
}

/* The whole auth band is centred as one unit. */
@media (min-width: 900px) {
  .auth-split {
    justify-content: center !important;
    align-content: center !important;
  }
  /* Cap the form so the card hugs its fields instead of holding side gutters. */
  .auth-split > .auth-panel { max-inline-size: 400px !important; }
}

/* The password eye must never overlap the label above it. */
.auth-form-wrap .form-group { position: relative; }

/* The three honesty points were the pitch; the legacy sheet hid them on phone,
   leaving the splash saying nothing about what the product does. Kept, compact. */
@media (max-width: 899px) {
  .auth-points { display: grid !important; margin-block: var(--space-4) var(--space-2) !important; }
}

/* Login RTL, final details from the Arabic screenshot:
   - the wordmark stayed LTR-shaped and detached from the glyph when the row
     mirrored; keep the mark itself LTR (it is a Latin brand) but let the row
     sit at the start of the RTL line.
   - the language pill clipped "العربية" -> "العـبة": give the select room. */
body.rtl .sv-mark, [dir="rtl"] .sv-mark {
  flex-direction: row;
  direction: ltr;           /* the Latin mark reads left-to-right as a unit */
  justify-content: flex-start;
}
body.rtl .auth-wordmark, [dir="rtl"] .auth-wordmark { text-align: start; }

/* The language select must fit its longest label in any language. */
.auth-panel-top select, .auth-split select {
  min-inline-size: 132px;
  padding-inline: var(--space-3);
  text-overflow: clip;
}
body.rtl .auth-panel-top, [dir="rtl"] .auth-panel-top { justify-content: flex-start; }

/* Login must fit the viewport with no scroll. min-height:100dvh PLUS vertical
   padding measured 917px of content into an 844px phone -- the padding added
   on top of a full-height box. Make the split exactly the viewport, put the
   padding inside it, and let it scroll ONLY if the content genuinely cannot
   fit (very short landscape phones), never otherwise. */
.auth-split {
  min-block-size: 100dvh !important;
  block-size: auto;
  box-sizing: border-box;
}
@media (max-width: 899px) {
  .auth-split {
    /* Stack, top-aligned, so a tall phone shows everything without centring
       pushing content off the top edge. */
    place-items: start stretch !important;
    align-content: start !important;
    gap: 0 !important;
    padding: var(--space-5) var(--space-5) calc(var(--space-6) + env(safe-area-inset-bottom)) !important;
  }
  /* Trim the vertical rhythm so the whole thing clears an 844px phone. */
  .auth-brand { margin-block-end: var(--space-4) !important; }
  .sv-mark { margin-block-end: var(--space-4) !important; }
  .auth-lede h1, .auth-brand h1 { font-size: clamp(26px, 7vw, 32px) !important; }
  .auth-lede, .auth-brand > p { font-size: 14px !important; line-height: 1.5 !important; }
  .auth-points { margin-block: var(--space-3) 0 !important; gap: var(--space-2) !important; }
  .auth-points li { font-size: 12px; }
  .auth-panel { padding: var(--space-5) !important; }
  .auth-form-wrap h2 { font-size: 26px !important; }
  .auth-sub { margin-block-end: var(--space-4) !important; }
  .form-group { margin-block-end: var(--space-3) !important; }
  .auth-disclaimer { margin-block-start: var(--space-4) !important; }
}

/* The phone total measured 904px in an 844px viewport; the 106px points list
   is the trim. On a phone the headline and lede already carry the pitch, and a
   splash that fits with no scroll beats one that lists three bullets and
   overflows. Points return at >=900px where there is room. */
@media (max-width: 899px) {
  /* Points return -- the reclaimed 60px made room -- but only the first two,
     compact, so the splash still clears an 844px phone with no scroll. */
  .auth-points { display: grid !important; margin-block: var(--space-3) 0 !important; gap: var(--space-2) !important; }
  .auth-points li:nth-child(3) { display: none; }
  .auth-brand { margin-block-end: var(--space-3) !important; }
}

/* The 60px scroll was body's bottom padding, reserved for the tab bar -- but
   the login page has no tab bar. Drop it there so the splash fits exactly. */
body:has(.auth-split) { padding-block-end: 0 !important; }

/* Login — visual critique pass, from the rendered screenshot:

   1. Fields were nearly invisible: a black inset well with a 10%-white border
      on a near-black ground, placeholder in --ink-3. Raise the field surface,
      strengthen the border, brighten the placeholder. A field a user cannot
      see is not premium, it is broken.
   2. The T mark was set in the display serif while the wordmark is a bold
      grotesk -- the letter did not match its own name beside it. The mark
      takes the body face, bold.
   3. "Sign in" at 30px serif competed with the 32px serif hero headline: two
      big serifs stacked. The form heading drops to a smaller, quieter size so
      the hero leads and the form supports. */

/* 1. Legible fields */
.auth-split .input, .auth-split input.input {
  background: rgba(255, 255, 255, 0.06) !important;
  border: 1px solid rgba(255, 255, 255, 0.16) !important;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3) !important;
  color: var(--ink-1) !important;
}
.auth-split .input::placeholder { color: rgba(163, 156, 144, 0.9) !important; }
.auth-split .input:hover { border-color: rgba(255, 255, 255, 0.24) !important; }
.auth-split .input:focus {
  border-color: var(--gold) !important;
  background: rgba(255, 255, 255, 0.08) !important;
  box-shadow: 0 0 0 3px rgba(201, 162, 39, 0.22) !important;
}

/* 2. The mark matches its wordmark */
.auth-glyph, .brand-glyph {
  font-family: var(--font-body) !important;
  font-weight: 700 !important;
}

/* 3. The form heading yields to the hero */
.auth-form-wrap h2 {
  font-family: var(--font-body) !important;
  font-size: 20px !important;
  font-weight: 600 !important;
  letter-spacing: -0.01em;
}
.auth-sub { font-size: 13px !important; }

/* ==========================================================================
   GOLD, AS A METAL
   A single flat #C9A227 reads as a yellow swatch. Real gold on a screen is a
   RANGE with light falling across it -- a bright specular highlight, a mid
   body, a shadow edge. These stops are the vocabulary the login hero uses; a
   metallic gradient built from them reads as bullion, a flat fill reads as
   paint. Defined once here so every gold surface can draw from the same metal.
   ========================================================================== */
:root {
  --gold-hi:   #F6E7A8;   /* specular highlight */
  --gold-1:    #E9CE77;   /* light body */
  --gold-2:    #C9A227;   /* mid (the existing accent) */
  --gold-3:    #9A7317;   /* shadow */
  --gold-deep: #6E4E0C;   /* deepest edge */

  /* A believable brushed-metal fill: light from top-left, shadow bottom-right,
     with a bright band across the upper third where the highlight catches. */
  --gold-metal: linear-gradient(135deg,
    var(--gold-hi) 0%,
    var(--gold-1) 22%,
    var(--gold-2) 46%,
    var(--gold-3) 74%,
    var(--gold-deep) 100%);
  --gold-metal-soft: linear-gradient(135deg,
    var(--gold-1) 0%, var(--gold-2) 55%, var(--gold-3) 100%);
}

/* The wordmark and the mark are the first gold the eye meets; make them the
   metal, not a flat colour. This is the smallest change with the largest
   "expensive" return -- a metallic wordmark reads as an engraved plate. */
.auth-wordmark b {
  background: var(--gold-metal);
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
}
.auth-glyph, .auth-split .brand-glyph {
  background: var(--gold-metal) !important;
  color: var(--gold-deep) !important;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.6),
    inset 0 -2px 3px rgba(110,78,12,0.5),
    0 6px 18px rgba(154,115,23,0.35) !important;
}

/* ==========================================================================
   THE HERO GROUND — engraved guilloché
   A flat near-black field is what makes a login read as a template. Bullion,
   banknotes and share certificates share one device: a fine engine-turned
   guilloché lattice, barely visible, that says "this is a document of value".
   Built as an inline SVG data-URI (no library, no image request), at ~4%
   opacity so it is texture, not pattern -- you feel it before you see it.
   Warm gold hairlines, lit from the top so it fades toward the base.
   ========================================================================== */
.auth-split::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160' viewBox='0 0 160 160'%3E%3Cg fill='none' stroke='%23C9A227' stroke-width='0.6' opacity='0.5'%3E%3Ccircle cx='80' cy='80' r='70'/%3E%3Ccircle cx='80' cy='80' r='54'/%3E%3Ccircle cx='80' cy='80' r='38'/%3E%3Cpath d='M80 4 A76 76 0 0 1 156 80 A76 76 0 0 1 80 156 A76 76 0 0 1 4 80 A76 76 0 0 1 80 4'/%3E%3Cpath d='M24 24 L136 136 M136 24 L24 136'/%3E%3C/g%3E%3C/svg%3E");
  background-size: 220px 220px;
  /* Lit from the top: the lattice is present up top and dissolves to nothing
     by the fold, so it frames the brand without touching the form. */
  -webkit-mask-image: linear-gradient(180deg, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.35) 34%, transparent 60%);
  mask-image: linear-gradient(180deg, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.35) 34%, transparent 60%);
  opacity: 0.10;
}
/* Everything sits above the engraving. */
.auth-split > * { position: relative; z-index: 1; }

/* A single warm light source, top-centre, over the guilloché -- one lamp on
   the plate, not a flat wash. */
.auth-split {
  background:
    radial-gradient(680px 460px at 50% -8%, rgba(233,206,119,0.10), transparent 62%),
    var(--s0) !important;
}

/* ==========================================================================
   LOGIN — the art direction, executed
   Brief: the screen was a B2B split-template with cool blue-grey text wearing
   gold paint, no hero, timid 40px headline. This rebuilds it as a warm, dimly
   lit assay office: one overhead lamp, a corner vignette, an engraved gold
   rosette bleeding off the edge, and the word "Gold" struck in real metal.
   ========================================================================== */

/* The login uses its own warm ramp + a real gold metal range, scoped so the
   app's themes are untouched. */
.auth-split {
  --ink-1: #F3ECDE;
  --ink-2: #C9BCA4;
  --ink-3: #8A7E68;
  --au-spec: #FCEFC7;
  --au-100:  #E8C86B;
  --au-300:  #C99A3A;
  --au-500:  #A9761F;
  --au-700:  #6E4A15;

  /* One directional lamp, top-centre, and a vignette that pulls the corners to
     black -- the screen is LIT, not flat-filled. */
  background:
    radial-gradient(1100px 720px at 50% -12%, rgba(201,154,46,0.20), transparent 55%),
    radial-gradient(150% 130% at 50% -8%, transparent 55%, rgba(0,0,0,0.72) 100%),
    #0B0906 !important;
}
/* Retire the earlier guilloché-tile background; the SVG rosette replaces it. */
.auth-split::before { display: none !important; }

/* Anchor the composition into the top of the light pool -- no more 340px dead
   band from vertical centring. */
@media (min-width: 900px) {
  .auth-split {
    align-content: start !important;
    padding-block-start: clamp(64px, 12vh, 160px) !important;
  }
}

/* The engraved rosette: large, bleeding off the left, dissolved into the ground
   by a soft-circle mask. This is the hero moment and the edge anchor. */
/* clip, not hidden: the rosette is a decoration that bleeds past the edge by
   design, and without clipping it widened the page to 461px on a 390px phone
   -- a horizontal scrollbar on the sign-in screen. `clip` contains it without
   creating a scroll container the way `hidden` would. */
.auth-brand { position: relative; overflow: hidden; overflow: clip; }
.guilloche {
  position: absolute;
  inset-block-start: -40px;
  inset-inline-start: -140px;
  inline-size: 560px; block-size: 560px;
  z-index: 0;
  opacity: 0.09;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(circle at 42% 40%, transparent 12%, rgba(0,0,0,0.55) 34%, rgba(0,0,0,0.35) 52%, transparent 70%);
  mask-image: radial-gradient(circle at 42% 40%, transparent 12%, rgba(0,0,0,0.55) 34%, rgba(0,0,0,0.35) 52%, transparent 70%);
}
.guilloche svg { display: block; inline-size: 100%; block-size: 100%; }
.auth-brand > *:not(.guilloche) { position: relative; z-index: 1; }

/* Wordmark demoted to one line, in light gold. */
.auth-wordmark b {
  background: none !important;
  -webkit-text-fill-color: initial;
  color: var(--au-100) !important;
  font-size: 12px; letter-spacing: 0.2em; font-weight: 600;
}

/* The hero: Playfair Display, one dramatic size, "Gold" struck in metal. */
.auth-hero, .auth-lede h1, .auth-brand h1 {
  font-family: "Playfair Display", Georgia, serif !important;
  font-size: clamp(46px, 8.5vw, 104px) !important;
  font-weight: 500 !important;
  letter-spacing: -0.018em !important;
  line-height: 0.98 !important;
  margin: 0 0 var(--space-4) -0.055em !important;
  color: #F3ECDE;
  text-wrap: balance;
  max-inline-size: 12ch;
}
.auth-hero .au {
  background: linear-gradient(180deg,#FCEFC7 0%,#E4C169 24%,#B98A2E 50%,#8A631C 61%,#E8C773 82%,#A9791F 100%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 1px 0 rgba(0,0,0,0.55));
}
.auth-lede, .auth-brand > p.auth-lede {
  font-size: 15px !important; line-height: 1.6 !important;
  color: var(--ink-2) !important; max-inline-size: 42ch;
}
/* One honesty line, no icon, no bullet list. */
.auth-oneline {
  margin-block-start: var(--space-4) !important;
  font-size: 13px; color: var(--ink-3);
  padding-inline-start: var(--space-4);
  border-inline-start: 2px solid var(--au-700);
  max-inline-size: 40ch; line-height: 1.5;
}

/* The T tile, real metal. */
.auth-glyph, .auth-split .brand-glyph {
  background: linear-gradient(180deg,#F7E4A6 0%,#D8AC4A 34%,#B4832A 54%,#8A631C 68%,#C89A3C 100%) !important;
  color: #241A06 !important;
  font-family: var(--font-body) !important; font-weight: 700 !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.55), inset 0 -2px 3px rgba(110,74,21,0.55),
              0 6px 18px rgba(154,115,23,0.35) !important;
}

/* The form panel: quieter, out of the light pool. */
.auth-panel {
  background: #100D08 !important;
  border: 1px solid rgba(233,201,120,0.10) !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.03), 0 30px 70px -24px rgba(0,0,0,0.8) !important;
}
.auth-form-wrap h2 {
  font-family: var(--font-body) !important;
  font-size: 19px !important; font-weight: 600 !important; color: var(--ink-1);
}

/* Labels as a maker's mark. */
.form-label {
  font: 600 11px/1 "Inter Tight" !important;
  letter-spacing: 0.14em !important; text-transform: uppercase;
  color: #8A7E68 !important; margin-block-end: var(--space-2) !important;
}

/* Fields: warm, taller, hairline -- not black pits. */
.auth-split .input, .auth-split input.input {
  min-block-size: 52px !important;
  border-radius: 8px !important;
  background: #14110B !important;
  border: 1px solid rgba(233,201,120,0.12) !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.03) !important;
  color: var(--ink-1) !important; font-size: 15px !important;
}
.auth-split .input::placeholder { color: #6A6250 !important; }
/* Focus: a struck gold rule, the "ledger underline". */
.auth-split .input:focus {
  border-color: rgba(201,154,46,0.55) !important;
  border-block-end: 2px solid var(--au-300) !important;
  background: #171309 !important;
  box-shadow: 0 0 0 1px rgba(201,154,46,0.28), 0 0 30px -12px rgba(201,154,46,0.5) !important;
}

/* The button as a struck bar. */
.auth-submit {
  min-block-size: 52px !important; border-radius: 8px !important;
  background: linear-gradient(180deg,#F7E4A6 0%,#D8AC4A 30%,#B4832A 52%,#916819 65%,#C89A3C 100%) !important;
  color: #241A06 !important; font-weight: 600 !important; letter-spacing: 0.02em;
  border: 0 !important; border-top: 1px solid #FCEFC7 !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.28), 0 12px 34px -12px rgba(180,131,42,0.6),
              0 0 0 1px rgba(110,74,21,0.6) !important;
}
.auth-submit:hover { filter: brightness(1.04); }

/* A single hairline above the legal fine print. */
.auth-disclaimer {
  margin-block-start: var(--space-5) !important;
  padding-block-start: var(--space-4);
  border-block-start: 1px solid rgba(233,201,120,0.08);
  color: var(--ink-3) !important; font-size: 11px !important;
}

/* ==========================================================================
   LOGIN — polish pass (from measured misalignments)
   1. mark left 322 vs headline 316: the -0.055em optical hang broke the left
      edge instead of aligning it. Align them to one rule.
   2. "Sign in" sat 4px above the first label -- it choked the field. Give the
      heading breathing room.
   3. flat 36px rhythm everywhere -> a real hierarchy of spacing.
   4. vertically centre the form with the hero block on desktop.
   ========================================================================== */

/* 1. One left edge for mark, headline, lede, one-line. The optical hang is
   removed; a shared start alignment reads as intentional where a 6px stagger
   reads as a bug. */
.auth-hero, .auth-lede h1, .auth-brand h1 { margin-inline-start: 0 !important; }
.sv-mark { margin-inline-start: -2px; }   /* the glyph's own shadow inset, trued to the text */

/* 2 + 3. A deliberate vertical rhythm, not a flat 36px.
   mark -> headline: tight (they are one lockup)
   headline -> lede: generous (the hero breathes)
   lede -> oneline: medium */
.sv-mark { margin-block-end: var(--space-5) !important; }
.auth-hero { margin-block-end: var(--space-5) !important; }
.auth-lede { margin-block-end: var(--space-6) !important; }
.auth-oneline { margin-block-start: 0 !important; }

/* The form heading must not choke the first field. */
.auth-form-wrap h2 { margin-block-end: var(--space-5) !important; }
.form-group:first-of-type { margin-block-start: 0; }

/* 4. On desktop the form card centres against the hero column, not floating
   100px below it. */
@media (min-width: 900px) {
  .auth-split > .auth-panel { align-self: center !important; }
  .auth-split > .auth-brand { align-self: center !important; }
}

/* A last touch: the metallic "Gold" gets a hair of warmth in its cast shadow
   so it lifts off the ground like struck relief, not printed ink. */
.auth-hero .au {
  filter: drop-shadow(0 1px 0 rgba(0,0,0,0.6)) drop-shadow(0 0 18px rgba(201,154,46,0.18));
}

/* Login polish 2 — leading field icons + a bullion button.
   Empty dark wells read as holes; a faint leading glyph gives the field a
   purpose and left anchor. And the button gets a sharper specular band so it
   reads as struck metal, not a yellow block. */
.auth-split .field-icon { position: relative; display: block; }
.auth-split .field-icon > i:first-child {
  position: absolute;
  inset-inline-start: var(--space-4);
  inset-block-start: 50%;
  transform: translateY(-50%);
  font-size: 13px;
  color: #6E6350;
  pointer-events: none;
  z-index: 2;
}
.auth-split .field-icon .input { padding-inline-start: calc(var(--space-4) + 26px) !important; }
.auth-split .field-icon:focus-within > i:first-child { color: var(--au-300); }

/* The button as struck bullion: a bright specular sliver top, a reflected band
   low, a crisp bronze ring. */
.auth-submit {
  background: linear-gradient(177deg,
    #FCEFC7 0%, #EAC96D 12%, #D3A845 34%, #B4832A 54%, #916819 66%,
    #C89A3C 86%, #A9791F 100%) !important;
  border-top: 1px solid #FFF6D8 !important;
  text-shadow: 0 1px 0 rgba(255,255,255,0.25);
}
.auth-submit::after {
  content: ""; position: absolute; inset: 1px 1px auto 1px; block-size: 45%;
  border-radius: 7px 7px 40px 40px;
  background: linear-gradient(180deg, rgba(255,255,255,0.34), transparent);
  pointer-events: none;
}
.auth-submit { position: relative; overflow: hidden; }

/* ==========================================================================
   LOGIN — the living layer
   A luxury screen breathes. Two almost-subliminal motions: a specular sheen
   that travels across the metallic "Gold" every few seconds like light moving
   over a bar, and the guilloché turning once, impossibly slowly. Neither is
   an "animation" you notice; you feel the screen is alive. Both respect
   reduced-motion.
   ========================================================================== */

/* The sheen on "Gold": a bright band overlaid and swept across the letters,
   clipped to the text so only the glyphs light up. */
.auth-hero .au {
  position: relative;
  background:
    linear-gradient(105deg, transparent 30%, rgba(255,248,222,0.85) 46%, transparent 62%),
    linear-gradient(180deg,#FCEFC7 0%,#E4C169 24%,#B98A2E 50%,#8A631C 61%,#E8C773 82%,#A9791F 100%);
  background-size: 260% 100%, 100% 100%;
  background-position: 240% 0, 0 0;
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
  animation: gold-sheen 6.5s ease-in-out 1.2s infinite;
}
@keyframes gold-sheen {
  0%   { background-position: 240% 0, 0 0; }
  22%  { background-position: -60% 0, 0 0; }
  100% { background-position: -60% 0, 0 0; }
}

/* The rosette turns once every ~2 minutes -- below the threshold of "moving",
   above the threshold of "static". */
.guilloche { animation: rosette-turn 120s linear infinite; transform-origin: 42% 40%; }
@keyframes rosette-turn { to { transform: rotate(360deg); } }

/* The lamp gives the faintest slow pulse, like a light settling. */
.auth-split { animation: lamp-settle 9s ease-in-out infinite alternate; }
@keyframes lamp-settle {
  from { background-position: 50% -12%, 50% -8%, 0 0; }
  to   { background-position: 52% -10%, 50% -8%, 0 0; }
}

@media (prefers-reduced-motion: reduce) {
  .auth-hero .au, .guilloche, .auth-split { animation: none !important; }
  .auth-hero .au { background-position: -60% 0, 0 0; }
}

/* The form card gets a true metallic top edge -- a hairline of gold catching
   the overhead lamp, so the card reads as a plate, not a grey box. */
.auth-panel {
  border-top: 1px solid transparent !important;
  background:
    linear-gradient(#100D08, #100D08) padding-box,
    linear-gradient(180deg, rgba(233,201,120,0.5), rgba(233,201,120,0.06) 30%, transparent 60%) border-box !important;
  border: 1px solid transparent !important;
}

/* ==========================================================================
   WARM THE APP TO MATCH THE LOGIN
   The login is a warm near-black (#0B0906) with gold; the dashboard still sat
   on the cold blue-black the old theme shipped (#080B14 / bluish surfaces).
   The two read as different products. Warm the whole dark theme onto the
   login's palette so the gold owns every screen, not just the door.
   ========================================================================== */
:root:not([data-theme="light"]) {
  --s0: #0B0906;
  --s1: #131009;
  --s2: #1B160D;
  --s3: #251F13;
  --line: rgba(233, 224, 200, 0.10);
  --line-strong: rgba(233, 224, 200, 0.18);
  --ink-1: #F3ECDE;
  --ink-2: #C9BCA4;
  --ink-3: #8A7E68;
  --gold: #C99A3A;
  --gold-text: #E8C86B;
  --gold-ink: #241A06;
  --accent: #C99A3A;
  --surface: #1B160D;
  --surface-2: #251F13;
  --text-1: #F3ECDE;
  --text-2: #C9BCA4;
  --text-3: #8A7E68;
  --border: rgba(233, 224, 200, 0.10);
  --bg-0: #0B0906;
  --bg-1: #131009;
  --bg-2: #1B160D;
}
/* The body gradient, warm to match. */
body { background:
  radial-gradient(1100px 520px at 85% -8%, rgba(201,154,46,0.06), transparent 62%),
  #0B0906; }

/* The price gets the warm-ivory clip; it was reading blue-white before. */
.price-value { -webkit-text-fill-color: var(--ink-1); color: var(--ink-1); }

/* The bars kept a cool blue-black tint (rgba(8,11,18,...)) after the palette
   warmed; align them to the warm ground so the chrome matches the content. */
.top-nav, .tab-bar, .terminal-bar {
  background: rgba(11, 9, 6, 0.9) !important;
  border-color: rgba(233, 224, 200, 0.10) !important;
}
:root[data-theme="light"] .top-nav,
:root[data-theme="light"] .tab-bar,
:root[data-theme="light"] .terminal-bar {
  background: rgba(250, 248, 244, 0.9) !important;
}

/* The dashboard left-column cards and the technical-analysis block still
   sampled the old cool surface. Snap every legacy panel/card to the warm
   tokens so nothing on the page reads blue. */
.panel, .surface, .stat-card, .signal-card, .accordion-item,
.style-option, .positions-summary, .open-position, .measured-record,
.chart-cta, .news-section {
  background: var(--s1);
  border-color: var(--line);
}
.stat-card, .accordion-item { background: var(--s2); }
/* The surface snap above also flattened the SELECTED trading style: this
   unlayered rule beat the legacy sheet's .active highlight, so in the dark
   theme all three cards looked identical and a click appeared to do nothing
   (the save itself worked). The light theme has its own .active override;
   this is the dark one. */
.style-option.active {
  background: rgba(201, 154, 58, 0.10);
  border-color: var(--gold);
}
/* the status-dot green stays; nothing else blue survives */

/* ==========================================================================
   TOP NAV — rebuilt with hierarchy
   Was six equal-weight controls (bell, a raw OS <select>, Admin, Refresh,
   user, AI Analysis) with the product's primary verb looking like "Refresh".
   Now: metallic brand, ONE gold primary, the alerts bell, and everything else
   behind a single kebab menu at every width.
   ========================================================================== */
.brand { text-decoration: none; }
.brand-word {
  font-family: "Playfair Display", Georgia, serif;
  font-size: 17px; font-weight: 500; letter-spacing: 0.01em;
  background: var(--gold-metal, linear-gradient(180deg,#F6E7A8,#C9A227 55%,#9A7317));
  -webkit-background-clip: text; background-clip: text; color: transparent;
  -webkit-text-fill-color: transparent;
}
.nav-actions { display: flex; align-items: center; gap: var(--space-2); margin-inline-start: auto; }

/* The one gold action. Text hides on phones; the icon carries it. */
.nav-primary {
  min-block-size: 40px; padding-inline: var(--space-4);
  display: inline-flex; align-items: center; gap: var(--space-2);
}

/* The kebab: one quiet control that opens everything else. */
.nav-more {
  display: inline-flex; align-items: center; justify-content: center;
  min-inline-size: 40px; min-block-size: 40px;
  border-radius: var(--radius); cursor: pointer;
}

/* The overflow menu: a proper dropped panel, not a stack of pills. */
/* ---------------------------------------------------------------------------
   THE OVERFLOW NAVIGATION.

   A slim dropdown at every width, anchored under the top nav — the owner's
   call, and he is right: the wide bottom sheet I replaced it with was bigger
   without being clearer, and the only thing ever wrong with the dropdown was
   that it could not scroll.

   So the shape is the original one and the two real defects stay fixed. Its
   height is capped against the top nav AND the fixed tab bar (60px plus the
   home indicator), which is what put Logout under the bar on a phone; and it
   is portalled to <body>, because the nav's backdrop-filter makes it the
   containing block for any position:fixed child — that is what rendered the
   first attempt five pixels above the top of the screen.
   ------------------------------------------------------------------------- */
.nav-menu {
  position: fixed;
  inset-block-start: calc(var(--topnav-h, 56px) + var(--space-2));
  inset-inline-end: var(--space-4);
  z-index: 210;
  min-inline-size: 224px;
  max-inline-size: min(280px, calc(100vw - 2 * var(--space-4)));
  padding: var(--space-2);
  background: var(--s2);
  border: 1px solid var(--line);
  border-top-color: var(--line-strong);
  border-radius: 12px;
  box-shadow: 0 20px 48px -16px rgba(0,0,0,0.7);
  max-block-size: calc(100dvh - var(--topnav-h, 56px) - var(--tabs-h, 0px)
                       - env(safe-area-inset-bottom, 0px) - var(--space-6, 24px));
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
.nav-menu::-webkit-scrollbar { inline-size: 4px; }
.nav-menu::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 4px; }
@supports not (max-block-size: 100dvh) {
  .nav-menu {
    max-block-size: calc(100vh - var(--topnav-h, 56px) - var(--tabs-h, 0px)
                         - env(safe-area-inset-bottom, 0px) - var(--space-6, 24px));
  }
}

/* The sheet chrome is gone with the sheet: the kebab already turns into an ×,
   so a second close control and a title were height the list needed more. */
.nav-menu-head { display: none; }
/* The group labels stay. They cost one line each and turn fifteen
   undifferentiated rows into four short lists. */
.nav-menu-group {
  margin: var(--space-3) var(--space-2) var(--space-1);
  font-size: 0.66rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3);
}
.nav-menu-group:first-of-type { margin-block-start: var(--space-1); }
@media (max-width: 860px) {
  /* The one thing the sheet got right: a touch row is 44px. */
  .nav-menu-item { min-block-size: 44px; }
  .nav-menu { --tabs-h: 60px; }
}
.nav-menu-item {
  display: flex; align-items: center; gap: var(--space-3);
  inline-size: 100%; min-block-size: 44px; padding-inline: var(--space-3);
  border: 0; border-radius: 8px; background: transparent;
  color: var(--ink-2); font-family: inherit; font-size: 13px; text-align: start;
  text-decoration: none; cursor: pointer;
}
.nav-menu-item:hover { background: var(--s3); color: var(--ink-1); }
.nav-menu-item i { inline-size: 18px; color: var(--ink-3); }
.nav-menu-item:hover i { color: var(--gold); }
.nav-menu-sep { block-size: 1px; background: var(--line); margin: var(--space-2) var(--space-1); }
.nav-menu-user { color: var(--ink-3); font-size: 12px; }
.nav-actions { position: relative; }
/* Wraps the kebab button and its menu so one ref can own both: a press
   inside toggles, a press anywhere else dismisses (see useDismissable). */
.nav-more-wrap { position: relative; display: flex; }

/* The measured record: one hairline strip beside the verdict it disciplines.
   Quiet by design — it is a disclosure, not a boast. */
.measured-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-4);
  margin-block-start: var(--space-3);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: transparent;
  font-size: var(--text-2xs);
  color: var(--ink-3);
  text-decoration: none;
}
.measured-strip b { color: var(--ink-1); font-weight: 600; }
.measured-strip b.inconclusive { color: var(--ink-2); }
.measured-strip-name {
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
body.rtl .measured-strip-name { letter-spacing: 0; }
.measured-strip-ci { font-style: italic; }
.measured-strip:hover { border-color: var(--line-strong); }

/* Each alert is an order ticket with a shelf life; the chip says whether the
   setup is still worth acting on — the question every notification raised. */
.alert-row-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}
.alert-status {
  font-style: normal;
  font-size: 0.69rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 1px var(--space-2);
  border-radius: var(--radius-pill);
  border: 1px solid var(--line);
}
.alert-status.is-valid { color: var(--success); border-color: color-mix(in srgb, var(--success) 45%, transparent); }
.alert-status.is-expired { color: var(--ink-3); }
body.rtl .alert-status { letter-spacing: 0; }
.alerts-empty p { margin: 0; }
.alerts-empty a {
  display: inline-block;
  margin-block-start: var(--space-2);
  color: var(--gold-text);
  text-decoration: none;
}
.alerts-empty a:hover { text-decoration: underline; }

/* The bell panel is an anchored dropdown on desktop. On the phone that
   dropdown was 380px hung off the bell's right edge — half of it rendered
   beyond the screen. Below the breakpoint it is a fixed sheet under the nav. */
@media (max-width: 820px) {
  .alerts-panel {
    position: fixed;
    inset-inline: var(--space-3);
    inset-block-start: calc(56px + var(--space-2));
    inline-size: auto;
    max-block-size: min(70vh, 560px);
  }
}

@media (max-width: 600px) {
  .nav-primary span { display: none; }
  .nav-primary { min-inline-size: 40px; padding-inline: 0; justify-content: center; }
  .brand-word { display: none; }
}

/* ==========================================================================
   BOTTOM TAB BAR — polish
   Faults: mixed icon weights (a filled gauge next to line glyphs), the active
   item marked only by a faint top rule, no safe-area padding (it would sit
   under the iPhone home bar), and "Dashboard" crowding its neighbour.
   ========================================================================== */
.tab-bar {
  padding-block-end: env(safe-area-inset-bottom);
  block-size: calc(60px + env(safe-area-inset-bottom));
}
.tab-item {
  gap: 4px;
  font-size: 10px;                 /* even, so "Dashboard" and "News" balance */
  letter-spacing: 0.01em;
  font-weight: 500;
  color: var(--ink-3);
  padding-block: 8px;
  position: relative;
}
.tab-item i { font-size: 17px; line-height: 1; }
.tab-item.is-active { color: var(--gold-text); }
.tab-item.is-active i { color: var(--gold); }
/* Active marker: a soft gold wash behind the icon, not a hairline nobody sees. */
.tab-item.is-active::before {
  content: ""; position: absolute; inset-block-start: 6px;
  inline-size: 34px; block-size: 26px; border-radius: 8px;
  background: radial-gradient(closest-side, rgba(201,154,46,0.18), transparent);
  z-index: -1;
}

/* A whisper of gold on the bars' separating edge -- a hairline that catches the
   overhead lamp, so the chrome frames the content instead of merely bordering
   it. Applied top-nav bottom edge and tab-bar top edge. */
.top-nav { border-block-end: 1px solid transparent !important; box-shadow: 0 1px 0 rgba(201,154,46,0.10) !important; }
.tab-bar { border-block-start: 1px solid transparent !important; box-shadow: 0 -1px 0 rgba(201,154,46,0.10) !important; }

/* ==========================================================================
   DASHBOARD — Technical Analysis block
   It was a bordered panel nested inside the bordered aside, with an inline
   24px top margin that survived even when nothing rendered above it. The
   aside provides the frame; the inner block is flat.
   ========================================================================== */
.main-grid > aside .ta-block {
  border: 0;
  background: transparent;
  box-shadow: none;
  padding: 0;
  margin: 0;
}
.main-grid > aside .signal-card ~ .ta-block { margin-block-start: var(--space-4); }

/* ==========================================================================
   NUMERALS — one voice. (Owner: "the numbers are not comfortable, not clear.")
   The audit found three numeric faces fighting: the hero price in a
   high-contrast serif, the change line in a code mono with a dotted zero, and
   the facts in a third face. Decision: WORDS carry the luxury (Playfair on
   headlines and the brand); NUMBERS carry precision — every figure in the app
   is set in Inter Tight with tabular lining figures. Crisp, even, instantly
   comparable column to column.
   ========================================================================== */
:root, :root[data-theme="light"] {
  --font-numeric: "Inter Tight", "Inter", -apple-system, system-ui, sans-serif;
}

.price-value,
.price-change,
.price-facts dd,
.verdict-setup b,
.evidence-value,
.size-lots b, .size-detail b,
.live-r, .live-position-levels b,
.terminal-price b, .terminal-price span, .terminal-stats b,
.ohlc-readout, .tf-chip,
.measured-row b, .stat-value, .signal-value,
.alert-setup-levels b {
  font-family: var(--font-numeric) !important;
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
  letter-spacing: -0.01em;
}

/* The hero price: large, dense, engineered — weight and tracking make it
   luxurious, not serifs. Cents ride along at full size; a price is one number. */
.price-value {
  font-size: clamp(3rem, 9vw, 4.6rem) !important;
  font-weight: 650 !important;
  letter-spacing: -0.035em !important;
  line-height: 0.95;
}
.price-change { font-weight: 600; }
.price-facts dd, .verdict-setup b, .live-position-levels b,
.stat-value, .signal-value, .measured-row b {
  font-weight: 600;
}
.evidence-value { font-weight: 550; }

/* The dashboard news-scope chip was still the legacy violet -- the one cool
   colour left on a warm page. Gold-tinted like every other chip. */
.news-scope-symbol {
  background: rgba(201, 162, 39, 0.10) !important;
  color: var(--gold-text) !important;
  border: 1px solid rgba(201, 162, 39, 0.22) !important;
}
:root[data-theme="light"] .news-scope-symbol {
  background: rgba(201, 162, 39, 0.08) !important;
  color: #8A6A18 !important;
  border-color: rgba(201, 162, 39, 0.30) !important;
}

/* ---------------------------------------------------- critique round 2 */
/* The tab bar was glass, and page text ghosted through it on the phone —
   what should read as depth read as a compositing defect. The bottom bar
   is ground, not glass. */
.tab-bar {
  background: var(--s0) !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}

/* Disabled reference panels were dimmed to 55% — in the light theme that
   renders as skeleton loaders that never resolve. Locked must still be
   legible; the accordion chevrons and titles stay readable, only interaction
   quiets down. */
.panel-disabled { opacity: 0.78; filter: none; }

/* The legacy sheet force-LTRs whole value elements to pin stray numbers.
   Right instinct, wrong scope: a value that CONTAINS Arabic — the tally
   "18 شراء · 0 بيع" — corrupts under forced LTR, and the 18 lands beside
   بيع: the Arabic dashboard reported the opposite of the data. Figures are
   now isolated one by one in the markup (U+2066…U+2069), so the element
   itself may follow its own first strong character again. */
body.rtl .evidence-value,
body.rtl .alert-row span,
body.rtl .alert-row b {
  direction: inherit;
  unicode-bidi: plaintext;
}

/* The alert-tone picker: quiet segmented options, gold only on the choice.
   Tapping one previews it — a sound you cannot hear first is not a choice. */
.sound-options {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.sound-option {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--ink-2);
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}
.sound-option i { color: var(--ink-3); font-size: 11px; }
.sound-option:hover { border-color: var(--line-strong); color: var(--ink-1); }
.sound-option.active {
  border-color: rgba(201, 154, 58, 0.55);
  background: rgba(201, 154, 58, 0.10);
  color: var(--ink-1);
}
.sound-option.active i { color: var(--gold); }

/* ------------------------------------------------------- admin, rethemed */
/* The admin panel was still the legacy navy-and-teal app — a second product
   bolted onto the first (owner screenshot, 2026-08-08). Same ground, same
   ink, same gold as every other surface. */
.sidebar {
  background: var(--s1);
  border-color: var(--line);
}
.sidebar-link { color: var(--ink-2); }
/* The admin sidebar actions and the accordion header are real <button>s now
   (keyboard reachability); strip the native chrome so they keep the link look. */
button.sidebar-link, button.accordion-header {
  background: none;
  border: 0;
  font: inherit;
  color: inherit;
  width: 100%;
  text-align: inherit;
  cursor: pointer;
}
.sidebar-link.active, .sidebar-link:hover {
  background: rgba(201, 154, 58, 0.12);
  color: var(--ink-1);
}
.sidebar-link.active i, .sidebar-link:hover i { color: var(--gold); }
.chip {
  background: rgba(201, 154, 58, 0.12);
  color: var(--gold-text);
  border: 1px solid rgba(201, 154, 58, 0.25);
}

/* Phone: the sidebar is a header, not a first screen, and nothing —
   ever — scrolls sideways. */
@media (max-width: 820px) {
  /* Plain 1fr is minmax(auto,1fr): the users table's natural 720px width
     became the column's minimum, the page grew to fit, and the phone zoomed
     out to a shrunken desktop. minmax(0,1fr) lets the table scroll inside
     .table-wrap instead. */
  .admin-shell { grid-template-columns: minmax(0, 1fr); gap: var(--space-3); }
  .admin-shell > * { min-width: 0; }
  .admin-shell, .stat-card, .surface { min-width: 0; }
  .sidebar { padding: var(--space-3) var(--space-4); }
  .sidebar-nav {
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin-top: var(--space-3);
  }
  .sidebar-link { padding: var(--space-2) var(--space-3); font-size: 13px; }
  .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
}

/* ── No-Trade Detector (feature #35) ──────────────────────────────────────
   The honest "there is no clean setup" surface. Muted, not alarming: a stand-
   aside is information, not a failure. Uses tokens so it follows both themes. */
.no-trade {
  margin: var(--space-3) 0;
  padding: var(--space-3) var(--space-4);
  background: var(--s1);
  border: 1px solid var(--line);
  border-inline-start: 3px solid var(--gold);
  border-radius: var(--radius-2, 10px);
}
.no-trade-headline {
  display: block;
  font-size: 15px;
  color: var(--ink-1, var(--ink-2));
  margin-block-end: var(--space-2);
}
.no-trade-block { margin-block-start: var(--space-2); }
.no-trade-label {
  display: block;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3, var(--ink-2));
  margin-block-end: 2px;
}
.no-trade-block ul {
  margin: 0;
  padding-inline-start: var(--space-4);
  color: var(--ink-2);
  font-size: 13px;
  line-height: 1.5;
}
.no-trade-block li { margin-block-end: 2px; }

/* ── News-vs-Technical Conflict (feature #75) ─────────────────────────────
   Shown on a tradeable read when news flow opposes the technical direction.
   Amber, advisory — the trade is not refused, its conviction is lowered. */
.verdict-conflict {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  margin: var(--space-3) 0;
  padding: var(--space-3) var(--space-4);
  background: color-mix(in srgb, var(--gold) 10%, var(--s1));
  border: 1px solid color-mix(in srgb, var(--gold) 35%, var(--line));
  border-radius: var(--radius-2, 10px);
}
.verdict-conflict i { color: var(--gold); margin-block-start: 2px; }
.verdict-conflict b { display: block; font-size: 14px; margin-block-end: 2px; }
.verdict-conflict span { color: var(--ink-2); font-size: 13px; line-height: 1.5; }

/* ── Live price age (ticks every second) ──────────────────────────────────
   A pulsing dot + relative age so the price reads as live while staying honest
   about freshness. Green + pulse when fresh; muted amber when the feed lags. */
.price-age {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--ink-3, var(--ink-2));
  font-variant-numeric: tabular-nums;
}
.price-age-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--ink-3, #888);
  flex: none;
}
.price-age-live { color: var(--success, #10b981); }
.price-age-live .price-age-dot {
  background: var(--success, #10b981);
  animation: price-pulse 1.6s ease-in-out infinite;
}
.price-age-stale { color: var(--gold, #C99A3A); }
.price-age-stale .price-age-dot { background: var(--gold, #C99A3A); }
@keyframes price-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--success, #10b981) 55%, transparent); }
  50%      { box-shadow: 0 0 0 5px color-mix(in srgb, var(--success, #10b981) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .price-age-live .price-age-dot { animation: none; }
}

/* ------------------------------------------------------------- key levels */
/* Ranked confluence zones under the chart; every chip's tooltip shows the
   arithmetic of each contributing line. */
.key-levels {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-xs);
}
/* Five identical bells on one strip out-shouted the levels they belonged
   to. The bell shows when the level is engaged (hover/focus); the price
   does the talking at rest. */
@media (hover: hover) {
  .key-level .key-level-main i { opacity: 0; transition: opacity 120ms ease; }
  .key-level:hover .key-level-main i,
  .key-level:focus-visible .key-level-main i { opacity: 1; }
}
.key-levels-title {
  color: var(--ink-3);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.key-level { display: inline-flex; align-items: baseline; gap: 6px; }
.key-level b { font-variant-numeric: tabular-nums; }
.key-level.above b { color: var(--danger); }      /* resistance side */
.key-level.below b { color: var(--success, #2E9E6B); } /* support side */
.key-level small { color: var(--ink-3); }
.key-level-n {
  font-style: normal;
  color: var(--gold);
  border: 1px solid var(--gold);
  border-radius: 999px;
  padding: 0 5px;
}

/* -------------------------------------------------- journal analytics */
.journal-stat-row {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding: 6px 0;
  border-block-start: 1px solid var(--line);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}
.journal-stat-row:first-child { border-block-start: 0; }
.journal-stat-label { min-inline-size: 11em; color: var(--ink-1); font-weight: 600; }
.journal-stat-row .pos { color: var(--success, #2E9E6B); }
.journal-stat-row .neg { color: var(--danger); }
.journal-noise { color: var(--ink-3); font-style: normal; font-size: var(--text-xs); }
.journal-delta { margin: var(--space-2) 0 0; color: var(--ink-2); font-size: var(--text-sm); }
.journal-slice h4 { margin: var(--space-3) 0 4px; font-size: var(--text-xs);
                    letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); }

/* Key-level chips are buttons now (tap to watch); keep the chip look. */
button.key-level {
  background: none;
  border: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  padding: 2px 6px;
  border-radius: var(--radius-sm);
}
button.key-level:hover:not(:disabled) { background: var(--s2); }
button.key-level:disabled { opacity: 0.6; cursor: default; }
button.key-level.is-watched { box-shadow: inset 0 0 0 1px var(--gold); }
button.key-level i { color: var(--ink-3); font-size: 0.7rem; }
button.key-level.is-watched i { color: var(--gold); }
.level-alert-note { margin: 6px var(--space-3); font-size: var(--text-xs); color: var(--ink-2); }
.level-alert-note.is-error { color: var(--danger); }

/* Public legal + record links on the login page: judgeable before signup. */
.auth-legal { display: flex; flex-wrap: wrap; gap: 14px; justify-content: center;
              margin: 10px 0 0; }
.auth-legal a { color: var(--ink-3); font-size: var(--text-xs); text-decoration: underline; }
.auth-legal a:hover { color: var(--gold); }

/* ------------------------------------------------------------ password form */
.password-form { display: flex; flex-direction: column; gap: var(--space-3);
                 max-inline-size: 380px; }
.password-form label { display: flex; flex-direction: column; gap: 4px; }
.password-form small { color: var(--ink-3); font-size: var(--text-xs); }
.password-form input {
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--s2);
  color: var(--ink-1);
}
.password-note { margin: var(--space-2) 0 0; font-size: var(--text-sm); }
.password-note.is-error { color: var(--danger); }
.password-note.is-ok { color: var(--success, #2E9E6B); }
.password-forced { color: var(--gold); font-size: var(--text-sm); margin: 0 0 var(--space-3); }
.auth-forgot { text-align: center; margin: 10px 0 0; }
.linkish { background: none; border: 0; color: var(--ink-3); font: inherit;
           text-decoration: underline; cursor: pointer; font-size: var(--text-xs); }
.linkish:hover { color: var(--gold); }
.auth-forgot-note { color: var(--ink-2); font-size: var(--text-xs); margin: 8px 0 0;
                    text-align: center; line-height: 1.6; }

/* ==========================================================================
   CHART PAGE ON A PHONE — the canvas gets the screen back
   Measured before this block at 390x844: canvas 297px = 35% of the viewport,
   while the header wrapped to 125px and the key-level chips wrapped to FOUR
   lines (160px). The chart page was mostly chrome. Everything here buys
   vertical space back for the one element the page exists to show.
   ========================================================================== */
@media (max-width: 820px) {
  /* One row, never wrapping: the back arrow goes (the tab bar already has
     Dashboard) and the symbol/price/toggle sit on a single 56px line. */
  .terminal-bar {
    flex-wrap: nowrap !important;
    gap: var(--space-3);
    padding: 8px var(--space-3);
    min-block-size: 56px;
  }
  .terminal-back { display: none; }
  .terminal-symbol, .terminal-price { min-inline-size: 0; }
  .terminal-price { white-space: nowrap; }

  /* Measured at 390px: symbol 58 + price 142 + bell 44 + "The plan" 84 + gaps
     overran the 366px of usable bar, so the price CHANGE -- the one number in
     the header that moves -- was clipped behind the bell, and "The plan"
     wrapped to two lines inside a 44px row. The label goes; the icon carries
     it, which is what the rail's own header already says on open. */
  .terminal-rail-toggle span { display: none; }
  .terminal-change-abs { display: none; }
  .terminal-rail-toggle { flex: 0 0 auto; min-inline-size: 44px; justify-content: center; }
  .terminal-price { flex: 1 1 auto; overflow: hidden; }

  /* The level chips scroll sideways instead of stacking four rows deep. */
  .key-levels {
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    padding: 6px var(--space-3);
    gap: var(--space-2);
    min-block-size: 0;
  }
  .key-levels::-webkit-scrollbar { display: none; }
  .key-levels { scrollbar-width: none; }
  .key-levels-title { display: none; }
  button.key-level { flex: none; scroll-snap-align: start; }

  /* Only the STUDIES row still scrolls: with the timeframes collapsed to
     a dropdown, the controls hold just the type switch -- a scroll rail
     around it showed a scrollbar under nothing. */
  .chart-header { padding-block: 4px; }
  /* nowrap without a scroll pushed "Chart settings" to x=406 on a 390px
     screen -- a control that existed and could never be tapped. */
  .chart-controls { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  .chart-tools {
    padding-block: 4px;
    overflow-x: auto;
    flex-wrap: nowrap;
    scrollbar-width: none;   /* it scrolls, it does not LOOK like it scrolls */
  }

  /* Measured at 390x844: 262px of chrome stacked above the first candle --
     a heading naming the page it is on, a controls row, a studies row, the
     spine, and the OHLC legend, before a single price was drawn. On the
     terminal the studies join the controls row and the legend floats over the
     chart instead of taking a row of its own. */
  .terminal .chart-tools {
    padding-block: 0;
    margin-block-start: -8px;
  }
  .terminal .tool-chip { padding-block: 4px; font-size: 0.72rem; }
  .terminal .spine { padding-block: 6px; }
  .terminal .spine-detail { display: none; }
  .terminal .ohlc-readout {
    position: absolute; inset-block-start: 6px; inset-inline-start: 8px;
    z-index: 3; pointer-events: none;
    padding: 3px 7px; border-radius: 8px;
    background: color-mix(in srgb, var(--s1) 62%, transparent);
    font-size: 0.69rem;
    max-inline-size: 75%;
  }
  .terminal .chart-canvas { position: relative; }
  .chart-tools::-webkit-scrollbar, .chart-controls::-webkit-scrollbar { display: none; }

  /* What is left over is the chart -- edge to edge. Measured at 390px the
     canvas was 278px inside a card with 24px of margin and a border: the page
     whose entire job is the chart was giving 29% of its width to chrome. */
  /* The canvas takes what is LEFT and yields to its siblings: a hard 52vh
     floor forced the study panes past the page bottom on short screens.
     180px keeps candles readable; everything below stays on the page. */
  .chart-canvas { block-size: auto; flex: 1 1 auto; min-block-size: 180px; }
  .terminal-body { padding-inline: 0; }
  .terminal-chart { padding-inline: 0; }
  .terminal-chart > .surface {
    border-inline: 0;
    border-radius: 0;
    margin-inline: 0;
    padding-inline: 0;
  }
  /* The controls keep their inset; only the canvas goes edge to edge. */
  .chart-header, .chart-tools, .spine { padding-inline: var(--space-3); }

  /* On the chart page the assistant must not sit on top of the key-level bar,
     which is the one row a trader taps while watching price. Physical LEFT in
     both directions: the price axis lives on the chart's right edge whatever
     the UI language, and the resting pill was parked exactly on it (and on
     the spine's verdict text below). */
  .terminal .chat-pill {
    inset-inline: unset;
    left: 12px;
    right: auto;
    bottom: calc(var(--tabs-h, 60px) + env(safe-area-inset-bottom, 0px) + 64px);
  }
  /* At rest over candles it whispers; it only asserts itself when engaged.
     Anywhere on a phone-sized chart page is on the canvas -- opacity is the
     honest compromise between reachable and not-in-the-way. */
  .terminal .chat-pill.is-mini { opacity: 0.55; }
  .terminal .chat-pill.is-mini:hover,
  .terminal .chat-pill.is-mini:focus-visible,
  .terminal .chat-pill:not(.is-mini) { opacity: 1; }
}

/* ------------------------------------------------------- the verdict spine */
/* The chart's caption: one row, always present, tap for the reasoning. It is
   the chart's most important 44px -- the engine is silent ~97% of the time,
   and that silence has to be a stated state, not an empty screen. */
.spine {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  inline-size: 100%;
  padding: 10px var(--space-3);
  background: none;
  border: 0;
  border-block-end: 1px solid var(--line);
  border-inline-start: 3px solid var(--line);
  color: inherit;
  font: inherit;
  text-align: start;
  cursor: pointer;
}
.spine:hover { background: var(--s2); }
.spine-state { font-weight: 700; font-size: var(--text-sm); white-space: nowrap; }
.spine-detail {
  color: var(--ink-2);
  font-size: var(--text-xs);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-inline-size: 0;
}
.spine-stamp { margin-inline-start: auto; color: var(--ink-3); font-size: 0.7rem;
               white-space: nowrap; font-variant-numeric: tabular-nums; }
.spine-why { color: var(--ink-3); font-size: 0.8rem; }
/* Colour states the ENGINE's stance, never optimism: green only when a setup
   genuinely stands, amber while forming, blue when stood aside, grey silent. */
.spine-setup { border-inline-start-color: var(--gold); }
.spine-setup.spine-dir-buy .spine-state { color: var(--success, #2E9E6B); }
.spine-setup.spine-dir-sell .spine-state { color: var(--danger); }
.spine-forming { border-inline-start-color: var(--gold); }
.spine-forming .spine-state { color: var(--gold); }
.spine-stood_aside { border-inline-start-color: var(--danger); }
.spine-stood_aside .spine-state { color: var(--ink-1); }
.spine-no_setup .spine-state, .spine-unknown .spine-state { color: var(--ink-3); }
@media (max-width: 820px) {
  .spine { position: sticky; inset-block-start: 0; z-index: 5;
           background: var(--s1); padding: 8px var(--space-3); }
  .spine-stamp { display: none; }
}

/* ------------------------------------------------------------- "Why?" sheet */
/* Three layers: the claim, the evidence, the audit. A bottom sheet on the
   phone, a centred panel on desktop -- reachable by thumb either way. */
.why-scrim {
  /* Above the chat disc (201) and the tab bar: a sheet the reader opened
     IS the page until they close it -- nothing floats over its content. */
  position: fixed; inset: 0; z-index: 260;
  background: rgba(0,0,0,0.55);
  display: flex; align-items: flex-end; justify-content: center;
}
.why-sheet {
  inline-size: min(560px, 100%);
  max-block-size: 82vh;
  overflow-y: auto;
  background: var(--s1);
  border: 1px solid var(--line);
  border-radius: 14px 14px 0 0;
  padding: var(--space-4);
}
.why-head { display: flex; align-items: center; justify-content: space-between; }
.why-head h2 { margin: 0; font-size: var(--text-xs); letter-spacing: 0.12em;
               text-transform: uppercase; color: var(--ink-3); }
.why-claim { margin: var(--space-2) 0 0; font-size: var(--text-md, 1rem); color: var(--ink-1); }
.why-stamp { margin: 4px 0 var(--space-3); color: var(--ink-3); font-size: var(--text-xs);
             font-variant-numeric: tabular-nums; }
.why-rows { border-block-start: 1px solid var(--line); }
.why-row { display: flex; justify-content: space-between; gap: var(--space-3);
           padding: 8px 0; border-block-end: 1px solid var(--line);
           font-size: var(--text-sm); }
.why-row span { color: var(--ink-3); }
.why-row b { font-variant-numeric: tabular-nums; text-align: end; }
.why-help { margin-block-start: var(--space-3); }
.why-help h3 { font-size: var(--text-xs); letter-spacing: 0.08em; text-transform: uppercase;
               color: var(--ink-3); margin: 0 0 6px; }
.why-help ul { margin: 0; padding-inline-start: 1.1em; color: var(--ink-2);
               font-size: var(--text-sm); }
.why-audit { margin-block-start: var(--space-4); color: var(--ink-3); font-size: var(--text-xs); }
.why-audit summary { cursor: pointer; }
.why-audit p { margin: 8px 0; }
.why-audit a { color: var(--gold); }
@media (min-width: 821px) {
  .why-scrim { align-items: center; }
  .why-sheet { border-radius: 14px; }
}
.ohlc-range { color: var(--ink-2); }
.ohlc-when { color: var(--ink-3); font-size: 0.7rem; }
.ohlc-study { color: var(--ink-2); }
.ohlc-study small { color: var(--ink-3); margin-inline-end: 2px; }
@media (max-width: 480px) { .ohlc-when { display: none; } }

/* A service the operator switched off. Says which one, and why it is not the
   user's fault -- an empty page would read as a broken app. */
.service-off {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: 12px; padding: 48px 24px; max-width: 46ch; margin: 0 auto;
}
.service-off i { font-size: 2rem; color: var(--ink-3, #8A857B); }
.service-off h2 { margin: 0; font-size: 1.15rem; }
.service-off p { margin: 0; color: var(--ink-2, #C9C2B4); line-height: 1.6; }
.service-off .btn { margin-top: 8px; }

/* The discipline delta on the home screen. Deliberately a quiet strip, not an
   alarm: it is a measured fact about the user's own record, and it must not
   read as a scolding they learn to swipe past. */
.discipline-line {
  display: flex; align-items: baseline; gap: 12px; margin-top: 12px;
  padding: 12px 14px; border-radius: 12px; text-decoration: none;
  background: var(--surface-2, rgba(255,255,255,0.03));
  border: 1px solid var(--line, rgba(233,224,200,0.10));
  color: var(--text-2, #C9C2B4);
}
.discipline-delta { font-size: 1.15rem; font-weight: 650; font-variant-numeric: tabular-nums;
                    color: var(--text-1, #F3ECDE); flex: 0 0 auto; }
.discipline-line.is-costly .discipline-delta { color: var(--pos, #2E9E6B); }
.discipline-copy { font-size: 0.85rem; line-height: 1.5; }
.discipline-n { display: block; margin-top: 2px; font-size: 0.75rem;
                color: var(--text-3, #8A857B); }
[dir="rtl"] .discipline-line { text-align: right; }

/* --- the assistant ------------------------------------------------------- */

/* The launcher sits above the tab bar, clear of the thumb's home row so it is
   reachable without covering the row it sits above. */
.chat-pill {
  position: fixed; inset-inline: auto 16px;
  bottom: calc(var(--tabs-h, 62px) + env(safe-area-inset-bottom, 0px) + 16px);
  z-index: 201; display: inline-flex; align-items: center; gap: 8px;
  padding: 12px 18px; min-height: 48px; border-radius: 999px; border: 0;
  background: var(--gold); color: var(--gold-ink, #14110B);
  font: inherit; font-weight: 600; font-size: 0.9rem;
  box-shadow: 0 8px 24px rgba(0,0,0,0.35); cursor: pointer;
}
.chat-pill:active { transform: translateY(1px); }

/* While the sheet is up the tab bar is not a destination, and leaving it there
   put the Journal tab on top of the send button -- a stacking context the
   sheet's z-index cannot reach past. */
body.chat-open { overflow: hidden; }
body.chat-open .tab-bar,
body.chat-open .chat-pill { display: none; }

.chat-scrim {
  position: fixed; inset: 0; z-index: 300; display: flex; align-items: flex-end;
  background: rgba(0,0,0,0.5);
}
.chat-sheet {
  display: flex; flex-direction: column; width: 100%; max-height: 82vh;
  /* Deliberately not full height: the card being discussed stays visible
     above, which is what keeps this an assistant about the screen rather than
     a chatbot in its own room. */
  min-height: 56vh;
  background: var(--s1);
  border-radius: 20px 20px 0 0; border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.chat-head {
  position: relative; display: flex; align-items: center; gap: 10px;
  padding: 16px 16px 10px;
}
.chat-head h2 { margin: 0; font-size: 1rem; }
.chat-grip {
  position: absolute; top: 7px; inset-inline: 0; margin: auto;
  width: 38px; height: 4px; border-radius: 2px;
  background: var(--line-strong);
}
.chat-close {
  margin-inline-start: auto; min-width: 40px; min-height: 40px;
  background: none; border: 0; color: var(--ink-3); font-size: 1.05rem;
  cursor: pointer;
}

.chat-body { flex: 1; overflow-y: auto; padding: 4px 16px 12px;
             display: flex; flex-direction: column; gap: 12px; }
.chat-intro p { margin: 0 0 14px; color: var(--ink-2);
                font-size: 0.9rem; line-height: 1.6; }
.chat-suggestions { display: flex; flex-wrap: wrap; gap: 8px; }
.chat-suggestion {
  padding: 10px 14px; min-height: 44px; border-radius: 999px;
  background: var(--s2);
  border: 1px solid var(--line);
  color: var(--ink-1); font: inherit; font-size: 0.85rem; cursor: pointer;
}

.chat-you {
  align-self: flex-end; max-width: 85%; margin: 0;
  padding: 10px 14px; border-radius: 16px 16px 4px 16px;
  background: var(--s3); border: 1px solid var(--line-strong);
  color: var(--ink-1); font-size: 0.9rem; line-height: 1.5;
}
[dir="rtl"] .chat-you { border-radius: 16px 16px 16px 4px; }

.chat-answer {
  align-self: flex-start; max-width: 95%; margin: 0;
  padding: 12px 14px; border-radius: 16px 16px 16px 4px;
  background: var(--s2);
  border: 1px solid var(--line);
}
[dir="rtl"] .chat-answer { border-radius: 16px 16px 4px 16px; }
/* A refusal is not an error. It is the product working, so it does not wear
   error colour -- only a quieter left edge. */
.chat-answer.is-refusal { border-inline-start: 3px solid var(--ink-3); }
.chat-answer.is-error { color: var(--down); }
.chat-answer.is-thinking { color: var(--ink-3); font-size: 0.85rem; }

.chat-claim { margin: 0 0 10px; font-size: 0.9rem; line-height: 1.6;
              color: var(--ink-1); }
.chat-claim:last-of-type { margin-bottom: 4px; }
.chat-cites { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.chat-cite {
  padding: 3px 8px; border-radius: 6px; font-size: 0.7rem; letter-spacing: 0.02em;
  background: var(--s3);
  color: var(--ink-3); font-variant-numeric: tabular-nums;
}
.chat-foot { margin: 6px 0 0; font-size: 0.7rem; color: var(--ink-3); }

.chat-compose {
  display: flex; gap: 8px; padding: 10px 16px 14px;
  border-top: 1px solid var(--line);
}
.chat-compose input {
  flex: 1; min-height: 46px; padding: 10px 14px; border-radius: 999px;
  background: var(--s2);
  border: 1px solid var(--line);
  color: var(--ink-1); font: inherit; font-size: 0.9rem;
}
.chat-compose button {
  min-width: 46px; min-height: 46px; border-radius: 50%; border: 0;
  background: var(--gold); color: var(--gold-ink, #14110B); font-size: 1rem; cursor: pointer;
}
.chat-compose button:disabled { opacity: 0.45; }

/* "Change password" wrapped to two lines inside a 44px row at 390px. */
.settings-body .setting-row .btn { white-space: nowrap; flex: 0 0 auto; }

/* --- drawing tools ------------------------------------------------------- */
/* A vertical rail on the chart's leading edge: it never covers the price axis
   (which lives on the trailing edge) and it stays under the thumb. */
.draw-bar {
  position: absolute; z-index: 4;
  inset-block-end: 8px; inset-inline-start: 6px;
  display: flex; flex-direction: column-reverse; align-items: center; gap: 4px;
  padding: 3px; border-radius: 12px;
  background: none; border: 1px solid transparent;
}
/* Only the open rail earns a surface; closed, it is one button over candles. */
.draw-bar.is-open {
  background: color-mix(in srgb, var(--s1) 90%, transparent);
  border-color: var(--line);
}
.draw-toggle { color: var(--ink-2); background: color-mix(in srgb, var(--s1) 90%, transparent);
               border: 1px solid var(--line); }
.draw-bar.is-open .draw-toggle { background: none; border-color: transparent; }
.draw-tool {
  flex: none;
  min-inline-size: 40px;
  inline-size: 40px; block-size: 40px;
  display: grid; place-items: center;
  border: 0; border-radius: 9px; cursor: pointer;
  background: none; color: var(--ink-3); font-size: 0.85rem;
}
.draw-tool:hover { color: var(--ink-1); background: var(--s2); }
.draw-tool.is-armed { background: var(--gold); color: var(--gold-ink); }
.draw-tool.is-danger { color: var(--down); }
.draw-count {
  text-align: center; font-size: 0.69rem; color: var(--ink-3);
  font-variant-numeric: tabular-nums; padding-block-end: 2px;
}
.draw-hint {
  position: absolute; z-index: 4; inset-block-start: 8px;
  inset-inline: 0; margin: 0 auto; inline-size: fit-content;
  padding: 6px 12px; border-radius: 999px;
  background: var(--gold); color: var(--gold-ink);
  font-size: 0.75rem; font-weight: 600;
}
.discipline-money { display: block; margin-block: 4px 0; color: var(--ink-1);
                    font-weight: 600; font-size: 0.86rem; }
.alerts-detail { display: block; margin-block-start: 4px; color: var(--ink-3);
                 font-size: 0.72rem; font-family: ui-monospace, monospace; }
/* "On" somewhere else is not on here. Amber, because it is a warning about a
   thing the user believes is working. */
.alerts-stale { display: block; margin-block-start: 6px; color: var(--flag);
                font-size: 0.82rem; line-height: 1.5; }
/* The pass button is quiet on purpose: it must be easy to reach and must not
   compete with taking the trade, because the product has no opinion on which
   of the two is right. */
.btn-quiet { background: none; border: 1px solid var(--line);
             color: var(--ink-2); font-weight: 500; }
.btn-quiet:hover:not(:disabled) { border-color: var(--line-strong); color: var(--ink-1); }
.verdict-pass { inline-size: 100%; margin-block-start: 8px; min-block-size: 44px;
                display: inline-flex; align-items: center; justify-content: center; gap: 8px; }
.verdict-pass.is-answered { color: var(--up); border-color: var(--up); }

/* --- the macro strip ----------------------------------------------------- */
.macro-strip { margin-block-start: 16px; }
.macro-next {
  display: flex; align-items: center; gap: 14px; text-decoration: none;
  padding: 12px 14px; border-radius: 12px; margin-block-end: 12px;
  background: var(--s2); border: 1px solid var(--line); color: var(--ink-1);
}
/* Inside an hour it earns attention: this is the window where a technical
   stop stops being a stop. */
.macro-next.is-soon { border-color: var(--flag); background: color-mix(in srgb, var(--flag) 10%, var(--s2)); }
.macro-next-when { font-size: 1.05rem; font-weight: 700; font-variant-numeric: tabular-nums;
                   min-inline-size: 78px; white-space: nowrap; }
.macro-next-what { display: flex; flex-direction: column; gap: 2px; min-inline-size: 0; }
.macro-next-what b { font-size: 0.9rem; }
.macro-next-what small { color: var(--ink-3); font-size: 0.72rem; line-height: 1.4; }

.macro-tiles { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
@media (min-width: 620px) { .macro-tiles { grid-template-columns: repeat(4, 1fr); } }
.macro-tile {
  display: flex; flex-direction: column; gap: 2px;
  padding: 10px 12px; border-radius: 10px;
  background: var(--s2); border: 1px solid var(--line);
}
.macro-tile small { color: var(--ink-3); font-size: 0.7rem; letter-spacing: 0.03em; }
.macro-tile b { font-size: 1.05rem; font-variant-numeric: tabular-nums; }
.macro-trend { font-size: 0.72rem; font-variant-numeric: tabular-nums; }
.macro-trend.up { color: var(--down); }     /* rising yields are a gold headwind */
.macro-trend.down { color: var(--up); }
.macro-trend.flat { color: var(--ink-3); }
/* The date is not decoration: these series publish with a lag. */
.macro-asof { font-size: 0.64rem; color: var(--ink-3); font-variant-numeric: tabular-nums; }

.macro-cot { margin-block-start: 12px; display: flex; flex-direction: column; gap: 4px; }
.macro-cot span { font-size: 0.85rem; line-height: 1.5; }
.macro-cot small { color: var(--ink-3); font-size: 0.72rem; line-height: 1.5; }

/* --- the calendar screen ------------------------------------------------- */
.calendar-body { padding: 0 var(--space-3) calc(var(--tabs-h) + 32px); }
.calendar-intro { color: var(--ink-2); font-size: 0.85rem; line-height: 1.6;
                  margin-block: 0 18px; }
.calendar-empty { color: var(--ink-3); font-size: 0.88rem; line-height: 1.6; }
.calendar-day { margin-block-end: 20px; }
.calendar-day h2 {
  margin: 0 0 8px; font-size: 0.72rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--ink-3);
}
.calendar-row {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 10px 12px; border-radius: 10px; margin-block-end: 6px;
  background: var(--s1); border: 1px solid var(--line);
  border-inline-start: 3px solid var(--line);
}
/* Only the releases the engine actually stands aside for get an edge. */
.calendar-row.rel-high { border-inline-start-color: var(--flag); }
.calendar-row.rel-low { opacity: 0.62; }
.calendar-time { font-variant-numeric: tabular-nums; font-weight: 600;
                 font-size: 0.86rem; min-inline-size: 52px; }
.calendar-what { display: flex; flex-direction: column; gap: 2px; min-inline-size: 0; flex: 1; }
.calendar-what b { font-size: 0.88rem; font-weight: 600; }
.calendar-what small { color: var(--ink-3); font-size: 0.72rem; }
.calendar-flag { color: var(--flag); font-size: 0.78rem; }
/* Impact said in words: the tint alone was invisible in daylight. */
.cal-impact {
  align-self: center; font-size: 0.69rem; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase;
  padding: 2px 8px; border-radius: 999px; white-space: nowrap;
  border: 1px solid var(--line); color: var(--ink-3);
}
.cal-impact.high { color: var(--flag); border-color: var(--flag); }
.cal-impact.medium { color: var(--ink-2); }
/* The engine's next freeze, pinned above the week. */
.calendar-next-red {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 14px; margin-block-end: 16px;
  border-radius: 10px; border: 1px solid var(--flag);
  background: color-mix(in srgb, var(--flag) 8%, transparent);
  font-size: 0.84rem; color: var(--ink-2);
}
.calendar-next-red i { color: var(--flag); }
.calendar-next-red b { color: var(--ink-1); }
.calendar-next-red-clock {
  margin-inline-start: auto; color: var(--flag) !important;
  font-variant-numeric: tabular-nums;
}

/* --- alert governance ---------------------------------------------------- */
.settings-card { margin-block-start: 16px; padding-block-start: 14px;
                 border-block-start: 1px solid var(--line); }
.settings-card > strong { display: block; margin-block-end: 10px; font-size: 0.92rem; }
.alert-types { list-style: none; margin: 0 0 14px; padding: 0;
               display: flex; flex-direction: column; gap: 10px; }
.alert-types label { display: flex; align-items: flex-start; gap: 10px;
                     cursor: pointer; min-block-size: 40px; }
.alert-types input { inline-size: 20px; block-size: 20px; margin-block-start: 2px;
                     accent-color: var(--gold); flex: 0 0 auto; }
.alert-types span { display: flex; flex-direction: column; gap: 2px; }
.alert-types b { font-size: 0.86rem; font-weight: 600; }
.alert-types small { color: var(--ink-3); font-size: 0.74rem; line-height: 1.4; }

.alert-quiet, .alert-cap { margin-block-end: 14px; }
.alert-quiet-toggle { display: flex; align-items: center; gap: 10px;
                      min-block-size: 40px; cursor: pointer; font-size: 0.86rem; }
.alert-quiet-toggle input { inline-size: 20px; block-size: 20px; accent-color: var(--gold); }
.alert-quiet-range { display: flex; align-items: center; gap: 8px; margin-block: 8px; }
.alert-quiet-range select, .alert-cap input {
  padding: 8px 10px; border-radius: 8px; min-block-size: 40px;
  background: var(--s2); color: var(--ink-1); border: 1px solid var(--line);
  font: inherit; font-variant-numeric: tabular-nums;
}
.alert-cap label { display: flex; align-items: center; justify-content: space-between;
                   gap: 12px; font-size: 0.86rem; }
.alert-cap input { inline-size: 88px; text-align: center; }
.alert-quiet small, .alert-cap small { display: block; margin-block-start: 6px;
                                       color: var(--ink-3); font-size: 0.74rem; line-height: 1.5; }

/* --- the blind-spot inventory -------------------------------------------- */
.limits-body { padding: 0 var(--space-3) calc(var(--tabs-h) + 32px); }
.limits-intro { color: var(--ink-2); font-size: 0.88rem; line-height: 1.65;
                margin-block: 0 22px; max-inline-size: 62ch; }
.limit { margin-block-end: 20px; padding: 16px; border-radius: 12px;
         background: var(--s1); border: 1px solid var(--line); }
.limit h2 { margin: 0 0 8px; font-size: 0.98rem; }
.limit p { margin: 0 0 8px; font-size: 0.85rem; line-height: 1.6; color: var(--ink-2); }
.limit-why { color: var(--ink-3) !important; }
.limit-instead { color: var(--ink-1) !important; }
.limit-tag { display: inline-block; padding: 3px 9px; border-radius: 999px;
             font-size: 0.7rem; letter-spacing: 0.02em; }
.limit-tag.is-fixable { background: color-mix(in srgb, var(--flag) 18%, transparent);
                        color: var(--flag); }
.limit-tag.is-permanent { background: var(--s2); color: var(--ink-3); }

/* --- the session briefing ------------------------------------------------ */
.briefing {
  margin: 12px var(--space-3) 0;
  border-radius: 12px; overflow: hidden;
  background: var(--s1); border: 1px solid var(--line);
}
.briefing.has-warning { border-color: color-mix(in srgb, var(--flag) 45%, var(--line)); }
.briefing-head {
  inline-size: 100%; display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 12px 14px; min-block-size: 48px;
  background: none; border: 0; color: var(--ink-1); font: inherit;
  text-align: start; cursor: pointer;
}
.briefing-headline { font-size: 0.95rem; font-weight: 650; }
.briefing-head i { color: var(--ink-3); font-size: 0.75rem; }
.briefing-warning {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 10px 14px; background: color-mix(in srgb, var(--flag) 12%, transparent);
  border-block-start: 1px solid var(--line);
}
.briefing-warning i { color: var(--flag); margin-block-start: 2px; }
.briefing-warning span { display: flex; flex-direction: column; gap: 2px; }
.briefing-warning b { font-size: 0.85rem; }
.briefing-warning small { color: var(--ink-3); font-size: 0.74rem; }
.briefing-lines { list-style: none; margin: 0; padding: 4px 14px 12px;
                  display: flex; flex-direction: column; gap: 10px; }
.briefing-lines li { display: flex; flex-direction: column; gap: 1px;
                     font-size: 0.84rem; line-height: 1.5; }
.briefing-lines small { color: var(--ink-3); font-size: 0.74rem; line-height: 1.45; }
.briefing-lines em { color: var(--ink-3); font-size: 0.7rem; font-style: normal;
                     font-variant-numeric: tabular-nums; }
/* The style description, on screen rather than in a tooltip nobody on a phone
   can open. Small and quiet: it explains the choice without shouting it. */
.style-desc { display: block; margin-block-start: 6px; color: var(--ink-3);
              font-size: 0.72rem; line-height: 1.45; }

/* --- facts about a drawn line -------------------------------------------- */
.drawing-facts {
  position: absolute; z-index: 6; inset-inline: 10px; inset-block-end: 10px;
  padding: 14px 16px; border-radius: 12px;
  background: color-mix(in srgb, var(--s1) 96%, transparent);
  border: 1px solid var(--line-strong);
  box-shadow: 0 10px 30px rgba(0,0,0,0.35);
}
.drawing-facts-close {
  position: absolute; inset-block-start: 6px; inset-inline-end: 6px;
  inline-size: 36px; block-size: 36px; border: 0; background: none;
  color: var(--ink-3); font-size: 0.9rem; cursor: pointer;
}
.drawing-facts-list { display: grid; grid-template-columns: 1fr auto; gap: 6px 14px;
                      margin: 0; font-size: 0.82rem; }
.drawing-facts-list > div { display: contents; }
.drawing-facts-list dt { color: var(--ink-3); }
.drawing-facts-list dd { margin: 0; text-align: end; font-weight: 600;
                         font-variant-numeric: tabular-nums; }

/* Zoom and reset. Trailing edge, above the price axis labels, so they never
   sit over the candles the way a centred control would. */
.chart-nav {
  position: absolute; z-index: 4;
  inset-block-end: 34px; inset-inline-end: 8px;
  display: flex; flex-direction: column; gap: 4px;
}
.chart-nav button {
  inline-size: 36px; block-size: 36px; display: grid; place-items: center;
  border-radius: 9px; border: 1px solid var(--line); cursor: pointer;
  background: color-mix(in srgb, var(--s1) 88%, transparent);
  color: var(--ink-3); font-size: 0.78rem;
}
.chart-nav button:hover { color: var(--ink-1); }

/* --- the funded-account floor -------------------------------------------- */
.floor-strip { margin: 12px var(--space-3) 0; padding: 14px;
               border-radius: 12px; background: var(--s1); border: 1px solid var(--line); }
.floor-strip.is-breached { border-color: var(--down); }
.floor-head { display: flex; align-items: baseline; justify-content: space-between;
              gap: 10px; margin-block-end: 10px; }
.floor-head span { font-size: 0.8rem; color: var(--ink-3); letter-spacing: 0.04em;
                   text-transform: uppercase; }
.floor-head small { color: var(--ink-3); font-size: 0.7rem; font-variant-numeric: tabular-nums; }
.floor-bar { margin-block-end: 10px; }
.floor-bar-label { display: flex; justify-content: space-between; align-items: baseline;
                   font-size: 0.82rem; margin-block-end: 4px; }
.floor-bar-label b { font-variant-numeric: tabular-nums; font-size: 0.95rem; }
.floor-track { block-size: 6px; border-radius: 3px; background: var(--s3); overflow: hidden; }
/* Green while there is room, because this bar measures what is LEFT. */
.floor-fill { block-size: 100%; background: var(--up); transition: width 0.3s ease; }
.floor-strip.is-breached .floor-fill { background: var(--down); }
.floor-breached { margin: 6px 0 0; color: var(--down); font-size: 0.82rem; line-height: 1.5; }
.floor-source { margin: 8px 0 0; color: var(--ink-3); font-size: 0.7rem;
                line-height: 1.45; overflow-wrap: anywhere; }

/* --- the user's own alerts ----------------------------------------------- */
.alert-rows { list-style: none; margin: 8px 0 0; padding: 0;
              display: flex; flex-direction: column; gap: 6px; }
.alert-rows-head { display: block; margin-block-start: 14px; color: var(--ink-3);
                   font-size: 0.7rem; letter-spacing: 0.05em; text-transform: uppercase; }
.alert-rows li { display: flex; align-items: center; gap: 12px;
                 padding: 9px 11px; border-radius: 9px;
                 background: var(--s2); border: 1px solid var(--line); }
.alert-rows li.is-done { opacity: 0.62; }
.alert-row-price { font-weight: 650; font-variant-numeric: tabular-nums;
                   font-size: 0.9rem; min-inline-size: 68px; }
.alert-row-what { display: flex; flex-direction: column; gap: 1px; flex: 1; min-inline-size: 0; }
.alert-row-what b { font-size: 0.8rem; font-weight: 500; }
.alert-row-what small { color: var(--ink-3); font-size: 0.7rem; }
.alert-rows button { inline-size: 34px; block-size: 34px; flex: 0 0 auto;
                     border-radius: 8px; border: 1px solid var(--line);
                     background: none; color: var(--ink-3); cursor: pointer; }

/* --- first run ------------------------------------------------------------ */
.firstrun-scrim { position: fixed; inset: 0; z-index: 400; overflow-y: auto;
                  background: var(--s0); display: flex; align-items: flex-start;
                  justify-content: center; padding: 24px 16px 40px; }
.firstrun { inline-size: 100%; max-inline-size: 460px; }
.firstrun h1 { margin: 8px 0 6px; font-size: 1.3rem; line-height: 1.3; }
.firstrun-intro { margin: 0 0 22px; color: var(--ink-2); font-size: 0.88rem; line-height: 1.6; }
.firstrun-field { display: block; margin-block-end: 16px; }
.firstrun-field > span { display: block; margin-block-end: 8px; font-size: 0.8rem;
                         color: var(--ink-3); letter-spacing: 0.04em; text-transform: uppercase; }
.firstrun-field input { inline-size: 100%; min-block-size: 46px; padding: 10px 12px;
                        border-radius: 10px; background: var(--s2); color: var(--ink-1);
                        border: 1px solid var(--line); font: inherit;
                        font-variant-numeric: tabular-nums; }
.firstrun-styles { display: flex; flex-direction: column; gap: 8px; }
.firstrun-style { display: flex; flex-direction: column; gap: 2px; text-align: start;
                  padding: 12px 14px; min-block-size: 56px; border-radius: 10px;
                  background: var(--s2); border: 1px solid var(--line);
                  color: var(--ink-1); font: inherit; cursor: pointer; }
.firstrun-style.is-active { border-color: var(--gold); background: color-mix(in srgb, var(--gold) 12%, var(--s2)); }
.firstrun-style small { color: var(--ink-3); font-size: 0.74rem; }
.firstrun-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.firstrun-note { margin: 4px 0 20px; color: var(--ink-3); font-size: 0.76rem; line-height: 1.55; }
.firstrun-actions { display: flex; flex-direction: column; gap: 8px; }
.firstrun-actions .btn { inline-size: 100%; min-block-size: 48px; }
/* A two-way choice that is not a switch: both options are named, because
   "off" is not a language. */
.seg-choice { display: inline-flex; border: 1px solid var(--line);
              border-radius: 10px; overflow: hidden; flex: 0 0 auto; }
.seg-choice button { padding: 9px 14px; min-block-size: 42px; border: 0;
                     background: var(--s2); color: var(--ink-2); font: inherit;
                     font-size: 0.85rem; cursor: pointer; }
.seg-choice button + button { border-inline-start: 1px solid var(--line); }
.seg-choice button.is-active { background: var(--gold); color: var(--gold-ink); font-weight: 600; }

/* --- the stand-aside receipt --------------------------------------------- */
.receipt { margin: 12px var(--space-3) 0; padding: 14px; border-radius: 12px;
           background: var(--s1); border: 1px solid var(--line); }
.receipt-head { display: flex; align-items: center; gap: 10px; margin-block-end: 10px;
                font-size: 0.9rem; font-weight: 600; }
.receipt-head i { color: var(--up); }
.receipt-rows { display: grid; grid-template-columns: 1fr auto; gap: 5px 14px;
                margin: 0; font-size: 0.84rem; }
.receipt-rows > div { display: contents; }
.receipt-rows dt { color: var(--ink-3); }
.receipt-rows dd { margin: 0; text-align: end; font-variant-numeric: tabular-nums; }
.receipt-note { margin: 10px 0 0; color: var(--ink-3); font-size: 0.75rem; line-height: 1.55; }

/* --- a number you can interrogate ---------------------------------------- */
/* The underline is the affordance: it marks the numbers whose derivation the
   system actually kept, and only those. */
.sourced { background: none; border: 0; padding: 0; font: inherit; color: inherit;
           cursor: pointer; text-decoration: underline dotted;
           text-underline-offset: 3px; text-decoration-color: var(--ink-3); }
.sourced:hover { text-decoration-color: var(--gold); }
.sourced-scrim { position: fixed; inset: 0; z-index: 320; display: flex;
                 align-items: flex-end; justify-content: center;
                 background: rgba(0,0,0,0.5);
                 /* The sheet must land ABOVE the tab bar, not under it: the
                    level sheet's action buttons were half-swallowed by the
                    tabs on the owner's phone. */
                 padding: 0 12px calc(var(--tabs-h, 62px) + env(safe-area-inset-bottom, 0px) + 12px); }
.sourced-sheet { inline-size: 100%; max-inline-size: 460px; padding: 18px;
                 border-radius: 16px 16px 12px 12px; background: var(--s1);
                 border: 1px solid var(--line-strong);
                 max-block-size: 72vh; overflow-y: auto; }
.sourced-head { display: flex; align-items: baseline; justify-content: space-between;
                gap: 12px; margin-block-end: 14px; }
.sourced-head span { color: var(--ink-3); font-size: 0.78rem; letter-spacing: 0.04em;
                     text-transform: uppercase; }
.sourced-head b { font-size: 1.15rem; font-variant-numeric: tabular-nums; }
.sourced-row { display: flex; justify-content: space-between; gap: 14px;
               padding-block: 6px; border-block-start: 1px solid var(--line); }
.sourced-row dt { color: var(--ink-3); font-size: 0.78rem; margin: 0; flex: 0 0 auto; }
.sourced-row dd { margin: 0; text-align: end; font-size: 0.82rem; font-weight: 500; }
.sourced-note { margin: 12px 0 14px; color: var(--ink-2); font-size: 0.8rem; line-height: 1.55; }
.sourced-sheet .btn { inline-size: 100%; min-block-size: 44px; }

/* --- the user's own pause ------------------------------------------------ */
/* Amber, not red: this is a reminder of a decision the user made, not an
   error and not a prohibition. */
.cooldown { margin: 12px var(--space-3) 0; padding: 12px 14px; border-radius: 12px;
            display: flex; gap: 12px; align-items: flex-start;
            background: color-mix(in srgb, var(--flag) 12%, var(--s1));
            border: 1px solid color-mix(in srgb, var(--flag) 40%, var(--line)); }
.cooldown i { color: var(--flag); margin-block-start: 2px; }
.cooldown div { display: flex; flex-direction: column; gap: 3px; }
.cooldown b { font-size: 0.88rem; }
.cooldown small { color: var(--ink-2); font-size: 0.76rem; line-height: 1.5; }
.cooldown-note { margin: 0 0 12px; color: var(--ink-3); font-size: 0.76rem; line-height: 1.5; }
.cooldown-field { display: flex; align-items: center; justify-content: space-between;
                  gap: 12px; margin-block-end: 10px; font-size: 0.84rem; }
.cooldown-field select { min-block-size: 42px; padding: 8px 10px; border-radius: 9px;
                         background: var(--s2); color: var(--ink-1);
                         border: 1px solid var(--line); font: inherit;
                         font-variant-numeric: tabular-nums; min-inline-size: 92px; }

/* --- our own levels, graded ---------------------------------------------- */
.grades { margin-block-end: 22px; padding: 16px; border-radius: 12px;
          background: var(--s1); border: 1px solid var(--line); }
.grades h2 { margin: 0 0 8px; font-size: 0.98rem; }
.grades-intro { margin: 0 0 14px; color: var(--ink-2); font-size: 0.84rem; line-height: 1.6; }
.grades-headline { display: flex; align-items: baseline; gap: 10px; margin-block-end: 14px; }
.grades-headline b { font-size: 1.9rem; font-variant-numeric: tabular-nums; }
.grades-headline span { color: var(--ink-3); font-size: 0.8rem; }
.grades-rows { list-style: none; margin: 0 0 14px; padding: 0;
               display: flex; flex-direction: column; gap: 6px; }
.grades-rows li { display: grid; grid-template-columns: 1fr auto 54px;
                  gap: 12px; align-items: baseline; font-size: 0.84rem; }
.grades-rows b { font-variant-numeric: tabular-nums; }
.grades-rows small { color: var(--ink-3); font-size: 0.7rem; text-align: end;
                     font-variant-numeric: tabular-nums; }
.grades-note { margin: 0 0 8px; color: var(--ink-2); font-size: 0.8rem; line-height: 1.55; }
.grades-foot { margin: 0; color: var(--ink-3); font-size: 0.7rem; }

/* --- how this class of verdict resolved before --------------------------- */
.vhistory { margin: 12px var(--space-3) 0; padding: 14px; border-radius: 12px;
            background: var(--s1); border: 1px solid var(--line); }
.vhistory h4 { margin: 0 0 4px; font-size: 0.72rem; letter-spacing: 0.08em;
               text-transform: uppercase; color: var(--ink-3); }
.vhistory-class { margin: 0 0 12px; font-size: 0.86rem; font-weight: 600; }
.vhistory-rows { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.vhistory-rows > div { display: flex; flex-direction: column; gap: 2px; }
.vhistory-rows dt { color: var(--ink-3); font-size: 0.7rem; margin: 0; }
.vhistory-rows dd { margin: 0; font-size: 0.95rem; font-weight: 650;
                    font-variant-numeric: tabular-nums; }
/* The honest answer for a young record, and the one it gives most often. */
.vhistory-thin { margin: 12px var(--space-3) 0; color: var(--ink-3);
                 font-size: 0.78rem; line-height: 1.55; }
.verdict-sizing-trim { display: block; margin-block-start: 3px; color: var(--flag);
                       font-size: 0.72rem; line-height: 1.45; }

/* --- filter power -------------------------------------------------------- */
.power-rows { list-style: none; margin: 0 0 14px; padding: 0;
              display: flex; flex-direction: column; gap: 8px; }
.power-rows li { display: grid; grid-template-columns: 1fr auto auto;
                 gap: 10px; align-items: center; }
.power-what { display: flex; flex-direction: column; gap: 1px; }
.power-what b { font-size: 0.84rem; font-weight: 600; }
.power-what small { color: var(--ink-3); font-size: 0.7rem; }
.power-band { font-size: 0.72rem; padding: 3px 8px; border-radius: 999px;
              background: var(--s2); color: var(--ink-2); white-space: nowrap; }
.power-band.is-working { color: var(--up); }
.power-band.is-weak { color: var(--flag); }
/* The two readings a vendor would never print get the loudest colour. */
.power-band.is-dead, .power-band.is-inverted { color: var(--down); }
.power-band.is-none { color: var(--ink-3); }
.power-delta { font-variant-numeric: tabular-nums; font-size: 0.84rem;
               font-weight: 600; min-inline-size: 56px; text-align: end; }
.power-gaps { margin-block-end: 12px; padding-block-start: 12px;
              border-block-start: 1px solid var(--line); }
.power-gaps h3 { margin: 0 0 6px; font-size: 0.72rem; letter-spacing: 0.08em;
                 text-transform: uppercase; color: var(--ink-3); }
.power-gaps p { margin: 0 0 6px; color: var(--ink-2); font-size: 0.78rem; line-height: 1.5; }

/* --- the pre-trade card --------------------------------------------------- */
.pretrade { margin: 12px var(--space-3) 0; padding: 14px; border-radius: 12px;
            background: var(--s1); border: 1px solid var(--line); }
.pretrade.has-blockers { border-color: color-mix(in srgb, var(--down) 45%, var(--line)); }
.pretrade-head { display: flex; align-items: baseline; justify-content: space-between;
                 gap: 12px; margin-block-end: 12px; }
.pretrade-head h3 { margin: 0; font-size: 0.92rem; }
.pretrade-head span { font-size: 0.75rem; color: var(--ink-3); }
.pretrade-rows { list-style: none; margin: 0; padding: 0;
                 display: flex; flex-direction: column; gap: 9px; }
.pretrade-rows li { display: grid; grid-template-columns: 1fr auto;
                    gap: 4px 12px; align-items: baseline;
                    padding-inline-start: 10px; border-inline-start: 2px solid var(--line); }
/* Only a blocker earns a colour. A card where everything is coloured is a card
   where nothing stands out. */
.pretrade-rows li.stance-blocks { border-inline-start-color: var(--down); }
.pretrade-rows li.stance-cautions { border-inline-start-color: var(--flag); }
.pretrade-label { font-size: 0.82rem; color: var(--ink-2); }
.pretrade-value { font-size: 0.88rem; font-weight: 650; font-variant-numeric: tabular-nums; }
.pretrade-note { grid-column: 1 / -1; color: var(--ink-3); font-size: 0.74rem;
                 line-height: 1.45; }
.pretrade-rows li.stance-blocks .pretrade-note { color: var(--down); }
.pretrade-foot { margin: 12px 0 0; color: var(--ink-3); font-size: 0.72rem; }
.floor-unpriced { margin: 8px 0 0; color: var(--flag); font-size: 0.74rem; line-height: 1.5; }

/* --- touch targets --------------------------------------------------------
   On a coarse pointer every interactive chart control meets the 44px platform
   minimum. The compact 32-36px sizes stay for mouse users, where precision
   makes them fine and the quieter weight was a deliberate choice; on the
   phone -- the device this product is used from -- a missed tap on "reset
   zoom" or the alert dismiss is a real interaction failure, not a nicety. */
@media (pointer: coarse) {
  .chart-type-option,
  .chart-expand,
  .chart-controls .dropdown-button {
    min-block-size: 44px;
  }
  .chart-nav button {
    inline-size: 44px;
    block-size: 44px;
  }
  .alert-setup-x {
    min-block-size: 44px;
    min-inline-size: 44px;
  }
}

/* --- the trader's questions ----------------------------------------------
   Secondary dashboard content folds behind the question it answers. The bar
   is slim and quiet; the child keeps its own card styling when opened. */
.fold { margin-block-start: 10px; }
.fold-head {
  inline-size: 100%; display: flex; align-items: center; gap: 10px;
  min-block-size: 48px; padding: 10px 14px;
  border: 1px solid var(--line); border-radius: var(--radius, 12px);
  background: color-mix(in srgb, var(--s1) 92%, transparent);
  color: var(--ink-2); font: inherit; font-size: 0.92rem; font-weight: 600;
  cursor: pointer; text-align: start;
}
.fold-head:hover { color: var(--ink-1); }
.fold-title { display: inline-flex; align-items: center; gap: 10px; flex: 1; min-inline-size: 0; }
.fold-title i { color: var(--gold-text, var(--gold)); font-size: 0.85em; }
.fold-chev { color: var(--ink-3); font-size: 0.7rem; }
.fold.is-open > .fold-head { border-start-end-radius: var(--radius, 12px); }
.fold-body { margin-block-start: 8px; }
.fold-body > * + * { margin-block-start: 10px; }

/* The aside is a COLUMN, not a card: each child (signal card, question
   fold) carries its own surface. The wrapper's panel chrome nested a card
   inside an empty card around the technicals fold. */
.main-grid > aside.panel {
  padding: 0; border: 0; background: transparent;
  box-shadow: none; backdrop-filter: none;
}

/* --- first-run tour ------------------------------------------------------ */
.tour-scrim {
  position: fixed; inset: 0; z-index: 400;
  background: color-mix(in srgb, var(--bg, #0d1117) 55%, transparent);
  backdrop-filter: blur(2px);
  display: flex; align-items: flex-end; justify-content: center;
  padding: 20px; padding-block-end: calc(var(--tabs-h, 60px) + 24px);
}
.tour-card {
  inline-size: min(100%, 26rem);
  background: var(--s1); border: 1px solid var(--line);
  border-radius: 16px; padding: 20px;
  box-shadow: 0 18px 48px rgba(0,0,0,0.45);
}
.tour-card h3 { margin: 0 0 8px; font-size: 1.05rem; }
.tour-card p { margin: 0 0 16px; color: var(--ink-2); line-height: 1.6; font-size: 0.92rem; }
.tour-dots { display: flex; gap: 6px; margin-block-end: 12px; }
.tour-dots span {
  inline-size: 7px; block-size: 7px; border-radius: 50%;
  background: var(--line);
}
.tour-dots span.is-on { background: var(--gold); }
.tour-actions { display: flex; justify-content: space-between; gap: 10px; }

/* Alert-from-chart: the bell inside the OHLC readout. 44px on touch. */
.ohlc-watch {
  border: 0; background: transparent; color: var(--gold-text, var(--gold));
  cursor: pointer; font-size: 0.85rem; padding: 4px 6px; min-block-size: 28px;
}
.ohlc-watch:disabled { opacity: 0.5; }
@media (pointer: coarse) {
  .ohlc-watch { min-block-size: 44px; min-inline-size: 44px; }
}

/* The accordion header's tally: a closed section still states its lean. */
.accordion-tally { display: inline-flex; gap: 8px; margin-inline-start: auto;
                   padding-inline-end: 10px; font-size: 0.72rem;
                   font-variant-numeric: tabular-nums; }
.accordion-tally em { font-style: normal; color: var(--ink-3); }
.accordion-tally em.pos { color: var(--up, #2E9E6B); }
.accordion-tally em.neg { color: var(--down, #B4635A); }

/* Journal: the week line, the discipline streak, and the outcome filters. */
.journal-week { margin: 0 0 10px; font-size: 0.85rem; color: var(--ink-2); }
.journal-streak { margin: 8px 0 0; font-size: 0.85rem; color: var(--gold-text, var(--gold)); }
.journal-streak i { margin-inline-end: 6px; }
.journal-filters { display: flex; gap: 8px; flex-wrap: wrap; margin: 0 0 12px; }
.journal-filter {
  border: 1px solid var(--line); background: transparent; color: var(--ink-3);
  border-radius: 999px; padding: 5px 14px; font: inherit; font-size: 0.78rem;
  cursor: pointer; min-block-size: 32px;
}
.journal-filter.is-on { background: var(--s2); color: var(--ink-1); border-color: var(--ink-3); }
@media (pointer: coarse) { .journal-filter { min-block-size: 40px; } }

/* The ask-pill's resting state: a 52px disc that covers nothing. Grown, it
   carries its label for three seconds and either opens or retreats. */
.chat-pill.is-mini {
  padding: 0; inline-size: 52px; block-size: 52px;
  justify-content: center; border-radius: 50%;
}
.chat-pill { transition: inline-size 160ms ease, padding 160ms ease, border-radius 160ms ease; }

/* The two aux switches beside the chart type: quiet icons, gold when on. */
.chart-aux-toggle {
  border: 1px solid transparent; background: transparent; color: var(--ink-3);
  border-radius: 9px; min-block-size: 36px; min-inline-size: 36px;
  font-size: 0.8rem; cursor: pointer;
}
.chart-aux-toggle:hover { background: var(--s2); color: var(--ink-1); }
.chart-aux-toggle.is-on { color: var(--gold-text, var(--gold)); border-color: var(--gold); }
@media (pointer: coarse) { .chart-aux-toggle { min-block-size: 44px; min-inline-size: 44px; } }

/* --- multi-timeframe alignment strip ------------------------------------- */
.mtf-strip { display: flex; gap: 6px; padding: 6px var(--space-3); flex-wrap: wrap; }
.mtf-chip {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--line); background: transparent; color: var(--ink-2);
  border-radius: 999px; padding: 4px 12px; font: inherit; font-size: 0.76rem;
  cursor: pointer; min-block-size: 32px; font-variant-numeric: tabular-nums;
}
.mtf-chip b { font-weight: 600; }
.mtf-chip b.pos { color: var(--up, #2E9E6B); }
.mtf-chip b.neg { color: var(--down, #B4635A); }
.mtf-chip.is-current { border-color: var(--gold); color: var(--ink-1); }
.mtf-chip.is-stale { opacity: 0.45; }
@media (pointer: coarse) { .mtf-chip { min-block-size: 44px; } }

/* In the chart's narrow rail the three-column evidence grid starved the
   value column ("6 / Buy / · 6 / Neutral" one word per line). Stack it:
   label and stance share the top line, the reading takes the full width. */
.terminal-rail .evidence-row { grid-template-columns: 1fr auto; }
.terminal-rail .evidence-row .evidence-stance { grid-row: 1; grid-column: 2; }
.terminal-rail .evidence-row .evidence-value { grid-column: 1 / -1; }

/* Study sub-panes: a shorter synced chart under the price, sharing its axis
   gutter so the two time scales do not shear. */
.study-pane {
  position: relative; block-size: 110px;
  border-block-start: 1px solid var(--line);
}
.study-pane-canvas { position: absolute; inset: 0; }
/* The pane says its own name; three anonymous squiggle strips did not. */
.study-pane-name {
  position: absolute; inset-block-start: 4px; inset-inline-start: 8px;
  z-index: 3; pointer-events: none;
  font-size: 0.69rem; font-weight: 700; letter-spacing: 0.1em;
  color: var(--ink-3);
}

/* When a study pane is open the price canvas SHRINKS to make room inside
   the card's fixed budget -- the card clips overflow, so without this the
   panes rendered below the fold and simply never appeared. The chart's own
   ResizeObserver follows the canvas. */
.chart-card .chart-canvas { flex: 1 1 auto; min-block-size: 240px; }
.chart-card .study-pane { flex: 0 0 110px; }

/* The terminal locks the page height, and the canvas carried a hard 520px --
   so an opened study pane landed below the fold of a page that cannot
   scroll. Inside the terminal the canvas yields to flex: it shrinks when a
   pane opens, and the pane occupies real, visible room. */
.terminal-chart .chart-card { block-size: 100%; }
.terminal .chart-canvas { block-size: auto; flex: 1 1 240px; }

/* The measure answer chip: floats under the readout, one line of facts. */
.measure-chip {
  position: absolute; z-index: 5; inset-block-start: 56px; inset-inline-start: 8px;
  display: inline-flex; align-items: center; gap: 10px;
  background: color-mix(in srgb, var(--s1) 94%, transparent);
  border: 1px solid var(--line); border-radius: 10px;
  padding: 6px 10px; font-size: 0.78rem; font-variant-numeric: tabular-nums;
}
.measure-chip b.pos { color: var(--up, #2E9E6B); }
.measure-chip b.neg { color: var(--down, #B4635A); }
.measure-chip span { color: var(--ink-2); }
.measure-chip button { border: 0; background: transparent; color: var(--ink-3);
                       cursor: pointer; min-block-size: 28px; }

/* Journal -> chart: the row's trade, on the price that produced it. */
.journal-on-chart {
  margin-inline-start: 10px; font-size: 0.78rem; color: var(--gold-text, var(--gold));
  text-decoration: none; white-space: nowrap;
}
.journal-on-chart i { margin-inline-end: 4px; font-size: 0.72rem; }
.journal-on-chart:hover { text-decoration: underline; }

/* --- the chart's one control centre -------------------------------------- */
.chart-settings-wrap { position: relative; }
.chart-settings {
  position: absolute; z-index: 60; inset-inline-end: 0; inset-block-start: 44px;
  inline-size: min(86vw, 300px);
  background: var(--s1); border: 1px solid var(--line); border-radius: 12px;
  padding: 12px; box-shadow: 0 18px 44px rgba(0,0,0,0.4);
  display: flex; flex-direction: column; gap: 4px;
}
.chart-settings-title {
  font-size: 0.7rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-3); margin: 8px 0 4px; font-weight: 600;
}
.chart-settings-title:first-child { margin-block-start: 0; }
.chart-settings-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  border: 0; background: transparent; color: var(--ink-1);
  font: inherit; font-size: 0.86rem; padding: 7px 4px; cursor: pointer;
  min-block-size: 40px; text-align: start;
}
.chart-settings-row i { font-size: 1.2rem; color: var(--ink-3); }
.chart-settings-row[aria-checked="true"] i { color: var(--gold); }
.chart-settings-swatches {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 4px;
}
.chart-settings-swatches small { color: var(--ink-3); font-size: 0.72rem; min-inline-size: 64px; }
.chart-swatch {
  inline-size: 28px; block-size: 28px; border-radius: 8px;
  border: 2px solid var(--line); cursor: pointer; padding: 0; overflow: hidden;
}
.chart-swatch.is-on { border-color: var(--gold); }
.chart-swatch.is-pair { display: inline-flex; }
.chart-swatch.is-pair span { flex: 1; block-size: 100%; }

/* Theater: the chart takes the screen; the rail and page chrome step out. */
body.chart-theater .terminal-rail { display: none !important; }
body.chart-theater .terminal-bar .terminal-stats { display: none; }
body.chart-theater .key-levels { display: none; }

/* Real theater: the chart section takes the whole viewport (100dvh -- the
   iOS-safe unit), everything else steps out. In installed-PWA standalone
   there is no browser chrome, so this IS fullscreen on iPhone, where
   requestFullscreen for non-video elements never shipped. */
body.chart-theater .terminal-bar { display: none; }
body.chart-theater .terminal-chart {
  position: fixed; inset: 0; z-index: 300;
  block-size: 100dvh; inline-size: 100vw;
  background: var(--bg); padding: 0; margin: 0;
}
body.chart-theater .tab-bar { display: none; }

/* The forming bar's clock, in the readout row. */
.ohlc-countdown { color: var(--gold-text, var(--gold)); font-variant-numeric: tabular-nums; }
.ohlc-countdown i { margin-inline-end: 4px; font-size: 0.85em; }

/* --- Phase 1 composition discipline (CHART-PAGE-QA.md) ------------------- */
/* Canvas chrome uses PHYSICAL sides, never logical: the canvas itself does
   not flip in RTL -- the price scale stays on the physical right in both
   languages -- so logical insets put the zoom cluster and the draw rail ON
   TOP of the axis figures for every Arabic reader. 78px clears the ~72px
   price scale; physical `right` keeps it clear in both directions. */
.chart-nav { inset-inline-end: auto; inset-inline-start: auto; right: 78px; left: auto; }
.draw-bar { inset-inline-start: auto; inset-inline-end: auto; left: 6px; right: auto; }

/* The one control centre must scroll when the phone is shorter than its
   rows: the page under it is overflow:hidden by design, so a popover taller
   than the viewport simply amputated the colour swatches. */
.chart-settings { max-block-size: min(70vh, 520px); overflow-y: auto; }
/* And it must PAINT: without a stacking context on the header, the sibling
   sections below (studies row, MTF, the canvas) painted straight over the
   popover -- present in the DOM, invisible on the screen. z is MODEST on
   purpose: it must beat the card's own chrome (z 3-4) and nothing else --
   at 80 it punched through the plan rail (z 40) and the alert inbox. */
.chart-header { position: relative; z-index: 10; }
/* The PAGE bar outranks the chart card's header: its dropdowns (language,
   settings, alerts bell) were painting under the anchors row. 20 sits
   above the header's 10 and below the rail's 40. */
.terminal-bar { position: relative; z-index: 20; }

/* The plan rail on a phone: its content is taller than the screen, so it
   scrolls INSIDE itself and keeps clear of the tab bar; the assistant's
   disc yields while the rail is the focus. */
@media (max-width: 820px) {
  .terminal-rail {
    padding-block-end: calc(var(--tabs-h, 60px) + env(safe-area-inset-bottom, 0px) + 24px);
  }
  .rail-open .chat-pill { display: none; }
}
/* Theater + the gear: fixed anchors at the header's end, OUTSIDE the
   scrolling strip -- an overflow rail clips any popover born inside it. */
.chart-anchors { display: flex; align-items: center; gap: var(--space-2); flex: none; position: relative; }
/* The popover joins the physical-side law: the anchors sit at the physical
   right in both languages, so the panel pins its RIGHT edge and grows into
   the screen -- inset-inline-end in RTL pinned its LEFT edge and pushed
   every label off the viewport. */
.chart-settings { inset-inline-end: auto; right: 0; left: auto;
                  max-inline-size: calc(100vw - 24px); }
/* The anchors sit at the header's END -- physically LEFT in Arabic -- so
   there the popovers pin their LEFT edge and grow rightward into the
   screen. One rule, or every panel loses a third of itself off-screen. */
body.rtl .chart-anchors .chart-settings { left: 0; right: auto; }

/* Phones: the strip FLEXES inside the row and the anchors keep the row's
   end. The legacy 100%-width controls pushed gear+theater onto a second
   left-hand row -- and the popover pinned to that wrap hung off the left
   edge of a real phone (found on the owner's own screen). */
@media (max-width: 820px) {
  .chart-header { flex-wrap: nowrap; }
  .chart-controls { inline-size: auto !important; flex: 1 1 auto; min-inline-size: 0; }
  /* The chart is the biggest component, by law: vertical padding returns
     to the candles. */
  .terminal-body { padding-block: 0; }
}

/* The timeframe DROPDOWN: one chip carrying the current frame + the
   engine's read; the menu lists every frame with its read and regime. */
.tf-current {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  min-block-size: 36px; padding-inline: 12px;
  border: 1px solid var(--line); border-radius: 9px; cursor: pointer;
  background: var(--s2); color: var(--ink-1); font: inherit;
  font-variant-numeric: tabular-nums;
}
@media (pointer: coarse) { .tf-current { min-block-size: 44px; } }
.tf-current i { font-size: 0.65rem; color: var(--ink-3); }
.tf-menu { inline-size: 210px; }
.studies-menu { inline-size: 220px; }
.studies-menu .tool-swatch { display: inline-block; inline-size: 10px;
  block-size: 10px; border-radius: 3px; margin-inline-end: 8px; }
.studies-count { color: var(--gold-text, var(--gold)); font-size: 0.78rem;
  font-variant-numeric: tabular-nums; }
.tf-row { font-variant-numeric: tabular-nums; }
.tf-row.is-active { color: var(--gold-text, var(--gold)); }
.tf-row .tf-read small { color: var(--ink-3); margin-inline-start: 6px; }
/* The tf dropdown sits at the header's START: pin the popover to the
   near screen edge on each side. */
.tf-wrap .chart-settings { left: 0; right: auto; }
body.rtl .tf-wrap .chart-settings { right: 0; left: auto; }
/* The STUDIES button shares .tf-wrap but lives at the row's END since the
   spine merge -- left-pinned there, its menu ran off the right edge of the
   owner's phone ("Bollinge..."). It pins its own end instead. */
/* The studies menu has now been pinned to BOTH edges at different times --
   right, because it overflowed the screen when the button sat mid-toolbar;
   then left, once the button moved and the same rule pushed the panel to
   x=-36 with its labels cut ("llinger", "VAP"). An edge is the wrong thing to
   pin to: the panel has to stay inside the viewport wherever its button ends
   up. It anchors to the button's start edge and is then clamped by the
   viewport itself, so neither side can push it out again. */
.tf-wrap .studies-menu {
  left: 0; right: auto;
  max-inline-size: min(220px, calc(100vw - 24px));
  /* Keeps the panel on screen no matter where the toolbar puts the button. */
  margin-inline-start: max(0px, calc(-1 * var(--studies-overflow, 0px)));
}
body.rtl .tf-wrap .studies-menu { right: 0; left: auto; }
@media (max-width: 700px) {
  /* On a phone the toolbar is narrow enough that any anchoring can overflow.
     Centre it under the toolbar instead of guessing an edge. */
  .tf-wrap .studies-menu {
    position: fixed; inset-inline: 12px; inline-size: auto;
    max-inline-size: none; margin-inline-start: 0;
  }
}

/* The engine's read, on the frame chip and in the menu.
   Direction colours only ever mean direction (design law #10). */
.tf-chip .tf-read { margin-inline-start: 4px; font-weight: 600; }
.tf-read.pos { color: var(--up, #2E9E6B); }
.tf-read.neg { color: var(--down, #B4635A); }
.tf-read.is-stale { opacity: 0.4; }

/* The hovered bar's release, named in the readout where text belongs. */
.ohlc-event { color: var(--gold-text, var(--gold)); max-inline-size: 46vw;
              overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ohlc-event i { margin-inline-end: 4px; font-size: 0.85em; }

/* The zoom cluster whispers until wanted: translucent at rest, solid under
   the finger -- it was sitting at full weight on top of a level tag. */
.chart-nav button { opacity: 0.55; transition: opacity 120ms ease; }
.chart-nav button:hover, .chart-nav button:active,
.chart-nav button:focus-visible { opacity: 1; }

/* Touch devices carry NO floating chrome at all: pinch zooms, the pen and
   "back to now" live in the header anchors, the tools dock under the
   canvas -- exactly how TradingView and MT5 phones do it. The zoom
   buttons are desktop chrome; a phone pinches. */
@media (pointer: coarse), (max-width: 480px) {
  .chart-nav, .chart-zoom-btn { display: none; }
}

/* The docked drawing strip: fixed chrome under the canvas, named. */
.draw-dock {
  display: flex; align-items: center; gap: 4px;
  padding: 4px var(--space-3);
  border-block-start: 1px solid var(--line);
  overflow-x: auto; scrollbar-width: none;
}
.draw-dock::-webkit-scrollbar { display: none; }

/* The legend: every mark on the chart, explained with the visual it uses. */
.chart-legend { inline-size: min(92vw, 340px); gap: 2px; }
.legend-row { display: flex; align-items: flex-start; gap: 10px; padding: 7px 4px; }
.legend-text { display: flex; flex-direction: column; gap: 2px; min-inline-size: 0; }
.legend-text b { font-size: 0.82rem; }
.legend-text small { color: var(--ink-3); font-size: 0.72rem; line-height: 1.45; }
.legend-close { margin-block-start: 8px; }
.lg-sw { flex: none; inline-size: 34px; block-size: 18px; border-radius: 4px;
         margin-block-start: 2px; position: relative; background: var(--s2); }
.lg-candles { background:
  linear-gradient(to right, transparent 4px, #5E9E7A 4px, #5E9E7A 12px, transparent 12px,
                  transparent 22px, #B4635A 22px, #B4635A 30px, transparent 30px); }
.lg-sr { background: repeating-linear-gradient(to right, #e0a458 0 3px, transparent 3px 7px);
         background-size: 100% 2px; background-position: center; background-repeat: no-repeat; }
.lg-plan { background: repeating-linear-gradient(to right, #C99A3A 0 6px, transparent 6px 11px);
           background-size: 100% 2px; background-position: center; background-repeat: no-repeat; }
.lg-pos { background: linear-gradient(to bottom, #ffffff 0 2px, transparent 2px 8px,
          #B4635A 8px 10px, transparent 10px 15px, #2E9E6B 15px 17px, transparent 17px); }
.lg-alert { background: repeating-linear-gradient(to right, #C99A3A 0 5px, transparent 5px 9px);
            background-size: 100% 2px; background-position: center; background-repeat: no-repeat; }
.lg-alert::after { content: "⏰"; position: absolute; inset-inline-end: -2px;
                   inset-block-start: -7px; font-size: 9px; }
.lg-draw { background: linear-gradient(135deg, transparent 40%, #C9A227 40%, #C9A227 55%, transparent 55%); }
.lg-session { background: linear-gradient(to right, rgba(110,155,255,0.14) 0 25%,
              rgba(201,162,39,0.16) 25% 50%, rgba(201,162,39,0.3) 50% 75%, rgba(46,158,107,0.16) 75%); }
.lg-event::after { content: "⚑"; color: #C99A3A; position: absolute;
                   inset-inline-start: 50%; transform: translateX(-50%);
                   inset-block-start: -1px; font-size: 12px; }
.lg-journal::after { content: "▲ ●"; color: #5E9E7A; position: absolute;
                     inset-inline-start: 50%; transform: translateX(-50%);
                     inset-block-start: 0; font-size: 10px; }
.lg-pulse::after { content: ""; position: absolute; inset-inline-start: 50%;
                   inset-block-start: 50%; transform: translate(-50%, -50%);
                   inline-size: 8px; block-size: 8px; border-radius: 50%;
                   background: var(--gold); box-shadow: 0 0 6px 2px rgba(201,162,39,0.4); }
.lg-readout::after { content: "OHLC"; position: absolute; inset: 0;
                     display: grid; place-items: center;
                     font-size: 8px; letter-spacing: 1px; color: var(--ink-2); }
.lg-chip { border: 1px solid var(--gold); border-radius: 9px; background: none; }
.lg-chip::after { content: "×2 ⌾"; position: absolute; inset: 0; display: grid;
                  place-items: center; font-size: 8px; color: var(--gold-text, var(--gold)); }

/* --- Harsh-critique round: rhythm ---------------------------------- */
/* The anchors breathe evenly -- wrapper divs were injecting ragged gaps. */
.chart-anchors { gap: 6px; }
.chart-anchors .chart-settings-wrap { display: inline-flex; }
@media (max-width: 480px) {
  .chart-anchors { gap: 3px; }
  .chart-anchors .chart-aux-toggle { inline-size: 40px; min-inline-size: 40px; }
}
/* Key levels: ONE line at every width, sliding, never an orphan chip
   wrapped alone under the row. */
.key-levels { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
.key-levels::-webkit-scrollbar { display: none; }
.key-levels .key-level { flex: none; }
/* The rail's tail gets room on desktop too. */
.terminal-rail { padding-block-end: var(--space-5); }
/* The spine sits tight to its chart -- the dead band above it is gone. */
.spine { padding-block: 6px; }
/* The level entries, QUIET (the owner's eye: boxes and loud colours were
   "irritating to look at"). Hierarchy by size and whitespace, never by
   borders: the side word tiny in its line's structural colour, the price
   plain ink and tabular, the bell grey until it is actually watching.
   Red and green stay reserved for direction -- a level is structure. */
.key-level, button.key-level {
  display: inline-flex; flex-direction: column; align-items: flex-start;
  gap: 0; padding: 4px 2px; border: 0; background: none; border-radius: 8px;
}
button.key-level:hover:not(:disabled) { background: var(--s2); }
.key-level-side { font-size: 0.69rem; letter-spacing: 0.05em; font-weight: 600; }
.key-level.support .key-level-side, .key-level.below .key-level-side { color: #e0a458; }
.key-level.resistance .key-level-side, .key-level.above .key-level-side { color: #B9A88F; }
.key-level b, .key-level.above b, .key-level.below b,
.key-level.support b, .key-level.resistance b {
  color: var(--ink-1); font-variant-numeric: tabular-nums; font-weight: 600;
}
.key-level-main { display: inline-flex; align-items: center; gap: 6px; }
.key-level-main i { color: var(--ink-3); font-size: 0.78rem; }
.key-level.is-watched .key-level-main i { color: var(--gold); }
/* Watching is said by the gold bell ALONE -- the inset gold ring around
   the whole chip was the loudest thing on the row. */
button.key-level.is-watched { box-shadow: none; }
.key-levels { gap: var(--space-5); }
/* The alert bell keeps its place in the flow -- pushed by auto-margin it
   wrapped onto a lonely centred line of its own. */
.ohlc-readout .ohlc-watch { margin-inline-start: 0; }
/* Phones show the levels that FIT -- no half-cut entry inviting a slide.
   The rest are on the chart itself, and in the gear's levels layer. */
/* Phone (the terminal's own breakpoint, 820 -- the owner's device is
   ~509px and sat OUTSIDE the first 480 cut): EVERYTHING visible at once,
   nothing slides, overflow closed so it can never invite a drag. */
@media (max-width: 820px) {
  .key-levels { gap: 10px; overflow-x: hidden; justify-content: space-between;
                padding-inline: 10px; }
  /* No title on phones: the row explains itself (side words + bells), the
     legend says the rest, and the ~96px buys the fifth level its place.
     !important because an older flex rule on the title outlives the
     cascade order here. */
  .key-levels .key-levels-title { display: none !important; }
  .key-level-side { font-size: 0.55rem; }
  .key-level-main b { font-size: 0.78rem; }
  .key-level-main i { font-size: 0.7rem; }
  .key-levels .key-level:nth-child(n+7) { display: none; }
}
/* Nothing inside the card may paint past it -- the column clips before it
   ever covers the tab bar or a neighbour. Panes never flex-shrink. */
.terminal-chart .chart-card { overflow: hidden; }
.study-pane { flex: none; block-size: 110px; }
/* ONE flexible child: the canvas. Every fixed row refuses to shrink, so a
   height deficit lands entirely on the chart (which has a 180px floor) --
   letting flex spread the pain crushed the level row to thirteen pixels. */
.terminal .chart-header, .terminal .spine, .terminal .key-levels,
.terminal .draw-dock { flex: none; }
/* Short screens: the panes slim down so the level row keeps its place on
   the page -- an oscillator needs its SHAPE, not its acreage. flex-basis
   is the real height in this column (the 110px basis rule outranks a bare
   block-size), so both are set at matching specificity. */
@media (max-height: 760px) {
  .study-pane, .chart-card .study-pane { flex: 0 0 68px; block-size: 68px; }
}
/* And the canvas floor drops to match on phones -- the desktop 240px rule
   (.chart-card .chart-canvas) outranked the earlier media floor and kept
   the column 40px too tall for a 660px screen with two panes open. */
@media (max-width: 820px) {
  .chart-card .chart-canvas { min-block-size: 160px; }
}
/* The missing link in the height chain: the grid ROW must be bounded or
   it grows with content and the whole card slides under the tab bar --
   the canvas can only yield inside a column that itself cannot grow. */
.terminal-body { grid-template-rows: minmax(0, 1fr); }
.terminal-chart { min-block-size: 0; }

/* The narrowest phones hold four levels comfortably; the fifth returns
   at ~500px. Nothing ever slides at any width. */
@media (max-width: 460px) {
  .key-levels .key-level:nth-child(n+6) { display: none; }
  /* The reading row wraps CLEANLY when it must: tight rows, even gaps,
     and the bell stays a small inline glyph beside the clock instead of
     dropping to a lonely centred line of its own. */
  .ohlc-readout { row-gap: 2px; column-gap: 10px; padding: 6px 10px; }
  .ohlc-readout .ohlc-watch { min-block-size: 28px; min-inline-size: 28px;
                              padding: 2px; }
}

/* The reading row's own name, quiet, before the figures. */
.ohlc-name { padding-inline: 0 4px; }

/* Layouts in the control centre: save the current setup, return anytime. */
.layout-save-row { display: flex; gap: 6px; padding: 2px 4px; }
.layout-save-row input { min-inline-size: 0; flex: 1; }
.layout-name { flex: 1; margin: 0; }
.layout-save-btn { flex: none; min-block-size: 40px; }
.layout-row { display: flex; align-items: center; gap: 4px; padding-inline: 4px; }
.layout-apply {
  flex: 1; display: inline-flex; align-items: center; gap: 8px;
  min-block-size: 40px; padding-inline: 8px; text-align: start;
  border: 1px solid var(--line); border-radius: 9px;
  background: none; color: var(--ink-1); font: inherit; cursor: pointer;
}
.layout-apply:hover { background: var(--s2); }
.layout-apply i { color: var(--ink-3); }
.layout-delete { border: 0; background: none; color: var(--ink-3);
                 min-block-size: 40px; min-inline-size: 36px; cursor: pointer; }
.layout-delete:hover { color: var(--down); }

/* The assistant's disc clears the level chips row entirely. */
.terminal .chat-pill {
  bottom: calc(var(--tabs-h, 60px) + env(safe-area-inset-bottom, 0px) + 116px);
}

.drawing-critique-btn { margin-block-start: 8px; inline-size: 100%; }
.drawing-facts .chat-answer { margin-block-start: 8px; }

/* A closed question carries its answer's one-liner. */
.fold-side { display: inline-flex; align-items: center; gap: 10px; min-inline-size: 0; }
.fold-hint { color: var(--ink-3); font-size: 0.72rem;
             font-variant-numeric: tabular-nums;
             overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
             max-inline-size: 46vw; }

/* The briefing admits it is loading instead of sitting as an empty box. */
.briefing-skeleton { display: inline-block; inline-size: min(46vw, 220px);
  block-size: 0.9em; border-radius: 6px;
  background: linear-gradient(90deg, var(--s2) 25%, var(--s3, var(--s2)) 50%, var(--s2) 75%);
  background-size: 200% 100%; animation: briefShimmer 1.1s linear infinite; }
@keyframes briefShimmer { to { background-position: -200% 0; } }

/* A row that says what it is: the small label leading each strip. */
.row-label {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  font-size: 0.64rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--ink-3); padding-inline: 4px 8px;
}
.row-label i { font-size: 0.8em; }

/* Finger floors on the most finger-driven controls the page has. */
@media (pointer: coarse) {
  .draw-tool { inline-size: 44px; block-size: 44px; }
  .chart-settings-row { min-block-size: 44px; }
  .chart-swatch { inline-size: 34px; block-size: 34px; }
}

/* The assistant's disc is canvas chrome too: physical right, both
   languages, or in Arabic it lands exactly on the drawing toggle. And it
   ranks BELOW every panel and dropdown (bar context 20, rail 40, sheets
   260+): the disc invites, it never covers what the reader opened. The
   open chat itself lives on its own 300 scrim, untouched. */
.terminal .chat-pill { left: auto; right: 12px; z-index: 15; }

/* The series wardrobe in the control centre: six renderings of one truth. */
.chart-style-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; padding: 4px; }
.chart-style-chip {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 8px 4px; min-block-size: 52px;
  border: 1px solid var(--line); border-radius: 9px; cursor: pointer;
  background: none; color: var(--ink-3);
}
.chart-style-chip small { font-size: 0.69rem; }
.chart-style-chip.is-on { border-color: var(--gold); color: var(--ink-1); }
.chart-goto {
  margin: 2px 4px 6px; padding: 8px 10px; min-block-size: 40px;
  border: 1px solid var(--line); border-radius: 9px;
  background: var(--s2); color: var(--ink-1); font: inherit; font-size: 0.82rem;
  color-scheme: dark light;
}

/* The one legitimately animated pixel: the live price's breathing dot. */
.price-pulse {
  position: absolute; z-index: 3; inline-size: 8px; block-size: 8px;
  border-radius: 50%; background: var(--gold); opacity: 0;
  pointer-events: none; transition: opacity 200ms ease;
}

/* 390px: the control row must FIT -- "one row, never three" is only a rule
   if the row does not clip the gear off the screen. The type switch drops
   its words (the icons are the standard glyphs), the chips tighten. */
@media (max-width: 480px) {
  .chart-type-option span { display: none; }
  .chart-type-option { padding-inline: var(--space-2); }
  .tf-chip { padding-inline: 7px; }
  .chart-header { gap: var(--space-1); }
  .terminal-price { flex: 1 1 auto; min-inline-size: 0; flex-wrap: wrap; row-gap: 2px; }
}

/* Rhythm: the space above the canvas was dead air stacked from three rows'
   worth of default padding. Tightened to a beat, not a hole. */
.chart-tools { padding-block: 4px; }
.mtf-strip { padding-block: 2px 4px; }

/* The MTF strip is a READING, not a control row -- it must not look like a
   second timeframe selector. Quieter chips, a hairline seam above, and the
   current frame carries the only emphasis. */
.mtf-strip { border-block-start: 1px dashed var(--line); margin-inline: var(--space-3); padding-inline: 0; }
.mtf-chip { border-style: dashed; font-size: 0.7rem; min-block-size: 28px; padding-block: 2px; opacity: 0.9; }
.mtf-chip.is-current { border-style: solid; }
@media (pointer: coarse) { .mtf-chip { min-block-size: 36px; } }

/* The analysis admits its age: the cached read wears its clock. */
.analysis-asof { color: var(--ink-3); font-size: 0.74rem; margin: 4px 0 0;
                 display: flex; align-items: center; gap: 6px;
                 font-variant-numeric: tabular-nums; }

/* --- the AI page's comparison rows, responsive and in-system ---------- */
.kf-row { background: var(--s1); border: 1px solid var(--line);
          border-radius: 12px; padding: 12px 14px; }
.kf-head { display: flex; align-items: center; justify-content: space-between;
           gap: 10px; margin-block-end: 8px; }
.kf-head b { font-size: 0.92rem; }
.kf-impact { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.04em;
             padding: 3px 9px; border-radius: 999px; border: 1px solid; }
.kf-impact.is-major { color: var(--down); border-color: var(--down); }
.kf-impact.is-high  { color: var(--gold-text, var(--gold)); border-color: var(--gold); }
.kf-impact.is-mild  { color: var(--ink-3); border-color: var(--line2, var(--line)); }
.kf-views { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.kf-views small { display: block; color: var(--ink-3); font-size: 0.7rem;
                  margin-block-end: 2px; }
.kf-views span { color: var(--ink-2); font-size: 0.86rem; }
@media (max-width: 480px) { .kf-views { grid-template-columns: 1fr; gap: 8px; } }

/* The advisor panel joins the system's palette -- gold, not purple. */
.card-advisor { background: linear-gradient(175deg, var(--s1), transparent);
                border: 1px solid var(--line2, var(--line));
                border-inline-start: 3px solid var(--gold);
                border-radius: 14px; padding: 20px; margin-block-end: 20px; }
.card-advisor-head { display: flex; align-items: center; gap: 12px;
                     margin-block-end: 14px; }
.card-advisor-head i { color: var(--gold); font-size: 1.2rem; }
.card-advisor-head h3 { margin: 0; color: var(--ink-1); }

/* The brand glyph became the Mithqal mark (an <img>): the old letter-tile
   gradient behind it turns gold-on-gold into mush. An image brings its own
   shape; the tile is for letters only. */
img.brand-glyph, img.auth-glyph {
  background: none !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  padding: 0 !important;
}

/* ------------------------------------------------- comfort: motion exists */
/* The page had transition: all 0s everywhere -- the only motion was a
   loading spinner. 120-220ms is the whole budget; anything longer is lag. */
.terminal-rail { transition: transform 220ms ease; }
.chart-settings, .tf-menu, .nav-menu, .sourced-sheet, .why-sheet {
  animation: menu-rise 160ms ease-out;
}
@keyframes menu-rise {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: translateY(0); }
}
button, .tool-chip, .tf-chip, .journal-filter, .key-level {
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
@media (prefers-reduced-motion: reduce) {
  .terminal-rail { transition: none; }
  .chart-settings, .tf-menu, .nav-menu, .sourced-sheet, .why-sheet { animation: none; }
}

/* ------------------------------------------- comfort: switches don't blank */
/* A timeframe switch keeps the old candles painted; this quiet corner pill
   is the only announcement. The full-canvas veil is reserved for a first
   load (nothing painted yet) and for errors. */
.chart-switch-pill {
  position: absolute; inset-block-start: 8px; inset-inline-end: 76px;
  z-index: 6; display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: 999px;
  background: color-mix(in srgb, var(--s1) 88%, transparent);
  border: 1px solid var(--line);
  color: var(--ink-3); font-size: 0.7rem; font-weight: 600;
  pointer-events: none;
}
/* The key-levels row holds its ground during a switch: ghost chips reserve
   the height so the canvas never grows-then-snaps. */
.key-levels.is-waiting { opacity: 0.55; }
.key-level-ghost {
  display: inline-block; inline-size: 92px; block-size: 30px;
  border-radius: 8px; border: 1px dashed var(--line);
}

/* --------------------------------------------- comfort: the canvas is hero */
/* Measured: 243px of chrome before the first candle (TradingView: ~90).
   Tighter card padding and row gaps on the terminal buy back most of it
   without restructuring the rows. */
.terminal .chart-card { padding: 12px; }
.terminal .terminal-body { gap: 8px; padding: 12px; }
.terminal .chart-header { padding-block: 2px; }
.terminal .spine { padding-block: 4px; }
/* The OHLC readout is a legend, not a billboard: transparent ground, no
   self-naming label on the terminal (the row's content IS its name there),
   values keep their weight. */
.terminal .ohlc-readout {
  background: transparent; border: 0;
  display: flex; flex-wrap: nowrap; overflow: hidden;
  white-space: nowrap; align-items: center; gap: 8px;
  max-inline-size: calc(100% - 96px);
  block-size: 22px;
  /* A hard clip slices the last glyph in half -- it reads as a rendering
     blur, not a boundary. The line dissolves instead. */
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
}
body.rtl .terminal .ohlc-readout {
  -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 26px), transparent);
  mask-image: linear-gradient(to left, #000 calc(100% - 26px), transparent);
}
.terminal .ohlc-readout > * { flex: none; }
/* The release flag has its own lane on the chart; inside the one-line
   terminal legend it was a half-clipped smudge. */
.terminal .ohlc-readout .ohlc-event { display: none; }
.terminal .ohlc-name { display: none; }
/* The resting ask-pill whispers: translucent gold ground, gold glyph. The
   audit found the solid #c99a3a disc was the most saturated object on the
   screen, parked on live prices. Engaged (grown) it returns to full gold. */
.terminal .chat-pill.is-mini {
  background: rgba(201, 154, 58, 0.14);
  color: var(--gold);
  box-shadow: none;
  opacity: 1;
}

/* Unconditional, last in the sheet: the ask-pill must NEVER sit on the price
   axis. The earlier media-scoped rule lost a cascade fight the owner's own
   screenshot exposed (pill at the right edge, on top of the axis labels).
   Physical left in every direction: the axis lives on the chart's right. */
.terminal .chat-pill {
  inset-inline: unset !important;
  left: 12px !important;
  right: auto !important;
}

/* ------------------------------------------------------- chart-vision chat */
.chat-shot-btn {
  flex: none; inline-size: 44px; block-size: 44px;
  display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: 50%;
  background: transparent; color: var(--ink-2); cursor: pointer;
}
.chat-shot-btn:hover { color: var(--gold); border-color: var(--gold); }
.chat-shot-strip {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 14px; border-block-start: 1px solid var(--line);
  font-size: 0.72rem; color: var(--ink-3);
}
.chat-shot-strip img {
  inline-size: 56px; block-size: 34px; object-fit: cover;
  border-radius: 6px; border: 1px solid var(--gold);
}
.chat-shot-strip button {
  margin-inline-start: auto; border: 0; background: none;
  color: var(--ink-3); cursor: pointer; min-inline-size: 32px; min-block-size: 32px;
}
.chat-you-shot {
  display: block; max-inline-size: 180px; border-radius: 8px;
  margin-block-end: 6px; border: 1px solid var(--line);
}

/* --------------------------------------- comfort: one row, verdict included */
/* The spine joins the controls row: flexes into the middle at desktop, wraps
   to its own slim full-width line on phones. Its bottom border goes -- the
   header already draws the row's floor. */
.chart-header .spine {
  flex: 1 1 auto;
  min-inline-size: 0;
  inline-size: auto;
  border-block-end: 0;
  padding-block: 4px;
}
.chart-header .spine .spine-state { white-space: nowrap; }
@media (max-width: 820px) {
  .chart-header { flex-wrap: wrap; }
  .chart-header .spine { flex-basis: 100%; order: 9; padding-block: 6px; }
}

/* ------------------------------------------------------------- bar replay */
.replay-dock {
  position: absolute; inset-inline: 12px; inset-block-end: 10px;
  z-index: 7; display: flex; align-items: center; gap: 6px;
  padding: 8px 10px; border-radius: 12px;
  background: color-mix(in srgb, var(--s1) 92%, transparent);
  border: 1px solid var(--line);
  box-shadow: 0 10px 30px rgba(0,0,0,0.35);
}
.replay-dock button {
  min-inline-size: 38px; min-block-size: 38px;
  display: grid; place-items: center;
  border: 0; border-radius: 9px; cursor: pointer;
  background: none; color: var(--ink-2); font: inherit; font-size: 0.8rem;
}
.replay-dock button:hover { background: var(--s2); color: var(--ink-1); }
.replay-dock .replay-play { background: var(--gold); color: var(--gold-ink); }
.replay-dock .replay-speed.is-on { color: var(--gold); }
.replay-pos {
  margin-inline-start: auto; font-size: 0.72rem; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
@media (max-width: 480px) { .replay-dock { gap: 2px; padding: 6px; } }

/* --------------------------------------- comfort: topbar twins match (audit #14) */
/* The bell measured 45x40 beside a 40x40 kebab -- mismatched twins read as
   sloppiness at the very top of the page. One size, one radius, 12px rhythm. */
.terminal-bar .alerts-bell, .terminal-bar .nav-more {
  min-inline-size: 40px; min-block-size: 40px;
  inline-size: 40px; block-size: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
}
.terminal-bar { column-gap: 12px; }

/* ------------------------------- comfort: the terminal chrome follows the theme */
/* The legacy sheet pinned the terminal bar and slide-over rail to a fixed
   navy --bg-1 with no light-theme value: in light mode the card went ivory
   while the frame stayed dark (and cold). The frame now stands on the same
   warm tokens as everything else, in both themes. */
.terminal-bar { background: var(--s0, var(--s1)); border-color: var(--line); }
@media (max-width: 820px) {
  .terminal-rail { background: var(--s0, var(--s1)); border-color: var(--line); }
}

/* The briefing's voice: a quiet speaker inside the head row. */
.briefing-voice {
  display: inline-flex; align-items: center; justify-content: center;
  min-inline-size: 36px; min-block-size: 36px; margin-inline-start: auto;
  border-radius: 50%; color: var(--ink-3); cursor: pointer;
}
.briefing-voice:hover { color: var(--gold); background: var(--s2); }

/* Condition alerts creator: one row of bounded choices. */
.cond-form { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.cond-form select, .cond-form input {
  min-block-size: 40px; padding-inline: 10px;
  background: var(--s2); color: var(--ink-1);
  border: 1px solid var(--line); border-radius: 8px; font: inherit;
}
.cond-form input { inline-size: 84px; font-variant-numeric: tabular-nums; }
.cond-note { color: var(--ink-3); font-size: 0.78rem; margin: 4px 0 10px; }
.cond-error { color: var(--down); font-size: 0.78rem; margin-block-start: 8px; }

/* ------------------------------------------------------------ /performance */
.perf-body { max-inline-size: 900px; margin-inline: auto; padding: var(--space-4);
             display: flex; flex-direction: column; gap: var(--space-4); }
.perf-intro { color: var(--ink-3); font-size: 0.88rem; line-height: 1.6; }
.perf-intro a { color: var(--gold); }
.perf-empty, .perf-caveat { color: var(--ink-3); font-size: 0.82rem; font-style: italic; }
.perf-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
              gap: var(--space-3); padding: var(--space-4); }
.perf-cards div { display: flex; flex-direction: column; gap: 4px; }
.perf-cards small { color: var(--ink-3); font-size: 0.7rem; text-transform: uppercase;
                    letter-spacing: 0.06em; }
.perf-cards b { font-size: 1.25rem; font-variant-numeric: tabular-nums; }
.perf-cards b.pos { color: var(--up, #2E9E6B); }
.perf-cards b.neg { color: var(--down, #B4635A); }
.perf-curve { inline-size: 100%; block-size: 140px; display: block; }
.perf-zero { stroke: var(--line); stroke-width: 1; stroke-dasharray: 4 4; }
.perf-line { fill: none; stroke-width: 2; }
.perf-line.pos { stroke: var(--up, #2E9E6B); }
.perf-line.neg { stroke: var(--down, #B4635A); }
.perf-bins { display: flex; gap: var(--space-3); align-items: flex-end;
             padding-block: var(--space-3); }
.perf-bin { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px; }
.perf-bin-bar { inline-size: 100%; max-inline-size: 56px; border-radius: 6px 6px 0 0;
                background: color-mix(in srgb, var(--gold) 45%, transparent); }
.perf-bin small { color: var(--ink-3); font-size: 0.68rem; }
.perf-table { inline-size: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.perf-table th, .perf-table td { padding: 8px 10px; text-align: start;
                                 border-block-start: 1px solid var(--line); font-size: 0.84rem; }
.perf-table th { color: var(--ink-3); font-size: 0.7rem; text-transform: uppercase;
                 letter-spacing: 0.06em; border-block-start: 0; }
.perf-table td.pos { color: var(--up, #2E9E6B); }
.perf-table td.neg { color: var(--down, #B4635A); }

/* --------------------------------------------------------------- /academy */
.academy-body { max-inline-size: 760px; margin-inline: auto; padding: var(--space-4);
                display: flex; flex-direction: column; gap: var(--space-3); }
.academy-progress { color: var(--gold); font-size: 0.82rem; font-weight: 600; }
.academy-track { padding: 0; overflow: hidden; }
.academy-track-head {
  display: flex; align-items: center; gap: 12px; inline-size: 100%;
  padding: 16px; border: 0; background: none; color: var(--ink-1);
  font: inherit; font-size: 0.95rem; cursor: pointer; text-align: start;
}
.academy-track-head > b { flex: 1; }
.academy-track-head small { color: var(--ink-3); font-variant-numeric: tabular-nums; }
.academy-track-head i:first-child { color: var(--gold); }
.academy-lesson { padding: 14px 16px; border-block-start: 1px solid var(--line); }
.academy-lesson h4 { margin: 0 0 8px; font-size: 0.9rem; }
.academy-lesson.is-done h4 i { color: var(--up, #2E9E6B); }
.academy-lesson p { margin: 0 0 12px; color: var(--ink-2); font-size: 0.86rem; line-height: 1.7; }
.academy-lesson-foot { display: flex; gap: 10px; align-items: center; }
.academy-mark { border: 0; background: none; color: var(--ink-3);
                font: inherit; font-size: 0.8rem; cursor: pointer; }
.academy-mark:hover { color: var(--gold); }

/* ---------------------------------------------------------------- /events */
.events-body { max-inline-size: 760px; margin-inline: auto; padding: var(--space-4);
               display: flex; flex-direction: column; gap: var(--space-3); }
.event-row { padding: 12px 0; border-block-start: 1px solid var(--line); }
.event-row:first-of-type { border-block-start: 0; }
.event-row-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.event-row-head > b { font-size: 0.9rem; }
.event-clock { margin-inline-start: auto; color: var(--flag);
               font-variant-numeric: tabular-nums; }
.event-when { color: var(--ink-3); margin-inline-start: auto; }
.event-blackout { display: flex; align-items: center; gap: 10px; margin-block-start: 8px; }
.event-blackout-band {
  inline-size: 120px; block-size: 8px; border-radius: 4px;
  background: linear-gradient(to right,
    color-mix(in srgb, var(--flag) 35%, transparent) 0 75%,
    color-mix(in srgb, var(--flag) 18%, transparent) 75% 100%);
}
.event-blackout small { color: var(--ink-3); font-size: 0.7rem; }
.event-measures { display: flex; gap: 18px; align-items: baseline;
                  margin-block-start: 8px; flex-wrap: wrap; }
.event-measures span { display: inline-flex; flex-direction: column; gap: 2px; }
.event-measures small { color: var(--ink-3); font-size: 0.68rem;
                        text-transform: uppercase; letter-spacing: 0.05em; }
.event-measures b { font-variant-numeric: tabular-nums; }
.event-measures b.pos { color: var(--up, #2E9E6B); }
.event-measures b.neg { color: var(--down, #B4635A); }

/* The patience counter: silence with a denominator. */
.patience-line {
  display: flex; align-items: baseline; gap: 10px;
  padding: 10px 14px; border-radius: 10px; text-decoration: none;
  background: var(--s1); border: 1px solid var(--line);
  color: var(--ink-2); font-size: 0.82rem; line-height: 1.55;
}
.patience-line i { color: var(--gold); }
.patience-line:hover { border-color: var(--line-strong); }

/* level sheet actions */
.level-sheet-actions { display: flex; gap: 10px; margin-block-start: 14px; flex-wrap: wrap; }
.level-sheet-actions .btn { flex: 1; justify-content: center; }

/* The refusal citing its own measurement. */
.no-trade-measured { margin: 8px 0 0; color: var(--ink-3); font-size: 0.76rem;
                     font-style: italic; line-height: 1.6; }

/* The brand made literal: spot in grams and مثقال. */
/* One quote in three units, with a caption that says so. The strip used to be
   three bare abbreviations; a figure whose label needs explaining is a figure
   nobody trusts. */
.gold-units-wrap { margin-block-start: 10px; }
.gold-units-cap {
  display: block; color: var(--ink-3); font-size: 0.68rem; letter-spacing: .01em;
}
.gold-units { display: flex; gap: 18px; margin-block-start: 4px; flex-wrap: wrap; }
.gold-units span { display: inline-flex; align-items: baseline; gap: 6px; }
.gold-units small { color: var(--ink-3); font-size: 0.7rem; }
.gold-units b { color: var(--ink-2); font-size: 0.82rem;
                font-variant-numeric: tabular-nums; font-weight: 600; }

/* The obedience curve: two lines, one lesson. */
.obedience-curve { margin-block-end: 14px; }
.obedience-curve svg { inline-size: 100%; block-size: 110px; display: block; }
.obedience-fol { fill: none; stroke: var(--gold, #C9A227); stroke-width: 2; }
.obedience-ovr { fill: none; stroke: var(--ink-3); stroke-width: 1.5;
                 stroke-dasharray: 5 4; }
.obedience-legend { display: flex; gap: 20px; margin-block-start: 8px;
                    font-size: 0.76rem; color: var(--ink-3); flex-wrap: wrap; }
.obedience-legend b { margin-inline-start: 6px; font-variant-numeric: tabular-nums; }
.obedience-legend b.pos { color: var(--up, #2E9E6B); }
.obedience-legend b.neg { color: var(--down, #B4635A); }
.obedience-dot { display: inline-block; inline-size: 14px; block-size: 3px;
                 border-radius: 2px; margin-inline-end: 6px; vertical-align: middle; }
.obedience-dot.fol { background: var(--gold, #C9A227); }
.obedience-dot.ovr { background: var(--ink-3); }
.patience-cadence { display: block; margin-block-start: 4px; color: var(--ink-3);
                    font-size: 0.72rem; }
.limits-sources { list-style: none; margin: 0; padding: 0;
                  display: flex; flex-direction: column; gap: 12px; }
.limits-sources li { font-size: 0.86rem; line-height: 1.7; color: var(--ink-2); }
.limits-sources b { color: var(--ink-1); }

/* What's new: the gold dot that earns its tap. */
.whats-new-dot { position: absolute; inset-block-start: 6px; inset-inline-end: 6px;
                 inline-size: 8px; block-size: 8px; border-radius: 50%;
                 background: var(--gold); }
.nav-more { position: relative; }
.nav-menu-item .whats-new-dot { position: static; margin-inline-start: auto; }
.whats-new-list { list-style: none; margin: 0; padding: 0;
                  display: flex; flex-direction: column; gap: 10px; }
.whats-new-list li { font-size: 0.86rem; color: var(--ink-2); line-height: 1.6;
                     padding-inline-start: 18px; position: relative; }
.whats-new-list li::before { content: "◆"; position: absolute; inset-inline-start: 0;
                             color: var(--gold); font-size: 0.6rem; top: 4px; }


/* Narrow windows: mid-toolbar popovers center on the viewport instead of
   hanging off their anchor (the legend bled off the left edge). */
@media (max-width: 700px) {
  .chart-anchors .chart-settings {
    position: fixed;
    left: 50% !important;
    right: auto !important;
    transform: translateX(-50%);
    inset-block-start: 132px;
    max-inline-size: calc(100vw - 20px);
    max-block-size: min(64vh, 480px);
  }
}

/* Wave defects #2 and #11: the RTL compose row shoved Send off-screen (an
   input refusing to shrink), and the replay counter wrapped to three lines. */
.chat-compose input { min-inline-size: 0; flex: 1 1 0; }
.replay-pos { white-space: nowrap; }
label.chat-shot-btn { cursor: pointer; }

/* Candle pairs per theme: equal-luminance dark pair; a dedicated saturated
   pair for ivory, where the dark-tuned greens washed out at 3.2:1. */
:root { --candle-up: #5E9E7A; --candle-down: #C96F63; }
:root[data-theme="light"] { --candle-up: #1E7A52; --candle-down: #C2453A; }

/* Engine health + personal proof on the record page. The health card carries
   its state in colour because a degraded engine must not read like a stat. */
.perf-health small, .perf-proof small { display: block; margin-block-start: 8px;
  color: var(--text-3); font-size: 0.78rem; line-height: 1.6; }
.perf-health.is-degraded { border-color: color-mix(in srgb, var(--danger) 55%, transparent); }
.perf-health.is-degraded p { color: var(--danger); font-weight: 600; }
.perf-health.is-watching p { color: var(--text-2); }
.perf-proof .btn { margin-block-start: 10px; }

/* Comfort audit #20: the first chart load. A skeleton in the shape of the
   answer, not a spinner in the shape of a fault. The shimmer is slow and
   low-contrast on purpose -- it says "coming", not "look here". */
.chart-skeleton { position: absolute; inset: 0; display: flex;
  flex-direction: column; justify-content: flex-end; gap: 10px;
  padding: 18px 16px 26px; pointer-events: none; }
.chart-skeleton-bars { display: flex; align-items: flex-start; gap: 6px;
  block-size: 62%; inline-size: 100%; }
.skeleton-bar { flex: 1 1 0; border-radius: 2px;
  background: color-mix(in srgb, var(--text-3) 16%, transparent);
  animation: skeleton-breathe 2.4s ease-in-out infinite; }
.skeleton-bar:nth-child(3n) { animation-delay: .35s; }
.skeleton-bar:nth-child(3n+1) { animation-delay: .7s; }
.chart-skeleton-note { color: var(--text-3); font-size: .8rem;
  text-align: center; }
@keyframes skeleton-breathe {
  0%, 100% { opacity: .55; } 50% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .skeleton-bar { animation: none; opacity: .7; }
}


/* The quality caveat, made visible.
   It lived in a title= attribute, which on a phone is no attribute at all.
   A letter grade beside a number reads as odds unless something on the same
   screen says otherwise, and across 6,188 trades this score's correlation
   with the outcome is -0.0005. */
.verdict-quality-caveat {
  display: block;
  grid-column: 1 / -1;
  margin-block-start: 6px;
  font-size: 0.72rem;
  line-height: 1.5;
  color: var(--ink-3, #8A857B);
}


/* SIGNED NUMBERS IN RTL, and this is a correctness fix, not a cosmetic one.
   `+` and `-` are bidi class ES: with no digit on both sides they resolve to
   the paragraph direction and jump to the far end. Measured per character with
   Range.getBoundingClientRect on the live pages, in Arabic:

       20+   rendered as  +20      "twenty or more" became "positive twenty"
       +1.5R rendered as  1.5R+
       -1R   rendered as  1R-      in the PUBLIC RECORD TABLE

   The last one is the whole product: the one page that exists to show wins
   and losses honestly was putting the sign on the wrong side of the number.

   The codebase already solved this twice -- react-app.js wraps the gold units
   in dir="ltr" and app.py has _bidi_num() for push copy -- and the record and
   the landing never got it. Isolation is the structural answer: the number is
   its own bidi run wherever it appears, so nothing outside it can reorder it.

   2026-08-15: four of the eight selectors here -- .r-value, .stat-num, .rec-r
   and .signed -- matched no element in the product any more. The elements had
   been renamed and this rule was never re-checked, which is the failure mode a
   stylesheet has and a test does not: it goes on looking like protection.
   Meanwhile .price-change (the headline change beside the live price, the most
   looked-at number here) and .ohlc-change (the chart's bar readout) had never
   been on the list at all, and both print a signed number. Dead selectors out,
   the two real ones in, and tests/test_surfaces.py now reads THIS list so the
   next rename fails a test instead of silently unprotecting a number. */
[dir="rtl"] .num,
[dir="rtl"] .money,
[dir="rtl"] .price,
[dir="rtl"] .price-change,
[dir="rtl"] .ohlc-change,
[dir="rtl"] td.num,
body.rtl .num, body.rtl .money, body.rtl .price,
body.rtl .price-change, body.rtl .ohlc-change, body.rtl td.num {
  unicode-bidi: isolate;
  direction: ltr;
}

/* Arabic has no italics. A synthesised oblique is a defect, not emphasis --
   and the setup-quality caveat, promoted from a tooltip to a visible line
   today, was rendering as fake italic in the one language it matters in. */
body.rtl .no-trade-measured,
body.rtl .perf-empty,
body.rtl .perf-caveat,
body.rtl .measured-strip-ci,
body.rtl .signal-reason,
[dir="rtl"] .no-trade-measured,
[dir="rtl"] .perf-caveat { font-style: normal; }


/* The order type, on the ticket. Not decoration: the customer places this at
   their own broker and a market click costs 3-7% of R that the measurement
   assumed nobody paid. */
.setup-pending b { color: var(--warn, #C99A3A); font-size: 0.82rem; }


/* A refusal is not a hint. A failed style change kept the previous selection
   and said nothing, so the customer believed they had switched the setting
   that decides which signals reach them. */
.style-error { margin: 8px 0 0; padding: 8px 12px; border-radius: 8px;
               font-size: 0.82rem; line-height: 1.5; color: var(--bad, #B4635A);
               background: color-mix(in srgb, var(--bad, #B4635A) 10%, transparent);
               border-inline-start: 3px solid var(--bad, #B4635A); }

/* ---------------------------------------------------------------- alerts
   The inbox grew without a way to empty itself, and every alert rendered as
   two lines of flat text -- so a ticket a trader had to act on looked exactly
   like a briefing they could ignore. Three things change that: a side badge in
   the market colour, the levels laid out and labelled, and a way out of the
   list. Green and red stay MARKET SEMANTICS here, never decoration: they mean
   buy/sell and stop/target, which is what the rest of the product uses them
   for. -------------------------------------------------------------------- */
.alert-row {
  display: flex;
  align-items: stretch;
  gap: var(--space-1);
}

.alert-row-main {
  flex: 1;
  min-inline-size: 0;                 /* long bodies must wrap, not push */
}

.alert-dismiss {
  flex: none;
  align-self: flex-start;
  background: none;
  border: 0;
  color: var(--ink-3);
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  cursor: pointer;
  line-height: 1;
  /* A touch target, not a pixel: this sits beside a link the thumb is aiming
     for, so it has to be reachable without being easy to hit by accident. */
  min-inline-size: 40px;
  min-block-size: 40px;
}

.alert-dismiss:hover { color: var(--ink-1); background: var(--s2); }
.alert-dismiss:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }

.alerts-clear {
  margin-inline-start: auto;
  font-size: 0.78rem;
  padding: 2px var(--space-2);
}

.alert-side {
  display: inline-block;
  font-size: 0.66rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  padding: 1px 6px;
  border-radius: var(--radius-pill);
  margin-inline-end: 6px;
  vertical-align: middle;
  /* The badge is a figure in a sentence: isolate it so an Arabic paragraph
     cannot reorder it away from the title it labels. */
  unicode-bidi: isolate;
}

.alert-side.is-buy {
  color: var(--up);
  background: rgba(33, 201, 122, 0.12);
  border: 1px solid rgba(33, 201, 122, 0.28);
}

.alert-side.is-sell {
  color: var(--down);
  background: rgba(242, 85, 90, 0.12);
  border: 1px solid rgba(242, 85, 90, 0.28);
}

.alert-levels {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-block-start: 6px;
}

.alert-level {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 4px 8px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--s2);
}

.alert-level em {
  font-style: normal;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.alert-level b { font-size: 0.86rem; color: var(--ink-1); }
.alert-level.is-stop  b { color: var(--down); }
.alert-level.is-target b { color: var(--up); }

/* ============================ rooms =====================================
   The desk's rooms, inside the app. Visually a conversation and nothing like
   a trade ticket: no side colours, no level grid. The one deliberate accent
   is the desk's own messages, because "who said this" is the first question
   in a room where one participant publishes the calls. */
.group-invite {
  display: flex; flex-wrap: wrap; gap: var(--space-3);
  align-items: center; justify-content: space-between;
  padding: var(--space-3); margin-block-end: var(--space-3);
  background: var(--s2); border: 1px solid var(--line);
  border-inline-start: 3px solid var(--gold); border-radius: var(--radius);
}
.group-invite strong { display: block; }
.group-invite small, .group-invite em {
  display: block; color: var(--ink-2); font-size: var(--text-sm);
}
.group-invite em { font-style: normal; margin-block-start: 4px; }
.group-invite-actions { display: flex; gap: var(--space-2); }

.group-list { display: grid; gap: var(--space-2); margin-block-end: var(--space-4); }
.group-row {
  display: block; inline-size: 100%; text-align: start;
  padding: var(--space-3); background: var(--s2);
  border: 1px solid var(--line); border-radius: var(--radius);
  color: inherit; cursor: pointer;
}
.group-row.is-open { border-color: var(--gold); background: var(--s3, var(--s2)); }
.group-row small { display: block; color: var(--ink-2); font-size: var(--text-sm); }
.group-row-name { display: flex; align-items: center; gap: var(--space-2); font-weight: 600; }
.group-unread {
  min-inline-size: 20px; padding-inline: 6px; border-radius: 10px;
  background: var(--gold); color: #0A0A0C;
  font-size: 0.72rem; font-weight: 700; text-align: center;
  font-variant-numeric: tabular-nums;
}
.group-muted-note {
  display: flex; align-items: center; gap: 6px; margin-block-start: 6px;
  color: var(--ink-2); font-size: var(--text-sm); font-style: normal;
}

.group-thread {
  padding: var(--space-3); background: var(--s2);
  border: 1px solid var(--line); border-radius: var(--radius);
}
.group-thread h2 { margin-block: 0 var(--space-3); font-size: var(--text-md); }
.group-msg { padding-block: var(--space-2); border-block-start: 1px solid var(--line); }
.group-msg:first-of-type { border-block-start: 0; }
.group-msg p { margin: 4px 0 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.group-msg-head { display: flex; align-items: baseline; gap: var(--space-2); }
.group-msg-head small { color: var(--ink-3); font-size: 0.72rem; }
.group-desk-badge {
  padding: 1px 7px; border-radius: 999px;
  background: rgba(201, 162, 39, 0.16); color: var(--gold-2);
  font-size: 0.68rem; font-weight: 700;
}
.group-msg.is-desk { border-inline-start: 2px solid var(--gold); padding-inline-start: var(--space-2); }

.group-composer { display: flex; gap: var(--space-2); margin-block-start: var(--space-3); }
.group-composer textarea {
  flex: 1; min-inline-size: 0; resize: vertical;
  padding: var(--space-2); background: var(--s1, var(--s2));
  border: 1px solid var(--line); border-radius: var(--radius); color: inherit;
  font: inherit;
}
.group-muted-banner {
  display: flex; align-items: center; gap: var(--space-2);
  margin-block-start: var(--space-3); padding: var(--space-2) var(--space-3);
  background: rgba(201, 162, 39, 0.08); border: 1px solid var(--line);
  border-radius: var(--radius); color: var(--ink-2); font-size: var(--text-sm);
}

/* A room message in the alert inbox. Neutral by construction: it must never
   be mistaken at a glance for a setup arriving. */
.alert-side.is-room {
  display: inline-flex; align-items: center; gap: 5px;
  background: rgba(148, 163, 184, 0.16); color: var(--ink-2);
}
.alert-row.is-room { border-inline-start: 2px solid var(--ink-3); }

.nav-menu-badge {
  margin-inline-start: auto; min-inline-size: 20px; padding-inline: 6px;
  border-radius: 10px; background: var(--gold); color: #0A0A0C;
  font-size: 0.72rem; font-weight: 700; text-align: center;
  font-variant-numeric: tabular-nums;
}

/* ===================================================== Explain This Market
   The one-button answer, and the first thing a customer reads. It sits above
   the detail it summarises, so it carries the weight: a heavier ground, a
   gold rule down the inline start, and the headline at display size.

   The five sections are typographically identical to each other on purpose.
   Ranking them by colour or size would be a claim about which matters most,
   and the whole point is that "what contradicts it" is worth exactly as much
   attention as "what supports it". */
.explain {
  margin-block-end: var(--space-5);
  padding: var(--space-5);
  border-radius: var(--radius);
  background: linear-gradient(180deg, var(--s2), var(--s1));
  border: 1px solid var(--line);
  border-inline-start: 2px solid var(--gold);
}
/* A disputed read is marked on the container, not by recolouring the text:
   the words already say it, and colouring them would be saying it twice in a
   way that stops meaning anything. */
.explain.is-contested { border-inline-start-color: var(--flag); }

.explain > h4 {
  margin: 0 0 var(--space-3);
  font-size: var(--text-2xs, 0.7rem);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 600;
}
.explain-headline {
  margin: 0 0 var(--space-4);
  font-family: var(--font-display, Georgia, serif);
  font-size: 1.2rem;
  line-height: 1.45;
  color: var(--ink-1);
  text-wrap: pretty;
}
.explain-none { margin: 0; color: var(--ink-2); line-height: 1.6; }

.explain-section { margin-block-start: var(--space-4); }
.explain-section > b {
  display: block;
  margin-block-end: 6px;
  font-size: var(--text-2xs, 0.7rem);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold-text, var(--gold));
  font-weight: 600;
}
.explain-section ul {
  margin: 0;
  padding-inline-start: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.explain-section li {
  position: relative;
  padding-inline-start: 14px;
  color: var(--ink-2);
  line-height: 1.55;
  text-wrap: pretty;
}
/* A rule rather than a bullet glyph: a dot before every line in five stacked
   lists reads as noise, and the marker has to work in both directions. */
.explain-section li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0.62em;
  inline-size: 6px;
  block-size: 1px;
  background: var(--ink-3);
}

@media (max-width: 560px) {
  .explain { padding: var(--space-4); }
  .explain-headline { font-size: 1.06rem; }
}

/* ============================================== Replay without the answer
   The levels sit in a monospace row so the four figures line up, same rule as
   the Telegram ticket: a column a thumb has to compare is a column nobody
   reads. */
.replay-exercise { margin-block-start: var(--space-5); }
.replay-levels {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: var(--space-3); margin-block: var(--space-4);
  padding: var(--space-4); border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--s2);
}
.replay-levels span { display: flex; flex-direction: column; gap: 4px; }
.replay-levels small {
  font-size: var(--text-2xs, .7rem); letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3);
}
.replay-levels b {
  font-family: var(--font-numeric, ui-monospace, monospace);
  font-variant-numeric: tabular-nums; color: var(--ink-1);
}
.replay-ask p { color: var(--ink-2); line-height: 1.55; }
.replay-reveal {
  margin-block-start: var(--space-4); padding: var(--space-4);
  border-radius: var(--radius); background: var(--s2);
  border-inline-start: 2px solid var(--ink-3);
}
/* The outcome tints the RULE, never the lesson text: a pass on a call that
   won is not a mistake, and colouring the words green would say it was. */
.replay-reveal.is-won { border-inline-start-color: var(--up); }
.replay-reveal.is-lost { border-inline-start-color: var(--down); }
.replay-lesson { margin: 0 0 var(--space-3); color: var(--ink-1); line-height: 1.6; }

@media (max-width: 560px) {
  .replay-levels { grid-template-columns: repeat(2, 1fr); }
}

/* ============================================ Why did I get this alert?
   Opens under the alert it is about. A reason on another page is a reason
   nobody reads at 03:12. */
.alert-why-open {
  background: none; border: 0; padding: 4px 0; cursor: pointer;
  color: var(--ink-3); font: inherit; font-size: var(--text-2xs, .72rem);
  text-decoration: underline; text-underline-offset: 3px;
}
.alert-why-open:hover { color: var(--ink-1); }
.alert-why {
  grid-column: 1 / -1; margin-block-start: 8px; padding: var(--space-3);
  border-radius: var(--radius-sm, 8px); background: var(--s2);
  border-inline-start: 2px solid var(--ink-3);
}
.alert-why-rule { margin: 0 0 8px; color: var(--ink-1); line-height: 1.5; }
.alert-why-state { display: grid; gap: 4px; margin: 0 0 8px; }
.alert-why-state > div { display: flex; gap: 8px; }
.alert-why-state dt {
  color: var(--ink-3); font-size: var(--text-2xs, .72rem);
  text-transform: uppercase; letter-spacing: .08em; min-inline-size: 72px;
}
.alert-why-state dd {
  margin: 0; font-family: var(--font-numeric, ui-monospace, monospace);
  font-variant-numeric: tabular-nums; color: var(--ink-2);
}
.alert-why-tally { display: block; color: var(--ink-2); margin-block-end: 6px; }

/* ===================================================== Position calculator */
.calc-form { display: grid; gap: var(--space-3); margin-block: var(--space-4); }
.calc-form label { display: flex; flex-direction: column; gap: 4px; }
.calc-form label span {
  font-size: var(--text-2xs, .72rem); letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3);
}
.calc-out {
  padding: var(--space-4); border-radius: var(--radius);
  background: var(--s2); border-inline-start: 2px solid var(--up);
}
/* The warning case is a size SMALLER than one lot -- the trade the customer
   wants does not exist at their risk. That is not an error, it is an answer. */
.calc-out.is-warn { border-inline-start-color: var(--flag); }
.calc-headline { display: flex; align-items: baseline; gap: 8px; }
.calc-headline b {
  font-family: var(--font-numeric, ui-monospace, monospace);
  font-size: 1.8rem; font-variant-numeric: tabular-nums; color: var(--ink-1);
}
.calc-rr { margin: 8px 0 0; color: var(--ink-2); }
.calc-rr.is-bad { color: var(--down); }

/* ==================================================== Historical research
   The sample is the finding. `research-sample` is the only figure rendered
   large; whatever the matched days did is a footnote to how few of them
   there were. */
.research-filters {
  display: grid; gap: var(--space-3); margin-block: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}
.research-filters label { display: flex; flex-direction: column; gap: 4px; }
.research-filters label span {
  font-size: var(--text-2xs, .72rem); letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3);
}
.research-out {
  margin-block-start: var(--space-4); padding-block-start: var(--space-4);
  border-block-start: 1px solid var(--line);
}
.research-question {
  margin: 0 0 var(--space-3); color: var(--ink-3);
  font-size: var(--text-xs, .8rem);
}
.research-sample { display: flex; align-items: baseline; gap: 8px; }
.research-sample b {
  font-family: var(--font-numeric, ui-monospace, monospace);
  font-size: 2.2rem; font-variant-numeric: tabular-nums; color: var(--ink-1);
  line-height: 1;
}
.research-counts {
  list-style: none; margin: var(--space-4) 0 0; padding: 0;
  display: grid; gap: 2px;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
}
.research-counts li {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 8px; padding: 8px 10px; border-radius: var(--radius-sm, 8px);
  background: var(--s2);
}
.research-counts b {
  font-family: var(--font-numeric, ui-monospace, monospace);
  font-variant-numeric: tabular-nums;
}
/* The caution is not decorated as an error. It is arithmetic about the
   search, and dressing it in red would train the reader to dismiss it. */
.research-caution {
  margin-block-start: var(--space-4); padding: var(--space-3);
  border-inline-start: 2px solid var(--flag); border-radius: var(--radius-sm, 8px);
  background: var(--s2); color: var(--ink-2); line-height: 1.55;
  font-size: var(--text-xs, .8rem);
}
.research-table { inline-size: 100%; border-collapse: collapse; margin-block-start: var(--space-4); }
.research-table th, .research-table td {
  padding: 8px 10px; text-align: start; border-block-end: 1px solid var(--line);
}
.research-table th {
  font-size: var(--text-2xs, .72rem); text-transform: uppercase;
  letter-spacing: .08em; color: var(--ink-3); font-weight: 600;
}
.research-table td { font-variant-numeric: tabular-nums; color: var(--ink-2); }
.research-table .is-up { color: var(--up); }
.research-table .is-down { color: var(--down); }

/* ════════════════════════════════════════════════════════════════════════
   THE UNSTYLED SURFACES

   A sweep of every className the app renders against every rule that
   exists found 115 classes with no CSS at all — most of the intelligence
   work wired up this week, rendering as raw HTML. That is the same disease
   as the nine features nobody rendered, one layer down: the markup was
   right, the component was tested, and the screen was ugly.

   `test_every_rendered_class_has_a_rule` fails the build on the next one.
   ════════════════════════════════════════════════════════════════════════ */

/* ─────────────────────────────────────────────── shared, used everywhere */

/* The explanatory line under a heading. Used on seven surfaces and styled
   on none of them, so every one of those paragraphs rendered at body
   weight and competed with the thing it was explaining. */
.settings-hint {
  margin: 0 0 var(--space-4); color: var(--ink-2);
  font-size: var(--text-sm); line-height: 1.6; max-inline-size: 62ch;
}

/* A refusal the customer needs to read. Not an alarm: it is usually the
   product declining to guess, which is the behaviour being paid for. */
.note-bad {
  margin: 0 0 var(--space-3); padding: var(--space-3);
  border-radius: var(--radius-sm);
  border-inline-start: 2px solid var(--bad, var(--down));
  background: color-mix(in srgb, var(--bad, var(--down)) 8%, transparent);
  color: var(--ink-1); font-size: var(--text-sm); line-height: 1.55;
}

.lede { color: var(--ink-2); font-size: var(--text-md); line-height: 1.65;
        max-inline-size: 62ch; margin-block-end: var(--space-4); }
.muted { color: var(--ink-3); }
.stat-label { display: block; color: var(--ink-3); font-size: var(--text-2xs);
              text-transform: uppercase; letter-spacing: .08em; }
.row-actions { display: flex; flex-wrap: wrap; gap: var(--space-2);
               margin-block-start: var(--space-3); }
.empty-state { padding: var(--space-5); text-align: center; color: var(--ink-3);
               line-height: 1.6; }
.form-error { color: var(--bad, var(--down)); font-size: var(--text-sm);
              margin-block-start: var(--space-2); }

/* Wide content scrolls inside its own box. The page itself must never
   scroll sideways — a customer who has to drag a settings screen left and
   right is reading a broken app, whatever the layout underneath is doing. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch;
                margin-inline: calc(var(--space-3) * -1);
                padding-inline: var(--space-3); }

/* A heading row that carries a heading and one small fact. */
.panel-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--space-3); flex-wrap: wrap;
}
.panel-head h3 { margin: 0; }

/* ──────────────────────────────────────────────── the customer's own rules */

.rules-list { list-style: none; margin: 0 0 var(--space-4); padding: 0;
              display: grid; gap: var(--space-2); }
.rules-list li {
  display: grid; gap: 4px; padding: var(--space-3);
  grid-template-columns: 1fr auto; align-items: start;
  border-radius: var(--radius-sm); background: var(--s2);
  border-inline-start: 2px solid var(--gold, var(--ink-3));
}
/* A paused rule is dimmed, never hidden. It is still the customer's rule
   and it comes back the moment they resume it. */
.rules-list li.is-off { opacity: .55; border-inline-start-color: var(--line-strong); }
.rule-text { color: var(--ink-1); line-height: 1.5; }
.rule-unchecked {
  grid-column: 1 / -1; color: var(--ink-3); font-size: var(--text-2xs);
  line-height: 1.5;
}
.rule-actions { display: flex; gap: var(--space-2); align-items: center; }
.rule-actions button {
  background: none; border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 4px 10px; color: var(--ink-2); font: inherit;
  font-size: var(--text-2xs); cursor: pointer;
  transition: border-color .15s var(--ease, ease), color .15s var(--ease, ease);
}
.rule-actions button:hover { border-color: var(--line-strong); color: var(--ink-1); }

.rules-form {
  display: grid; gap: var(--space-3); align-items: end;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  padding-block-start: var(--space-4); border-block-start: 1px solid var(--line);
}
.rules-form label { display: flex; flex-direction: column; gap: 4px; min-inline-size: 0; }
.rules-form label > span {
  font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: .1em;
  color: var(--ink-3);
}
/* The sentence in the customer's own words is the important field and gets
   the whole row; the machine-readable half is the small print beside it. */
.rules-sentence { grid-column: 1 / -1; }
.rules-form button[type="submit"] { grid-column: 1 / -1; justify-self: start; }

/* ───────────────────────────────────────────────── settings page furniture */

.style-panel .style-options {
  display: grid; gap: var(--space-2); margin-block-start: var(--space-3);
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
}
.alerts-actions { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.alerts-status { display: block; color: var(--ink-2); font-size: var(--text-2xs);
                 margin-block-start: 4px; line-height: 1.5; }
.sound-row select { inline-size: 100%; max-inline-size: 220px; }
.risk-row input { max-inline-size: 120px; }

.open-positions { display: grid; gap: var(--space-2); margin-block-start: var(--space-3); }
.open-position {
  display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: baseline;
  padding: var(--space-3); border-radius: var(--radius-sm); background: var(--s2);
  font-variant-numeric: tabular-nums; font-size: var(--text-sm);
  border-inline-start: 2px solid var(--line-strong);
}
.open-position.buy { border-inline-start-color: var(--up); }
.open-position.sell { border-inline-start-color: var(--down); }
.position-side { font-weight: 600; letter-spacing: .06em; font-size: var(--text-2xs); }
.open-position.buy .position-side { color: var(--up); }
.open-position.sell .position-side { color: var(--down); }
.position-stat { display: flex; flex-direction: column; gap: 2px; }
.measured-sample { color: var(--ink-3); font-size: var(--text-2xs);
                   font-variant-numeric: tabular-nums; }

/* ───────────────────────────────────────────────────────── the base field

   There was no base input style in this app. Every form styled its own
   fields — .auth-split, .cond-form, .alert-cap, .password-form, nine more —
   so anything written afterwards rendered as raw browser chrome: a white
   box with a hairline border on a warm dark ground.

   Element selectors, deliberately: specificity 0-0-1 loses to every one of
   those bespoke class rules, so this raises the floor without touching a
   single form that already had a considered look. */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
select,
textarea {
  inline-size: 100%;
  min-block-size: var(--control-h, 40px);
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--s1);
  color: var(--ink-1);
  font: inherit;
  font-size: var(--text-sm);
  transition: border-color .15s var(--ease, ease), background .15s var(--ease, ease);
}
textarea { min-block-size: 88px; resize: vertical; line-height: 1.55; }
input[type="number"] { font-variant-numeric: tabular-nums; }
input::placeholder, textarea::placeholder { color: var(--ink-3); opacity: 1; }
input:hover:not(:disabled), select:hover:not(:disabled),
textarea:hover:not(:disabled) { border-color: var(--line-strong); }
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: none; border-color: var(--gold, var(--ink-1));
  background: var(--s2);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--gold, var(--ink-3)) 18%, transparent);
}
input:disabled, select:disabled, textarea:disabled {
  opacity: .5; cursor: not-allowed;
}
/* The native arrow is drawn in the OS chrome colour and reads as a
   light-mode control on a dark panel. */
select {
  appearance: none;
  padding-inline-end: 32px;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-3) 50%),
                    linear-gradient(135deg, var(--ink-3) 50%, transparent 50%);
  background-size: 5px 5px, 5px 5px;
  background-position: right 16px center, right 11px center;
  background-repeat: no-repeat;
}
:root[dir="rtl"] select, [dir="rtl"] select {
  background-position: left 11px center, left 16px center;
}

/* ─────────────────────────────────── the pre-trade card's intelligence blocks

   Nine features were built, tested, reachable and rendered — and every one
   of them came out as a bare <h4> with a bullet list under it. These are
   the blocks that carry the product's actual argument, so they get a
   consistent shape: a small caps heading, a rule down the inline start in
   the colour of what the block MEANS, and figures in tabular numerals. */
.pretrade-narration, .pretrade-guardian, .pretrade-against,
.pretrade-scenarios {
  margin-block-start: var(--space-4); padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm); background: var(--s2);
  border-inline-start: 2px solid var(--line-strong);
}
.pretrade-narration h4, .pretrade-guardian h4, .pretrade-against h4,
.pretrade-scenarios h4 {
  margin: 0 0 var(--space-2); font-size: var(--text-2xs);
  text-transform: uppercase; letter-spacing: .1em; color: var(--ink-3);
  font-weight: 600; display: flex; justify-content: space-between;
  align-items: baseline; gap: var(--space-3);
}
.pretrade-narration ul, .pretrade-guardian ul, .pretrade-against ul {
  margin: 0; padding-inline-start: 1.1em; display: grid; gap: 6px;
}
.pretrade-narration li, .pretrade-guardian li, .pretrade-against li {
  color: var(--ink-2); line-height: 1.55; font-size: var(--text-sm);
}

/* The customer's own rules, and the case against the trade, are the two
   blocks that exist to slow somebody down. They carry the warning colour —
   neither one blocks anything, so neither one is red. */
.pretrade-guardian { border-inline-start-color: var(--flag); }
.pretrade-against { border-inline-start-color: var(--warn, var(--flag)); }
.pretrade-guardian li b { display: block; color: var(--ink-1); }
.pretrade-against h4 span { font-variant-numeric: tabular-nums; color: var(--ink-2); }
/* Confidence only ever falls. When it has, the arrow is worth seeing. */
.pretrade-against h4 span.neg { color: var(--down); }

.pretrade-conditions {
  display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4);
  margin-block-start: var(--space-3); color: var(--ink-2);
  font-size: var(--text-sm);
}
/* Two readings that are never blended into one score, so they are never
   drawn as one bar either. */
.pretrade-conditions span {
  padding: 3px 10px; border-radius: 999px; background: var(--s2);
  border: 1px solid var(--line);
}

.pretrade-scenarios { display: grid; gap: var(--space-3); }
/* Scenarios are never ranked. Identical treatment, in source order — a
   highlight on one of them is a prediction by typography. */
.scenario {
  padding: var(--space-3); border-radius: var(--radius-sm);
  background: var(--s1); border: 1px solid var(--line);
}
.scenario > b { display: block; color: var(--ink-1); margin-block-end: 6px; }
.scenario ul { margin: 0; padding-inline-start: 1.1em; display: grid; gap: 4px; }
.scenario li { color: var(--ink-2); font-size: var(--text-sm); line-height: 1.5; }
/* What would prove the scenario wrong is the half people skip, so it is
   set apart rather than appended to the list. */
.scenario-invalidation {
  display: block; margin-block-start: 8px; padding-block-start: 8px;
  border-block-start: 1px dashed var(--line); color: var(--ink-3);
  font-size: var(--text-2xs); line-height: 1.5;
}

/* What is ALREADY TRUE that makes a path coherent -- never a forecast, and
   deliberately quieter than the conditions above it. It was computed on every
   request and rendered by nothing until the scenarios were translated; the
   view had no element for it at all. */
.scenario-evidence {
  margin: 8px 0 0; padding: 0; list-style: none;
  display: grid; gap: 4px;
}
.scenario-evidence li {
  color: var(--ink-3); font-size: var(--text-2xs); line-height: 1.5;
}

/* ────────────────────────────────────────────── what gold is moving with */

.macro-corr { margin-block-start: var(--space-3); }
.macro-corr-head {
  display: block; margin-block-end: var(--space-2); color: var(--ink-3);
  font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: .08em;
}
.macro-corr ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.macro-corr li {
  display: grid; grid-template-columns: 1fr auto; gap: 2px var(--space-3);
  align-items: baseline; padding: 8px 10px; border-radius: var(--radius-sm);
  background: var(--s2);
}
.macro-corr li b { font-variant-numeric: tabular-nums; color: var(--ink-1); }
.macro-corr li small { grid-column: 1 / -1; color: var(--ink-3);
                       font-size: var(--text-2xs); line-height: 1.45; }
.macro-corr-label { color: var(--ink-2); }
/* Outside its usual range is the only thing here worth a colour, and it is
   a flag rather than an alarm: a relationship changing is information, not
   a problem. */
.macro-corr li.is-unusual { border-inline-start: 2px solid var(--flag); }
.macro-corr li.is-unusual b { color: var(--flag); }
.macro-corr-note { display: block; margin-block-start: var(--space-2);
                   color: var(--ink-3); font-size: var(--text-2xs); line-height: 1.5; }

/* ──────────────────────────────────── the journal's calibration and discipline */

.journal-calibration, .journal-discipline { margin-block-start: var(--space-4); }
.calib-reading { color: var(--ink-1); line-height: 1.6; margin: 0 0 var(--space-3); }
.calib-buckets { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.calib-buckets li {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: var(--space-3); padding: 8px 10px; border-radius: var(--radius-sm);
  background: var(--s2);
}
.calib-buckets b { font-variant-numeric: tabular-nums; color: var(--ink-1); }
.calib-label { color: var(--ink-2); }
.calib-note { display: block; margin-block-start: var(--space-2);
              color: var(--ink-3); font-size: var(--text-2xs); line-height: 1.5; }
.journal-discipline { display: grid; gap: var(--space-2); }

/* ───────────────────────────────────────────────────────── the odds and ends */

/* The generic card, used in 81 places and styled in none of them. */
.card {
  padding: var(--space-4); border-radius: var(--radius);
  background: var(--s1); border: 1px solid var(--line);
}
.live-action-error {
  margin: var(--space-3) 0 0; color: var(--bad, var(--down));
  font-size: var(--text-sm); line-height: 1.5;
}
.news-shell { min-block-size: 100%; }
.news-lang-note { margin: 0 0 var(--space-3); color: var(--ink-3);
                  font-size: var(--text-2xs); line-height: 1.5; }
.auth-signup { margin-block-start: var(--space-4); color: var(--ink-2);
               text-align: center; font-size: var(--text-sm); }
.auth-signup-link { color: var(--gold-text, var(--gold)); text-decoration: none;
                    font-weight: 600; }
.auth-signup-link:hover { text-decoration: underline; text-underline-offset: 3px; }
.firstrun-alerts { display: grid; gap: var(--space-3); justify-items: start; }
.replay-exit {
  position: absolute; inset-block-start: 8px; inset-inline-end: 8px;
  inline-size: 32px; block-size: 32px; display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: 50%;
  background: var(--s1); color: var(--ink-2); cursor: pointer;
}
.replay-exit:hover { color: var(--ink-1); border-color: var(--line-strong); }
/* A measured row carries numbers this product stands behind. */
.event-row.is-measured { border-inline-start: 2px solid var(--up); }
.is-loading { opacity: .6; }

/* The research scanner's own shell. Its children were styled and it was not,
   which left the filters flush against the fold that contains them. */
.research { display: grid; gap: 0; }

/* ─────────────────────────────────────────── what the rail caught the model at

   The withheld count is first and largest. It is the number that proves the
   check runs at all, and a product that reports "212 answers checked" while
   burying "4 withheld" is reporting its activity rather than its results. */
/* The panel sits below the model's answer, separated rather than boxed
   inside it: it is a statement about the machinery, not part of the reading. */
.ai-quality { margin-block-start: var(--space-5); }
.ai-quality-figures {
  display: grid; gap: var(--space-3); margin-block: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
}
.ai-quality-figures > div {
  padding: var(--space-3); border-radius: var(--radius-sm); background: var(--s2);
}
.ai-quality-figures b {
  display: block; font-family: var(--font-numeric, ui-monospace, monospace);
  font-size: 1.7rem; font-variant-numeric: tabular-nums; color: var(--ink-1);
  line-height: 1.1;
}
/* The denominator is context, not a second figure competing with the first. */
.ai-quality-figures b span { font-size: 1rem; color: var(--ink-3); }
.ai-quality-figures small {
  display: block; margin-block-start: 4px; color: var(--ink-3);
  font-size: var(--text-2xs); line-height: 1.4;
}
.ai-quality-reading { margin: 0 0 var(--space-3); color: var(--ink-1); line-height: 1.6; }
.ai-quality-drift {
  margin: 0 0 var(--space-3); padding: var(--space-3);
  border-inline-start: 2px solid var(--flag); border-radius: var(--radius-sm);
  background: var(--s2); color: var(--ink-2); line-height: 1.55;
  font-size: var(--text-sm);
}
/* What this does NOT measure is part of the reading, not small print to be
   styled away -- it is the sentence that stops the figure above being read
   as a score for the model's thinking. */
.ai-quality-caveat {
  margin: 0; color: var(--ink-3); font-size: var(--text-xs); line-height: 1.6;
}

/* ───────────────────────────────────────────────────── the command palette

   Ctrl/Cmd-K or "/". It sits above everything, is dismissed by Escape or a
   press outside, and never animates its list — the entries here change
   settings, so an item must not move between the keystroke and the Enter. */
.palette-scrim {
  position: fixed; inset: 0; z-index: 900;
  display: flex; justify-content: center; align-items: flex-start;
  padding: max(8vh, 48px) var(--space-4) var(--space-4);
  background: color-mix(in srgb, #000 55%, transparent);
  backdrop-filter: blur(3px);
}
.palette {
  inline-size: min(560px, 100%);
  border-radius: var(--radius-lg, 16px);
  background: var(--s1); border: 1px solid var(--line-strong);
  box-shadow: var(--shadow-md, 0 24px 60px rgba(0, 0, 0, .5));
  overflow: hidden;
}
.palette-field {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-block-end: 1px solid var(--line);
}
.palette-field i { color: var(--ink-3); }
/* The one field in the app that is deliberately chrome-less: the box IS the
   dialog, and a bordered input inside a bordered dialog is two boxes. */
.palette-field input {
  flex: 1; min-inline-size: 0; border: 0; background: none;
  padding: 4px 0; font-size: var(--text-md); color: var(--ink-1);
}
.palette-field input:focus-visible { outline: none; box-shadow: none; }
.palette-list {
  list-style: none; margin: 0; padding: var(--space-2);
  max-block-size: 46vh; overflow-y: auto;
}
.palette-list li {
  display: flex; align-items: center; gap: var(--space-3);
  padding: 10px 12px; border-radius: var(--radius-sm);
  color: var(--ink-2); cursor: pointer;
}
.palette-list li i { color: var(--ink-3); inline-size: 18px; text-align: center; }
/* Keyboard cursor and pointer hover are the SAME state. Two different
   highlights on one list is two answers to "which one will Enter run". */
.palette-list li.is-cursor { background: var(--s2); color: var(--ink-1); }
.palette-list li.is-cursor i { color: var(--gold, var(--ink-1)); }
.palette-empty { margin: 0; padding: var(--space-5); text-align: center;
                 color: var(--ink-3); }
.palette-foot {
  display: flex; gap: var(--space-4); flex-wrap: wrap;
  padding: 10px var(--space-4); border-block-start: 1px solid var(--line);
  color: var(--ink-3); font-size: var(--text-2xs);
}
.palette-foot span { display: inline-flex; align-items: center; gap: 4px; }
kbd {
  display: inline-block; padding: 1px 6px; border-radius: 4px;
  border: 1px solid var(--line-strong); background: var(--s2);
  font-family: var(--font-numeric, ui-monospace, monospace);
  font-size: var(--text-2xs); color: var(--ink-2); line-height: 1.5;
}
/* Touch has no keyboard. The hints are the only part that is useless there;
   the palette itself still opens from the menu. */
@media (hover: none) { .palette-foot { display: none; } }

/* ──────────────────────────── what argues for waiting, and the days like today */

/* Waiting is not a warning. This block exists to slow somebody down, and it
   carries the flag colour rather than the loss colour — nothing here says
   the trade is wrong, only that these things argue for not taking it yet. */
.pretrade-wait {
  margin-block-start: var(--space-4); padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm); background: var(--s2);
  border-inline-start: 2px solid var(--flag);
}
.pretrade-wait h4 {
  margin: 0 0 var(--space-2); font-size: var(--text-2xs);
  text-transform: uppercase; letter-spacing: .1em; color: var(--ink-3);
  font-weight: 600;
}
.pretrade-wait-head { margin: 0 0 var(--space-3); color: var(--ink-1); line-height: 1.55; }
.pretrade-wait ul { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--space-2); }
.pretrade-wait li { display: grid; gap: 2px; }
.pretrade-wait li b { color: var(--ink-1); font-weight: 500; line-height: 1.5; }
/* Every reason states what would end it. A reason to wait with no exit is
   a mood, and this product does not have moods. */
.wait-clears { color: var(--ink-3); font-size: var(--text-2xs); line-height: 1.45; }

.pretrade-twins { margin-block-start: var(--space-4); }
.pretrade-twins h4 {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: var(--space-3); margin: 0 0 var(--space-2);
  font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: .1em;
  color: var(--ink-3); font-weight: 600;
}
/* Matched-of-searched, beside the heading. It is the honest headline for
   this feature: nine days out of eight hundred is the finding. */
.pretrade-twins h4 span {
  font-family: var(--font-numeric, ui-monospace, monospace);
  font-variant-numeric: tabular-nums; color: var(--ink-2); letter-spacing: 0;
}
.twins-table { inline-size: 100%; border-collapse: collapse; }
.twins-table th, .twins-table td {
  padding: 7px 10px; text-align: start; border-block-end: 1px solid var(--line);
  white-space: nowrap;
}
.twins-table th {
  font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-3); font-weight: 600;
}
.twins-table td { color: var(--ink-2); font-variant-numeric: tabular-nums; }

/* ─────────────────────────────────────── the level map grading itself, in public

   Folded shut by default and never hidden. A chart is not the place to
   lecture somebody, but the answer has to be one tap from the lines it is
   about — a grading on a different page is a grading nobody reads before
   placing a stop against one of these levels. */
.level-score { margin-block-start: var(--space-2); }
.level-score-toggle {
  display: flex; align-items: center; gap: var(--space-2); inline-size: 100%;
  padding: 8px 10px; border: 1px dashed var(--line); border-radius: var(--radius-sm);
  background: none; color: var(--ink-3); font: inherit;
  font-size: var(--text-2xs); cursor: pointer; text-align: start;
}
.level-score-toggle span { flex: 1; min-inline-size: 0; }
.level-score-toggle:hover { color: var(--ink-1); border-color: var(--line-strong); }
.level-score-body {
  padding: var(--space-3); margin-block-start: var(--space-2);
  border-radius: var(--radius-sm); background: var(--s2);
}
.level-score-reading { margin: 0 0 var(--space-3); color: var(--ink-1);
                       line-height: 1.6; font-size: var(--text-sm); }
.level-score-arms { list-style: none; margin: 0 0 var(--space-3); padding: 0;
                    display: grid; gap: 2px; }
.level-score-arms li {
  display: grid; grid-template-columns: 1fr auto; gap: 0 var(--space-3);
  align-items: baseline; padding: 7px 10px; border-radius: var(--radius-sm);
  background: var(--s1);
}
/* Every arm is drawn identically. Colouring "ours" differently from the
   control would be arguing for a result the numbers do not support. */
.level-score-arms li b {
  font-family: var(--font-numeric, ui-monospace, monospace);
  font-variant-numeric: tabular-nums; color: var(--ink-1);
}
.level-score-arms li span { color: var(--ink-2); font-size: var(--text-sm); }
.level-score-arms li small { grid-column: 1 / -1; color: var(--ink-3);
                             font-size: var(--text-2xs); }
.level-score-use { margin: 0 0 var(--space-2); color: var(--ink-2);
                   font-size: var(--text-2xs); line-height: 1.55; }

/* The agreement pair, labelled. A percentage beside a proposed entry and stop
   reads as the chance the trade works unless something on screen says what it
   measures — so the label rides the number and the note sits under it. */
.pretrade-against h4 span small {
  color: var(--ink-3); text-transform: uppercase; letter-spacing: .08em;
  font-size: var(--text-2xs); margin-inline-end: 6px;
}
.pretrade-agreement-note {
  margin: 0 0 var(--space-3); color: var(--ink-3);
  font-size: var(--text-2xs); line-height: 1.5;
}

/* ─────────────────────────────────── the four readings that reached no pixel

   Data health, market state, market DNA and personal compatibility were each
   computed on every /api/pre-trade request and rendered by nothing. Three of
   the four are on the owner's own list of signature features. The styles below
   are the second half of wiring them; the first half was two lines in
   setExtra. See docs/FIX-PLAN.md Batch 17. */

/* Data health leads the card because it QUALIFIES everything under it: a
   stale feed does not make the analysis wrong, it makes it unverified. Kept
   to a strip rather than a panel — it has to be seen first, not read first. */
.pretrade-health {
  margin-block-end: var(--space-3); padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm); background: var(--s2);
  border-inline-start: 2px solid var(--up);
}
.pretrade-health.is-degraded { border-inline-start-color: var(--flag); }
.pretrade-health-count {
  font-size: var(--text-2xs); font-weight: 600; color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.pretrade-health-sources {
  display: flex; flex-wrap: wrap; gap: var(--space-2);
  margin: var(--space-2) 0 0; padding: 0; list-style: none;
}
.pretrade-health-sources li {
  display: inline-flex; align-items: baseline; gap: 4px;
  padding: 2px 8px; border-radius: 999px; background: var(--s3, var(--s1));
  font-size: var(--text-2xs); color: var(--ink-2);
}
/* A source's state is named as well as coloured. Colour alone is a claim a
   colour-blind reader cannot check, and "fresh" is the only state that needs
   no word — the other three carry theirs in the markup. */
.pretrade-health-sources li.src-fresh { border: 1px solid color-mix(in srgb, var(--up) 40%, var(--line)); }
.pretrade-health-sources li.src-stale { border: 1px solid var(--flag); }
.pretrade-health-sources li.src-down { border: 1px solid var(--down); }
.pretrade-health-sources li.src-unknown { border: 1px dashed var(--line); }
.pretrade-health-sources li small { color: var(--ink-3); }
.pretrade-health > .pretrade-note { display: block; margin-block-start: var(--space-2); }

.pretrade-mstate, .pretrade-dna, .pretrade-compat {
  margin-block-start: var(--space-4); padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm); background: var(--s2);
  border-inline-start: 2px solid var(--line);
}
.pretrade-mstate h4, .pretrade-dna h4, .pretrade-compat h4 {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--space-2);
  margin: 0 0 var(--space-2); font-size: var(--text-2xs);
  text-transform: uppercase; letter-spacing: .1em; color: var(--ink-3);
  font-weight: 600;
}
.pretrade-mstate h4 b {
  text-transform: none; letter-spacing: 0; font-size: var(--text-sm);
  color: var(--ink-1); font-weight: 650;
}
.pretrade-mstate h4 small { text-transform: none; letter-spacing: 0; color: var(--ink-3); }
.pretrade-mstate-nums { display: flex; gap: var(--space-4); margin-block-end: var(--space-2); }
.pretrade-mstate-nums span {
  display: grid; gap: 1px; font-variant-numeric: tabular-nums;
  color: var(--ink-1); font-weight: 600;
}
.pretrade-mstate-nums small {
  font-size: var(--text-2xs); color: var(--ink-3); font-weight: 400;
  text-transform: uppercase; letter-spacing: .06em;
}
/* The evidence, not the verdict alone. "expansion" by itself is an assertion;
   beside the readings that produced it, it is something you can disagree with. */
.pretrade-mstate ul, .pretrade-dna ul {
  margin: 0; padding: 0; list-style: none; display: grid; gap: var(--space-2);
}
.pretrade-mstate li { color: var(--ink-2); font-size: var(--text-2xs); line-height: 1.5; }
.pretrade-dna-summary { margin: 0 0 var(--space-3); color: var(--ink-1); line-height: 1.55; }
.pretrade-dna li { display: grid; grid-template-columns: 1fr auto; gap: 2px var(--space-3); }
.pretrade-dna li b { color: var(--ink-1); font-weight: 500; }
.pretrade-dna li .pretrade-note,
.pretrade-dna li small { grid-column: 1 / -1; }
/* Every trait carries its own n, on the same line as its value. A number
   here is not readable without it. */
.pretrade-dna li small {
  color: var(--ink-3); font-size: var(--text-2xs);
  font-variant-numeric: tabular-nums;
}

.pretrade-compat-reading { margin: 0 0 var(--space-3); color: var(--ink-1); line-height: 1.55; }
.compat-table { inline-size: 100%; border-collapse: collapse; }
.compat-table th, .compat-table td {
  padding: 6px 10px; text-align: start; border-block-end: 1px solid var(--line);
  white-space: nowrap;
}
.compat-table th {
  font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-3); font-weight: 600;
}
.compat-table td { color: var(--ink-2); font-variant-numeric: tabular-nums; }
.compat-table td small { color: var(--ink-3); }
.compat-table tr.is-current td { color: var(--ink-1); font-weight: 600; }
.compat-table tr.is-current td:first-child small {
  margin-inline-start: 6px; padding: 1px 6px; border-radius: 999px;
  background: var(--s3, var(--s1)); font-weight: 500; text-transform: uppercase;
  letter-spacing: .06em; font-size: var(--text-2xs);
}
.compat-table td.neg { color: var(--down); }

/* The anomaly reading, under "What just happened" — the same question the
   sentences above it answer, given as a number. Renders at zero as well:
   a panel that appears only on excitement teaches its own silence to mean
   "nothing was checked". */
.pretrade-unusual {
  display: grid; gap: 2px; margin: var(--space-3) 0 0;
  padding-block-start: var(--space-2); border-block-start: 1px solid var(--line);
}
.pretrade-unusual b { color: var(--ink-1); font-weight: 550; }
.pretrade-unusual span {
  color: var(--ink-2); font-size: var(--text-2xs);
  font-variant-numeric: tabular-nums;
}
.pretrade-unusual small { color: var(--ink-3); font-size: var(--text-2xs); line-height: 1.45; }

/* The card without a setup. Same panel, different question: "before you take
   it" becomes "the market right now". No blocker chip, no checklist, and the
   readings that were always about the market rather than about a trade. */
.pretrade.is-no-setup { border-color: var(--line); }
.pretrade-no-setup {
  margin: 0 0 var(--space-3); color: var(--ink-3);
  font-size: var(--text-2xs); line-height: 1.5;
}

/* ─────────────────────────────────────────────── the execution page (Batch 21)

   MT5 runs on the customer's own machine, so this page reports a LOCAL state.
   Two design rules carry the honesty position rather than decorating it: a
   missing connector is styled as a neutral state and not an alarm, because it
   is where most customers are most of the time; and the automatic-execution
   row sits directly above the measured expectancy, permanently, because a
   switch that automates trading belongs beside the number saying the edge is
   indistinguishable from zero. */
.exec-body { padding: var(--space-4) var(--space-3) var(--space-8); }
.exec-status { border-inline-start: 3px solid var(--line); }
.exec-status.is-live { border-inline-start-color: var(--up); }
.exec-status.is-down { border-inline-start-color: var(--ink-3); }
.exec-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3); flex-wrap: wrap;
}
.exec-head b { font-size: var(--text-md); color: var(--ink-1); }
.exec-reason { margin: var(--space-3) 0 0; color: var(--ink-2); line-height: 1.55; }
.exec-rows {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--space-3); margin: var(--space-4) 0 0;
}
.exec-rows div { display: grid; gap: 2px; }
.exec-rows dt {
  font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-3);
}
.exec-rows dd {
  margin: 0; color: var(--ink-1); font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.exec-auto { margin-block-start: var(--space-4); }
.exec-auto-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--space-3);
}
.exec-auto-head b { color: var(--ink-1); }
.exec-auto-head span { font-size: var(--text-2xs); color: var(--ink-3); }
.exec-auto h4 {
  margin: var(--space-4) 0 var(--space-2); font-size: var(--text-2xs);
  text-transform: uppercase; letter-spacing: .1em; color: var(--ink-3);
}
/* The number. Deliberately not small, not grey, and not below the fold. */
.exec-measured {
  margin: 0; padding: var(--space-3); border-radius: var(--radius-sm);
  background: var(--s2); border-inline-start: 2px solid var(--flag);
  color: var(--ink-1); line-height: 1.6;
}
.exec-table { inline-size: 100%; border-collapse: collapse; }
.exec-table th, .exec-table td {
  padding: 7px 10px; text-align: start; border-block-end: 1px solid var(--line);
  white-space: nowrap;
}
.exec-table th {
  font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-3); font-weight: 600;
}
.exec-table td { color: var(--ink-2); font-variant-numeric: tabular-nums; }
.exec-setup { margin-block-start: var(--space-4); }
.exec-setup ol { margin: 0 0 var(--space-3); padding-inline-start: var(--space-5); }
.exec-setup li { color: var(--ink-2); line-height: 1.6; margin-block-end: var(--space-2); }

/* ───────────────────────────────────── the dashboard's own section bar (B20)

   Measured cause: the Arabic dashboard renders ~3,750px tall at 1280x900 --
   four screens, with the market readings, the record and the news all below
   the fold.

   Sticky, not fixed, so it scrolls into place under the top nav rather than
   permanently spending vertical space on a phone, where the canvas is already
   the scarce thing.

   NO NEGATIVE MARGINS. The first version bled the bar past the shell padding
   to sit edge-to-edge, and in RTL that clipped the first pill off the right of
   the viewport -- the active one, which is the single item that must always be
   visible. It sits inside the shell now and scrolls within it. */
.dash-nav {
  /* Measured in the browser, not guessed: .top-nav is position:fixed at y=0,
     56px tall, z-index 50. Sticking this to 0 put it UNDERNEATH the top nav --
     it was sticking correctly and was simply invisible, which is the kind of
     bug a screenshot finds and a computed-style check does not. */
  position: sticky; inset-block-start: var(--topnav-h, 56px); z-index: 30;
  display: flex; gap: 10px; overflow-x: auto; overscroll-behavior-x: contain;
  /* Matches .app-shell's own horizontal padding. Measured in the browser:
     with 2px here the bar spanned the full 1280px viewport and the ACTIVE pill
     sat 2px from the right edge in RTL -- visually clipped, and the active one
     is the single item that must always be readable. */
  padding: 12px clamp(16px, 2vw, 32px); margin-block-end: var(--space-4);
  background: color-mix(in srgb, var(--s1) 88%, transparent);
  backdrop-filter: saturate(140%) blur(12px);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  border-block-end: 1px solid color-mix(in srgb, var(--line) 70%, transparent);
  scrollbar-width: none;
}
.dash-nav::-webkit-scrollbar { display: none; }

.dash-nav-item {
  flex: 0 0 auto;
  display: inline-flex; align-items: center;
  min-block-size: 36px; padding: 0 16px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--line) 85%, transparent);
  background: color-mix(in srgb, var(--s2) 60%, transparent);
  color: var(--ink-3);
  font-size: var(--text-2xs); font-weight: 500; letter-spacing: .01em;
  text-decoration: none; white-space: nowrap;
  transition: color .18s ease, border-color .18s ease,
              background .18s ease, box-shadow .18s ease;
}
.dash-nav-item:hover {
  color: var(--ink-1);
  border-color: color-mix(in srgb, var(--gold, var(--ink-2)) 40%, var(--line));
}
/* The active pill carries the one strong colour on this bar. Everything else
   stays quiet, because a row of five loud chips is a row with no answer in it. */
.dash-nav-item.is-active {
  color: var(--ink-1); font-weight: 650;
  background: var(--s2);
  border-color: color-mix(in srgb, var(--gold, var(--ink-2)) 55%, var(--line));
  box-shadow: 0 1px 0 color-mix(in srgb, var(--gold, var(--ink-2)) 45%, transparent) inset,
              0 2px 10px color-mix(in srgb, var(--gold, var(--ink-2)) 12%, transparent);
}
.dash-nav-item:focus-visible {
  outline: 2px solid var(--gold, var(--ink-1)); outline-offset: 2px;
}

/* Zero-height markers above each section, so a jump lands on the heading
   rather than mid-panel and the sticky bar does not cover it. */
/* Clear BOTH bars: the fixed top nav and this sticky one. */
[id^="dash-"] { scroll-margin-block-start: calc(var(--topnav-h, 56px) + 64px); }

@media (pointer: coarse) {
  /* A 36px pill is under the 44px target this product holds itself to
     everywhere else on touch. */
  .dash-nav-item { min-block-size: 44px; padding: 0 18px; }
}
@media (prefers-reduced-motion: reduce) {
  .dash-nav-item { transition: none; }
}

/* ---------------------------------------------------------------------------
   THE PALETTE NAMES THIS APP ACTUALLY HAS.

   Everything below was first written against --ok / --warn / --bad, which are
   the OPERATOR console's names. tokens.css defines them; the customer app does
   not load tokens.css, so in the browser they resolved to the empty string —
   and an empty custom property is not a fallback, it is a dropped declaration.
   Every satisfied condition drew an invisible bar, the caution dot on the
   status strip had no colour at all, and a dissenting expert's border was the
   same as an agreeing one. Nothing threw; it just quietly stopped meaning
   anything, which is the worst way for a status colour to fail.

   The customer app's own names are --success / --warning / --danger (plus
   --up / --down for market direction), and they are what is used from here on.
   ------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
   The auto-execution preflight.

   A checklist, not a form: every row is a statement about this account that is
   either true or not, and an untrue one carries the way to make it true. The
   satisfied rows stay visible rather than collapsing -- "what did I already
   set" is the second question anybody asks here.
   ------------------------------------------------------------------------- */
/* The card itself carries the block spacing; the rows below carry the rest.
   A rendered class with no rule anywhere is a feature shipped as raw HTML,
   which is what tests/test_styles_exist.py exists to catch. */
.preflight { margin-block-start: var(--space-4); }
.preflight-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3); margin-bottom: var(--space-2);
}
.preflight-head h3 { margin: 0; }
.preflight-chip {
  font-size: var(--text-2xs); letter-spacing: 0.04em; text-transform: uppercase;
  padding: 4px 10px; border-radius: 999px; white-space: nowrap;
  border: 1px solid var(--line-strong); color: var(--ink-2);
}
.preflight-chip.ok { color: var(--success); border-color: color-mix(in srgb, var(--success) 45%, transparent); }
.preflight-chip.todo { color: var(--warning); border-color: color-mix(in srgb, var(--warning) 45%, transparent); }

.preflight-list { list-style: none; margin: 0; padding: 0; }
.preflight-list li {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3) 0; border-top: 1px solid var(--line);
}
.preflight-list li:first-child { border-top: 0; }
.preflight-list li > i { font-size: 1.05rem; width: 1.2em; text-align: center; }
.preflight-list li.done > i { color: var(--success); }
.preflight-list li.todo > i { color: var(--warning); }
.preflight-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.preflight-body b { font-size: var(--text-sm); }
.preflight-body small { color: var(--ink-3); font-size: var(--text-2xs); line-height: 1.5; }
.preflight-value { font-family: var(--font-numeric); color: var(--ink-2); font-size: var(--text-sm); }
.preflight-fix { white-space: nowrap; display: inline-flex; align-items: center; gap: var(--space-2); }
.preflight-fix i { font-size: 0.7em; }
body.rtl .preflight-fix i { transform: scaleX(-1); }

.preflight-switch {
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
  margin-top: var(--space-4); padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}
.preflight-blocked { color: var(--ink-3); font-size: var(--text-2xs); }
.preflight-note {
  margin: var(--space-3) 0 0; padding: var(--space-3);
  border-radius: var(--radius-sm); background: var(--s2);
  border-inline-start: 2px solid var(--gold);
  color: var(--ink-2); font-size: var(--text-2xs); line-height: 1.6;
}
.preflight-error { margin: var(--space-2) 0 0; color: var(--danger); font-size: var(--text-2xs); }

/* The connector, one click away. */
.exec-download {
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
  margin: var(--space-3) 0;
}
.exec-download small { color: var(--ink-3); font-size: var(--text-2xs); }
/* A failed download says so on the page. The browser's own "file wasn't
   available" tells the customer nothing they can act on. */
.exec-download-error {
  flex-basis: 100%; margin: 0; color: var(--danger);
  font-size: var(--text-2xs);
}
.exec-run { margin: var(--space-3) 0 var(--space-2); color: var(--ink-2); }
.exec-cmd {
  display: block; padding: 10px 12px; border-radius: var(--radius-sm);
  background: var(--s2); border: 1px solid var(--line);
  font-family: var(--font-numeric, ui-monospace, monospace);
  color: var(--ink-1); font-size: var(--text-2xs); overflow-x: auto;
}

/* The companion: what the app says about an open trade without instructing.
   Quieter than the coach on purpose — the coach gives advice and states its
   cost; this reports, and a report that shouts reads as an alarm. */
.companion { margin-block-end: var(--space-3); }
.companion-now {
  margin: 0 0 var(--space-2); padding: 10px 12px;
  border-radius: var(--radius-sm); background: var(--s2);
  border-inline-start: 2px solid var(--line);
  color: var(--ink-2); font-size: var(--text-2xs); line-height: 1.55;
}
.companion-timeline summary {
  cursor: pointer; color: var(--ink-3); font-size: var(--text-2xs);
  padding: 4px 0;
}
.companion-timeline ul {
  margin: var(--space-2) 0 0; padding-inline-start: var(--space-4);
  display: grid; gap: 4px;
}
.companion-timeline li { color: var(--ink-3); font-size: var(--text-2xs); line-height: 1.5; }
.companion-autopsy p { margin: 0 0 4px; color: var(--ink-2); font-size: var(--text-2xs); }

/* Levels decided in advance. Expired rows stay visible and dimmed rather than
   disappearing: a panel that showed only the ones price reached would be a
   highlight reel, and the untouched ones are most of the honest answer. */
.prepared { margin-block-start: var(--space-4); }
.prepared-table { inline-size: 100%; border-collapse: collapse; }
.prepared-table th, .prepared-table td {
  padding: 7px 10px; text-align: start; border-block-end: 1px solid var(--line);
  white-space: nowrap;
}
.prepared-table th {
  font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-3); font-weight: 600;
}
.prepared-table td { color: var(--ink-2); font-variant-numeric: tabular-nums; }
.prepared-table tr.is-expired td { color: var(--ink-3); opacity: .65; }
.prepared-table tr.is-reached td { color: var(--ink-1); font-weight: 600; }

/* ---------------------------------------------------------------------------
   SCORE PER INDICATOR PER FRAME.

   A grid because the fact IS two-dimensional: RSI on 5m and RSI on the daily
   are not the same reading, and every product that collapses them into "3 of
   7" has thrown away the disagreement that was the information. The bar is a
   DISTANCE (0 to 1), never a probability, and neutral cells are drawn rather
   than dropped -- "saying nothing" is a reading a chair can use.
   ------------------------------------------------------------------------- */
.score-grid { margin-block-start: var(--space-4); }
.score-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--space-3); margin-block-end: var(--space-3);
}
.score-head h3 { margin: 0; }
.score-split {
  font-size: var(--text-2xs); padding: 3px 9px; border-radius: 999px;
  border: 1px solid var(--line-strong); white-space: nowrap;
}
.score-split.wide { color: var(--warning); border-color: color-mix(in srgb, var(--warning) 45%, transparent); }
.score-split.narrow { color: var(--ink-2); }

.score-table { display: flex; flex-direction: column; gap: 6px; }
.score-row { display: grid; grid-template-columns: 4.5rem repeat(auto-fit, minmax(0, 1fr)); gap: 6px; align-items: stretch; }
.score-header .score-cell-head {
  font-size: var(--text-2xs); color: var(--ink-3); text-align: center;
  text-transform: uppercase; letter-spacing: .06em;
}
.score-name {
  font-size: var(--text-2xs); color: var(--ink-2); letter-spacing: .04em;
  display: flex; align-items: center;
}
.score-cell {
  position: relative; overflow: hidden; min-height: 34px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--s2); color: var(--ink-2);
  font-size: var(--text-2xs); cursor: pointer; padding: 0;
  display: flex; align-items: center; justify-content: center;
}
.score-cell b { position: relative; font-weight: 600; letter-spacing: .04em; }
.score-cell.buy { color: var(--up); border-color: color-mix(in srgb, var(--up) 35%, var(--line)); }
.score-cell.sell { color: var(--down); border-color: color-mix(in srgb, var(--down) 35%, var(--line)); }
.score-cell.neutral { color: var(--ink-3); }
.score-cell.empty { background: transparent; border-style: dashed; cursor: default; color: var(--ink-3); }
.score-cell.is-open { border-color: var(--gold); }
.score-bar {
  position: absolute; inset-block: 0; inset-inline-start: 0; inline-size: 100%;
  transform-origin: left center; opacity: .16;
}
/* The LOCAL direction, not the page's. `body.rtl` matched even inside a
   subtree forced to LTR, so the bar grew leftward from an anchor pinned to the
   left edge and a weak reading floated detached from its own cell edge. */
[dir="rtl"] .score-bar, body.rtl .score-table:not([dir="ltr"]) .score-bar {
  transform-origin: right center;
}
.score-cell.buy .score-bar { background: var(--up); }
.score-cell.sell .score-bar { background: var(--down); }
.score-cell.neutral .score-bar { background: var(--ink-3); opacity: .08; }
.score-detail {
  margin: var(--space-3) 0 0; padding: var(--space-3);
  background: var(--s2); border-radius: var(--radius-sm);
  color: var(--ink-2); font-size: var(--text-2xs);
  border-inline-start: 2px solid var(--gold);
}
.score-note { margin: var(--space-3) 0 0; color: var(--ink-3); font-size: var(--text-2xs); line-height: 1.6; }

/* ---------------------------------------------------------------------------
   THE PANEL, ON SCREEN.

   The two things a conclusion alone would hide are given the most room: the
   agreement rate (near 1.0 means the experts are not independent, and the
   whole structure is cost without information) and the dissents, which keep
   their own border rather than being folded into the ruling.
   ------------------------------------------------------------------------- */
.council { margin-block-start: var(--space-4); }
.council-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--space-3); margin-block-end: var(--space-3); flex-wrap: wrap;
}
.council-head h3 { margin: 0 0 2px; }
.council-head small { color: var(--ink-3); font-size: var(--text-2xs); line-height: 1.5; display: block; max-inline-size: 46ch; }
.council-quiet {
  padding: var(--space-4); background: var(--s2); border-radius: var(--radius-sm);
  color: var(--ink-2); font-size: var(--text-sm);
}
.council-quiet p { margin: 0 0 var(--space-2); }
.council-quiet small { display: block; color: var(--ink-3); font-size: var(--text-2xs); margin-block-end: var(--space-3); }
.council-error { color: var(--danger); font-size: var(--text-2xs); }

.council-ruling {
  display: flex; gap: var(--space-4); align-items: flex-start;
  padding: var(--space-4); border-radius: var(--radius-sm);
  background: var(--s2); border: 1px solid var(--line);
}
.council-side { display: flex; flex-direction: column; gap: 2px; min-inline-size: 5.5rem; }
.council-side small { color: var(--ink-3); font-size: var(--text-2xs); }
.council-side b { font-size: var(--text-lg); letter-spacing: .04em; }
.council-side.buy b { color: var(--up); }
.council-side.sell b { color: var(--down); }
.council-side.hold b, .council-side.wait b { color: var(--ink-2); }
.council-reasons { margin: 0; padding-inline-start: 1.1em; color: var(--ink-2); font-size: var(--text-2xs); line-height: 1.6; }

/* When the chair had nothing to add, it says so in one line rather than
   reprinting the analysts. */
.council-agreed { margin: 0; color: var(--ink-3); font-size: var(--text-2xs); line-height: 1.6; }
.council-agreement { margin-block-start: var(--space-3); }
.council-meter {
  block-size: 6px; border-radius: 999px; background: var(--s3); overflow: hidden;
}
.council-meter span { display: block; block-size: 100%; background: var(--gold); }
.council-agreement small { display: block; margin-block-start: 6px; color: var(--ink-3); font-size: var(--text-2xs); line-height: 1.5; }

.council-experts {
  display: grid; gap: var(--space-3); margin-block-start: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.council-card {
  padding: var(--space-3); border-radius: var(--radius-sm);
  background: var(--s1); border: 1px solid var(--line);
}
.council-card.dissent { border-color: color-mix(in srgb, var(--warning) 50%, var(--line)); }
.council-card header { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2); }
.council-card header b { font-size: var(--text-sm); }
.council-frame { font-size: var(--text-2xs); color: var(--ink-3); font-family: var(--font-numeric); }
.council-vote {
  display: inline-block; margin-block: 6px; font-size: var(--text-2xs);
  letter-spacing: .06em; text-transform: uppercase;
}
.council-vote.buy { color: var(--up); }
.council-vote.sell { color: var(--down); }
.council-vote.hold, .council-vote.neutral, .council-vote.wait { color: var(--ink-3); }
.council-card ul { margin: 0; padding-inline-start: 1.05em; color: var(--ink-3); font-size: var(--text-2xs); line-height: 1.55; }
.council-changed, .council-dissent { display: block; margin-block-start: 6px; font-size: var(--text-2xs); }
.council-changed { color: var(--ink-3); }
.council-dissent { color: var(--warning); }
.council-shadow {
  margin: var(--space-4) 0 0; color: var(--ink-3); font-size: var(--text-2xs);
  line-height: 1.6; padding-block-start: var(--space-3); border-block-start: 1px solid var(--line);
}
.score-cell { flex-direction: column; gap: 1px; padding: 4px 2px; }
.score-figure {
  position: relative; font-family: var(--font-numeric); font-size: 0.62rem;
  color: var(--ink-3); line-height: 1;
}

/* ---------------------------------------------------------------------------
   THE TRADING DAY AS ONE STRIP.

   Proportional to the clock, so the eye reads duration as width: Asia is seven
   hours and looks it. The current minute is a hairline rather than a moving
   block -- a marker that covers a session is a marker that hides the thing it
   is pointing at. The measured median range sits inside each window because
   that number is the whole reason this strip is worth its height.
   ------------------------------------------------------------------------- */
/* FULL BLEED, and taller. The shell caps at 1500px, so on a wide monitor the
   day-strip stopped short of the glass with dead ground either side — and at
   42px with two lines of 0.6rem type inside it, it read as a thin empty band
   rather than as the day. It breaks out to the viewport on both sides (both
   margins set, so it is direction-agnostic) and the type inside grows with it.
   `100vw` is the whole viewport including any scrollbar gutter; the parent
   clips instead of the page scrolling sideways. */
.ribbon {
  margin-block: var(--space-3);
  inline-size: 100vw;
  margin-inline-start: calc(50% - 50vw);
  margin-inline-end: calc(50% - 50vw);
  padding-inline: clamp(10px, 2vw, 28px);
  overflow: clip;
}
.ribbon-track {
  position: relative; block-size: 56px; border-radius: var(--radius-sm);
  background: var(--s1); border: 1px solid var(--line); overflow: hidden;
}
.ribbon-seg {
  position: absolute; inset-block: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 1px;
  border-inline-end: 1px solid var(--line);
  background: color-mix(in srgb, var(--gold) 5%, transparent);
  overflow: hidden; padding: 0 2px;
}
.ribbon-seg.london_ny_overlap { background: color-mix(in srgb, var(--gold) 13%, transparent); }
.ribbon-seg.london { background: color-mix(in srgb, var(--gold) 9%, transparent); }
.ribbon-seg.is-quiet { background: transparent; }
.ribbon-seg.is-now {
  background: color-mix(in srgb, var(--gold) 26%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--gold) 55%, transparent);
}
/* A weight difference, not only a tint: at a glance the eye should land on the
   session that is running without having to compare two shades of gold. */
.ribbon-seg.is-now .ribbon-range { color: var(--ink-2); font-weight: 600; }
.ribbon-seg:not(.is-now) .ribbon-label { opacity: .82; }
.ribbon-label {
  font-size: var(--text-xs); color: var(--ink-2); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; max-inline-size: 100%;
}
.ribbon-seg.is-now .ribbon-label { color: var(--ink-1); font-weight: 600; }
.ribbon-range {
  font-family: var(--font-numeric); font-size: var(--text-2xs); color: var(--ink-3);
}
.ribbon-now {
  position: absolute; inset-block: 0; inline-size: 2px; background: var(--gold);
  box-shadow: 0 0 8px color-mix(in srgb, var(--gold) 60%, transparent);
}
.ribbon-cap {
  margin: 0 2px 5px; color: var(--ink-3); font-size: 0.66rem;
  letter-spacing: .04em;
}
/* The live state is the sentence that changes, so it carries the ink; the
   standing fact under it is a footnote and is set as one. */
.ribbon-line {
  margin: 7px 2px 0; color: var(--ink-1); font-size: var(--text-2xs);
  font-weight: 600;
}
.ribbon-foot { margin: 2px 2px 0; color: var(--ink-3); font-size: 0.66rem; line-height: 1.5; }

/* The gate, as a gauge. Rows are numbers the engine already publishes; the
   bar is progress toward a threshold and never a probability of arriving. */
.gate { margin-block-start: var(--space-4); }
.gate-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); }
.gate-head h3 { margin: 0 0 var(--space-3); }
.gate-count { font-family: var(--font-numeric); color: var(--ink-2); font-size: var(--text-sm); }
.gate-rows { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.gate-rows li {
  display: grid; grid-template-columns: minmax(7rem, 1fr) minmax(60px, 2fr) auto;
  gap: var(--space-3); align-items: center;
}
.gate-label { font-size: var(--text-2xs); color: var(--ink-2); }
.gate-bar { block-size: 6px; border-radius: 999px; background: var(--s3); overflow: hidden; }
.gate-bar > span {
  display: block; block-size: 100%; background: var(--ink-3);
  transform-origin: left center; transition: transform .5s var(--ease);
}
body.rtl .gate-bar > span { transform-origin: right center; }
.gate-rows li.met .gate-bar > span { background: var(--success); }
.gate-value { font-family: var(--font-numeric); font-size: var(--text-2xs); color: var(--ink-2); white-space: nowrap; }
.gate-rows li.met .gate-value { color: var(--success); }
.gate-withheld {
  margin: var(--space-3) 0 0; font-size: var(--text-2xs); color: var(--ink-2);
  padding: var(--space-3); background: var(--s2); border-radius: var(--radius-sm);
  border-inline-start: 2px solid var(--warning);
}
.gate-note { margin: var(--space-3) 0 0; color: var(--ink-3); font-size: var(--text-2xs); line-height: 1.6; }

/* ---------------------------------------------------------------------------
   THE STATE, IN THE PLACE THE EYE LANDS FIRST.

   One dot, three states, the same language the Telegram ticket speaks. RED IS
   STAND-ASIDE, not an error: on this product it is the honest state most days,
   so it gets the same weight as the other two rather than an alarm's styling.
   ------------------------------------------------------------------------- */
.strip {
  display: flex; align-items: center; gap: var(--space-3);
  padding: 10px var(--space-4); margin-block: var(--space-3);
  border-radius: var(--radius-md); background: var(--s1);
  border: 1px solid var(--line);
}
.strip-dot {
  inline-size: 10px; block-size: 10px; border-radius: 50%; flex: none;
  box-shadow: 0 0 0 4px color-mix(in srgb, currentColor 16%, transparent);
}
.strip-dot.live { background: var(--up); color: var(--up); }
.strip-dot.caution { background: var(--warning); color: var(--warning); }
.strip-dot.standby { background: var(--down); color: var(--down); }
.strip-word { flex: 1; font-size: var(--text-sm); color: var(--ink-1); font-weight: 600; }
.strip-side.buy { color: var(--up); }
.strip-side.sell { color: var(--down); }
.strip-clock {
  font-family: var(--font-numeric); font-size: var(--text-2xs); color: var(--ink-3);
  white-space: nowrap;
}
.strip-live { border-color: color-mix(in srgb, var(--up) 30%, var(--line)); }
.strip-caution { border-color: color-mix(in srgb, var(--warning) 30%, var(--line)); }

/* The mirror: two columns of the customer's OWN trades. Each carries its n,
   because a rate without a sample size is a sentence pretending to be a
   measurement. */
.mirror { margin-block-start: var(--space-4); }
.mirror h3 { margin: 0 0 var(--space-3); }
.mirror-cols { display: grid; gap: var(--space-3); grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
.mirror-col { padding: var(--space-3); background: var(--s2); border-radius: var(--radius-sm); border: 1px solid var(--line); }
.mirror-col h4 { margin: 0; font-size: var(--text-sm); }
.mirror-col > small { display: block; color: var(--ink-3); font-size: var(--text-2xs); margin-block: 2px var(--space-3); line-height: 1.5; }
.mirror-col dl { margin: 0; display: grid; gap: 6px; }
.mirror-col dl > div { display: flex; justify-content: space-between; gap: var(--space-3); align-items: baseline; }
.mirror-col dt { color: var(--ink-3); font-size: var(--text-2xs); }
.mirror-col dd { margin: 0; font-family: var(--font-numeric); font-size: var(--text-sm); color: var(--ink-1); }
.mirror-col dd.up { color: var(--up); }
.mirror-col dd.down { color: var(--down); }
.mirror-delta { margin: var(--space-3) 0 0; font-size: var(--text-sm); color: var(--ink-2); }
.mirror-delta b { font-family: var(--font-numeric); font-size: var(--text-lg); }
.mirror-delta.up b { color: var(--up); }
.mirror-delta.down b { color: var(--down); }
.mirror-thin { margin: var(--space-3) 0 0; color: var(--ink-3); font-size: var(--text-2xs); line-height: 1.6; }
.mirror-note { margin: var(--space-3) 0 0; color: var(--ink-3); font-size: var(--text-2xs); line-height: 1.6; }

/* The risk ruler. The slider is the question ("stop here or there?"); the two
   figures are the server's answer, and the sentence under them is the server's
   own -- including "rounded DOWN so it never exceeds the % you set", which is
   the reason to trust the number above it. */
.ruler { margin-block-start: var(--space-4); }
.ruler-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap; }
.ruler-head h3 { margin: 0 0 var(--space-3); }
.ruler-sides { display: flex; gap: 6px; }
.ruler-side {
  border: 1px solid var(--line); background: transparent; color: var(--ink-3);
  border-radius: var(--radius-sm); padding: 5px 14px; cursor: pointer;
  font: inherit; font-size: var(--text-2xs); letter-spacing: .05em;
}
.ruler-side.is-on.buy { color: var(--up); border-color: color-mix(in srgb, var(--up) 45%, transparent); }
.ruler-side.is-on.sell { color: var(--down); border-color: color-mix(in srgb, var(--down) 45%, transparent); }
.ruler-prices { display: flex; gap: var(--space-5); flex-wrap: wrap; margin-block-end: var(--space-3); }
.ruler-prices small { display: block; color: var(--ink-3); font-size: var(--text-2xs); }
.ruler-prices b { font-family: var(--font-numeric); font-size: var(--text-md); color: var(--ink-1); }
.ruler-range { inline-size: 100%; accent-color: var(--gold); }
.ruler-out {
  display: flex; gap: var(--space-5); flex-wrap: wrap; align-items: baseline;
  margin-block-start: var(--space-4); padding-block-start: var(--space-3);
  border-block-start: 1px solid var(--line);
}
.ruler-figure small { display: block; color: var(--ink-3); font-size: var(--text-2xs); }
.ruler-figure b { font-family: var(--font-numeric); font-size: var(--text-xl); color: var(--gold-text); }
.ruler-out.is-refused .ruler-figure b { color: var(--ink-3); }
.ruler-note { flex-basis: 100%; margin: 0; color: var(--ink-3); font-size: var(--text-2xs); line-height: 1.6; }
.ruler-problem { margin: var(--space-3) 0 0; color: var(--danger); font-size: var(--text-2xs); }

/* Inside the verdict card the gauge is not a card of its own: a panel nested
   in a panel is two borders saying one thing. */
.gate-inline { margin-block-start: var(--space-3); }
.gate-inline .gate-head h3 { font-size: var(--text-sm); }
.gate-help {
  margin: var(--space-3) 0 0; padding-inline-start: 1.1em;
  color: var(--ink-2); font-size: var(--text-2xs); line-height: 1.6;
}
.mirror-money { display: block; margin-block-start: 6px; color: var(--ink-2); font-size: var(--text-2xs); font-weight: 500; }

/* The glossary. A definition list that opens one term at a time: seventeen
   paragraphs at once is a wall, and a beginner arriving from the chat came for
   exactly one word. */
.glossary { margin-block-start: var(--space-4); }
.glossary > h3 { margin: 0 0 var(--space-2); }
.glossary-list { margin: var(--space-3) 0 0; }
.glossary-list > div { border-block-start: 1px solid var(--line); }
.glossary-list > div:first-child { border-block-start: 0; }
.glossary-list dt > button {
  inline-size: 100%; display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3); background: none; border: 0; cursor: pointer;
  padding: var(--space-3) 0; color: var(--ink-1); font: inherit;
  font-size: var(--text-sm); text-align: start;
}
.glossary-list dt > button i { color: var(--ink-3); font-size: 0.75em; }
.glossary-list > div.is-open dt > button { color: var(--gold-text); }
.glossary-list dd {
  margin: 0 0 var(--space-3); color: var(--ink-2); font-size: var(--text-2xs);
  line-height: 1.75; max-inline-size: 70ch;
}

/* The trade's own shelf life, and how far it has gone against you. Both ride
   the card that already exists: a second progress element with a second
   denominator on one screen is how a dashboard ends up contradicting itself. */
.live-shelf {
  font-family: var(--font-numeric); font-size: var(--text-2xs);
  color: var(--ink-3); white-space: nowrap;
}
.live-shelf.is-near { color: var(--warning); }
.live-adverse {
  margin: var(--space-2) 0 0; color: var(--ink-2); font-size: var(--text-2xs);
  line-height: 1.5;
}
/* The distance to the level, beside the level. Muted and monospace: it is the
   second number on the chip and must not compete with the price itself. */
.key-level-away {
  font-family: var(--font-numeric); font-size: 0.66rem; color: var(--ink-3);
  margin-inline-start: 4px;
}
.key-level.is-watched .key-level-away { color: var(--ink-2); }

/* Three profiles, three records, no ranking. Every interval spans zero, so
   nothing here is highlighted as better — the customer's own row is marked,
   and that is the only emphasis the measurement can carry. */
.style-compare { inline-size: 100%; border-collapse: collapse; margin-block-start: var(--space-3); }
.style-compare th, .style-compare td {
  padding: 7px 8px; text-align: left; border-block-end: 1px solid var(--line);
  font-size: var(--text-2xs); white-space: nowrap;
}
.style-compare th { color: var(--ink-3); text-transform: uppercase; letter-spacing: .06em; font-weight: 600; }
.style-compare td { color: var(--ink-2); font-variant-numeric: tabular-nums; }
.style-compare tr.is-yours td { color: var(--ink-1); background: var(--s2); }
.style-compare b { font-family: var(--font-numeric); }
.style-compare b.inconclusive { color: var(--ink-2); }
.style-compare b.pos { color: var(--up); }
.style-compare b.neg { color: var(--down); }
.style-compare small { display: block; color: var(--ink-3); font-size: 0.62rem; }
/* Inside the auto-execution card the checklist has no chrome of its own. */
.preflight-inline { margin-block-start: var(--space-4); padding-block-start: var(--space-3);
                    border-block-start: 1px solid var(--line); }
.preflight-inline .preflight-head h4 { margin: 0; font-size: var(--text-sm); }
/* Inside the technicals fold the grid is the first half of one card, not a
   card of its own: the fold's question already names it. */
.score-grid-inline { margin-block-end: var(--space-3); }
.score-grid-inline .score-head h4 { margin: 0 0 var(--space-2); font-size: var(--text-sm); }
.ta-raw-label {
  margin: 0 0 var(--space-2); color: var(--ink-3); font-size: 0.66rem;
  letter-spacing: .1em; text-transform: uppercase;
}
/* The two inputs the typed calculator used to own. Secondary to the slider —
   the drag is the question, these are for a level price has not reached. */
.ruler-inputs { display: flex; gap: var(--space-4); flex-wrap: wrap; margin-block-start: var(--space-3); }
.ruler-inputs label { display: flex; flex-direction: column; gap: 3px; }
.ruler-inputs small { color: var(--ink-3); font-size: var(--text-2xs); }
.ruler-inputs input {
  inline-size: 8.5rem; padding: 7px 9px; font: inherit; font-size: var(--text-sm);
  font-family: var(--font-numeric); color: var(--ink-1);
  background: var(--s2); border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.ruler-inputs input:focus-visible { outline: 2px solid var(--focus, var(--gold)); outline-offset: 1px; }
/* The between-sessions band names itself where there is room and shows a dash
   where there is not — never nothing, which reads as a hole in the strip. */
.ribbon-label-short { display: none; color: var(--ink-3); }
@media (max-width: 560px) {
  .ribbon-seg.between .ribbon-label-long { display: none; }
  .ribbon-seg.between .ribbon-label-short { display: inline; }
}

/* Total open exposure. One line, above the card that shows a single trade —
   it is the sentence that changes what a customer does next, so it sits where
   they will read it before they read anything about one position. */
.exposure {
  margin-block: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--s2);
  border: 1px solid var(--line);
  border-inline-start: 3px solid var(--ink-3);
}
.exposure.is-concentrated { border-inline-start-color: var(--warning); }
.exposure-main { display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; }
.exposure-main > b {
  font-family: var(--font-numeric); font-size: var(--text-lg); color: var(--ink-1);
}
.exposure-main > span { color: var(--ink-2); font-size: var(--text-2xs); line-height: 1.5; }
.exposure-money { font-family: var(--font-numeric); color: var(--ink-2); }
.exposure-note {
  margin: var(--space-2) 0 0; color: var(--warning); font-size: var(--text-2xs);
  line-height: 1.6;
}

/* ---------------------------------------------------------------------------
   THE PRIMARY NAVIGATION ON A POINTER DEVICE.

   The five destinations were a phone tab bar and nothing else — `.tab-bar` is
   display:none above 860px and no desktop equivalent existed, so a laptop
   could reach the Chart, the AI page, News and the Journal only by opening the
   overflow kebab. Owner, on his own laptop: "aslan ma f navigation bar".

   Hidden below 861px, where the tab bar owns the job: two primary navigations
   on one screen is the duplication everything else here is being cleared of.
   ------------------------------------------------------------------------- */
.desk-nav { display: none; }
@media (min-width: 861px) {
  .desk-nav {
    display: flex; align-items: center; gap: 2px;
    margin-inline-start: var(--space-5);
    flex: 1; min-inline-size: 0;
  }
  .desk-nav-item {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 8px 12px; border-radius: var(--radius-sm);
    color: var(--ink-2); text-decoration: none; white-space: nowrap;
    font-size: var(--text-sm); line-height: 1;
  }
  .desk-nav-item i { font-size: 0.9em; color: var(--ink-3); }
  .desk-nav-item:hover { background: var(--s2); color: var(--ink-1); }
  .desk-nav-item:hover i { color: var(--gold); }
  /* The current page is named by weight and a rule, not by a filled pill:
     the gold pill is the primary ACTION's clothing on this bar, and a
     destination wearing it reads as a button. */
  .desk-nav-item.is-active {
    color: var(--ink-1); font-weight: 600;
    box-shadow: inset 0 -2px 0 var(--gold);
  }
  .desk-nav-item.is-active i { color: var(--gold); }
  .desk-nav-item:focus-visible { outline: 2px solid var(--focus, var(--gold)); outline-offset: 2px; }
}
/* Narrow laptops: the labels go before the bar wraps or scrolls. */
@media (min-width: 861px) and (max-width: 1100px) {
  .desk-nav-item span { display: none; }
  .desk-nav-item { padding: 8px 10px; }
}

/* ---------------------------------------------------------------------------
   THE MEASURE.

   Typography has one number that is not a matter of taste: a line of 45–90
   characters is read, and a line past about 100 is scanned twice because the
   eye loses its place on the return sweep. Measured on the owner's own laptop
   at 1920, the dashboard was running 180-character lines — and the session
   strip's footnote, which inherits the full-bleed width, reached 352.

   This is what "not responsive on a laptop" actually was: nothing overflowed,
   nothing scrolled sideways, every card simply grew until its prose was
   unreadable. Cards keep their width — the figures, tables and rails want it
   — and only the PROSE inside them is bounded.

   ch is the right unit here because it tracks the font: a card that later
   sets smaller text keeps the same number of characters per line rather than
   silently widening.
   ------------------------------------------------------------------------- */
.gate-note,
.gate-help li,
.gate-withheld,
.mirror-note,
.mirror-thin,
.score-note,
.score-detail,
.council-shadow,
.council-head small,
.council-quiet p,
.preflight-body small,
.preflight-note,
.exposure-note,
.ruler-note,
.live-adverse,
.pretrade-note,
.pretrade-wait li,
.patience-cadence,
.measured-caveat,
.journal-note,
.explain-headline,
.ribbon-cap,
.ribbon-line,
.ribbon-foot,
.glossary-list dd,
.no-trade li,
.pretrade-unusual small,
.pretrade-unusual p,
.scenario-evidence li,
.patience-line span,
.gold-units-cap {
  max-inline-size: 78ch;
}

/* The strip runs edge to edge on purpose; its SENTENCES must not. Without
   this the footnote under a full-bleed band measured 352 characters — the
   worst line in the product, created by the fix that made the band full
   width. */
.ribbon-cap, .ribbon-line, .ribbon-foot { margin-inline-end: auto; }

/* THE BAR NEEDS NO ALIGNMENT RULE, and measuring is what proved it.
   `.top-nav` already begins at the shell's left edge, so its plain 16px inner
   padding lands the wordmark 4px from the first card at 390, 509, 861, 1366
   and 1920 alike. The 210px gap I set out to close was mine: the first
   attempt's `calc((100vw - 1760px)/2 …)` pushed it there, and the second
   attempt made it worse because `100%` inside a position:fixed element
   resolves against the VIEWPORT while the element itself starts at the
   container's edge — the two were being added together.

   Left with no rule at all. The measurement that would have prevented both
   attempts took ninety seconds and is written down here so it is not
   attempted a third time. */
