/* ============================================================================
   app.css — base, mobile (<768), and the wide-touch band (768–1023).
   Desktop (>=1024) lives in desktop.css.

   VISUAL LANGUAGE (supersedes the original §8 palette): modern minimalist,
   black and silver, backlit. Brushed metal under cold light, not neon.

   Two rules govern the whole sheet:

   1. HUE APPEARS ONLY FOR WIN/LOSS. Everything else is black, silver, grey.
   2. GLOW IS CHROME ONLY — borders, focus, active states, primary buttons,
      the equity line. Never on body text or table figures: glowing numerals
      are unreadable at small sizes.

   Contrast on true black, measured:
     --text-primary   #E8EAF0  17.5:1  body, figures
     --text-secondary #9BA0AB   7.9:1  supporting text
     --text-muted     #757B87   4.9:1  labels (raised from #5C616B, 3.4:1,
                                       which failed AA and could not carry
                                       even labels)
     --text-dim       #4A4F58   ~2.4:1 DECORATIVE ONLY — dividers, disabled
     --win            #34E39B  12.6:1
     --loss           #FF5F70   7.1:1

   Losses are dimmed at CHROME level only — recessed row, darker edge, no
   glow — never by dimming the figures, because losing trades are the ones
   most studied and dim numerals degrade exactly the data that matters.
   ========================================================================== */

:root {
  --bg: #000000;
  --surface-1: #0A0A0C;
  --surface-2: #121216;
  --surface-3: #17171C;
  --border: #1F1F25;
  --border-lit: rgba(198, 214, 235, 0.16);

  --text-primary: #E8EAF0;
  --text-secondary: #9BA0AB;
  --text-muted: #757B87;
  --text-dim: #4A4F58;

  --glow: rgba(198, 214, 235, 0.30);
  --glow-soft: 0 0 24px rgba(198, 214, 235, 0.10), 0 0 1px rgba(198, 214, 235, 0.35);
  --glow-tight: 0 0 10px rgba(198, 214, 235, 0.14), 0 0 1px rgba(198, 214, 235, 0.40);

  --win: #34E39B;
  --loss: #FF5F70;
  --win-glow: 0 0 12px rgba(52, 227, 155, 0.28);
  --warn: #D9A13B;

  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --sans: -apple-system, system-ui, "Segoe UI", sans-serif;
  --radius: 10px;

  /* Inputs must never be under 16px: iOS Safari force-zooms the viewport on
     focus of anything smaller and does not zoom back out. */
  --input-size: 16px;

  color-scheme: dark;
}

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

/* Safety net, not a fix — the causes are dealt with where they occur (see the
   grid rules below). A journal that slides sideways under your thumb is
   miserable to use, and the one surface this has to be right on is the one
   that is hardest to test, so the page itself is not allowed to scroll
   horizontally whatever gets added later.
   `clip`, never `hidden`: `hidden` makes the root a scroll container and
   silently breaks every `position: sticky` inside it (the header, the table
   head, the backtest tally). `clip` does not. Deliberately NOT applied to
   `.filterbar`, `.dt-wrap` or any other element that is meant to scroll
   sideways on purpose. */
html { overflow-x: clip; }

body {
  background: var(--bg);
  color: var(--text-primary);
  font: 15px/1.45 var(--sans);
  padding-bottom: calc(64px + env(safe-area-inset-bottom));
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;      /* no rubber-band, no pull-to-refresh */
}

/* ---------- installed-app behaviour ----------
   Four browser defaults that make a PWA feel like a web page rather than an
   app, all of them wrong here:

   1. DOUBLE-TAP ZOOM. iOS ignores `user-scalable=no` on purpose, so the meta
      tag alone does nothing there. `touch-action: manipulation` is what
      actually removes it — it tells the browser this element needs no
      double-tap gesture, which also drops the 300ms click delay that makes
      taps feel sluggish. Applied broadly, then relaxed on the two places
      that genuinely need their own gestures.
   2. TEXT SELECTION on chrome. Long-pressing a tab or a day box brought up
      the selection callout and a blue highlight. Real controls do not select.
      Content and inputs are exempted below — the journal is for reading.
   3. THE TAP FLASH. A grey box on every touch is unmistakably a web page.
   4. TEXT INFLATION. iOS silently enlarges text in some orientations unless
      `-webkit-text-size-adjust` pins it. */
html {
  overscroll-behavior: none;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}
body,
button, .seg button, .tag, .day-box, .navbtn, #tabbar button, summary, label {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
button, .seg button, .tag, .day-box, .navbtn, #tabbar button, summary,
label.field > span.lbl, h2.section, .brand, th {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
/* ...but never on what the journal exists to let you read and copy. */
input, textarea, select, .notes, .trade-sub, td, .banner, .warnbox, .empty, .help-note p {
  -webkit-user-select: text;
  user-select: text;
}
/* Panes that scroll on purpose keep their own momentum and stay contained, so
   a flick inside a list cannot start scrolling the page behind it. */
.dt-wrap, .split-list, .split-form, .filterbar, .tbl-scroll, .modal {
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

/* The desktop sidebar does not exist below 1024 — the bottom tab bar and the
   compact header serve those widths. desktop.css turns it back on. */
#sidebar { display: none; }

/* ---------- header ---------- */

#topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  padding-top: calc(10px + env(safe-area-inset-top));
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--border);
}

/* The wordmark is DESKTOP ONLY — see desktop.css. On a phone the app is the
   screen you are looking at, and a title bar naming it costs width the system
   picker can use. The sidebar does not exist below 1024, so `.brand` has
   nothing to render into here. */
.brand { display: none; }

/* Both switchers. The mobile one now takes the width the wordmark used to
   hold, which is the point of removing it: system names are long and were
   being truncated to fit a label nobody needed. */
#system-switcher,
#system-switcher-m {
  flex: 1;
  min-width: 0;
  background: var(--surface-2);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 10px;
  font: var(--input-size) var(--sans);
}

.chip {
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-secondary);
  font: 11px var(--mono);
  border-radius: 999px;
  padding: 6px 10px;
  white-space: nowrap;
  max-width: 40vw;
  overflow: hidden;
  text-overflow: ellipsis;
}
.chip.chip-warn { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 45%, var(--border)); }
.chip.chip-error { color: var(--loss); border-color: color-mix(in srgb, var(--loss) 55%, var(--border)); }

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

#tabbar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 20;
  display: grid;
  /* Six destinations now. At 375px that is 62.5px each — measured, and every
     label still fits without truncating. They are allowed to ellipsise rather
     than wrap onto a second line, which would make the bar taller than the
     safe-area allowance. */
  grid-template-columns: repeat(6, minmax(0, 1fr));
  background: color-mix(in srgb, var(--surface-1) 92%, transparent);
  backdrop-filter: blur(14px);
  border-top: 1px solid var(--border);
  padding-bottom: env(safe-area-inset-bottom);
}

#tabbar button {
  appearance: none;
  background: none;
  border: 0;
  color: var(--text-muted);
  font: 11px var(--sans);
  padding: 9px 0 11px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  cursor: pointer;
  position: relative;
}
#tabbar button .ico { font-size: 19px; line-height: 1.1; }
#tabbar button {
  min-width: 0;
  padding-left: 2px;
  padding-right: 2px;
}
#tabbar button > :not(.ico) {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
@media (max-width: 380px) {
  #tabbar button { font-size: 10px; }
  #tabbar button .ico { font-size: 18px; }
}
#tabbar button.active { color: var(--text-primary); }
#tabbar button.active::after {
  content: "";
  position: absolute;
  top: 0;
  left: 22%;
  right: 22%;
  height: 1px;
  background: var(--glow);
  box-shadow: var(--glow-tight);
}

/* ---------- main view ---------- */

#view {
  max-width: 560px;
  margin: 0 auto;
  padding: 14px;
  outline: none;
}

/* The view-level toggle is a header for everything under it, so it needs to
   read as separated from the first block of figures. Without this the stat
   tiles sat flush against it. Scoped to a direct child of #view so the segs
   INSIDE forms (direction, instrument) keep their label spacing. */
#view > .seg { margin-bottom: 14px; }
#view > details { margin-top: 4px; }

h2.section {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-muted);
  margin: 22px 0 8px;
}

.card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
  margin-bottom: 10px;
}

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

/* Win/loss double-encoded: hue AND luminance, always paired with +/- signs. */
.pos { color: var(--win); }
.neg { color: var(--loss); }
.warn-text { color: var(--warn); }

/* ---------- forms ---------- */

label.field { display: block; margin-bottom: 12px; }
label.field > span.lbl {
  display: block;
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  margin-bottom: 5px;
  text-transform: uppercase;
}

input[type="text"], input[type="email"], input[type="datetime-local"],
input[type="date"], textarea, select {
  width: 100%;
  background: var(--surface-2);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 11px 12px;
  font: var(--input-size)/1.3 var(--sans);
  transition: border-color 140ms ease, box-shadow 140ms ease;
}

/* iOS gives `input[type=date]` a large intrinsic width for its native picker,
   and `min-width: auto` on a grid/flex child means `width: 100%` does not
   actually hold it in. Both are needed or the box hangs off its card. */
input[type="date"], input[type="datetime-local"] {
  min-width: 0;
  max-width: 100%;
}

/* ONE HEIGHT for every single-line control.
   Each control type sizes itself from its own internal furniture, so a text
   box, a select and a datetime picker all came out different — mildly off in
   Chrome, obviously ragged on iOS, where a `datetime-local` with step="1"
   renders a much taller control than the text field beside it. Pinning the
   box removes the browser's opinion from the layout. */
input[type="text"], input[type="email"], input[type="number"],
input[type="date"], input[type="datetime-local"], select {
  height: 46px;
  line-height: normal;
}
/* Date and time pickers additionally arrive centred and chrome-heavy on iOS;
   stripping the native appearance makes them sit like every other field. */
input[type="date"], input[type="datetime-local"] {
  -webkit-appearance: none;
  appearance: none;
  text-align: left;
}

/* A date is eleven characters. Stretched to the full width of a card it is a
   large empty box with the value stranded in the middle of it, and on iOS the
   native control can push past the padding entirely. Sized to its content
   instead — a full-width TEXT field still makes sense, a full-width date does
   not. */
label.field > input[type="date"] { width: auto; max-width: min(240px, 100%); }

input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: var(--border-lit);
  box-shadow: var(--glow-tight);
}

input.mono-in { font-family: var(--mono); }
textarea { min-height: 76px; resize: vertical; }

input.invalid, textarea.invalid, select.invalid {
  border-color: var(--loss);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--loss) 30%, transparent);
}
.field-error { color: var(--loss); font-size: 12px; margin-top: 4px; }

/* `minmax(0, 1fr)`, never a bare `1fr`. A grid item defaults to
   `min-width: auto`, so a bare 1fr track cannot shrink below its content's
   min-content width and the whole page slides sideways instead. That is
   invisible in Chrome and very visible on iOS, where form controls —
   `datetime-local` above all — have far wider intrinsic minimums. */
.row2 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 10px; }
.row3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.row2 > *, .row3 > * { min-width: 0; }

/* Even a shrinkable track cannot help a control that refuses to shrink. */
.row2 input, .row2 select, .row3 input, .row3 select { min-width: 0; max-width: 100%; }

/* A row holding a date+time picker gets one per line on a phone. iOS renders
   `datetime-local step="1"` as a full dd/mm/yyyy --:--:-- control; two of them
   side by side cannot fit a 375px screen at any font size, so stacking is the
   only honest answer. */
@media (max-width: 560px) {
  .row2.row-dates { grid-template-columns: minmax(0, 1fr); }

  /* Three controls never fit a phone. Inputs are pinned at 16px (anything
     smaller makes iOS zoom the viewport on focus and never zoom back), and
     16px text plus 24px of padding plus a native select chevron needs about
     130px each — 3 x 130 + gaps + page padding is ~438px against a 375px
     screen. That is the sideways scroll on the Log and Backtest forms: the
     rows were ~60px too wide and dragged the whole page with them. */
  .row3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Two columns still hold at 375px (168px each against a ~132px control), so
   the single-column fallback is reserved for genuinely tiny screens. */
@media (max-width: 340px) {
  .row3 { grid-template-columns: minmax(0, 1fr); }
}

/* segmented control */
.seg {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
.seg button {
  appearance: none;
  border: 0;
  background: none;
  color: var(--text-muted);
  padding: 11px 4px;
  font: 600 13px var(--sans);
  letter-spacing: 0.04em;
  cursor: pointer;
  transition: color 140ms ease, background 140ms ease;
}
.seg button.on {
  background: var(--surface-3);
  color: var(--text-primary);
  box-shadow: inset 0 0 0 1px var(--border-lit), var(--glow-tight);
}
.seg.dir button.on.long { color: var(--win); box-shadow: inset 0 -2px 0 var(--win), var(--win-glow); }
.seg.dir button.on.short { color: var(--loss); box-shadow: inset 0 -2px 0 var(--loss); }
.seg.mini button { padding: 4px 10px; font-size: 11px; }

/* toggle */
.toggle { display: flex; align-items: center; gap: 10px; padding: 8px 0; }
.toggle input { width: auto; }

/* tag chips */
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chips .tag {
  border: 1px solid var(--border);
  background: var(--surface-1);
  color: var(--text-secondary);
  border-radius: 999px;
  padding: 8px 13px;
  font-size: 13px;
  cursor: pointer;
  transition: border-color 140ms ease, color 140ms ease, box-shadow 140ms ease;
}
.chips .tag.on {
  border-color: var(--border-lit);
  color: var(--text-primary);
  box-shadow: var(--glow-tight);
}

/* sizing card */
#sizing-card {
  position: sticky;
  top: calc(52px + env(safe-area-inset-top));
  z-index: 10;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 11px 13px;
  margin-bottom: 14px;
  font-family: var(--mono);
  font-size: 13px;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 7px 10px;
  box-shadow: var(--glow-soft);
}
#sizing-card .k {
  color: var(--text-muted);
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  display: block;
}
/* Each figure cell holds one label line plus one value line, always. Values
   change length constantly while typing ("$100.00 (1.0%)" becomes "$19.18
   (1.0%)" the moment the spot cap bites) and a cell that rewraps to a second
   line, or back off one, resizes the whole grid row under the user's hand. */
#sizing-card > div:not(.sizing-notes) {
  min-height: 32px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
#sizing-card .warn {
  color: var(--warn);
  font-family: var(--sans);
  font-size: 13px;
  line-height: 1.4;
}

/* RESERVED SPACE, the whole point of this block.
   The sizing warnings appear and vanish on almost every keystroke — the spot
   affordability cap trips the instant the stop gets tight enough, the heat
   warning the instant risk crosses the limit. Each appearance re-flowed the
   entire form 43px downwards while a thumb was resting on it.
   The slot therefore always exists and always occupies its footprint. The
   height fits the tallest of these messages at 375px (the spot cap warning,
   three lines at 13px/1.4 plus its margin); anything shorter simply leaves
   the rest blank rather than dragging the form around. */
#sizing-card .sizing-notes {
  grid-column: 1 / -1;
  min-height: 58px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  justify-content: flex-start;
}
/* Same treatment one level down: the liquidation readout and its warning both
   come and go while leverage is being typed. */
.fut-block .liq-slot {
  min-height: 74px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

/* Desktop has the room, and the form panel is narrower, so the same messages
   wrap to more lines there. */
@media (min-width: 1024px) {
  #sizing-card .sizing-notes { min-height: 64px; }
}

/* sticky save — bottom third, thumb reach */
.savebar {
  position: sticky;
  bottom: calc(64px + env(safe-area-inset-bottom));
  z-index: 15;
  padding: 8px 0;
  background: linear-gradient(transparent, var(--bg) 42%);
}

button.primary {
  width: 100%;
  appearance: none;
  border: 1px solid var(--border-lit);
  border-radius: 12px;
  background: linear-gradient(180deg, #1C1C22 0%, #101014 100%);
  color: var(--text-primary);
  font: 600 16px var(--sans);
  letter-spacing: 0.02em;
  padding: 15px;
  cursor: pointer;
  box-shadow: var(--glow-soft);
  transition: box-shadow 140ms ease, border-color 140ms ease;
}
button.primary:disabled { opacity: 0.45; box-shadow: none; }

button.ghost {
  appearance: none;
  background: var(--surface-1);
  border: 1px solid var(--border);
  color: var(--text-secondary);
  border-radius: 8px;
  padding: 10px 14px;
  font: 14px var(--sans);
  cursor: pointer;
  transition: border-color 140ms ease, color 140ms ease, box-shadow 140ms ease;
}
button.danger { border-color: color-mix(in srgb, var(--loss) 45%, var(--border)); color: var(--loss); }

/* ---------- trades list ---------- */

.filterbar {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding-bottom: 8px;
  margin-bottom: 6px;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.filterbar::-webkit-scrollbar { display: none; }
.filterbar > * { flex: 0 0 auto; width: auto; }
.filterbar input[type="text"] { width: 150px; }
/* Date inputs need the same explicit width as the text field above: the base
   form rule is `input[type="date"] { width: 100% }` at (0,1,1), which outranks
   `.filterbar > *` at (0,1,0), so each one would otherwise swell to the full
   bar width and push Sort off the end of the scroller. */
.filterbar input[type="date"] { width: 142px; }
.filterbar select { width: auto; font-size: var(--input-size); padding: 9px 26px 9px 10px; }

.trade-card { position: relative; overflow: hidden; margin-bottom: 8px; }
.trade-card .swipe-inner {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 11px 13px;
  transition: transform 160ms ease;
  position: relative;
  z-index: 1;
}
/* chrome-level loss dimming: the row recedes, the figures do not */
.trade-card.is-loss .swipe-inner {
  background: #070709;
  border-color: #17171B;
}
.trade-card.is-win .swipe-inner { border-color: color-mix(in srgb, var(--win) 18%, var(--border)); }

.trade-card .swipe-del {
  position: absolute;
  inset: 0 0 0 auto;
  width: 96px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--loss);
  color: #100406;
  border-radius: var(--radius);
  font-weight: 700;
  border: 0;
  z-index: 0;
}
.trade-head { display: flex; align-items: baseline; gap: 8px; }
.trade-head .asset { font-weight: 600; letter-spacing: 0.01em; }
.badge {
  font: 600 9.5px var(--mono);
  letter-spacing: 0.08em;
  border-radius: 4px;
  padding: 2px 6px;
  border: 1px solid;
  text-transform: uppercase;
}
.badge.long { color: var(--win); border-color: color-mix(in srgb, var(--win) 40%, transparent); }
.badge.short { color: var(--loss); border-color: color-mix(in srgb, var(--loss) 40%, transparent); }
.badge.bt { color: var(--text-secondary); border-color: var(--border); }
/* A forward test is real money, so it must not read as paper. */
.badge.fwd { color: #7FC8FF; border-color: rgba(127, 200, 255, 0.4); }
.badge.attn { color: var(--warn); border-color: var(--warn); }
.badge.st-draft { color: var(--text-muted); border-color: var(--border); }
.badge.st-testing,
.badge.st-backtesting { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 45%, transparent); }
/* Forward testing is real money, so it reads closer to live than to paper. */
.badge.st-forward_testing { color: #7FC8FF; border-color: rgba(127, 200, 255, 0.45); }
.badge.st-validated { color: var(--text-primary); border-color: var(--border-lit); }
.badge.st-live { color: var(--win); border-color: color-mix(in srgb, var(--win) 40%, transparent); }
.badge.st-archived { color: var(--text-dim); border-color: var(--border); }

.trade-head .r { margin-left: auto; font: 600 18px var(--mono); }
.trade-head .r.pos { text-shadow: var(--win-glow); }
.trade-sub {
  display: flex;
  gap: 10px;
  font-size: 12.5px;
  color: var(--text-muted);
  margin-top: 4px;
  flex-wrap: wrap;
}
.trade-detail { border-top: 1px solid var(--border); margin-top: 10px; padding-top: 10px; }
.kv { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 5px 12px; font-size: 13px; }
.kv .k { color: var(--text-muted); }
.kv .v { font-family: var(--mono); text-align: right; color: var(--text-primary); }
.trade-actions { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.notes-block { white-space: pre-wrap; font-size: 13.5px; margin-top: 8px; color: var(--text-secondary); }
.shots { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; }
.shots img {
  width: 84px; height: 84px; object-fit: cover;
  border-radius: 6px; border: 1px solid var(--border);
}

.open-total { font: 13px var(--mono); color: var(--text-secondary); margin-bottom: 8px; }

/* ---------- empty states ---------- */

.empty {
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  padding: 22px 18px;
  color: var(--text-secondary);
  font-size: 14px;
  line-height: 1.6;
}
.empty b { color: var(--text-primary); }

/* ---------- toast ---------- */

#toast-host {
  position: fixed;
  bottom: calc(78px + env(safe-area-inset-bottom));
  left: 0; right: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  z-index: 50;
  pointer-events: none;
}
.toast {
  background: var(--surface-3);
  border: 1px solid var(--border-lit);
  color: var(--text-primary);
  border-radius: 10px;
  padding: 11px 16px;
  font-size: 14px;
  max-width: 90vw;
  box-shadow: var(--glow-soft), 0 8px 28px rgba(0, 0, 0, 0.7);
  animation: toast-in 160ms ease;
}
.toast.error { border-color: var(--loss); }
.toast.warn { border-color: var(--warn); }
.toast-update { pointer-events: auto; display: flex; gap: 10px; align-items: center; }
.toast-update button {
  background: var(--surface-2); color: var(--text-primary);
  border: 1px solid var(--border-lit); border-radius: 6px;
  padding: 5px 11px; font: 13px var(--sans); cursor: pointer;
}
@keyframes toast-in { from { opacity: 0; transform: translateY(6px); } }

/* ---------- modal ---------- */

.modal-back {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(0, 0, 0, 0.78);
  backdrop-filter: blur(3px);
  display: flex; align-items: flex-end; justify-content: center;
}
.modal {
  background: var(--surface-1);
  border: 1px solid var(--border-lit);
  border-radius: 14px 14px 0 0;
  width: 100%;
  max-width: 560px;
  max-height: 84vh;
  overflow-y: auto;
  padding: 16px;
  padding-bottom: calc(16px + env(safe-area-inset-bottom));
  box-shadow: var(--glow-soft);
}
.modal h3 { margin: 0 0 10px; font-size: 16px; }
.err-list { font: 12.5px var(--mono); color: var(--loss); max-height: 30vh; overflow-y: auto; }
.warn-list { font: 12.5px var(--mono); color: var(--warn); max-height: 20vh; overflow-y: auto; }

/* ---------- rules, tally, futures, banners, stats ---------- */

.rulebanner {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-left: 2px solid var(--border-lit);
  border-radius: var(--radius);
  padding: 9px 12px;
  font-size: 13px;
  margin-bottom: 12px;
  color: var(--text-secondary);
}
.rulebanner b { color: var(--text-muted); font-weight: 600; }
/* A banner that reports a blocking configuration problem rather than a rule
   reminder: warm edge, and its bold lead keeps full luminance so the headline
   is not dimmed to the same weight as the explanation behind it. */
.rulebanner.warn-text { border-left-color: var(--warn, #E8B44A); color: var(--text-secondary); }
.rulebanner.warn-text b { color: var(--warn, #E8B44A); }
.linkish {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--text-primary);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.linkish:hover { color: #fff; }
/* A pinned column in the picker: the state has to read at a glance, because
   the button's own label is the only other clue. */
.ghost.on {
  color: var(--text-primary);
  border-color: var(--border-lit);
  background: var(--surface-2);
}

.tally {
  position: sticky;
  top: calc(52px + env(safe-area-inset-top));
  z-index: 10;
  background: var(--surface-2);
  border: 1px solid var(--border-lit);
  border-radius: 999px;
  padding: 8px 14px;
  font-size: 13px;
  text-align: center;
  margin-bottom: 12px;
  box-shadow: var(--glow-soft);
}

.fut-block {
  grid-column: 1 / -1;
  border-top: 1px solid var(--border);
  padding-top: 8px;
  font-family: var(--sans);
  font-size: 13px;
  color: var(--text-secondary);
}
.fut-row { display: flex; justify-content: space-between; gap: 10px; padding: 2px 0; }

.warnbox {
  background: color-mix(in srgb, var(--loss) 10%, var(--surface-1));
  border: 1px solid var(--loss);
  color: var(--loss);
  border-radius: 8px;
  padding: 9px 11px;
  margin-top: 6px;
  font-size: 13px;
  font-family: var(--sans);
  line-height: 1.45;
}

.banner {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px 12px;
  font-size: 13.5px;
  margin: 10px 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  color: var(--text-secondary);
}

.mixed-chip {
  display: none;
  background: color-mix(in srgb, var(--warn) 12%, var(--surface-1));
  border: 1px solid var(--warn);
  color: var(--warn);
  border-radius: 8px;
  padding: 7px 10px;
  font: 600 11px var(--mono);
  letter-spacing: 0.06em;
  margin-bottom: 8px;
}

.footerbar {
  position: sticky;
  bottom: calc(64px + env(safe-area-inset-bottom));
  z-index: 12;
  background: var(--surface-2);
  border: 1px solid var(--border-lit);
  border-radius: 999px;
  padding: 9px 16px;
  text-align: center;
  font-size: 13px;
  margin-top: 10px;
  box-shadow: var(--glow-soft);
}

details {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-1);
  margin-bottom: 10px;
  padding: 0 12px;
}
details summary {
  cursor: pointer;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-muted);
  padding: 12px 0;
  list-style: none;
}
details summary::-webkit-details-marker { display: none; }
details summary::before { content: "▸ "; }
details[open] summary::before { content: "▾ "; }
details > *:not(summary) { margin-bottom: 12px; }

.stat-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px; }
.stat-grid > *, .kv > * { min-width: 0; }
.tile {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 11px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.tile .k { font-size: 9.5px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); }
.tile .v { font-size: 17px; font-weight: 600; font-variant-numeric: tabular-nums; }
.tile.pos { border-color: color-mix(in srgb, var(--win) 22%, var(--border)); }
.tile.pos .v { color: var(--win); }
/* loss tiles recede via chrome; the figure keeps full luminance */
.tile.neg { background: #070709; border-color: #17171B; }
.tile.neg .v { color: var(--loss); }
.tile .s { font-size: 11.5px; color: var(--text-muted); }
.tile.explainable { cursor: pointer; }

.tbl-scroll { overflow-x: auto; }
table.bd { border-collapse: collapse; width: 100%; margin-top: 6px; font-size: 12.5px; }
table.bd th {
  text-align: right; font-weight: 600; color: var(--text-muted);
  font-size: 9.5px; text-transform: uppercase; letter-spacing: 0.07em;
  padding: 5px 8px; border-bottom: 1px solid var(--border);
}
table.bd th:first-child, table.bd td:first-child { text-align: left; padding-left: 0; }
table.bd td {
  padding: 6px 8px; text-align: right;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
  font-variant-numeric: tabular-nums;
}
table.bd tr.thin td { color: var(--text-dim); }

.checklist-row .tag { font-size: 12px; padding: 7px 11px; }

/* ---------- charts ---------- */

.chart-card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  /* Charts need more room around them than a figure tile does: a line that
     runs to the edge of its container reads as overlapping whatever sits
     above it, which is exactly how the equity curve looked under the tiles. */
  padding: 12px 14px 16px;
  margin: 0 0 14px;
}
.chart-card + .chart-card { margin-top: 14px; }
.chart-title {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-muted);
  margin-bottom: 6px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.chart-title .seg { margin-left: auto; }
.chart-holder { position: relative; margin-top: 6px; }
.chart-holder canvas { width: 100%; display: block; }
/* A bare canvas keeps its intrinsic 600px and drags the page sideways on a
   phone; every canvas in the app is fluid, not just the ones in a holder. */
canvas.chart { width: 100%; max-width: 100%; display: block; height: 220px; }
.chart-tip {
  position: absolute;
  transform: translateX(-50%);
  background: var(--surface-3);
  border: 1px solid var(--border-lit);
  color: var(--text-primary);
  font: 11px var(--mono);
  padding: 4px 8px;
  border-radius: 6px;
  pointer-events: none;
  white-space: nowrap;
  box-shadow: var(--glow-tight);
  z-index: 5;
}

/* the sizing calculation, shown as arithmetic rather than just an answer */
.workings {
  background: var(--surface-2);
  border: 1px solid var(--border-lit);
  border-radius: 8px;
  padding: 9px 11px;
  margin-bottom: 10px;
  font-size: 13px;
  line-height: 1.5;
  box-shadow: var(--glow-tight);
}
.workings .muted { font-size: 11.5px; }

/* drag-and-drop screenshot target */
form.drop-target, .shot-drop.drop-target {
  outline: 1px dashed var(--glow);
  outline-offset: 6px;
  border-radius: var(--radius);
}

/* ---------- systems ---------- */

.sys-card { border-left: 2px solid var(--border); }
.sys-card.st-live { border-left-color: color-mix(in srgb, var(--win) 55%, transparent); }
.sys-card.st-testing,
.sys-card.st-backtesting { border-left-color: var(--warn); }
.sys-card.st-forward_testing { border-left-color: #7FC8FF; }

/* promotion gate: paper against reality, side by side */
.cmp { width: 100%; margin: 6px 0 10px; }
.cmp th { text-align: right; font-size: 9.5px; text-transform: uppercase; letter-spacing: .07em; color: var(--text-muted); padding: 4px 6px; }
.cmp th:first-child, .cmp td:first-child { text-align: left; color: var(--text-secondary); }
.cmp td { text-align: right; padding: 4px 6px; border-top: 1px solid var(--border); font-size: 13px; }
.sys-card.st-draft { border-left-color: var(--text-dim); }
.sys-card.st-archived { opacity: 0.55; }
.progress {
  height: 3px;
  background: var(--surface-3);
  border-radius: 2px;
  margin-top: 9px;
  overflow: hidden;
}
.progress-fill {
  height: 100%;
  background: var(--glow);
  box-shadow: var(--glow-tight);
}

/* ============================================================================
   WIDE TOUCH — 768 to 1023 (iPad portrait).
   Still a two-handed touch device, so bottom tabs and coarse targets stay.
   But cards at 768px are mostly empty gutter, so content densifies.
   ========================================================================== */

@media (min-width: 768px) and (max-width: 1023px) {
  #view { max-width: 720px; padding: 18px; }
  .stat-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .kv { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .row3, .row2 { gap: 14px; }
  .trade-sub { font-size: 13px; }
  #sizing-card { grid-template-columns: repeat(6, minmax(0, 1fr)); }
}

/* ---------- touch targets & pointer refinements ---------- */

@media (pointer: coarse) {
  input[type="text"], input[type="email"], input[type="datetime-local"],
  select, .seg button, button.ghost { min-height: 44px; }
  .chips .tag { min-height: 40px; display: inline-flex; align-items: center; }
  #tabbar button { min-height: 52px; }
}

@media (pointer: fine) {
  :focus-visible {
    outline: 1px solid var(--glow);
    outline-offset: 2px;
    border-radius: 4px;
    box-shadow: var(--glow-tight);
  }
  button.ghost:hover { border-color: var(--border-lit); color: var(--text-primary); }
  button.primary:hover { box-shadow: 0 0 30px rgba(198, 214, 235, 0.16), 0 0 1px rgba(198, 214, 235, 0.5); }
  .chips .tag:hover { border-color: var(--text-dim); }
  #tabbar button:hover { color: var(--text-secondary); }
  .card:hover { border-color: color-mix(in srgb, var(--border-lit) 60%, var(--border)); }
}
:focus:not(:focus-visible) { outline: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ---------- Goal Crushers ---------- */

.goals-head select { margin-top: 8px; }

/* One column on a phone; the sheet's side-by-side arrangement returns at
   desktop widths in desktop.css. */
.goals-split { display: block; }

.help-note {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 8px 12px;
  margin: 12px 0;
  background: var(--surface-1);
}
.help-note summary {
  cursor: pointer;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}
.help-note p { margin: 8px 0 0; }

.task-card { padding: 10px 12px; }
.task-top { display: flex; align-items: center; gap: 10px; }
.task-top input { flex: 1; min-width: 0; }
.task-score {
  color: var(--text-secondary);
  font-size: 13px;
  white-space: nowrap;
}

/* Seven dated boxes. Equal columns so the week reads as a week — a missed
   Wednesday should be findable by position, not by reading each label. */
.day-row {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 5px;
  margin-top: 9px;
}
.day-box {
  appearance: none;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text-muted);
  padding: 9px 0;
  font: 12px var(--mono);
  cursor: pointer;
  min-height: 40px;
  transition: border-color 140ms ease, box-shadow 140ms ease, color 140ms ease;
}
.day-box.on {
  color: var(--win);
  border-color: color-mix(in srgb, var(--win) 50%, transparent);
  box-shadow: var(--win-glow);
}
.day-box.wide { width: 100%; margin-top: 9px; font-size: 14px; }
.day-n { display: block; }

.stepper { display: flex; align-items: center; gap: 12px; margin-top: 9px; }
.stepper button { min-width: 46px; font-size: 18px; padding: 7px 0; }
.stepper-val { font-size: 20px; min-width: 40px; text-align: center; }

.task-more { margin-top: 8px; }
.task-more summary { font-size: 11.5px; cursor: pointer; }

/* Score % is the figure being judged, so it is the largest thing on screen. */
.goal-total { text-align: center; padding: 16px 14px; }
.goal-pct {
  font-size: 42px;
  line-height: 1;
  color: var(--text-primary);
  text-shadow: 0 0 26px rgba(198, 214, 235, 0.28);
}

.reward-tbl { width: 100%; }
.reward-tbl th {
  text-align: left;
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-muted);
  padding: 4px 6px;
}
.reward-tbl td { padding: 4px 6px; border-top: 1px solid var(--border); font-size: 13px; vertical-align: middle; }
.reward-tbl td input { padding: 7px 9px; font-size: 14px; }
.reward-tbl tr.reached td { color: var(--text-primary); }
.reward-tbl tr.current {
  background: color-mix(in srgb, var(--win) 9%, transparent);
  box-shadow: inset 2px 0 0 var(--win);
}

/* ---------- MMA/EOD (amendment 38) ---------- */

/* Date navigation. The arrows are fixed-width and the picker takes the slack,
   so stepping through days never moves the arrow under your thumb. */
.review-head { display: flex; flex-direction: column; gap: 10px; }
.review-nav { display: flex; align-items: center; gap: 8px; }
.review-nav > button {
  flex: 0 0 auto;
  width: 46px;
  min-height: 46px;
  font-size: 20px;
  line-height: 1;
  padding: 0;
}
.review-nav input.review-date {
  flex: 1 1 auto;
  min-width: 0;
  width: auto;
  max-width: none;
  text-align: center;
}
.review-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13px; color: var(--text-secondary); }

/* A second-level segment inside a view already carrying one. Smaller, so the
   hierarchy reads at a glance rather than looking like two peer switches. */
.seg.seg-sub { margin-bottom: 12px; }
.seg.seg-sub button { font-size: 12px; padding: 8px 12px; }

.review-body > .section:first-child { margin-top: 2px; }

.field-card, .watch-row, .mark-row, .passed-row { display: flex; flex-direction: column; gap: 8px; }
.field-card .field, .watch-row .field, .passed-row .field { margin: 0; }

.watch-top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.watch-top .watch-asset { flex: 1 1 140px; min-width: 0; text-transform: uppercase; }
.watch-top .asset { font-weight: 600; }
.watch-top > button.danger {
  flex: 0 0 auto;
  width: 40px;
  min-height: 40px;
  padding: 0;
  font-size: 18px;
  line-height: 1;
  margin-left: auto;
}
.watch-top select { flex: 0 0 auto; width: auto; }

/* Bias and outcome pickers. Buttons rather than a select because the whole
   point is that the choice is visible on the card afterwards without opening
   anything — an unmarked call has to look unmarked. */
.bias-pick, .outcome-pick { display: flex; gap: 6px; flex-wrap: wrap; }
.bias-btn, .outcome-btn {
  appearance: none;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text-muted);
  font: 12px var(--sans);
  padding: 7px 12px;
  min-height: 36px;
  cursor: pointer;
}
/* Bias labels are single lowercase words from the data model; outcome labels
   are already sentence-cased, and capitalising them gives "Played Out". */
.bias-btn { text-transform: capitalize; }
.outcome-pick { margin-top: 2px; }
.outcome-btn { flex: 1 1 0; min-width: 0; }
.bias-btn.on, .outcome-btn.on { color: var(--text-primary); border-color: var(--text-muted); background: var(--surface-3, var(--surface-2)); }
.bias-btn.bias-bullish.on, .outcome-btn.outcome-played_out.on {
  color: var(--win); border-color: color-mix(in srgb, var(--win) 55%, var(--border));
}
.bias-btn.bias-bearish.on, .outcome-btn.outcome-didnt.on {
  color: var(--loss); border-color: color-mix(in srgb, var(--loss) 55%, var(--border));
}
.badge.bias-bullish, .badge.outcome-played_out { color: var(--win); border-color: color-mix(in srgb, var(--win) 45%, var(--border)); }
.badge.bias-bearish, .badge.outcome-didnt { color: var(--loss); border-color: color-mix(in srgb, var(--loss) 45%, var(--border)); }

/* Read-only trades. Flat, and visibly not a form — nothing here is editable
   and the card must not invite a tap that does nothing. */
.review-trades { display: flex; flex-direction: column; gap: 8px; }
.review-trade { cursor: pointer; padding: 10px 12px; }
.review-trade:hover { border-color: var(--text-dim); }

.day-card { display: flex; flex-direction: column; gap: 6px; }

/* Screenshot thumbnails carry their own remove control. */
.shot { position: relative; }
.shot-x {
  position: absolute;
  top: -6px;
  right: -6px;
  width: 24px;
  min-height: 24px;
  padding: 0;
  border-radius: 999px;
  font-size: 14px;
  line-height: 1;
  background: var(--surface-1);
}

/* The file input itself is never shown — a bare one renders as a 21px browser
   widget in a column of 46px controls and is the one thing on the page that
   still looks like a web form. It stays in the DOM and focusable-adjacent so
   the button can open it. */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.shot-drop {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 8px;
}

/* ---------- cost sizing & drafts (amendment 39) ---------- */

/* When the size is named, the risk is the ANSWER — so it is the loudest thing
   in the readout. "100 USDT at 10x" hides a 20 USDT loss, and finding that out
   after the fact is exactly what this is here to prevent. */
#sizing-card .risk-lead {
  border-color: color-mix(in srgb, var(--warn) 40%, var(--border));
  background: color-mix(in srgb, var(--warn) 7%, var(--surface-2));
}
#sizing-card .risk-lead .k { color: var(--warn); }

/* An input that is not driving anything right now: still readable, visibly
   not in play. Never hidden — hiding it would move everything below it every
   time the mode changes, which is the layout-shift bug all over again. */
.muted-block { opacity: 0.5; }
.muted-block input:disabled { color: var(--text-muted); }

/* Reserved line: the backtest running result. Fixed height so the row below
   it cannot move while you type. */
.bt-preview {
  min-height: 20px;
  font-size: 12.5px;
  color: var(--text-secondary);
  margin: -4px 0 10px;
}
