/* MinJi dashboard — Korean school-uniform theme.
   Navy blazer, white shirt, ribbon red, brass badge.

   The CHROME is allowed to be bright and playful. The DATA marks are not:
   thin strokes, hairline solid grids, washes rather than saturated
   blocks. Data colours below are measured, not picked by eye —
   blue<->red separates 3x better than green<->red under CVD
   (deuteranopia dE 21.6 vs 7.2), so profit is navy and loss is red, and
   every figure carries an explicit sign as secondary encoding. */

:root {
  /* Uniform chrome */
  --navy:        #1b2a54;
  --navy-deep:   #142040;
  --navy-soft:   #2c3f73;
  --ribbon:      #d8344a;
  --ribbon-ink:  #c22a40;  /* 5.68:1 on white — safe as text */
  --brass:       #f0b429;

  /* Surfaces & ink */
  --plane:       #eef1f8;
  --surface:     #ffffff;
  --ink:         #0f172a;  /* 17.85:1 */
  --ink-2:       #475569;  /* 7.58:1  */
  --muted:       #64748b;  /* 4.76:1  */
  --grid:        #e2e8f0;
  --rule:        #cbd5e1;
  --hairline:    rgba(15, 23, 42, 0.10);

  /* Data — diverging: profit (blue) <-> loss (red), neutral midpoint */
  --profit:      #2a78d6;
  --profit-ink:  #1d5fae;
  --profit-100:  #cde2fb;
  --profit-200:  #9ec5f4;
  --profit-300:  #5598e7;
  --profit-400:  #256abf;
  --loss:        #d03b3b;
  --loss-ink:    #c22a40;
  --loss-100:    #fbd9d9;
  --loss-200:    #f2a9a9;
  --loss-300:    #e37272;
  --loss-400:    #d03b3b;
  --neutral:     #eef1f8;

  /* In-cell label ink, measured per step against that step's own fill —
     a luminance rule of thumb gets this wrong (white measures 2.99:1 on
     the light 300). Every pair below clears 4.5:1. The mapping is NOT
     the same shape in dark mode, which is why it lives in a variable
     rather than a `step === 400` test in the chart code. */
  --profit-100-ink: #0b1220;  /* 14.15 */
  --profit-200-ink: #0b1220;  /* 10.47 */
  --profit-300-ink: #0b1220;  /*  6.27 */
  --profit-400-ink: #ffffff;  /*  5.39 */
  --loss-100-ink:   #0b1220;  /* 14.29 */
  --loss-200-ink:   #0b1220;  /*  9.83 */
  --loss-300-ink:   #0b1220;  /*  6.17 */
  --loss-400-ink:   #ffffff;  /*  4.80 */

  /* Single-series line colour. Kept separate from --navy: --navy is
     chrome (topbar, pressed buttons) and must stay dark in both themes,
     while a data line has to invert or it vanishes (navy measures
     1.16:1 on the dark surface). */
  --series-1:    #1b2a54;
  --sel-bg:      #1b2a54;   /* pressed segmented button */
  --sel-ink:     #ffffff;
  --tip-bg:      #142040;
  --tip-ink:     #ffffff;
  --mark-ring:   #ffffff;   /* 2px ring separating overlapping marks */

  /* Status (reserved — never used as a series colour) */
  --good:        #0ca30c;
  --warning:     #fab219;
  --critical:    #d03b3b;

  --r:   14px;
  --r-s: 9px;
  --sans: system-ui, -apple-system, "Segoe UI", "Noto Sans Thai", sans-serif;
}

/* ── Dark theme ───────────────────────────────────────────────────
   Selected, not flipped. Every data step below was measured against
   the dark surface rather than derived from the light one, and the
   label-ink mapping comes out INVERTED: on white, steps 100-300 take
   dark ink and 400 takes white; on the dark surface, 100-300 take
   white and 400 takes dark ink. An automatic inversion would have put
   white on profit-400, which measures 2.96:1 and fails.

   The blazer chrome (navy topbar, white text) is already dark and is
   deliberately left alone — it is what makes the two themes read as
   the same product.

   data-theme is always present: an inline script in <head> stamps it
   from localStorage, falling back to prefers-color-scheme, before the
   first paint. That keeps the palette defined exactly once — a
   @media(prefers-color-scheme) block would have to repeat all 30
   values and could then drift out of step with this one — and it also
   avoids the white flash a body-end script would cause. */
:root[data-theme="dark"] {
  --plane:       #0b1120;
  --surface:     #16203a;
  --ink:         #e8eefc;  /* 13.88 on surface */
  --ink-2:       #b3c0da;
  --muted:       #8b9ab8;  /* 5.24 on surface */
  --grid:        #26314f;
  --rule:        #35426a;
  --hairline:    rgba(232, 238, 252, 0.12);

  --profit:      #4d9ae8;
  --profit-ink:  #7ab3f0;  /* used as text and as grid-level rules */
  --profit-100:  #1c3457;
  --profit-200:  #24507f;
  --profit-300:  #2f74b8;
  --profit-400:  #4d9ae8;
  --loss:        #e26a63;
  --loss-ink:    #f08b84;
  --loss-100:    #40202c;
  --loss-200:    #6e2e34;
  --loss-300:    #a8413f;
  --loss-400:    #e26a63;
  --neutral:     #1a2440;

  --profit-100-ink: #ffffff;  /* 12.51 */
  --profit-200-ink: #ffffff;  /*  8.30 */
  --profit-300-ink: #ffffff;  /*  4.87 */
  --profit-400-ink: #0b1220;  /*  6.33 */
  --loss-100-ink:   #ffffff;  /* 14.37 */
  --loss-200-ink:   #ffffff;  /*  9.98 */
  --loss-300-ink:   #ffffff;  /*  6.01 */
  --loss-400-ink:   #0b1220;  /*  5.77 */

  --series-1:    #5598e7;   /* 5.40 on surface */
  --sel-bg:      #4d9ae8;
  --sel-ink:     #0b1220;
  --tip-bg:      #f2f5fd;
  --tip-ink:     #0f172a;
  --mark-ring:   #16203a;   /* the ring is the surface, whatever it is */
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* The UA rule for [hidden] is display:none at element specificity, so any
   class that sets display — .page (flex), .kv (grid) — silently beats it
   and the attribute stops hiding anything. Routing sets .hidden on page
   sections, so this has to win. */
[hidden] { display: none !important; }

body {
  font-family: var(--sans);
  background: var(--plane);
  color: var(--ink);
  font-size: 14px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

.mono { font-variant-numeric: tabular-nums; }
.muted { color: var(--muted); }
.r { text-align: right; }

/* ── Top bar: navy blazer with a tartan ribbon edge ───────────── */

.topbar {
  display: flex;
  align-items: center;
  gap: 22px;
  padding: 12px 22px;
  background: linear-gradient(180deg, var(--navy-soft), var(--navy));
  color: #fff;
  position: sticky;
  top: 0;
  z-index: 50;
  flex-wrap: wrap;
  border-bottom: 3px solid var(--ribbon);
}
/* Tartan: navy + ribbon + brass threads, kept faint so it reads as
   fabric rather than noise behind the text. */
.topbar::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.16;
  background:
    repeating-linear-gradient(45deg, transparent 0 13px, rgba(255,255,255,.5) 13px 15px),
    repeating-linear-gradient(-45deg, transparent 0 21px, var(--ribbon) 21px 24px),
    repeating-linear-gradient(90deg, transparent 0 34px, var(--brass) 34px 36px);
}
.topbar > * { position: relative; }

.brand { display: flex; align-items: center; gap: 11px; }
.crest {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border-radius: 10px;
  background: var(--brass);
  color: var(--navy-deep);
  font-weight: 800;
  font-size: 18px;
  box-shadow: inset 0 0 0 2px rgba(255,255,255,.55);
}
.brand-text { display: flex; flex-direction: column; line-height: 1.15; }
.brand-text b { font-size: 17px; letter-spacing: .3px; }
.brand-text small { font-size: 11px; opacity: .75; }

.tabs { display: flex; gap: 4px; flex-wrap: wrap; }
.tabs a {
  color: rgba(255,255,255,.8);
  text-decoration: none;
  padding: 7px 15px;
  border-radius: 999px;
  font-weight: 600;
  font-size: 13.5px;
  white-space: nowrap;
}
.tabs a:hover { background: rgba(255,255,255,.13); color: #fff; }
.tabs a.on { background: #fff; color: var(--navy); }

.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 12px; }
.pill {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 13px; border-radius: 999px;
  font-size: 12.5px; font-weight: 600;
  background: rgba(255,255,255,.15);
}
.pill .dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; }
.pill-live { background: rgba(255,255,255,.95); color: #0a7a34; }
.pill-down { background: var(--ribbon); color: #fff; }
.pill-idle { color: rgba(255,255,255,.85); }
.refresh { font-size: 11.5px; opacity: .7; font-variant-numeric: tabular-nums; }

/* ── Layout ───────────────────────────────────────────────────── */

main { max-width: 1180px; margin: 0 auto; padding: 22px 18px 60px; }
.page { display: flex; flex-direction: column; gap: 16px; }

.card {
  background: var(--surface);
  border-radius: var(--r);
  padding: 18px;
  box-shadow: 0 1px 2px rgba(15,23,42,.06), 0 0 0 1px var(--hairline);
}
.card-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 14px;
}
.card-head h2 { font-size: 14px; font-weight: 700; color: var(--ink); }
.card-label {
  font-size: 11px; font-weight: 600; color: var(--muted);
  letter-spacing: .04em; text-transform: uppercase;
}

.hero-row { display: grid; grid-template-columns: minmax(260px, 1fr) 2fr; gap: 16px; }
.hero-card { display: flex; flex-direction: column; justify-content: center; }
/* Proportional figures on the hero — tabular makes big numbers loose. */
.hero-figure { font-size: 44px; font-weight: 700; letter-spacing: -1px; line-height: 1.1; margin-top: 4px; }
/* The verdict is a word, not a figure. 44px is tuned for digits like
   "$2,916.76" — set Thai text at that size and it shouts, and the
   negative letter-spacing that tightens numerals crowds the glyphs. */
.verdict-figure {
  font-size: 26px; font-weight: 700; line-height: 1.25;
  letter-spacing: 0; margin-top: 4px;
}
.hero-sub { display: flex; gap: 12px; font-size: 12.5px; color: var(--ink-2); margin-top: 6px; flex-wrap: wrap; }

.kpi-row { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
.kpi-row-wide { grid-template-columns: repeat(4, 1fr); }
.stat-value { font-size: 24px; font-weight: 700; margin-top: 2px; }
.stat-sub { font-size: 11.5px; color: var(--muted); margin-top: 2px; }
.pos { color: var(--profit-ink); }
.neg { color: var(--loss-ink); }

.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }

/* ── Filters ──────────────────────────────────────────────────── */

.filter-row { display: flex; align-items: center; gap: 12px; }
.filter-label { font-size: 12px; font-weight: 600; color: var(--ink-2); }
.segmented {
  display: inline-flex; background: var(--surface);
  border-radius: 999px; padding: 3px;
  box-shadow: 0 0 0 1px var(--hairline);
}
.segmented button {
  border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 12.5px; font-weight: 600;
  /* --muted measures 4.41:1 on the segmented track, just under the
     4.5:1 floor. The unselected options in a control are still text
     the reader has to compare against the selected one, so they get
     --ink-2 (6.70:1). Applies to every toggle on the dashboard. */
  color: var(--ink-2); padding: 6px 15px; border-radius: 999px;
}
.segmented button:hover { color: var(--navy); background: var(--plane); }
.segmented button.on { background: var(--sel-bg); color: var(--sel-ink); }

.ghost-btn {
  border: 0; background: var(--plane); cursor: pointer;
  font: inherit; font-size: 12px; font-weight: 600; color: var(--ink-2);
  padding: 5px 12px; border-radius: 999px;
}
.ghost-btn:hover { background: var(--grid); color: var(--navy); }

/* Theme toggle sits on the navy blazer in both themes, so it is styled
   against the topbar rather than against the surface. */
.theme-btn {
  display: inline-flex; align-items: center; gap: 6px;
  border: 0; cursor: pointer; font: inherit;
  font-size: 12.5px; font-weight: 600;
  color: rgba(255,255,255,.9);
  background: rgba(255,255,255,.15);
  padding: 6px 13px; border-radius: 999px;
  white-space: nowrap;
}
.theme-btn:hover { background: rgba(255,255,255,.26); color: #fff; }
.theme-btn:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }

/* Controls that live inside a card head rather than a filter row. */
.head-tools { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.segmented.small button { font-size: 11.5px; padding: 4px 11px; }
.chart-note {
  font-size: 11.5px; color: var(--muted);
  margin: -8px 0 10px;
}

/* ── Charts ───────────────────────────────────────────────────── */

.chart { width: 100%; height: 260px; position: relative; }
/* The grid chart carries a right-hand label gutter and 7 level rules,
   so it gets more vertical room than the plain equity line. */
.chart-tall { height: 320px; }
.level-buy  { stroke: var(--profit); }
.level-sell { stroke: var(--loss); }
.level-label { font-size: 10px; font-weight: 600; font-variant-numeric: tabular-nums; }
.chart svg { display: block; width: 100%; height: 100%; overflow: visible; }
.chart-empty { display: grid; place-items: center; height: 100%; color: var(--muted); font-size: 13px; }
.gridline { stroke: var(--grid); stroke-width: 1; }
.axis-text { fill: var(--muted); font-size: 10.5px; font-variant-numeric: tabular-nums; }
.crosshair { stroke: var(--rule); stroke-width: 1; }

.table-view { max-height: 300px; overflow: auto; }

/* ── Position & meters ────────────────────────────────────────── */

.pos-head { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.pos-size { font-size: 26px; font-weight: 700; }
.tag {
  font-size: 11.5px; font-weight: 700; letter-spacing: .04em;
  padding: 3px 11px; border-radius: 999px;
}
.tag-long  { background: var(--profit-100); color: var(--profit-ink); }
.tag-short { background: var(--loss-100);   color: var(--loss-ink); }
.tag-flat  { background: var(--plane);      color: var(--muted); }
.tag-read  { background: var(--plane);      color: var(--ink-2); }

.kv { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px 18px; }
.kv > div { display: flex; flex-direction: column; gap: 2px; }
.kv span:last-child { font-size: 15px; font-weight: 600; }

.meters { display: flex; flex-direction: column; gap: 14px; }
.meter-top { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 5px; }
.track { height: 8px; border-radius: 999px; background: var(--plane); overflow: hidden; }
.track i { display: block; height: 100%; border-radius: 999px; background: var(--profit-300); transition: width .3s; }
.track i.warn { background: var(--warning); }
.track i.crit { background: var(--critical); }
.regime {
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--grid);
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
}
.regime b { font-size: 15px; }

/* ── Tables ───────────────────────────────────────────────────── */

.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th {
  text-align: left; font-size: 11px; font-weight: 600; color: var(--muted);
  text-transform: uppercase; letter-spacing: .04em;
  padding: 0 10px 8px; border-bottom: 1px solid var(--grid); white-space: nowrap;
}
td { padding: 8px 10px; border-bottom: 1px solid var(--grid); font-variant-numeric: tabular-nums; white-space: nowrap; }
tr:last-child td { border-bottom: 0; }
.stats-table td:first-child { color: var(--ink-2); font-variant-numeric: normal; }
.stats-table td:last-child { text-align: right; font-weight: 600; }
.empty { color: var(--muted); text-align: center; padding: 22px 0; font-size: 13px; }
.note { font-size: 12px; color: var(--muted); margin-bottom: 12px; line-height: 1.6; }
.note code { background: var(--plane); padding: 1px 6px; border-radius: 5px; font-size: 11.5px; }
.side-buy  { color: var(--profit-ink); font-weight: 600; }
.side-sell { color: var(--loss-ink);   font-weight: 600; }
.backfill-mark { color: var(--muted); cursor: help; }

/* ── P&L calendar ─────────────────────────────────────────────── */

.cal-head { flex-wrap: wrap; }
.month-nav { display: flex; align-items: center; gap: 12px; }
.month-nav b { font-size: 14px; min-width: 132px; text-align: center; }
.cal-summary { display: flex; gap: 22px; flex-wrap: wrap; margin-bottom: 14px; font-size: 13px; }
.cal-summary b { font-size: 17px; }

.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.cal-dow { font-size: 10.5px; font-weight: 600; color: var(--muted); text-align: center; padding-bottom: 2px; }
.cal-cell {
  aspect-ratio: 1 / 1;
  border-radius: var(--r-s);
  background: var(--neutral);
  padding: 6px 7px;
  display: flex; flex-direction: column; justify-content: space-between;
  cursor: default;
  min-height: 54px;
}
.cal-cell.blank { background: transparent; }
.cal-cell .d { font-size: 10.5px; font-weight: 600; opacity: .85; font-variant-numeric: tabular-nums; }
.cal-cell .v { font-size: 11.5px; font-weight: 700; font-variant-numeric: tabular-nums; }
.cal-cell.today { box-shadow: 0 0 0 2px var(--brass); }
.cal-cell:hover { filter: brightness(.96); }

.cal-legend { display: flex; align-items: center; gap: 10px; margin-top: 14px; font-size: 11.5px; }
.cal-legend .scale { display: flex; gap: 3px; }
.cal-legend .scale i { width: 22px; height: 10px; border-radius: 3px; display: block; }

/* ── Tooltip ──────────────────────────────────────────────────── */

.tip {
  position: fixed; z-index: 99; pointer-events: none;
  background: var(--tip-bg); color: var(--tip-ink);
  padding: 9px 12px; border-radius: var(--r-s);
  font-size: 12px; line-height: 1.5;
  box-shadow: 0 6px 20px rgba(15,23,42,.28);
  max-width: 260px;
}
.tip .tip-v { font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums; }
.tip .tip-k { opacity: .72; font-size: 11px; }
.tip .key { display: inline-block; width: 12px; height: 2px; border-radius: 2px; vertical-align: middle; margin-right: 6px; }

@media (max-width: 900px) {
  .hero-row, .two-col { grid-template-columns: 1fr; }
  .kpi-row, .kpi-row-wide { grid-template-columns: repeat(2, 1fr); }
  .topbar { gap: 12px; }
  .topbar-right { width: 100%; margin-left: 0; }
  .hero-figure { font-size: 36px; }
  .verdict-figure { font-size: 22px; }
}

/* ── Login gate ───────────────────────────────────────────────── */

.login-gate {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
  /* Opaque, not translucent: a blurred-but-readable dashboard behind a
     login form still shows the numbers it is meant to be gating. */
  background: var(--plane);
}
.login-card {
  width: 100%; max-width: 360px; text-align: center;
  display: flex; flex-direction: column; gap: 10px;
}
.login-crest {
  width: 44px; height: 44px; margin: 0 auto 4px;
  display: grid; place-items: center; border-radius: 12px;
  background: var(--brass); color: var(--navy-deep);
  font-weight: 800; font-size: 22px;
}
.login-card h2 { font-size: 20px; color: var(--ink); }
.login-sub { font-size: 12.5px; color: var(--muted); margin-bottom: 6px; }
.login-label {
  font-size: 11px; font-weight: 600; color: var(--muted);
  letter-spacing: .04em; text-transform: uppercase; text-align: left;
}
.login-input {
  font: inherit; font-size: 15px; padding: 10px 12px;
  border-radius: var(--r-s); border: 0;
  background: var(--plane); color: var(--ink);
  box-shadow: 0 0 0 1px var(--rule);
}
.login-input:focus {
  outline: none; box-shadow: 0 0 0 2px var(--navy);
}
.login-btn {
  font: inherit; font-size: 14px; font-weight: 700; cursor: pointer;
  border: 0; border-radius: var(--r-s); padding: 11px 16px;
  background: var(--navy); color: #fff;
}
.login-btn:hover { background: var(--navy-deep); }
.login-btn[disabled] { opacity: .6; cursor: default; }
.login-error {
  font-size: 12.5px; color: var(--loss-ink); margin-top: 2px;
}

/* ── Order ticket ─────────────────────────────────────────────── */

.order-grid {
  display: grid; grid-template-columns: 150px 1fr;
  gap: 8px 12px; align-items: center; margin-bottom: 10px;
}
.order-grid .login-label { text-align: left; }
.confirm-summary {
  font-size: 17px; font-weight: 700; color: var(--ink);
  background: var(--plane); border-radius: var(--r-s);
  padding: 12px; margin: 6px 0; word-break: break-word;
}
@media (max-width: 700px) {
  .order-grid { grid-template-columns: 1fr; gap: 4px; }
}

/* ── Options: strategy picker ─────────────────────────────────────
   Eight tiles, one per play. The tile states the market view in words
   because that is the question the operator actually has; the mechanism
   name ("call credit spread") is the answer, not the prompt.

   Selection is carried by border weight, background and an explicit
   aria-selected — not by colour alone, so the picker still reads under
   CVD and in forced-colors. */

.strat-grid {
  display: grid; gap: 10px;
  grid-template-columns: repeat(4, 1fr);
}
.strat {
  display: flex; flex-direction: column; gap: 6px;
  padding: 12px; text-align: left; cursor: pointer;
  background: var(--surface); color: var(--ink);
  border: 1.5px solid var(--rule); border-radius: var(--r-s);
  font: inherit; transition: border-color .12s, background .12s;
}
.strat:hover:not([disabled]) { border-color: var(--navy-soft); background: var(--plane); }
.strat.on {
  border-color: var(--navy); border-width: 2px;
  background: var(--plane); padding: 11.5px;   /* hold size as the border grows */
}
.strat[disabled] { opacity: .45; cursor: default; }

.strat-head { display: flex; align-items: center; gap: 8px; }
.strat-icon {
  width: 22px; height: 22px; flex: none;
  display: grid; place-items: center;
  border-radius: 6px; font-size: 13px; font-weight: 700;
}
/* Direction glyphs use the diverging pair the charts use: up is the
   profit hue, down is the loss hue. They are arrows first — the colour
   repeats what the shape already says. */
/* Ink measured against the 100 step itself, not against the surface:
   --profit-ink on --profit-100 is 4.33:1 in light mode, which fails at
   this size. The design system already names the passing pair. */
.strat-icon.bull { background: var(--profit-100); color: var(--profit-100-ink); }
.strat-icon.bear { background: var(--loss-100); color: var(--loss-100-ink); }
.strat-name { font-size: 13.5px; font-weight: 700; line-height: 1.25; }
.strat-view { font-size: 12px; color: var(--ink-2); line-height: 1.4; flex: 1; }
.strat-foot { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.strat-count { font-size: 11px; color: var(--muted); margin-left: auto; }

/* These pills sit on a light surface, unlike the topbar ones. */
.strat .pill, .play .pill {
  padding: 2px 8px; font-size: 10.5px; font-weight: 700;
  background: var(--neutral); color: var(--ink-2);
}
.pill-credit { background: var(--profit-100); color: var(--profit-100-ink); }
.pill-debit  { background: var(--neutral);    color: var(--ink-2); }
.pill-favoured { background: var(--brass); color: #3a2a00; }
.pill-warn { background: var(--loss-100); color: var(--loss-100-ink); }
.pill-ok   { background: var(--profit-100); color: var(--profit-100-ink); }

/* ── Options: candidate cards ─────────────────────────────────────
   A spread has two legs and a shape; neither fits a table cell. The
   card leads with the picture and the four figures that decide the
   trade, and spells the legs out underneath in the exact form that
   will be submitted. */

/* List on the left, the selected candidate on the right. The list is
   sized to hold six rows without scrolling, because scrolling to
   compare defeats the point of putting them in one column. */
.play-picker {
  display: grid; grid-template-columns: minmax(210px, 260px) minmax(0, 1fr);
  gap: 16px; align-items: start;
}
/* The list is shorter than the detail panel beside it, and on a tall
   page that leaves the column stranded once you scroll to the bottom
   of the chart. Sticking it to the top keeps the other candidates
   reachable while the detail is being read, which is the whole point
   of putting them side by side. */
.play-rows {
  display: grid; gap: 6px; align-content: start;
  position: sticky; top: 16px;
  /* Fifteen rows is taller than many viewports, and a sticky element
     taller than the screen pins in place with its last rows permanently
     out of reach. Capping it to the viewport and letting it scroll
     internally keeps every candidate reachable. */
  max-height: calc(100vh - 32px);
  overflow-y: auto;
  padding-right: 2px;   /* room for the scrollbar, so rows keep their width */
}
.play-row {
  display: grid; gap: 3px; padding: 9px 11px; text-align: left;
  cursor: pointer; font: inherit; color: var(--ink);
  background: var(--surface);
  border: 1.5px solid var(--rule); border-radius: var(--r-s);
  transition: border-color .12s, background .12s;
}
.play-row:hover { border-color: var(--navy-soft); background: var(--plane); }
.play-row.on {
  border-color: var(--navy); border-width: 2px;
  background: var(--plane); padding: 8.5px 10.5px;   /* hold size */
}
.play-row-top { display: flex; align-items: center; gap: 7px; }
.play-rank {
  flex: none; width: 17px; height: 17px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 10px; font-weight: 700;
  background: var(--neutral); color: var(--ink-2);
}
.play-rank.best { background: var(--brass); color: #3a2a00; }
.play-row-name {
  font-size: 12.5px; font-weight: 700;
  font-variant-numeric: tabular-nums; overflow-wrap: anywhere;
}
.play-row-bot {
  display: flex; align-items: baseline; gap: 8px;
  font-size: 11px; color: var(--ink-2); padding-left: 24px;
}
.play-row-money { margin-left: auto; font-weight: 700; font-variant-numeric: tabular-nums; }
.play-row-money.pos { color: var(--profit-ink); }
.play-row-money.neg { color: var(--loss-ink); }
.play-row-odds {
  font-variant-numeric: tabular-nums; font-weight: 600;
  flex: none; min-width: 30px; text-align: right;
}

.play-detail {
  border: 1px solid var(--rule); border-radius: var(--r-s);
  padding: 14px; background: var(--surface); min-width: 0;
}
.play-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.play-title { font-size: 16px; font-weight: 700; font-variant-numeric: tabular-nums; }
.play-sub { font-size: 12px; color: var(--muted); }
.play-tags { margin-left: auto; display: flex; gap: 6px; flex-wrap: wrap; }

.play-chart { height: 300px; min-width: 0; margin: 12px 0; }
.play-figs {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 10px; margin-bottom: 12px;
}
.play-fig {
  background: var(--plane); border-radius: var(--r-s); padding: 9px 11px;
}
.play-fig-v {
  font-size: 19px; font-weight: 700; margin-top: 1px;
  font-variant-numeric: tabular-nums;
}
.play-fig-v.pos { color: var(--profit-ink); }
.play-fig-v.neg { color: var(--loss-ink); }
/* --muted is 4.76:1 on the surface but only 4.21:1 on --plane, which
   is what this sits on. Same trap the calendar's no-trade cell hit. */
.play-fig-s { font-size: 11px; color: var(--ink-2); margin-top: 1px; }

.play-legs { display: grid; gap: 5px; margin-top: 4px; }
.leg, .ticket-leg {
  display: flex; align-items: center; gap: 9px;
  font-size: 12.5px; padding: 6px 9px;
  background: var(--plane); border-radius: 6px;
}
.leg-side {
  flex: none; min-width: 34px; text-align: center;
  padding: 1px 7px; border-radius: 5px;
  font-size: 11px; font-weight: 700;
}
/* Buy and sell repeat the diverging pair, and the word is always there
   — the colour is never the only thing saying which way the leg goes. */
.leg-side.buy  { background: var(--profit-100); color: var(--profit-100-ink); }
.leg-side.sell { background: var(--loss-100);   color: var(--loss-100-ink); }
.leg-name {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 11.5px; color: var(--ink-2); overflow-wrap: anywhere;
}
.leg-px { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--muted); flex: none; }
.leg-order {
  flex: none; width: 18px; height: 18px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--navy); color: #fff; font-size: 10.5px; font-weight: 700;
}
.play-note { font-size: 11.5px; color: var(--muted); margin-top: 8px; line-height: 1.5; }
.play-btn { margin-top: 12px; width: auto; padding: 9px 20px; }

.order-legs { display: grid; gap: 6px; margin-bottom: 12px; }
/* The confirm dialog lists one leg per line and must keep them apart. */
.confirm-summary { white-space: pre-line; }

@media (max-width: 1000px) {
  .strat-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 860px) {
  /* Stack: the list becomes a horizontal strip above the detail.
     It must also stop being sticky — a horizontally scrolling strip
     pinned to the top of the viewport covers the content below it.
     This override lives here, after the base rule, because a media
     query adds no specificity and would otherwise lose to it. */
  .play-picker { grid-template-columns: 1fr; }
  .play-rows {
    position: static; max-height: none; overflow-y: visible;
    grid-auto-flow: column; grid-auto-columns: minmax(180px, 1fr);
    overflow-x: auto; padding-bottom: 4px;
  }
  .play-figs { grid-template-columns: 1fr 1fr; }
  .play-chart { height: 230px; }
}
@media (max-width: 460px) {
  .strat-grid { grid-template-columns: 1fr; }
  .play-figs { grid-template-columns: 1fr 1fr; }
}

/* On a narrow screen the topbar's right-hand group (status pill,
   timestamp, theme toggle, and — once authentication is on — a logout
   button) is wider than the viewport and pushed the whole page 9px
   sideways. Letting the row wrap costs a line of height and removes
   the horizontal scroll. */
@media (max-width: 700px) {
  .topbar { flex-wrap: wrap; gap: 12px; padding: 10px 14px; }
  .topbar-right { flex-wrap: wrap; gap: 8px; row-gap: 6px; }
  .tabs { order: 3; width: 100%; overflow-x: auto; }
}

/* ── Options: the two verdicts ────────────────────────────────────
   Volatility on the left, direction on the right, sized equally
   because neither answers the other's question. */
.verdict-row {
  display: grid; grid-template-columns: 1fr 1fr; gap: 16px;
  margin-bottom: 12px;
}
.lean-parts {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 12px;
}
.lean-part {
  display: grid; gap: 1px;
  background: var(--plane); border-radius: var(--r-s); padding: 8px 10px;
}
/* The shared .card-label is --muted, which clears 4.5:1 on the card
   surface but only 4.21:1 on --plane, which is what these sit on. */
.lean-part .card-label { color: var(--ink-2); }
.lean-v { font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums; }
.lean-s { font-size: 11px; color: var(--ink-2); line-height: 1.4; }
/* The direction word gets a subdued tint, never the full status red or
   green: "down" argues for four of the eight plays, it is not an alarm
   about the account. The arrow in the text carries the direction, so
   colour is reinforcing and never the only cue. */
.lean-up   { color: var(--profit-ink); }
.lean-down { color: var(--loss-ink); }
.lean-neutral { color: var(--ink-2); }

@media (max-width: 860px) {
  .verdict-row { grid-template-columns: 1fr; }
}

/* ── Options: greeks ──────────────────────────────────────────────
   Four tiles, each carrying its unit. Vega is dollars per ONE vol
   point and theta dollars per DAY — neither is guessable, and both
   are where a factor-of-100 misreading usually happens. */
.greeks-row { margin: 4px 0 12px; }
.greeks-head {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 6px; flex-wrap: wrap;
}
.greeks-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.greek {
  background: var(--plane); border-radius: var(--r-s); padding: 7px 9px;
}
.greek-n {
  font-size: 10.5px; font-weight: 700; color: var(--ink-2);
  text-transform: uppercase; letter-spacing: .4px;
}
.greek-v {
  font-size: 15px; font-weight: 700; margin-top: 1px;
  font-variant-numeric: tabular-nums;
}
/* The sign carries the meaning — a premium seller wants theta positive
   and vega negative — so it is spelled out in the text as well as
   coloured, and the diverging pair is reused rather than status red. */
.greek-v.pos { color: var(--profit-ink); }
.greek-v.neg { color: var(--loss-ink); }
.greek-s { font-size: 10px; color: var(--ink-2); margin-top: 1px; line-height: 1.35; }

/* Delta on each candidate row, highlighted inside the 25-30 band. */
.play-row-delta {
  font-variant-numeric: tabular-nums; font-weight: 600;
  color: var(--ink-2); flex: none;
}
.play-row-delta.band {
  background: var(--brass); color: #3a2a00;
  padding: 0 5px; border-radius: 4px;
}

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

/* Bid/ask on each ticket leg. Muted until the live quote replaces the
   scan's figures, then given full ink — the difference between "what
   the scan saw" and "where the book is now" is worth seeing. */
.leg-book {
  font-size: 11px; color: var(--ink-2);
  font-variant-numeric: tabular-nums; flex: none;
  padding: 1px 6px; border-radius: 4px; background: var(--surface);
}
.leg-book.live { color: var(--ink); }
/* A post-only order priced through the book is rejected, not filled. */
.leg-book.stale-price {
  background: var(--loss-100); color: var(--loss-100-ink); font-weight: 700;
}
@media (max-width: 560px) {
  .ticket-leg { flex-wrap: wrap; row-gap: 4px; }
  .leg-book { margin-left: 26px; }
}

/* ── Options: the recommendation ──────────────────────────────────
   Deliberately the most prominent thing in section 1 — it is the join
   of the two readings above it, and that join is the actual decision.
   Bordered rather than filled: it is a conclusion drawn from weak
   evidence, and a saturated block would overstate it. */
.reco {
  border: 2px solid var(--navy); border-radius: var(--r-s);
  padding: 14px; margin: 14px 0 10px; background: var(--plane);
}
.reco-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.reco-tag {
  background: var(--navy); color: #fff;
  padding: 3px 10px; border-radius: 5px;
  font-size: 11px; font-weight: 700; letter-spacing: .8px;
}
.reco-name { font-size: 18px; font-weight: 700; }
.reco .pill { padding: 2px 9px; font-size: 10.5px; font-weight: 700; }
.reco-why {
  font-size: 12.5px; color: var(--ink-2);
  line-height: 1.6; margin: 8px 0 10px;
}
.reco-legs {
  display: flex; align-items: center; gap: 7px;
  flex-wrap: wrap; margin-bottom: 10px;
}
.reco-when { font-size: 12px; color: var(--ink-2); }
.reco-figs { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
.reco-fig {
  display: grid; gap: 1px;
  background: var(--surface); border-radius: 6px; padding: 7px 9px;
}
.reco-fig-v {
  font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.reco-fig-v.pos { color: var(--profit-ink); }
.reco-fig-v.neg { color: var(--loss-ink); }
.reco-none { font-size: 12.5px; color: var(--ink-2); margin-bottom: 10px; }
#reco-go { margin-top: 12px; }

/* The non-directional tiles read as a third group, not a third
   direction: neutral ink rather than the profit/loss pair, because
   they express a view on distance travelled, not on which way. */
.strat-icon.flat { background: var(--neutral); color: var(--ink); }

@media (max-width: 860px) {
  .reco-figs { grid-template-columns: 1fr 1fr; }
}

/* ── Resting option orders ────────────────────────────────────────
   The way out of a half-filled spread. Only options ever appear here;
   the grid bot's perpetual orders are filtered upstream so no cancel
   button can ever sit next to one. */
.oo-list { display: grid; gap: 6px; }
.oo-row {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 10px; background: var(--plane); border-radius: var(--r-s);
  font-size: 12.5px; flex-wrap: wrap;
}
.oo-px { font-variant-numeric: tabular-nums; color: var(--ink-2); }
.oo-state { margin-left: auto; font-size: 11.5px; color: var(--ink-2); }
/* A partially filled order is the dangerous one — the position is
   already open and unbalanced — so it is called out rather than
   sitting quietly among the untouched ones. */
.oo-state.partial {
  background: var(--brass); color: #3a2a00;
  padding: 1px 7px; border-radius: 4px; font-weight: 700;
}
.oo-cancel { flex: none; }

/* Fill-risk warning on the confirm dialog. Amber, not red: the order
   is legal and will be accepted — it simply may rest instead of fill,
   which is a thing to know, not an error. */
.confirm-warn {
  white-space: pre-line; text-align: left;
  font-size: 12px; line-height: 1.6;
  background: var(--brass); color: #3a2a00;
  border-radius: var(--r-s); padding: 10px 12px; margin: 8px 0;
}

/* Management signals: several can apply at once (near expiry AND in the
   money AND past the take-profit), so the cell lays them out with gaps
   rather than letting them run into one another. */
.grid-table td .pill { margin: 1px 4px 1px 0; }

/* Combo vs leg-by-leg. Sits above the size field because it changes
   what the confirm dialog will describe, so it has to be chosen first. */
.order-mode {
  display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap; margin-bottom: 10px;
}
.order-mode .chart-note { width: 100%; margin: 0; }

/* Totals row under the held options.
   A tfoot is not just the last row: it is a different KIND of number, so
   it carries a rule above it and a heavier weight. The surface is the
   plane tint rather than a fill, because a coloured band here would
   compete with the profit/loss ink the row exists to show. */
.grid-table tfoot .total-row td {
  border-top: 2px solid var(--rule);
  background: var(--plane);
  font-weight: 700;
  padding-top: 10px;
}
/* On the plane, --muted drops to 4.21:1. The totals row uses ink-2 for
   anything that is not already carrying a profit/loss colour. */
.grid-table tfoot .total-row td:not(.pos):not(.neg) { color: var(--ink-2); }
.grid-table tfoot .total-row td:first-child { color: var(--ink); }

/* Per-leg selection on the held-options table. */
.pick-col { width: 34px; text-align: center; }
.pick-leg { width: 16px; height: 16px; accent-color: var(--accent); cursor: pointer; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Walk control. Boxed off from the plain limit fields above it because
   it changes what the order DOES, not just its numbers. */
.order-walk {
  border: 1px dashed var(--rule); border-radius: var(--r-s);
  padding: 10px 12px; margin: 10px 0;
}
.walk-toggle { display: flex; align-items: center; gap: 8px; cursor: pointer; }
.walk-toggle input { width: 16px; height: 16px; accent-color: var(--accent); }
.walk-toggle span { font-weight: 600; color: var(--ink); }
#walk-fields { margin-top: 10px; }
#walk-fields .chart-note { margin-top: 6px; }

/* ── Closed option trades ─────────────────────────────────────── */
/* Headline figures as tiles. They were a second table sharing the row
   with the trades, which left the trades half the card and forced a
   sideways scroll to read a five-row list. */
.closed-kpis {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 12px; margin-bottom: 14px;
}
.closed-kpi { background: var(--plane); border-radius: var(--r-s); padding: 10px 12px; }
.closed-kpi-v { font-size: 20px; font-weight: 700; margin-top: 2px; }

/* Two lines in one cell: the strike carries the row, the expiry is
   context. Splitting the name is what let the table lose two columns. */
.ct-strike { font-weight: 600; }
.ct-expiry { display: block; font-size: 11px; color: var(--ink-2); margin-top: 1px; }
.ct-span { white-space: nowrap; }
.ct-held { display: block; font-size: 11px; color: var(--ink-2); margin-top: 1px; }
.closed-table td { vertical-align: top; }

/* The full statistics, folded away rather than deleted — rarely needed,
   never missing. */
.closed-more { margin-top: 12px; }
.closed-more > summary {
  cursor: pointer; font-size: 12px; font-weight: 600;
  color: var(--ink-2); padding: 6px 0; list-style-position: inside;
}
.closed-more > summary:hover { color: var(--ink); }
.closed-more .stats-table { margin-top: 6px; max-width: 420px; }

@media (max-width: 720px) {
  .closed-kpis { grid-template-columns: repeat(2, 1fr); }
}

/* Divides the summary above from the list below — without it the two
   halves of this card run together as one undifferentiated block. */
.closed-list-head {
  font-size: 13px; font-weight: 600; color: var(--ink-2);
  margin: 18px 0 8px; padding-top: 14px;
  border-top: 1px solid var(--rule);
}

/* Says the window this chart is fixed to, beside its title — it does not
   follow the range buttons and nothing else on the page would say so. */
.head-hint {
  font-size: 11.5px; font-weight: 600; color: var(--ink-2);
  background: var(--plane); border-radius: 4px;
  padding: 2px 7px; margin-left: 8px; vertical-align: middle;
}
