/* ---------- self-hosted faces ----------
   These used to come from fonts.googleapis.com behind a render-blocking
   stylesheet, which cost a DNS lookup, a TLS handshake and a round trip to a
   third party before a single glyph could paint — and told Google who was
   reading the page. Same files, same origin, one year immutable.
   Archivo is the VARIABLE cut, so one file covers 500-800 rather than four.
   unicode-range keeps latin-ext off the wire for anyone who never needs it. */
@font-face {
  font-family: "Anton";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/anton-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Anton";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/anton-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/assets/fonts/archivo-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/assets/fonts/archivo-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/ibm-plex-mono-400.woff2") format("woff2");
}

/* ============================================================
   AWAKE — RECURSIVE TRADING PLATFORM (paper stage)
   SaturnDesign direction (compose 2026-08-07, mobile residual):
     "Mercury × Membership Club (grammar) × Data brutalism
      × Marketplace liquidity flywheel" — synthesize, never clone.
   Instrument still: carbon-copy cockpit, dense scan grid, muted
   chrome, monochrome candles. Mint = live/risk ONLY, never décor.
   Signature: TEAR-OFF RECEIPTS + PAPER STAGE seal.
   Hierarchy: MONEY > LOGO. Mono owns numbers. No purple SaaS,
   glass cards, pill soup, or fake invite exclusivity.
   ============================================================ */

:root {
  /* --- DTCG-aligned color roles (compose tokens + product facts) --- */
  --bg: #ece7db;
  --surface: #e0dac9;
  --ink: #141312;
  --ink-muted: #57534b;
  --accent: #d9e8cf;
  --accent-ink: #141312;
  --paper: var(--bg);
  --paper-deep: var(--surface);
  --mint: var(--accent);
  --tape: rgba(196, 186, 158, 0.55);
  /* #57534b → 6.20:1 on paper / 5.48:1 on paper-deep (AA floor held) */
  --muted: var(--ink-muted);
  --line: 1px solid var(--ink);

  /* --- compose spacing scale (base 8px) --- */
  --space-050: 4px;
  --space-100: 8px;
  --space-150: 12px;
  --space-200: 16px;
  --space-300: 24px;
  --space-400: 32px;
  --pad: clamp(var(--space-150), 2vw, var(--space-300));

  /* --- type scale ratio 1.25 from base 16 (compose) ---
     Furniture uses xs/sm; money+mid uses base→2xl. SIZE and WEIGHT are
     earned only by numbers that CHANGE and cost money. */
  --t-fine: 10.2px;   /* tokens.type-scale.xs — disclosures */
  --t-label: 12.8px;  /* sm — labels (display-shrunk via letter-space) */
  --t-data: 12.8px;   /* sm — table + readout data */
  --t-lead: 16px;     /* base — P/L you stare at */
  --t-big: 20px;      /* lg — equity */
  --t-hero: 31.3px;   /* 2xl — live price, loudest in the room */
  --t-stamp: 25px;    /* xl — place / side stamps */
  --font: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --display: "Anton", "Archivo", sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --rail-w: 236px;
  --radius: 0; /* data brutalism — no soft corners on instrument chrome */

  /* --- theme plumbing (INK MODE) — every rgba() wash/hairline/plate below
     references these triplets, so ONE override block retints the sheet --- */
  color-scheme: light;
  --ink-rgb: 20, 19, 18;
  --paper-rgb: 236, 231, 219;
  --muted-rgb: 107, 103, 95;
  --mint-rgb: 217, 232, 207;
  --shadow-rgb: 20, 19, 18;   /* blurred TRUE shadows; hard offsets are press
                                 impressions and keep --ink-rgb in both themes */
  --behind: var(--bg);        /* what shows through a tear. Resolves AT :root,
                                 so .receipt's re-pins can't reach it */
  --receipt-paper: #f4f0e6;   /* the printer prints on paper in BOTH themes */
}

/* ============================================================
   INK MODE — "THE NEGATIVE". The same broker sheet run back
   through the copier with the toner inverted: warm carbon
   ground, cream ink. Mint is untouched — live/risk only, the
   one thing the negative never flips. Receipts stay paper (see
   the .receipt token re-pin), so fills land as physical light
   objects on the dark desk. Contrast, measured: ink 14.4:1,
   muted 7.0:1 on ground / 6.4:1 on surface — AA+ everywhere.
   ============================================================ */
html[data-theme="ink"] {
  color-scheme: dark;
  --bg: #17140f;
  --surface: #211d15;
  --ink: #e9e3d2;
  --ink-muted: #a89f8b;
  --tape: rgba(70, 62, 47, 0.5);
  --ink-rgb: 233, 227, 210;
  --paper-rgb: 23, 20, 15;
  --muted-rgb: 168, 159, 139;
  --shadow-rgb: 0, 0, 0;
}

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

/* The terminal shows and hides almost everything through the [hidden]
   attribute, but the browser's `[hidden] { display: none }` is a USER-AGENT
   rule that any author `display` beats — the failure mode is a panel that
   ignores `.hidden = true` and just stays on screen. Six one-off patches
   below this line were written after that bit; this closes the class. */
[hidden] { display: none !important; }

html, body { height: 100%; }

/* iOS: stop text auto-inflating in landscape; kill the default gray tap
   flash so presses read through the brand's own micro-press feedback
   instead (see ":active" rules near the bottom of this file). */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}

body {
  font-family: var(--font);
  background: var(--paper);
  color: var(--ink);
  font-weight: 500;
  line-height: 1.3;
  -webkit-font-smoothing: antialiased;
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  overflow-x: hidden;
}

::selection { background: var(--mint); color: var(--ink); }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
input { font: inherit; color: inherit; }

/* print grain over everything — same sheet as the main site */
.grain {
  position: fixed;
  inset: 0;
  z-index: 100;
  pointer-events: none;
  opacity: 0.5;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.10 0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ink, not mint: mint on paper is 1.04:1 — a focus ring nobody can see, and
   it spent the risk accent on chrome. Ink is 15:1 and clears WCAG 1.4.11. */
:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; }

/* THE NEGATIVE's ground: the noise inverts to toner specks and screens on;
   the shared Saturn plate draws paper+ink inside its own shader, so the
   smart-invert pair flips it to warm-dark without touching plate.js */
html[data-theme="ink"] .grain { filter: invert(1); mix-blend-mode: screen; opacity: 0.3; }
html[data-theme="ink"] .plate { filter: invert(1) hue-rotate(180deg); }

/* ============ masthead ============ */

.mast {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px var(--pad);
  border-bottom: 2px solid var(--ink);
  flex-wrap: wrap;
  position: relative;
  z-index: 60;
  background: var(--paper);
}

/* mast-row: structural wrapper only (see index.html comment). Desktop/
   tablet unwrap it with display:contents so #mast's own flex-wrap keeps
   laying out the eight children directly, in the sequence pinned by the
   "order" values below — visually identical to the old flat markup. */
.mast-row { display: contents; }

.mast-brand {
  order: 1;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 9px;
  border: var(--line);
  background: var(--paper);
  white-space: nowrap;
}
.mast-brand:hover { box-shadow: 3px 3px 0 rgba(var(--ink-rgb), 0.9); transform: translateY(-1px); }
.mast-brand-arrow { font-size: 12px; }

.mast-id { order: 2; display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }

.mast-title {
  font-family: var(--display);
  /* a wordmark, not an instrument — it should be legible, not competitive */
  font-size: 16px;
  line-height: 1;
  letter-spacing: 0.02em;
  background: var(--ink);
  color: var(--paper);
  padding: 4px 12px 6px;
  transform: rotate(-0.6deg);
}

.mast-tag {
  font-family: var(--mono);
  font-size: var(--t-fine);
  font-weight: 400;
  letter-spacing: 0.18em;
  color: var(--muted);
  padding-left: 2px;
  white-space: nowrap;
}

/* ============ the book strip — izzy's real on-chain positions ============
   SaturnDesign craft (stage 2026-08-07): instrument rail, not marketing.
   Position rows are the live risk; #bookTrack is the trailing 90D record
   that keeps the strip load-bearing when the book is FLAT. Mint still
   means live/risk only. */

.book-strip {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 6px var(--pad);
  border-bottom: 2px solid var(--ink);
  background: var(--paper-deep);
  font-family: var(--mono);
  overflow: hidden;
  white-space: nowrap;
  transition: box-shadow 0.15s ease;
}
.book-strip[hidden] { display: none; }
.book-strip:hover { box-shadow: inset 0 -4px 0 var(--ink); }
.book-strip:focus-visible { outline: 3px solid var(--ink); outline-offset: -3px; }
/* FLAT is a real published state — quiet the strip, don't hide the claim */
.book-strip.is-flat {
  background-image: repeating-linear-gradient(
    -45deg,
    rgba(var(--ink-rgb), 0.05) 0 8px,
    transparent 8px 16px
  );
}

.book-label {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  padding-right: 13px;
  border-right: 2px solid var(--ink);
}
.book-dot {
  width: 9px;
  height: 9px;
  background: var(--mint);
  outline: 1px solid var(--ink);
  animation: connPulse 2s ease-in-out infinite;
}

.book-rows {
  flex: 0 1 auto;
  min-width: 0;
  display: inline-flex;
  gap: 18px;
  overflow-x: auto;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
}
.book-rows::-webkit-scrollbar { display: none; }

.book-row { display: inline-flex; align-items: baseline; gap: 7px; font-size: 11px; font-weight: 700; }
.book-row-sym { font-weight: 800; }
.book-row-side { font-size: 9px; letter-spacing: 0.08em; padding: 1px 4px; border: 1px solid var(--ink); }
.book-row-side--short { background: var(--ink); color: var(--paper); }
.book-row-meta { font-size: 9px; color: var(--muted); font-weight: 600; font-variant-numeric: tabular-nums; }
.book-row-pnl { font-variant-numeric: tabular-nums; }
.book-row-pnl--up { background: var(--mint); outline: 1px solid var(--ink); padding: 0 4px; }
.book-row-pnl--down { background: var(--ink); color: var(--paper); padding: 0 4px; }
.book-flat {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--muted);
  padding-right: 4px;
}

/* trailing-90D track + spark — consumes /api/gmx/stats */
.book-track {
  flex: none;
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  padding: 0 10px;
  margin-left: 2px;
  border-left: 2px solid var(--ink);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  font-variant-numeric: tabular-nums;
}
.book-track[hidden] { display: none; }
.book-track-win {
  font-size: 9px;
  letter-spacing: 0.12em;
  padding: 1px 5px;
  border: 1px solid var(--ink);
  background: var(--paper);
}
.book-track-pnl { font-size: 11px; }
.book-track-meta { font-size: 9px; color: var(--muted); font-weight: 600; }

.book-spark {
  flex: none;
  width: 88px;
  height: 20px;
  border: 1px solid var(--ink);
  background: var(--paper);
  image-rendering: pixelated;
}
.book-spark[hidden] { display: none; }

.book-note {
  flex: 1 1 auto;
  min-width: 0;
  text-align: right;
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
}

.chip {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  padding: 4px 8px;
  border: var(--line);
  background: var(--paper);
  white-space: nowrap;
}
/* unmissable in CONTRAST, no longer competing in SIZE — it is a fact you
   read once, not a number you watch. It had the largest area on screen. */
.chip-sim { order: 3; background: var(--ink); color: var(--paper); transform: rotate(0.8deg); font-size: var(--t-fine); padding: 3px 6px; }
.chip-btn:hover { box-shadow: 3px 3px 0 rgba(var(--ink-rgb), 0.9); transform: translateY(-1px); }

/* ============ replay transport — practicing on past bars ============
   sibling of .book-strip. the mint dot follows the app's existing
   "something is currently active" language (conn-dot, book-dot); the
   hatch on .chip-sim / .book-strip is the separate "not live" tell so
   the two states can never be confused for each other. */

.replay-bar {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 6px var(--pad);
  border-bottom: 2px solid var(--ink);
  background:
    repeating-linear-gradient(-45deg, rgba(var(--ink-rgb), 0.07) 0 8px, transparent 8px 16px),
    var(--paper-deep);
  font-family: var(--mono);
  overflow-x: auto;
  white-space: nowrap;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
}
.replay-bar[hidden] { display: none; }
.replay-bar::-webkit-scrollbar { display: none; }

.replay-label {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  padding-right: 13px;
  border-right: 2px solid var(--ink);
}
.replay-dot {
  width: 9px;
  height: 9px;
  background: var(--mint);
  outline: 1px solid var(--ink);
  animation: connPulse 2s ease-in-out infinite;
  flex: none;
}

.replay-btn, .replay-exit { flex: none; }
.replay-exit { margin-left: auto; background: var(--ink); color: var(--paper); }
.replay-exit:hover { background: var(--paper); color: var(--ink); box-shadow: 3px 3px 0 rgba(var(--ink-rgb), 0.9); }

.replay-speed-field {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--muted);
}
.replay-speed-field select {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 4px 6px;
  border: var(--line);
  background: var(--paper);
  color: var(--ink);
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
}
.replay-speed-field select:hover { background: var(--paper-deep); }

.replay-clock {
  flex: none;
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.replay-progress {
  flex: none;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

/* the unmistakable "not live" tell — set on <body> by the JS while
   replay is armed. touches only decorative chrome, never a number. */
body.is-replay .chip-sim {
  background-image: repeating-linear-gradient(-45deg, transparent 0 6px, rgba(var(--mint-rgb), 0.3) 6px 12px);
}
body.is-replay .book-strip {
  background-image: repeating-linear-gradient(-45deg, rgba(var(--ink-rgb), 0.08) 0 9px, transparent 9px 18px);
  opacity: 0.55;
}
body.is-replay .book-strip:hover { opacity: 0.85; }

/* pair tabs */
.mast-pairs { order: 5; display: flex; gap: 0; margin-left: 6px; flex-wrap: wrap; }
#whatIs { order: 4; }
#moreMarkets { order: 6; }
.pair-tab {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 6px 11px;
  border: var(--line);
  margin-left: -1px;
  background: var(--paper);
  position: relative;
}
.pair-tab:first-child { margin-left: 0; }
.pair-tab:hover { background: var(--paper-deep); }
.pair-tab.is-on { background: var(--ink); color: var(--paper); }
.pair-tab .pair-mid {
  display: block;
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.03em;
  opacity: 0.75;
}

/* live block */
/* the two instrument clusters — what the market is doing, what your money is
   doing — get walls so the eye lands on a ZONE instead of hunting through a
   row of identically-sized chips */
.mast-live { order: 7; display: flex; align-items: baseline; gap: 12px; margin-left: auto; padding: 2px 12px; border-left: 1px dashed var(--muted); }

.conn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
}
.conn-dot { width: 9px; height: 9px; background: var(--ink); }
.conn[data-state="live"] .conn-dot { background: var(--mint); outline: 1px solid var(--ink); animation: connPulse 2s ease-in-out infinite; }
.conn[data-state="connecting"] .conn-dot,
.conn[data-state="stale"] .conn-dot { animation: connBlink 0.9s steps(2, start) infinite; }
@keyframes connPulse { 50% { opacity: 0.55; } }
@keyframes connBlink { 50% { opacity: 0.15; } }

.mast-mark {
  font-family: var(--mono);
  font-size: var(--t-hero);
  font-weight: 700;
  letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
}
.mast-stat {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.mast-stat.is-neg { background: var(--ink); color: var(--paper); padding: 2px 5px; }

/* account block */
.mast-acct { order: 8; display: flex; align-items: center; gap: 10px; }
.equity-spark { border: var(--line); background: var(--paper); image-rendering: pixelated; }
.mast-acct-num { display: flex; flex-direction: column; align-items: flex-end; }
.mast-acct-label { font-family: var(--mono); font-size: 9px; font-weight: 700; letter-spacing: 0.12em; color: var(--muted); }
.mast-acct-val { font-family: var(--mono); font-size: var(--t-big); font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1.05; }

/* session day ledger under equity — realized paper P/L for UTC day only */
.mast-session {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--muted);
  margin-top: 2px;
}
.mast-session[hidden] { display: none; }
.mast-session em {
  font-style: normal;
  font-variant-numeric: tabular-nums;
  padding: 0 3px;
}
.mast-session em.is-up { background: var(--mint); color: var(--ink); }
.mast-session em.is-down { background: var(--ink); color: var(--paper); }

/* account health — three tight columns + a liquidation meter, the persistent
   risk read of a real perps desk, in the masthead's own mono idiom */
.mast-health {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  padding-left: 12px;
  border-left: var(--line);
}
.mast-health > div { display: flex; flex-direction: column; align-items: flex-end; }
.mast-health dt {
  font-family: var(--mono);
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--muted);
}
.mast-health dd {
  font-family: var(--mono);
  font-size: var(--t-data);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
}
/* PnL sign stays in ink, not mint — mint is the risk colour, and a green
   number is not a risk. Up = plain ink, down = inverted chip. */
.mast-health dd.is-down { background: var(--ink); color: var(--paper); padding: 0 3px; }
.mast-health .mast-health-ratio { align-items: flex-end; }
.mast-health .health-meter {
  width: 66px;
  height: 4px;
  margin-top: 3px;
  border: 1px solid var(--ink);
  background: var(--paper);
  position: relative;
}
.mast-health .health-meter i {
  display: block;
  height: 100%;
  width: 0;
  background: var(--ink);
  transition: width 0.3s ease;
}
/* the one legitimate mint: the account is genuinely near liquidation */
.mast-health .health-meter i.is-risk { background: var(--mint); }
.mast-health dd.is-risk-text { background: var(--mint); color: var(--ink); padding: 0 3px; }

/* ============ cockpit grid ============ */

.cockpit {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px var(--rail-w);
  grid-template-rows: minmax(320px, 1fr) minmax(180px, 260px);
  grid-template-areas:
    "chart ticket rail"
    "desk  desk   rail";
  gap: 0;
  min-height: 0;
}

.panel { border-right: 2px solid var(--ink); border-bottom: 2px solid var(--ink); min-width: 0; min-height: 0; display: flex; flex-direction: column; }
.panel-chart { grid-area: chart; }
.panel-ticket { grid-area: ticket; overflow-y: auto; }
.panel-desk { grid-area: desk; border-bottom: none; }
.rail { grid-area: rail; border-bottom: none; }

.panel-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 10px;
  border-bottom: 1px dashed var(--muted);
  flex: none;
  min-height: 38px;
}

.panel-tag {
  font-family: var(--display);
  font-size: 12px;
  letter-spacing: 0.05em;
  background: var(--ink);
  color: var(--paper);
  padding: 1px 8px 2px;
}

/* timeframe rail */
.tf-rail { display: flex; }
.tf-btn {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  padding: 4px 8px;
  border: var(--line);
  margin-left: -1px;
  background: var(--paper);
}
.tf-btn:first-child { margin-left: 0; }
.tf-btn:hover { background: var(--paper-deep); }
.tf-btn.is-on { background: var(--ink); color: var(--paper); }

.ohlc-read {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  font-variant-numeric: tabular-nums;
}

.chip-follow { margin-left: auto; background: var(--mint); }

.chart-wrap { position: relative; flex: 1; min-height: 0; cursor: crosshair; }
#chart { position: absolute; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; }

.chart-badge {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%) rotate(-1deg);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  padding: 6px 12px;
  background: var(--ink);
  color: var(--paper);
  animation: connBlink 1.2s steps(2, start) infinite;
}

/* ============ order ticket ============ */

.ticket-bal { margin-left: auto; font-family: var(--mono); font-size: 10px; font-weight: 700; color: var(--muted); font-variant-numeric: tabular-nums; }

.side-switch { display: flex; margin: 10px 10px 0; }
.side-btn {
  flex: 1;
  font-family: var(--display);
  font-size: var(--t-big);
  letter-spacing: 0.06em;
  padding: 8px 0 9px;
  border: 2px solid var(--ink);
  border-radius: var(--radius);
  background: var(--paper);
}
.side-short { margin-left: -2px; }
.side-btn.is-on { background: var(--ink); color: var(--paper); }
.side-btn:not(.is-on):hover { background: var(--paper-deep); }

.ticket-row { display: flex; gap: 8px; margin: 10px 10px 0; }
.ticket-type .type-btn {
  flex: 1;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  padding: 5px 0;
  border: 1px dashed var(--muted);
  background: var(--paper);
}
.ticket-type .type-btn.is-on { border: var(--line); background: var(--paper-deep); }

.ticket-field { display: flex; flex-direction: column; gap: 4px; margin: 10px 10px 0; }
/* pre-existing bug fix: any element with an author "display" rule silently
   ignores the [hidden] attribute (author styles beat the UA stylesheet at
   equal specificity) — .ticket-field never had the override that
   .book-strip/.replay-bar/.gate/.intro-banner already carry below, so
   #nameField, #limitField and #stopField rendered even while hidden=true.
   Same bug on .ticket-preview (it hid #ticketPreviewRr in name only). */
.ticket-field[hidden], .ticket-preview[hidden] { display: none; }
.ticket-row .ticket-field { margin: 0; flex: 1; min-width: 0; }
.ticket-triggers { margin: 10px 10px 0; }
.ticket-field > span {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: var(--muted);
}
.ticket-field em { font-style: normal; opacity: 0.7; }
.ticket-field input {
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 700;
  padding: 7px 9px;
  border: var(--line);
  background: var(--paper);
  width: 100%;
  font-variant-numeric: tabular-nums;
}
.ticket-field input:focus { outline: 3px solid var(--ink); outline-offset: 0; }

/* percent-of-balance sizing — the caption exists because "25%" alone never
   says a percent OF WHAT, and a title attribute is invisible on a phone */
.size-chips-head {
  margin: 8px 10px 3px;
  font-family: var(--mono);
  font-size: var(--t-label);
  font-weight: 600;
  letter-spacing: 0.1em;
  color: var(--muted);
}
.size-chips { display: flex; gap: 6px; margin: 0 10px; }
.size-chip {
  flex: 1;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 5px 0;
  border: 1px dashed var(--muted);
  background: var(--paper);
}
.size-chip:hover { border-style: solid; border-color: var(--ink); background: var(--paper-deep); }
.size-chip:active { transform: translateY(1px); }

.size-warn {
  margin: 6px 10px 0;
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.05em;
  padding: 4px 7px;
  background: var(--ink);
  color: var(--paper);
}

.ticket-field em#sizeAsset { color: var(--ink); opacity: 1; }

.ticket-preview-rr { margin-top: 6px; }
.ticket-preview dd.rr-good { background: var(--mint); padding: 0 3px; display: inline-block; }

.lev-block { margin: 12px 10px 0; }
.lev-head {
  display: flex;
  justify-content: space-between;
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: var(--muted);
}
.lev-val { font-size: 13px; color: var(--ink); }
.lev-block input[type="range"] {
  width: 100%;
  margin: 8px 0 2px;
  -webkit-appearance: none;
  appearance: none;
  height: 2px;
  background: var(--ink);
}
.lev-block input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  background: var(--paper);
  border: 2px solid var(--ink);
  /* --lev-shadow is set by ticketPreview() via the CSSOM, offset only —
     leverage climbing reads as heavier, not as a new alarm color */
  box-shadow: var(--lev-shadow, 2px) var(--lev-shadow, 2px) 0 rgba(var(--ink-rgb), 0.9);
  cursor: ew-resize;
}
.lev-block input[type="range"]::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border-radius: 0;
  background: var(--paper);
  border: 2px solid var(--ink);
  box-shadow: var(--lev-shadow, 2px) var(--lev-shadow, 2px) 0 rgba(var(--ink-rgb), 0.9);
  cursor: ew-resize;
}
.lev-marks { display: flex; justify-content: space-between; font-family: var(--mono); font-size: 8px; color: var(--muted); }

.ticket-preview { display: flex; gap: 0; margin: 12px 10px 0; border: 1px dashed var(--muted); }
.ticket-preview > div { flex: 1; padding: 6px 8px; border-left: 1px dashed var(--muted); }
.ticket-preview > div:first-child { border-left: none; }
.ticket-preview dt { font-family: var(--mono); font-size: 8px; font-weight: 700; letter-spacing: 0.1em; color: var(--muted); }
.ticket-preview dd { font-family: var(--mono); font-size: 13px; font-weight: 800; font-variant-numeric: tabular-nums; }
.ticket-preview dd.is-risk { background: var(--mint); padding: 0 3px; display: inline-block; }

.place-btn {
  display: block;
  margin: var(--space-150) 10px;
  width: calc(100% - 20px);
  font-family: var(--display);
  font-size: var(--t-stamp);
  letter-spacing: 0.06em;
  padding: 10px 0 12px;
  border: 2px solid var(--ink);
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--paper);
  transition: box-shadow 0.12s ease, transform 0.12s ease;
}
.place-btn:hover { box-shadow: 5px 5px 0 rgba(var(--ink-rgb), 0.45); transform: translate(-1px, -1px); }
.place-btn:active { transform: translate(1px, 1px); box-shadow: none; }
.place-btn[disabled] { opacity: 0.4; cursor: not-allowed; box-shadow: none; transform: none; }
/* Not-ready state. Deliberately NOT [disabled]: the button still takes a click
   so it can say what is missing. Hollow + dashed reads "not armed" at a glance
   without the dead-end feel of a greyed-out control. */
.place-btn[aria-disabled="true"] {
  background: var(--paper);
  color: var(--ink);
  border-style: dashed;
}
.place-btn[aria-disabled="true"]:hover { box-shadow: none; transform: none; }
.place-btn[aria-disabled="true"]:active { transform: translate(1px, 1px); }

.ticket-note {
  margin: 0 10px 12px;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 6px 8px;
  border: var(--line);
  background: var(--paper-deep);
}

/* ============ desk ============ */

.desk-tabs {
  display: flex;
  align-items: center;
  gap: 0;
  padding: 7px 10px 0;
  border-bottom: var(--line);
  flex: none;
}
.desk-tab {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  padding: 6px 10px 5px;
  border: var(--line);
  border-bottom: none;
  margin-left: -1px;
  background: var(--paper-deep);
  position: relative;
  top: 1px;
}
.desk-tab:first-child { margin-left: 0; }
.desk-tab.is-on { background: var(--paper); border-bottom: 2px solid var(--paper); }
.desk-count { opacity: 0.6; }

.desk-stats {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  padding-bottom: 4px;
  font-variant-numeric: tabular-nums;
}

.desk-scroll { flex: 1; overflow: auto; min-height: 0; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }

.desk-table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.desk-table th {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--muted);
  text-align: right;
  padding: 6px 10px 4px;
  border-bottom: 1px dashed var(--muted);
  position: sticky;
  top: 0;
  background: var(--paper);
  white-space: nowrap;
}
.desk-table th:first-child, .desk-table td:first-child { text-align: left; }
.desk-table td {
  font-family: var(--mono);
  font-size: var(--t-data);
  font-weight: 600;
  text-align: right;
  padding: 5px 10px;
  border-bottom: 1px solid rgba(var(--muted-rgb), 0.25);
  white-space: nowrap;
}
.desk-table tr:hover td { background: var(--paper-deep); }

/* P/L is the number a trader stares at — it outranks every label near it */
.pnl-chip { padding: 2px 6px; font-weight: 800; font-size: var(--t-lead); }
/* the eye should find P/L without reading a header */
#tblPositions td:nth-child(12), #tblPositions th:nth-child(12) { border-left: 1px dashed var(--muted); border-right: 1px dashed var(--muted); }
.pnl-pos { background: var(--mint); outline: 1px solid var(--ink); }
.pnl-neg { background: var(--ink); color: var(--paper); }

.side-cell-long::before { content: "▲ "; font-size: 9px; }
.side-cell-short::before { content: "▼ "; font-size: 9px; }

.row-btn {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.08em;
  padding: 3px 7px;
  border: var(--line);
  background: var(--paper);
}
.row-btn:hover { background: var(--ink); color: var(--paper); }
/* full CLOSE is the decisive action — inverted at rest so the finger finds it
   among the partial rungs without scanning label text */
.row-btn-close {
  background: var(--ink);
  color: var(--paper);
}
.row-btn-close:hover { background: var(--paper); color: var(--ink); }
/* pair cells jump the chart to that market — underlined only on hover so the
   desk doesn't look link-noisy at rest */
.cell-pair { cursor: pointer; }
.cell-pair:hover { text-decoration: underline; text-underline-offset: 2px; }

/* keep partial rungs + FLIP + CLOSE on one sticky thumb rail without wrapping
   into a multi-line pile that steals desk vertical budget */
.cell-actions {
  white-space: nowrap;
  text-align: right;
}
.cell-actions .row-btn { margin-left: 3px; }

/* size crafts as coins over live notional — numbers only, no card chrome */
.cell-size {
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
  white-space: nowrap;
}
.cell-size .sz-asset {
  display: block;
  font-weight: 700;
}
.cell-size .sz-usd {
  display: block;
  font-size: var(--t-fine);
  font-weight: 600;
  color: var(--muted);
  letter-spacing: 0.02em;
}

/* about-to-be-liquidated must NOT look like in-profit — both were mint, the
   best and worst states in the product wearing the same color. Danger reads
   as inverted ink (the same language a losing P/L already speaks) and keeps
   the blink; mint stays for live-and-positive only. */
.liq-near { background: var(--ink); color: var(--paper); animation: connBlink 0.8s steps(2, start) infinite; padding: 1px 5px; font-weight: 700; }

.desk-empty {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--muted);
  padding: 18px 12px;
}

/* ============ receipts rail ============ */

.rail {
  display: flex;
  flex-direction: column;
  min-height: 0;
  background:
    repeating-linear-gradient(0deg, transparent 0 26px, rgba(var(--muted-rgb), 0.08) 26px 27px),
    var(--paper-deep);
}

.rail-head {
  display: flex;
  align-items: center;
  gap: 0;
  padding: 7px 10px 0;
  border-bottom: 2px solid var(--ink);
  background: var(--paper);
  flex: none;
}

/* ---------- THE WIRE: headlines you can trade off ----------
   This column used to print receipts of trades already done. A record of the
   past is worth less than a reason to act, so the wire owns it now and the
   receipts keep a tab. */

.rail-tab {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.09em;
  padding: 6px 10px 5px;
  border: var(--line);
  border-bottom: none;
  margin-right: -1px;
  background: var(--paper-deep);
  position: relative;
  top: 1px;
}
.rail-tab.is-on { background: var(--paper); border-bottom: 2px solid var(--paper); }
.rail-head .chip-btn { margin-left: auto; margin-bottom: 5px; }
/* unread count on RECEIPTS — a fill printed while the rail sat on MOVERS
   must say so; flat ink block, no radius, no blur, matches the sheet */
.tab-badge { margin-left: 5px; padding: 0 4px; background: var(--ink); color: var(--paper); font-size: 10px; font-weight: 800; }

.wire, .receipts-pane { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.wire[hidden], .receipts-pane[hidden] { display: none; }

.wire-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border-bottom: 1px dashed var(--muted);
  flex: none;
}
.wire-sub {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--muted);
}
#wireRefresh { margin-left: auto; font-size: 12px; line-height: 1; padding: 3px 7px; }

.wire-list { flex: 1; overflow-y: auto; min-height: 0; overscroll-behavior: contain; }

/* mode switch: UP / DOWN / BUSIEST */
.mv-modes { display: flex; gap: 0; }
.mv-mode {
  font-family: var(--mono);
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.1em;
  padding: 4px 7px;
  border: 1px solid var(--muted);
  margin-left: -1px;
  background: var(--paper);
}
.mv-mode:first-child { margin-left: 0; }
.mv-mode.is-on { background: var(--ink); color: var(--paper); border-color: var(--ink); }

/* one row per market — rank, symbol, price, move. Tap loads the chart. */
.mv-row {
  display: flex;
  align-items: baseline;
  gap: 7px;
  width: 100%;
  padding: 7px 10px;
  border-bottom: 1px solid rgba(var(--muted-rgb), 0.22);
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  text-align: left;
}
.mv-row:hover { background: var(--paper-deep); }
.mv-row:focus-visible { outline: 3px solid var(--ink); outline-offset: -3px; }
.mv-row.is-current { background: var(--paper-deep); box-shadow: inset 3px 0 0 var(--ink); }

.mv-rank { font-size: 8px; color: var(--muted); font-weight: 700; min-width: 13px; }
.mv-sym { font-size: 13px; font-weight: 800; letter-spacing: 0.02em; }
.mv-px { font-size: 10px; color: var(--muted); font-weight: 600; margin-left: auto; }
.mv-chg { font-size: var(--t-data); font-weight: 800; padding: 1px 4px; min-width: 58px; text-align: right; }
/* mint stays the live/positive accent; a drop wears inverted ink */
.mv-up { background: var(--mint); outline: 1px solid var(--ink); }
.mv-down { background: var(--ink); color: var(--paper); }
.mv-vol { font-size: var(--t-data); font-weight: 800; min-width: 58px; text-align: right; }

.wire-empty, .wire-note {
  font-family: var(--mono);
  font-size: 8px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--muted);
  padding: 9px 10px;
  line-height: 1.5;
}
.wire-note { border-top: 1px dashed var(--muted); flex: none; }
.wire-empty { font-size: 10px; }

/* NEWS wire rows — tag stamp + stack title + source/age meta.
   Ink stamp language (not cards). WAR/SHOCK invert; MACRO/POLICY/SIZE mint rail. */
.nw-row {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto auto;
  column-gap: 8px;
  row-gap: 3px;
  width: 100%;
  padding: 9px 10px;
  border-bottom: 1px solid rgba(var(--muted-rgb), 0.22);
  text-align: left;
  text-decoration: none;
  color: inherit;
  font-family: var(--mono);
}
.nw-row:hover { background: var(--paper-deep); }
.nw-row:focus-visible { outline: 3px solid var(--ink); outline-offset: -3px; }
.nw-tag {
  grid-row: 1 / span 2;
  align-self: start;
  font-size: 8px;
  font-weight: 800;
  letter-spacing: 0.1em;
  padding: 3px 5px;
  border: 1px solid var(--ink);
  background: var(--paper);
  min-width: 44px;
  text-align: center;
  line-height: 1.2;
}
.nw-tag-war,
.nw-tag-shock {
  background: var(--ink);
  color: var(--paper);
}
.nw-tag-macro,
.nw-tag-policy,
.nw-tag-size {
  background: var(--mint);
}
.nw-title {
  grid-column: 2;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.01em;
  line-height: 1.35;
  color: var(--ink);
}
.nw-meta {
  grid-column: 2;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 10px;
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--muted);
  text-transform: uppercase;
}
.nw-age { color: var(--ink); }

.rail-sub { font-family: var(--mono); font-size: 9px; font-weight: 700; letter-spacing: 0.14em; color: var(--muted); }
.rail-head .chip-btn { margin-left: auto; }

/* the printer slot the receipts slide out of */
.rail-slot {
  flex: none;
  height: 10px;
  margin: 8px 12px 0;
  background: var(--ink);
  box-shadow: inset 0 3px 0 rgba(var(--paper-rgb), 0.25);
}

.rail-stack { flex: 1; overflow-y: auto; padding: 10px 12px 16px; min-height: 0; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }

/* a receipt is PAPER, not chrome — it keeps its printed ink whatever the
   theme. Token re-pin, not duplicated rules: every receipt style reads these
   and stays ink-on-paper inside the negative. */
.receipt {
  --ink: #141312; --ink-rgb: 20, 19, 18;
  --paper: #f4f0e6; --paper-rgb: 244, 240, 230;
  --muted: #57534b; --muted-rgb: 87, 83, 75;
  --mint: #d9e8cf; --shadow-rgb: 20, 19, 18;
  /* and the COLOR itself: inherited color is a COMPUTED value from body
     (cream in ink mode) — without this line every un-ruled descendant
     (dd values, the head, the stamp text) prints invisible on the paper */
  color: var(--ink);
}
.receipt {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 600;
  background: var(--receipt-paper);
  border: 1px solid rgba(var(--ink-rgb), 0.75);
  padding: 8px 9px 10px;
  margin-bottom: 10px;
  box-shadow: 2px 3px 0 rgba(var(--ink-rgb), 0.28);
  position: relative;
  font-variant-numeric: tabular-nums;
}
.receipt:nth-child(odd) { transform: rotate(0.7deg); }
.receipt:nth-child(even) { transform: rotate(-0.8deg); }
.receipt.is-new { animation: printOut 0.45s cubic-bezier(0.2, 0.9, 0.3, 1); }
@keyframes printOut {
  from { transform: translateY(-26px) rotate(0deg); clip-path: inset(0 0 100% 0); }
  to { transform: translateY(0); clip-path: inset(0 0 0 0); }
}

/* tear-off perforation */
.receipt::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 0;
  right: 0;
  height: 0;
  border-top: 1px dashed var(--behind);
}

.receipt-head {
  display: flex;
  justify-content: space-between;
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.1em;
  border-bottom: 1px dashed rgba(var(--ink-rgb), 0.5);
  padding-bottom: 4px;
  margin-bottom: 5px;
}
/* the receipt's second header row — was an inline style attribute, which the
   page's style-src CSP refuses; it belongs in the stylesheet anyway */
.receipt-head--sub { border-bottom: none; margin-bottom: 2px; padding-bottom: 0; }

.receipt-body { display: grid; grid-template-columns: auto 1fr; gap: 1px 10px; }
.receipt-body dt { font-size: 8px; font-weight: 700; letter-spacing: 0.08em; color: var(--muted); align-self: baseline; }
.receipt-body dd { text-align: right; }
.receipt-stamp {
  margin-top: 6px;
  text-align: center;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.18em;
  padding: 2px 0;
}
.receipt-stamp.stamp-open { border: 1px solid var(--ink); }
.receipt-stamp.stamp-profit { background: var(--mint); outline: 1px solid var(--ink); }
.receipt-stamp.stamp-loss { background: var(--ink); color: var(--paper); }
.receipt-stamp.stamp-liq { background: var(--ink); color: var(--paper); letter-spacing: 0.3em; }
/* the 0.4s delay lands just after .receipt.is-new's printOut (0.45s) finishes
   — paper first, then the stamp comes down, instead of both arriving in the
   same motion. fill-mode both holds the pre-animation state through the
   delay so it doesn't flash full-size before dropping */
.receipt-stamp.stamp-in { animation: stampDown 0.24s cubic-bezier(0.34, 1.56, 0.64, 1) 0.4s both; }
@keyframes stampDown {
  from { transform: scale(1.7) rotate(-9deg); opacity: 0; }
  to { transform: scale(1) rotate(0deg); opacity: 1; }
}

/* barcode strip */
.receipt-code {
  margin-top: 6px;
  height: 14px;
  background: repeating-linear-gradient(90deg,
    var(--ink) 0 1px, transparent 1px 3px,
    var(--ink) 3px 5px, transparent 5px 6px,
    var(--ink) 6px 7px, transparent 7px 10px);
  opacity: 0.85;
}

.receipt-save {
  position: absolute;
  top: 22px;
  right: 6px;
  font-family: var(--mono);
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.08em;
  /* was 8px type in 2px padding — a ~16px-tall target, well under the 24px
     floor and impossible to hit deliberately */
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: 2px 7px;
  border: 1px solid rgba(var(--ink-rgb), 0.4);
  background: transparent;
  opacity: 0;
  transition: opacity 0.15s ease;
}
.receipt:hover .receipt-save { opacity: 1; }
/* Keyboard reach: opacity forms a rendering group, so at opacity 0 the global
   focus ring is painted at zero alpha too — a Tab stop that is completely
   invisible, ring and all. Focus reveals the button the way hover does. */
.receipt:focus-within .receipt-save,
.receipt-save:focus-visible { opacity: 1; }
@media (pointer: coarse) { .receipt-save { opacity: 0.7; } }
.receipt-save:hover { background: var(--ink); color: var(--paper); }
/* same inverted-ink "confirmed" language .row-btn:hover already uses —
   a download is silent in the OS tray, this is the on-page acknowledgment */
.receipt-save.is-saved { opacity: 1; background: var(--ink); color: var(--paper); border-color: var(--ink); }

.rail-empty {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--muted);
  padding: 14px;
}

/* ============ footer ============ */

.paper-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 18px;
  padding: 8px var(--pad) 10px;
  border-top: 2px solid var(--ink);
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.07em;
  color: var(--muted);
}
.foot-group {
  background: var(--ink);
  color: var(--paper);
  padding: 1px 6px;
  letter-spacing: 0.14em;
}
.foot-kbd { margin-left: auto; }

/* ============ command palette ============ */

.palette-backdrop {
  position: fixed;
  inset: 0;
  z-index: 190;
  background: rgba(var(--ink-rgb), 0.35);
}
.palette {
  position: fixed;
  z-index: 200;
  top: 14vh;
  left: 50%;
  transform: translateX(-50%) rotate(-0.4deg);
  width: min(480px, calc(100vw - 32px));
  background: var(--paper);
  border: 2px solid var(--ink);
  box-shadow: 7px 7px 0 rgba(var(--ink-rgb), 0.85);
}
.palette input {
  width: 100%;
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 11px 13px;
  border: none;
  border-bottom: 2px solid var(--ink);
  background: var(--paper);
}
.palette input:focus { outline: none; }
.palette-list { list-style: none; max-height: 46vh; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
.palette-item {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  padding: 8px 13px;
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  border-bottom: 1px solid rgba(var(--muted-rgb), 0.2);
}
.palette-item .cmd-hint { font-size: 9px; color: var(--muted); letter-spacing: 0.06em; }
.palette-item.is-active { background: var(--ink); color: var(--paper); }
.palette-item.is-active .cmd-hint { color: var(--paper); opacity: 0.7; }
.palette-empty { padding: 12px 13px; font-family: var(--mono); font-size: 11px; color: var(--muted); }

/* ---------- furniture stops shouting ----------
   Every label in the app was weight 700, the same as the live numbers, so
   weight carried no information at all. Labels are the frame, not the
   picture: lighter, muted, and quieter than anything that moves. Applied
   here in one place so it holds across every panel. */
.ticket-field > span,
.ticket-preview dt,
.mast-acct-label,
.mast-stat,
.mast-substat,
.desk-table th,
.report-grid dt,
.rail-sub,
.wire-sub,
.book-label,
.book-row-meta,
.book-track-meta,
.lev-head,
.lev-marks,
.desk-stats,
.paper-foot,
.receipt-body dt {
  font-weight: 600;
  color: var(--muted);
}
/* the one label that must not fade — it names what the money is */
.mast-acct-label { letter-spacing: 0.14em; }

/* ---------- prose gets its own voice ----------
   Everything in this app was rendering in mono, which is right for data and
   wrong for sentences: it turned the honesty copy into texture nobody reads.
   Archivo was already being downloaded and used by nothing. Mono stays on
   every number, label and chip; these four surfaces are the ones that are
   actually PROSE, so they get read instead of scanned. */
.intro-banner span,
.book-note,
.gate-copy,
.gate-fine {
  font-family: var(--font);
  letter-spacing: 0.005em;
  line-height: 1.5;
  text-transform: none;
}
.intro-banner span { font-size: 12px; font-weight: 600; }
.book-note { font-size: 11px; font-family: var(--mono); letter-spacing: 0.04em; line-height: 1.3; }
.gate-copy { font-size: 13px; font-weight: 500; }
.gate-fine { font-size: 10.5px; }

/* ============ the account gate ============ */

.gate {
  position: fixed;
  inset: 0;
  z-index: 150;
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgba(var(--paper-rgb), 0.72);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
.gate[hidden] { display: none; }

/* ---------- THE COVER SHEET ----------
   Same physical-paper recipe as .receipt: a token re-pin, not duplicated
   rules, so the sheet stays a light printed object — ink on cream — sitting
   on the dark desk (.gate's blurred wash) whichever theme is active. Every
   descendant (spec rows, inputs, links, the CTA block) reads var(--ink) /
   var(--paper) / var(--muted) / var(--mint) and gets the paper's colors for
   free. --behind is deliberately left un-repinned (see .receipt) so the tear
   at the top shows the real desk color through the paper. */
.cover-sheet {
  --ink: #141312; --ink-rgb: 20, 19, 18;
  --paper: #f4f0e6; --paper-rgb: 244, 240, 230;
  --paper-deep: #e7e0cd;
  --muted: #57534b; --muted-rgb: 87, 83, 75;
  --mint: #d9e8cf; --mint-rgb: 217, 232, 207;
  --shadow-rgb: 20, 19, 18;
  /* --line resolves AT :root (see the --behind note) — without this line the
     form-field borders arrive pre-resolved CREAM and sit invisible (1.13:1)
     on the paper. The v39 .receipt dd bug, third appearance. */
  --line: 1px solid #141312;
  color: var(--ink);
}
.gate-card {
  width: min(430px, 100%);
  background: var(--paper);
  border: 2px solid var(--ink);
  box-shadow: 8px 8px 0 rgba(var(--ink-rgb), 0.85);
  padding: 22px 22px 18px;
  transform: rotate(-0.4deg);
  position: relative;
}
/* torn top edge — the perforation the rest of this sheet tore off of,
   showing the desk color behind the paper (never re-pinned, see above) */
.gate-card::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 14px;
  right: 14px;
  height: 0;
  border-top: 1px dashed var(--behind);
}
/* corner stamp — a document, not a modal */
.cover-stamp {
  position: absolute;
  top: 10px;
  right: 12px;
  font-family: var(--mono);
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--muted);
  border: 1px solid var(--muted);
  padding: 2px 5px;
  transform: rotate(2deg);
}
.gate-card.gate-shake { animation: gateShake 0.4s ease; }
/* every step bakes in the card's resting rotate(-0.4deg), or the shake
   would snap the print-sheet tilt upright for its whole 0.4s */
@keyframes gateShake {
  0%, 100% { transform: translateX(0) rotate(-0.4deg); }
  10% { transform: translateX(-4px) rotate(-0.4deg); }
  20% { transform: translateX(4px) rotate(-0.4deg); }
  30% { transform: translateX(-4px) rotate(-0.4deg); }
  40% { transform: translateX(4px) rotate(-0.4deg); }
  50% { transform: translateX(-3px) rotate(-0.4deg); }
  60% { transform: translateX(3px) rotate(-0.4deg); }
  70% { transform: translateX(-2px) rotate(-0.4deg); }
  80% { transform: translateX(2px) rotate(-0.4deg); }
  90% { transform: translateX(-1px) rotate(-0.4deg); }
}
.gate-head { display: flex; flex-direction: column; gap: 3px; margin-bottom: 12px; }
.gate-word {
  font-family: var(--display);
  font-size: 42px;
  line-height: 1;
  letter-spacing: 0.02em;
  background: var(--ink);
  color: var(--paper);
  padding: 4px 14px 7px;
  align-self: flex-start;
}
.gate-tag {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.22em;
  color: var(--muted);
}
.gate-copy {
  /* prose, not data — Archivo (see the prose-voice block above) */
  font-family: var(--font);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.005em;
  text-transform: none;
  margin-bottom: 14px;
}
.gate-copy strong { font-weight: 800; border-bottom: 2px solid var(--ink); }

/* A standing condition, not a form error — stays up through every keystroke
   and submit until /api/awake/config reports mailReady again, unlike
   .gate-note which a later "SIGNING YOU IN…" or validation message
   overwrites. Same inverted ink/paper weight as .caps-warn so it reads as a
   fact about the system, not a mistake the visitor made. */
.gate-mail-down {
  font-family: var(--font);
  font-size: 12px;
  font-weight: 700;
  line-height: 1.45;
  letter-spacing: 0.005em;
  text-transform: none;
  margin: 0 0 14px;
  padding: 9px 10px;
  background: var(--ink);
  color: var(--paper);
}
/* ---------- password field details a real product ships ---------- */

.pw-wrap { position: relative; display: block; }
.pw-wrap input { padding-right: 56px; }
.pw-peek {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--muted);
  /* measured 36×24 with 5px padding — under the 24px minimum on the one
     control every single person taps on the way in */
  padding: 7px 8px;
  min-width: 44px;
  min-height: 28px;
  border: 1px solid transparent;
}
.pw-peek:hover { color: var(--ink); border-color: var(--ink); }
.pw-peek[aria-pressed="true"] { color: var(--ink); border-color: var(--ink); background: var(--paper-deep); }

/* strength is guidance, not a gate — it never blocks a submit */
.pw-meter { display: flex; align-items: center; gap: 8px; margin: 6px 10px 0; }
.pw-bar { flex: 1; height: 4px; background: var(--paper-deep); border: 1px solid var(--muted); position: relative; }
.pw-bar i { display: block; height: 100%; width: 0; background: var(--ink); transition: width 0.18s ease; }
.pw-word {
  font-family: var(--mono);
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--muted);
  min-width: 52px;
  text-align: right;
}

.caps-warn {
  margin: 6px 10px 0;
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.08em;
  padding: 4px 7px;
  background: var(--ink);
  color: var(--paper);
}

/* the live price slot — prints onto the paper like a stamped-in quote */
.cover-live {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 12px;
  padding: 7px 10px;
  border: 1px dashed var(--muted);
  background: var(--paper-deep);
}
.cover-live-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--mono);
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--muted);
}
.cover-live-label .conn-dot {
  width: 7px;
  height: 7px;
  background: var(--mint);
  outline: 1px solid var(--ink);
  animation: connPulse 2s ease-in-out infinite;
}
.cover-live-px {
  font-family: var(--mono);
  font-size: 21px;
  font-weight: 800;
  letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
}
.cover-live-px:empty::before { content: "\2014"; opacity: 0.4; font-weight: 400; }

/* the offer, printed as a spec sheet — exact grammar of .receipt-body */
.cover-spec {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 3px 12px;
  margin: 0 0 14px;
  padding: 10px 0;
  border-top: 1px dashed var(--muted);
  border-bottom: 1px dashed var(--muted);
}
.cover-spec dt {
  font-family: var(--mono);
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--muted);
  align-self: baseline;
  white-space: nowrap;
}
.cover-spec dd {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 600;
  text-align: right;
  line-height: 1.35;
}

.gate-mode { display: flex; gap: 8px; margin-bottom: 12px; }
.gate-mode .type-btn {
  flex: 1;
  font-family: var(--mono);
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 8px 0;
  font-size: 11px;
  border: 1px dashed var(--muted);
  background: transparent;
  color: var(--ink);
}
.gate-mode .type-btn.is-on { box-shadow: inset 0 -3px 0 var(--ink); }
/* CREATE ACCOUNT is the one loud action on the sheet — the true offer is a
   new paper account, so it always reads as the inverted-ink block, whether
   or not it is the currently active radio. SIGN IN stays a quiet outline. */
#modeSignUp {
  flex: 1.3;
  border: 2px solid var(--ink);
  background: var(--ink);
  color: var(--paper);
}
#modeSignUp.is-on { box-shadow: inset 0 -3px 0 var(--paper); }
#modeSignUp:hover { box-shadow: 3px 3px 0 rgba(var(--ink-rgb), 0.4); }
#modeSignIn { border: 1px dashed var(--muted); }
#modeSignIn:hover { background: var(--paper-deep); }

/* barcode strip — the sheet came off the same printer as the receipts */
.cover-code {
  margin-top: 12px;
  height: 14px;
  background: repeating-linear-gradient(90deg,
    var(--ink) 0 1px, transparent 1px 3px,
    var(--ink) 3px 5px, transparent 5px 6px,
    var(--ink) 6px 7px, transparent 7px 10px);
  opacity: 0.85;
}

.gate-form .ticket-field { margin: 0 0 10px; }
.gate-form .ticket-field em { font-style: normal; opacity: 0.75; }

/* The two ways out of a stuck sign-in — "forgot password" and "email me a
   link instead" — were 9px of unpadded text: about a 12px-tall target, half
   the 24px minimum, on the one screen where a stuck person needs them most.
   The padding grows the target; the negative margin keeps the sheet's layout
   where it was. */
.gate-link {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-decoration: underline;
  text-underline-offset: 3px;
  display: inline-block;
  padding: 8px 5px;
  margin: -8px -5px;
}
.gate-link:hover { background: var(--paper-deep); }
/* dimming a 10px recovery link on top of muted colour is one veil too many */
.gate-alt-small { margin-top: 12px; }
.gate-btn { margin: 0; width: 100%; font-size: 19px; }
.gate-note {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.05em;
  margin-top: 10px;
  padding: 7px 9px;
  background: var(--mint);
  outline: 2px solid var(--ink);
}
.gate-note.gate-note-err { background: var(--ink); color: var(--paper); outline: none; }
.gate-alt {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  margin-top: 14px;
}
/* the anchor gets the same grown hit area as .gate-link beside it */
.gate-alt a {
  text-decoration: underline;
  text-underline-offset: 3px;
  display: inline-block;
  padding: 8px 5px;
  margin: -8px -5px;
}
.gate-fine {
  font-family: var(--font);
  font-size: 10.5px;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.005em;
  color: var(--muted);
  margin-top: 10px;
  border-top: 1px dashed var(--muted);
  padding-top: 8px;
}

.chip-account { max-width: 140px; overflow: hidden; text-overflow: ellipsis; }
.chip-account.is-offline { background: var(--ink); color: var(--paper); }

/* ============ toast (order feedback) ============ */

.toast {
  position: fixed;
  z-index: 210;
  bottom: 18px;
  left: 50%;
  transform: translateX(-50%) rotate(-0.5deg);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  background: var(--ink);
  color: var(--paper);
  padding: 8px 14px;
  box-shadow: 4px 4px 0 rgba(var(--ink-rgb), 0.35);
  animation: toastIn 0.18s ease;
}
.toast.toast-mint { background: var(--mint); color: var(--ink); outline: 2px solid var(--ink); }
/* the worst outcome in the app — same ink/paper palette as every other
   toast, but heavier and held a beat longer so it can't be mistaken for a
   routine close */
/* an ink border on an ink toast is invisible — the edge has to be cut in
   paper to read as heavier, the same inversion .toast-mint uses */
.toast.toast-liq { border: 2px solid var(--paper); outline: 2px solid var(--ink); box-shadow: 5px 5px 0 rgba(var(--ink-rgb), 0.6); animation: toastIn 0.18s ease, toastShake 0.4s ease 0.18s; }
@keyframes toastIn { from { transform: translateX(-50%) translateY(8px) rotate(-0.5deg); opacity: 0; } }
/* keeps the toast's resting translateX(-50%) rotate(-0.5deg) at every step
   so the shake doesn't un-rotate the toast mid-animation */
@keyframes toastShake {
  0%, 100% { transform: translateX(-50%) rotate(-0.5deg); }
  20% { transform: translateX(calc(-50% - 3px)) rotate(-0.5deg); }
  40% { transform: translateX(calc(-50% + 3px)) rotate(-0.5deg); }
  60% { transform: translateX(calc(-50% - 2px)) rotate(-0.5deg); }
  80% { transform: translateX(calc(-50% + 2px)) rotate(-0.5deg); }
}

/* ============ build-out: chart controls ============ */

.chip-more { align-self: center; }

.ema-rail { display: flex; gap: 0; }
.ema-btn {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 4px 7px;
  border: 1px dashed var(--muted);
  margin-left: -1px;
  background: var(--paper);
  transition: background 0.12s ease;
}
.ema-btn:first-child { margin-left: 0; }
.ema-btn[aria-pressed="true"] { border: 1px solid var(--ink); background: var(--ink); color: var(--paper); }
.ema-btn:not([aria-pressed="true"]):hover { background: var(--paper-deep); }

#alertArm[aria-pressed="true"] { background: var(--mint); outline: 2px solid var(--ink); }

.chart-hint {
  position: absolute;
  bottom: 30px;
  left: 50%;
  transform: translateX(-50%) rotate(-0.5deg);
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  padding: 6px 12px;
  background: var(--mint);
  color: var(--ink);
  outline: 2px solid var(--ink);
  pointer-events: none;
  white-space: nowrap;
}

/* live price tick — mint = up-beat, ink = down-beat, one flash then gone */
.mast-mark { transition: background 0.35s ease, color 0.35s ease; padding: 0 4px; }
.mast-mark.is-tick { background: var(--mint); transition: none; }
.mast-mark.is-tick-down { background: var(--ink); color: var(--paper); transition: none; }

/* feed is stale/offline — every number these read is frozen, not current;
   strike them so nobody trades off a dead price without noticing. 0.65, not
   a rounder number: computed against the real hex values, this is the
   opacity floor that keeps mast-mark/equityVal (ink-on-paper), .pnl-neg
   (paper-on-ink) and .pnl-pos (ink-on-mint) all >= 4.5:1 once faded —
   0.55 measured 3.79-3.87:1 on every one of them. */
body.is-stale .mast-mark, body.is-stale .pnl-chip, body.is-stale #equityVal {
  opacity: 0.65;
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}
body.is-stale .liq-near { animation: none; }

.mast-substat {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.mast-acct-label em { font-style: normal; font-variant-numeric: tabular-nums; }
.mast-acct-label em.is-up { background: var(--mint); padding: 0 3px; color: var(--ink); }
.mast-acct-label em.is-down { background: var(--ink); padding: 0 3px; color: var(--paper); }

/* first-visit banner — impossible to miss, dies on GOT IT */
.intro-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px var(--pad);
  /* was full-bleed mint — the largest colored field in the product, spent on
     an onboarding notice. Mint means live-or-at-risk; a welcome message is
     neither. Ink rule carries the emphasis instead. */
  background: var(--paper-deep);
  border-left: 4px solid var(--ink);
  border-bottom: 2px solid var(--ink);
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.05em;
  position: relative;
  z-index: 55;
}
.intro-banner[hidden] { display: none; }
.intro-banner span { flex: 1; min-width: 0; }
.intro-banner .chip-btn { flex: none; }

.book-ro {
  font-style: normal;
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.1em;
  padding: 1px 4px;
  border: 1px solid var(--ink);
  background: var(--paper);
  color: var(--ink);
  margin-left: 6px;
}

/* ============ tape & book ============ */

.desk-table-tape td { padding: 3px 10px; font-size: 11px; }
.tape-sell td { background: rgba(var(--ink-rgb), 0.05); }
.tape-side { font-weight: 700; }
/* whale prints stand out — size talks */
.tape-whale td { font-weight: 800; border-top: 1px solid var(--ink); border-bottom: 1px solid var(--ink); }

/* book rows load the ticket on click */
.desk-table-book tbody tr:not(.book-spread) { cursor: pointer; }
.desk-table-book tbody tr:not(.book-spread):hover td { background: var(--paper-deep); }
.tape-new td { animation: tapeIn 0.25s ease; }
@keyframes tapeIn { from { background: var(--paper-deep); } }

.desk-table-book td { padding: 3px 10px; font-size: 11px; position: relative; }
.book-bar {
  position: absolute;
  inset: 1px 0;
  background: rgba(var(--ink-rgb), 0.12);
  pointer-events: none;
}
.book-ask .book-bar { background: rgba(var(--ink-rgb), 0.2); }
.book-bar-th, .book-bar-td { width: 34%; min-width: 90px; }
.book-spread td {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--muted);
  text-align: center !important;
  border-top: 1px dashed var(--muted);
  border-bottom: 1px dashed var(--muted);
  background: var(--paper-deep);
}

/* ============ report ============ */

.report { padding: 10px 12px 16px; }
.report-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.report-sub { font-family: var(--mono); font-size: 9px; font-weight: 700; letter-spacing: 0.1em; color: var(--muted); }
.report-head .chip-btn { margin-left: auto; }

.report-curve-wrap { position: relative; height: 120px; border: var(--line); background: var(--paper); margin-bottom: 10px; }
#reportCurve { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

.report-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));
  gap: 0;
  border: 1px dashed var(--muted);
  margin-bottom: 12px;
}
.report-grid > div { padding: 7px 9px; border: 1px dashed var(--muted); margin: -1px 0 0 -1px; }
.report-grid dt { font-family: var(--mono); font-size: 8px; font-weight: 700; letter-spacing: 0.1em; color: var(--muted); }
.report-grid dd { font-family: var(--mono); font-size: var(--t-lead); font-weight: 800; font-variant-numeric: tabular-nums; }
.report-grid dd .pnl-chip { font-size: 12px; }
.report-coins { border: var(--line); }
.report-empty { font-family: var(--mono); font-size: 11px; font-weight: 700; color: var(--muted); padding: 12px 0; letter-spacing: 0.08em; }

/* ============ journal — every note, dense ============ */

.report-head-style { margin-top: 16px; padding-top: 12px; border-top: 1px dashed var(--muted); }

.journal-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 12px;
  padding: 7px 2px;
  border-bottom: 1px solid rgba(var(--muted-rgb), 0.25);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
}
.journal-row:hover { background: var(--paper-deep); }
.journal-row .jr-date { flex: none; width: 74px; color: var(--muted); font-size: 10px; font-variant-numeric: tabular-nums; }
.journal-row .jr-pair { flex: none; width: 58px; font-weight: 800; }
.journal-row .jr-side { flex: none; width: 44px; font-size: 9px; letter-spacing: 0.08em; }
.journal-row .jr-pnl { flex: none; width: 76px; text-align: right; font-variant-numeric: tabular-nums; }
.journal-row .jr-note {
  flex: 1 1 160px;
  min-width: 0;
  color: var(--ink);
  font-weight: 600;
  font-style: normal;
  white-space: normal;
  word-break: break-word;
}
.journal-empty { font-family: var(--mono); font-size: 11px; font-weight: 700; color: var(--muted); padding: 14px 2px; letter-spacing: 0.08em; }

/* ============ inline TP/SL cell editing ============ */

.cell-editable { cursor: pointer; text-decoration: underline dotted rgba(var(--muted-rgb), 0.7); text-underline-offset: 3px; }
.cell-editable:hover { background: var(--paper-deep); }

/* note column — positions (editable) and history (read of what was set) */
.cell-note {
  max-width: 150px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: left !important;
  cursor: pointer;
  text-decoration: underline dotted rgba(var(--muted-rgb), 0.7);
  text-underline-offset: 3px;
}
.cell-note:hover { background: var(--paper-deep); }
.note-empty { color: var(--muted); font-weight: 600; opacity: 0.65; }
.cell-edit-input {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  width: 78px;
  padding: 2px 4px;
  border: 2px solid var(--ink);
  background: var(--paper);
  font-variant-numeric: tabular-nums;
}

/* micro-press feedback everywhere buttons live */
.chip-btn:active, .tf-btn:active, .ema-btn:active, .desk-tab:active,
.pair-tab:active, .row-btn:active, .type-btn:active, .side-btn:active { transform: translateY(1px); }

/* ============ responsive ============ */

@media (max-width: 1180px) {
  :root { --rail-w: 200px; }
}

@media (max-width: 1020px) {
  .cockpit {
    grid-template-columns: minmax(0, 1fr) 280px;
    grid-template-rows: minmax(300px, 1fr) minmax(170px, 240px) auto;
    grid-template-areas:
      "chart ticket"
      "desk  desk"
      "rail  rail";
  }
  .rail { border-top: 2px solid var(--ink); max-height: 300px; }
  .panel-desk { border-bottom: none; }
  .rail-stack { display: flex; gap: 10px; overflow-x: auto; padding: 12px; }
  .receipt { flex: 0 0 190px; margin-bottom: 0; }
  .rail-slot { display: none; }
}

@media (max-width: 760px) {
  /* ============ VERTICAL BUDGET: masthead rebuilt as 3 explicit rows ============
     Was up to 6 wrapped lines (brand, title, acct, live-stats, pairs each
     landing wherever flex-wrap happened to break them) eating ~270px before
     a single chart pixel showed. Rebuilt with "order" into exactly three
     deliberate rows so the chart — not the header — owns the first screen:
       row 1  brand + wordmark  ................  price + 24h delta
       row 2  PAPER STAGE + WHAT IS THIS  .......  equity + CTRL-K
       row 3  market tabs + MORE
     Funding/mark/volume drop to the CTRL-K palette + panel tooltips —
     real numbers, just not fighting for space on the smallest screen. */
  .mast { padding: 7px 10px; gap: 0; }
  /* each wrapper becomes a real flex row now — the "order" values set on
     the children (base rules, above) sort correctly inside every row
     since they're already ascending in the sequence this layout wants. */
  .mast-row { display: flex; align-items: center; flex-wrap: wrap; column-gap: 8px; row-gap: 5px; width: 100%; }
  .mast-row + .mast-row { margin-top: 6px; }

  /* MONEY > LOGO residual (W4-AW-01 / SaturnDesign 2026-08-07):
     prior 21px mark + 16px equity made price read as a peer of the 13px
     AWAKE stamp. Chrome quiets further; mark/equity reclaim type tokens. */
  .mast-brand { font-size: 8px; padding: 4px 6px; opacity: 0.72; letter-spacing: 0.04em; }
  .mast-title { font-size: 11px; padding: 2px 6px 3px; letter-spacing: 0.06em; }
  .mast-tag { display: none; } /* tagline is decoration once you're on the page */

  .mast-live { margin-left: auto; gap: 6px; align-items: baseline; }
  .mast-mark {
    /* clamp: loud at 390–430 without clipping at 320 */
    font-size: clamp(24px, 5.4vw + 10px, var(--t-hero));
    font-weight: 800;
    line-height: 1;
    letter-spacing: -0.02em;
  }
  .mast-stat { font-size: 10px; font-weight: 800; color: var(--ink); }
  #dayDelta { font-size: 11px; font-weight: 800; padding: 2px 5px; }
  /* secondary readouts: real data, just not first-screen real estate —
     still reachable via CTRL-K / the panel that already carries them */
  #realMark, #dayVol, #fundingRate { display: none; }

  .chip-sim { font-size: 8px; padding: 5px 7px; }

  .mast-acct { margin-left: auto; gap: 7px; }
  .equity-spark { display: none; }
  .mast-acct-label { font-size: 8px; }
  .mast-acct-val {
    font-size: var(--t-big);
    font-weight: 800;
    line-height: 1;
  }
  .mast-session {
    font-size: 10px;
    color: var(--ink);
    letter-spacing: 0.08em;
  }

  /* row 3: WHAT IS THIS + the market scroller + MORE. The scroller is the
     one flexible member — min-width:0 is the fix, not decoration: without
     it a flex item's minimum width defaults to its *content* width, so a
     10-market nav would refuse to shrink and blow the row wide instead of
     scrolling internally. */
  #whatIs { flex: none; font-size: 8px; padding: 5px 7px; }
  /* flex-basis:0 (not auto) is what actually keeps this on the same line
     as WHAT IS THIS/MORE — with "auto" the wrap algorithm sizes it by its
     scrollable *content* (multiple markets wide) before shrinking, which
     alone busts the row; starting from 0 and growing into the leftover
     space is what lets it dock beside its siblings and scroll inside that
     space instead of pushing them onto their own lines. */
  .mast-pairs { flex: 1 1 0; min-width: 0; margin-left: 0; overflow-x: auto; flex-wrap: nowrap; scrollbar-width: none; overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch; }
  .mast-pairs::-webkit-scrollbar { display: none; }
  #moreMarkets { flex: none; font-size: 9px; padding: 6px 8px; }

  /* A phone page SCROLLS — it does not squeeze four panels into one screen.
     The old rows were sized against the viewport (46vh) while the grid's box
     is the viewport minus ~395px of chrome, so the tracks summed ~175px taller
     than their container and, with overflow visible, the desk and rail painted
     straight over the footer (and the receipts rail collapsed to 2px).
     flex-shrink:0 lets the cockpit keep its natural height and hand the
     overflow to the page, where it belongs. */
  .cockpit {
    flex: 0 0 auto;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(300px, 52vh) auto minmax(190px, auto) auto;
    grid-template-areas:
      "chart"
      "ticket"
      "desk"
      "rail";
  }
  .panel, .rail { min-height: 0; }
  /* the receipts ARE the signature mechanism — give them real height on a
     phone instead of the 2px sliver the overflowing grid left behind */
  .rail { max-height: none; }
  .rail-stack { min-height: 168px; align-items: flex-start; }
  .receipt { flex: 0 0 200px; }
  .panel { border-right: none; }
  .panel-ticket { border-top: 2px solid var(--ink); overflow-y: visible; }
  .foot-kbd { display: none; }
  /* paper-foot padding-bottom: set once, further down, sized to clear the
     fixed PLACE bar (safe-area + bar height), not just the home indicator */

  /* CRITICAL: iOS Safari zooms the whole page on focus of any text input
     under 16px — every ticket/gate field was 15px, every trade or sign-in
     attempt would yank the viewport in. 16px kills the zoom outright. */
  .ticket-field input, .palette input { font-size: 16px; }

  /* GATE: comfortable on a phone, no scrolling behind an open keyboard.
     The .ticket-field[hidden] bug fix above already removed the spurious
     NAME field (~60px); the rest is tighter spacing and a smaller (still
     unmistakable) wordmark — copy itself is never shortened. Measured
     504px before this block, ~420px after, against an 812px-tall phone. */
  .gate { padding: 14px; }
  .gate-card { padding: 16px 16px 14px; }
  .gate-head { margin-bottom: 8px; }
  .gate-word { font-size: 28px; padding: 3px 10px 5px; }
  .gate-copy { font-size: 10px; line-height: 1.45; margin-bottom: 10px; }
  .gate-mail-down { font-size: 10px; line-height: 1.4; padding: 7px 8px; margin-bottom: 10px; }
  .cover-stamp { top: 8px; right: 10px; font-size: 7px; }
  .cover-live { padding: 6px 8px; margin-bottom: 10px; }
  .cover-live-label { font-size: 7.5px; }
  .cover-live-px { font-size: 17px; }
  .cover-spec { gap: 2px 8px; padding: 8px 0; margin-bottom: 10px; }
  .cover-spec dt { font-size: 7.5px; }
  .cover-spec dd { font-size: 9.5px; }
  .cover-code { margin-top: 8px; height: 11px; }
  .gate-mode { margin-bottom: 8px; }
  .gate-mode .type-btn { padding: 9px 0; font-size: 10px; }
  .gate-form .ticket-field { margin: 0 0 8px; }
  .gate-btn { padding: 10px 0 12px; font-size: 17px; }
  .gate-alt { margin-top: 8px; }
  .gate-alt-small { margin-top: 4px; }
  .gate-fine { margin-top: 8px; padding-top: 6px; }

  /* thumb-sized touch targets */
  .tf-btn { padding: 9px 11px; font-size: 12px; }
  .ema-btn { padding: 8px 9px; }
  .desk-tab { padding: 10px 12px 9px; }
  .pair-tab { padding: 10px 13px; }
  .row-btn { padding: 8px 11px; font-size: 10px; }
  .side-btn { padding: 12px 0 13px; }
  .place-btn { padding: 14px 0 16px; }
  .chip { padding: 7px 10px; }
  .panel-head { flex-wrap: wrap; min-height: 0; row-gap: 6px; }
  /* the OHLC readout is a hover affordance — desktop only */
  .ohlc-read { display: none; }
  /* the chart-head row already scrolls horizontally (nowrap below), so
     extra side padding here is free — it doesn't cost the vertical budget
     item 1 spent this whole pass cutting, only a bit more swipe distance.
     Measured 39x39 before (fails 44px on both axes); the wider padding
     clears 44px of width, same height. */
  .tf-btn { padding: 11px 17px; }
  /* chart controls: one swipeable row — the chart keeps its height */
  .panel-chart .panel-head { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  .panel-chart .panel-head::-webkit-scrollbar { display: none; }
  .tf-rail, .ema-rail { flex: none; }
  /* desk tabs: the PRO desk's six tabs are ~442px of min-content — wider
     than any phone — and this row was the one control strip that neither
     wrapped nor scrolled, so IT (not the chart head, which already scrolls)
     was inflating document.scrollWidth and letting the whole page wander
     sideways. Same swipe idiom as the chart head. The container's
     border-bottom moves into an inset shadow because a scroll container
     clips at its padding box: with the border, the tabs' 1px top-shift
     could no longer paint over the line and the active tab would read
     boxed-in instead of open into its pane. padding-bottom:1px keeps the
     shifted tabs inside the clip; the shadow draws the line in that last
     pixel, under the tabs, exactly where the border used to sit. */
  .desk-tabs { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch; border-bottom: none; padding-bottom: 1px; box-shadow: inset 0 -1px 0 var(--ink); }
  .desk-tabs::-webkit-scrollbar { display: none; }
  .desk-tab { flex: none; }
  /* the action column stays reachable while wide tables scroll */
  #tblPositions .cell-actions,
  #tblPositions th:last-child,
  #tblOrders td:last-child,
  #tblOrders th:last-child { position: sticky; right: 0; background: var(--paper); box-shadow: -6px 0 6px -4px rgba(var(--shadow-rgb), 0.25); }
  .cell-actions .row-btn { margin-left: 4px; }
  /* phone sticky actions stay 3 deep: half / flip / close — 25+75 hide so
     the sticky rail doesn't balloon past the thumb zone */
  .cell-actions [data-act="p25"],
  .cell-actions [data-act="p75"] { display: none; }
  .book-note { display: none; }
  /* keep the 90D track; drop worst/best on narrow to free room for rows */
  .book-track .book-track-meta:nth-of-type(n+3) { display: none; }
  .book-spark { width: 64px; }
  .intro-banner { position: sticky; top: 0; }
  .size-chip { padding: 9px 0; }

  /* replay bar: stays one swipeable row, thumb-sized controls */
  .replay-bar { padding: 8px 10px; gap: 10px; }
  .replay-label { font-size: 9px; padding-right: 10px; }
  .replay-btn, .replay-exit { padding: 8px 10px; }
  .replay-speed-field select { padding: 7px 6px; }

  /* note column stays out of the way of the sticky action column */
  .cell-note { max-width: 90px; }
  #tblHistory .cell-note { max-width: 70px; }

  /* TABLES: 14 columns is a lot at 375px. Positions keeps scrolling with
     its sticky action column, but ENTRY/LEV/FUNDING are the ones you
     check least — hidden with display:none on the th/td pair only, so
     the JS's tds[4]/[5]/[10]/[11]/[12] index binding (MID/LIQ/FUNDING/
     P&L/NOTE — see bindTriggerCell/posRowRefs in awake.js) never sees a
     cell removed or reordered, only skinnier rows. */
  #tblPositions th:nth-child(4), #tblPositions td:nth-child(4),   /* ENTRY */
  #tblPositions th:nth-child(9), #tblPositions td:nth-child(9),   /* LEV */
  #tblPositions th:nth-child(11), #tblPositions td:nth-child(11) /* FUNDING */
  { display: none; }

  /* the chart's own horizontal-scroll strip (timeframe + EMA rail) */
  .panel-chart .panel-head { overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch; }
  .panel-ticket { overscroll-behavior-y: contain; -webkit-overflow-scrolling: touch; }

  /* touch targets that live OUTSIDE the vertical-budget-critical header/
     chart-head chrome get a fuller bump — a table row's CLOSE/CANCEL and
     the identity row's CTRL-K don't cost first-screen space to grow.
     (tf-rail/ema-rail/pair-tab stay as sized above: those sit in the
     chrome we just spent this whole pass cutting, and width already
     clears 44px there, so height wasn't inflated back in — see report.) */
  .row-btn { padding: 10px 12px; }
  .cell-actions .row-btn + .row-btn { margin-left: 6px; }
  .desk-tab { padding: 11px 13px 10px; }
  .mast-acct .chip-btn { padding: 8px 10px; }
  #whatIs, #moreMarkets { padding: 8px 9px; }

  /* ============ THUMB REACH ============
     Chosen approach: PLACE stays pinned to the viewport bottom rather than
     reordering the grid so the ticket comes before the chart. Reordering
     would win back a few inches of thumb travel but directly fights the
     #1 priority above — the chart owning the first screen — since the
     ticket's own height (side switch, size, leverage, TP/SL, preview) is
     substantial. A fixed CTA is the standard trading-app resolution to
     that exact tension (Robinhood/Coinbase do the same): the chart still
     opens the page, and PLACE is never more than a thumb away regardless
     of whether you're reading the chart, scrolling the desk, or checking
     receipts. The ticket itself stays second in scroll order (right after
     the chart, before desk/rail) for anyone who wants the full context. */
  .panel-ticket { padding-bottom: 62px; }
  #placeBtn {
    position: fixed;
    left: 10px;
    right: 10px;
    bottom: calc(10px + env(safe-area-inset-bottom, 0px));
    margin: 0;
    width: auto;
    z-index: 45;
    box-shadow: 0 4px 0 rgba(var(--ink-rgb), 0.9), 0 8px 20px rgba(var(--shadow-rgb), 0.35);
  }
  #placeBtn:active { box-shadow: 0 2px 0 rgba(var(--ink-rgb), 0.9); }
  /* room so the fixed bar never covers the last thing on the page */
  .paper-foot { padding-bottom: calc(74px + env(safe-area-inset-bottom, 0px)); }
  /* the browser's own scroll-into-view for a focused field should stop
     short of the fixed bar, not underneath it */
  .ticket-field input { scroll-margin-bottom: 76px; }

  /* COARSE POINTER pads: layout-neutral 44×44. Painted box can stay smaller;
     measure getComputedStyle(el, "::after") for the real tap target (law #6). */
  .tf-btn,
  .ema-btn,
  .chip.chip-btn,
  .pair-tab,
  .desk-tab,
  .row-btn,
  .size-chip,
  .side-btn,
  #whatIs,
  #moreMarkets {
    position: relative;
    overflow: visible;
  }
  .tf-btn::after,
  .ema-btn::after,
  .chip.chip-btn::after,
  .pair-tab::after,
  .desk-tab::after,
  .row-btn::after,
  .size-chip::after,
  .side-btn::after,
  #whatIs::after,
  #moreMarkets::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: 44px;
    height: 44px;
    transform: translate(-50%, -50%);
  }
  #placeBtn {
    min-height: 48px;
    padding-top: 14px;
    padding-bottom: 14px;
  }
  .gate-mode .type-btn { min-height: 44px; }
  .gate-btn { min-height: 48px; }
}

/* ============ LANDSCAPE PHONE (e.g. 812x375) ============
   Width alone (812px) sits above the 760px breakpoint, so none of the
   portrait rules above fire here — the masthead was rendering at full
   desktop density (wrapping to ~207px) inside a viewport that's only
   375px tall, leaving the chart under 120px of visible canvas. Keyed off
   height, not width: a short viewport is the actual signal, regardless
   of how wide it is. Restores a real 2-pane cockpit (chart|ticket over
   desk|rail) instead of the portrait single-column stack, which would
   make the chart even shorter here, not taller. */
@media (max-height: 500px) and (orientation: landscape) {
  .mast { padding: 4px 10px; gap: 6px 8px; }
  /* height is the scarce axis here, not width: unwrap the three mobile rows
     back into ONE wrapping line (as on desktop) so 812px of width absorbs
     what would otherwise cost three stacked rows of vertical budget */
  .mast-row { display: contents; }
  /* the explainer is one tap away in the command palette — its chip is the
     cheapest thing to drop when every pixel of height is chart */
  #whatIs { display: none; }
  .mast-brand { font-size: 8px; padding: 3px 6px; opacity: 0.72; }
  .mast-title { font-size: 11px; padding: 2px 6px 3px; }
  .mast-tag { display: none; }
  .mast-live { margin-left: auto; gap: 6px; align-items: baseline; }
  /* height scarce — mark still outranks wordmark */
  .mast-mark {
    font-size: clamp(20px, 4vh + 8px, 26px);
    font-weight: 800;
    line-height: 1;
  }
  .mast-stat { font-size: 9px; font-weight: 800; color: var(--ink); }
  #realMark, #dayVol, #fundingRate { display: none; }
  .chip-sim { font-size: 8px; padding: 4px 6px; }
  .mast-acct { margin-left: auto; gap: 7px; }
  .equity-spark { display: none; }
  .mast-acct-label { font-size: 8px; }
  .mast-acct-val { font-size: 16px; font-weight: 800; line-height: 1; }
  .mast-pairs { flex: 1 1 0; min-width: 0; margin-left: 0; overflow-x: auto; flex-wrap: nowrap; scrollbar-width: none; overscroll-behavior-x: contain; }
  .pair-tab { padding: 4px 9px; font-size: 11px; }
  .pair-tab .pair-mid { font-size: 8px; }
  /* the chart's own control row is the last big vertical cost above it */
  .panel-chart .panel-head { padding: 3px 8px; min-height: 0; }
  .tf-btn, .ema-btn { padding: 5px 8px; }
  .panel-head .chip { padding: 4px 7px; }
  .mast-pairs::-webkit-scrollbar { display: none; }
  #moreMarkets { flex: none; font-size: 9px; padding: 4px 7px; }
  .book-strip, .replay-bar { padding-top: 4px; padding-bottom: 4px; }
  /* the footer's ~8 fact chips wrap to 2-3 lines at this width and were
     quietly eating 98px of a 375px-tall viewport (body is a flex column,
     so the footer's natural height competes with the cockpit's flex:1
     for real space) — the one disclosure that matters at a glance, PAPER
     STAGE, already stays pinned in the masthead above. */
  .paper-foot { display: none; }

  /* the real fix: 2 columns x 2 rows, not 1 column x 4 rows.
     Track sizing note: a non-flexible minmax() track (no fr) gets grown
     toward its max in an earlier pass than any fr track, so a generous
     max on the desk/rail row was winning the fight for space against the
     "flexible" chart row and leaving the chart shorter than the table
     below it — backwards. Giving the chart row its own floor (140px)
     fixes the priority: bases are reserved first (140 + 96 = 236 of
     266px available), then the small remainder tops up desk/rail toward
     its own cap, and chart only ever loses to an explicit floor, not to
     the other row's ceiling. */
  .cockpit {
    grid-template-columns: minmax(0, 1fr) 260px;
    /* chart floor raised now that the masthead unwrapped: the desk row keeps
       enough height for two readable rows, everything else goes to price */
    grid-template-rows: minmax(180px, 1fr) minmax(90px, 124px);
    grid-template-areas:
      "chart ticket"
      "desk  rail";
  }
  .panel-desk { border-right: 2px solid var(--ink); border-bottom: none; }
  .rail { border-top: none; border-left: 2px solid var(--ink); max-height: none; }
  .rail-stack { display: flex; flex-direction: column; overflow-y: auto; }
  .receipt { flex: none; }

  /* ticket keeps the desktop behavior here (scrolls in its own column —
     it's a side panel again, not a stacked block in page flow) */
  .ticket-field input, .palette input { font-size: 16px; }

  #tblPositions th:nth-child(4), #tblPositions td:nth-child(4),
  #tblPositions th:nth-child(9), #tblPositions td:nth-child(9),
  #tblPositions th:nth-child(11), #tblPositions td:nth-child(11)
  { display: none; }

  /* GATE: same reasoning as the portrait block — see the comment there */
  .gate { padding: 10px; }
  .gate-card { padding: 12px 16px 10px; max-height: calc(100vh - 20px); overflow-y: auto; }
  .gate-head { margin-bottom: 6px; }
  .gate-word { font-size: 22px; padding: 2px 8px 3px; }
  .gate-copy { font-size: 9px; line-height: 1.35; margin-bottom: 6px; }
  .gate-mail-down { font-size: 9px; line-height: 1.3; padding: 6px 7px; margin-bottom: 6px; }
  .gate-mode { margin-bottom: 6px; }
  .gate-form .ticket-field { margin: 0 0 6px; }
  .gate-btn { padding: 7px 0 8px; font-size: 15px; }
  .gate-alt, .gate-fine { margin-top: 5px; padding-top: 4px; }
}

/* reduced motion: no print theater, no pulses */
/* A just-opened position, marked once where it lives. Rows are only rebuilt on
   a structural change, so this plays a single time — never on a price tick. */
@keyframes rowFresh {
  0% { background: rgba(var(--ink-rgb), 0.2); }
  100% { background: transparent; }
}
.desk-table tr.row-fresh td { animation: rowFresh 1.6s ease-out 1; }

/* Same not-ready language as the place button, chip-sized. Still clickable so
   it can say why. */
.chip-btn[aria-disabled="true"] {
  border-style: dashed;
  opacity: 0.55;
}
.chip-btn[aria-disabled="true"]:hover { box-shadow: none; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .receipt.is-new { animation: none; }
  .receipt-stamp.stamp-in { animation: none; opacity: 1; }
  .conn-dot, .chart-badge, .liq-near { animation: none !important; }
  .toast { animation: none; }
  /* the heavier border/shadow still has to land — only the shake is motion */
  .toast.toast-liq { animation: none; }
  .desk-table tr.row-fresh td { animation: none; background: rgba(var(--ink-rgb), 0.09); }
  .mast-mark.is-tick, .mast-mark.is-tick-down { transition: none; }
  .mast-brand:hover, .chip-btn:hover, .place-btn:hover { transform: none; }
  .gate-card.gate-shake { animation: none; }
}

/* reduce-only toggle — a resting order that can only shrink a position */
.ticket-ronly { margin: 6px 10px 0; }
.ronly-btn {
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  padding: 6px 9px;
  min-height: 24px;
  border: 1px dashed var(--muted);
  background: var(--paper);
  color: var(--ink);
  cursor: pointer;
}
.ronly-btn:hover { border-style: solid; border-color: var(--ink); background: var(--paper-deep); }
/* armed reads as a committed stamp, the same inversion the type buttons use */
.ronly-btn.is-on {
  background: var(--ink);
  color: var(--paper);
  border-style: solid;
  border-color: var(--ink);
}
/* the RO marker in the ORDERS type cell */
.ro-tag {
  font-family: var(--mono);
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.06em;
  border: 1px solid var(--ink);
  padding: 0 3px;
  vertical-align: 1px;
}

/* ============================================================
   THE PLATE (2026-08-02) — the terminal prints on the shared
   halftone Saturn from /plate.css + /plate.js, the same ground as
   /saturnshop/ and the homepage.

   This is the one surface where the plate is deliberately
   SUBORDINATE. Everywhere else the ground is the point; here the
   page is a working tool with a documented vertical budget, live
   prices and a chart, and a moving halftone behind a number is a
   legibility problem, not atmosphere. So the trading area is
   sealed and the plate is allowed to read in the chrome and at
   the edges — present, never competing with a price.
   ============================================================ */

/* .cockpit measured fully transparent, which let the rings print straight
   through the chart and the panel gutters. Sealed: no dot ever lands inside
   the working area, whatever a panel does or does not fill. */
.cockpit {
  position: relative;
  z-index: 5;
  background: var(--paper);
}

/* The masthead is branded chrome rather than working surface, so it carries
   the ground instead of hiding it — a paper wash thin enough to show the
   halftone underneath and heavy enough that the dense chip rows still read as
   ink on stock. This is the one place on the terminal the plate is meant to
   be seen. */
.mast {
  position: relative;
  z-index: 6;
  background: color-mix(in srgb, var(--paper) 82%, transparent);
}

/* the sign-in gate floats over both; it already carries its own veil */
.gate { z-index: 40; }


/* ============================================================
   SIMPLE DESK — progressive disclosure for first contact.
   The library's own rule: never open a first-time flow in full
   terminal density. SIMPLE keeps side / size / leverage / place
   / positions / history / report / movers; PRO is the whole
   cockpit, one tap away. State: body.desk-simple, device pref.
   ============================================================ */
body.desk-simple .ticket-type,
body.desk-simple #reduceRow,
body.desk-simple .ticket-triggers,
body.desk-simple #ticketPreviewRr,
body.desk-simple #limitField,
body.desk-simple #stopField,
body.desk-simple .ema-rail,
body.desk-simple #alertArm,
body.desk-simple #tabTape,
body.desk-simple #tabBook,
body.desk-simple #fundingRate,
body.desk-simple #dayVol { display: none !important; }
/* working orders can only exist after a PRO detour — the tab returns the
   moment there is one to see, and leaves when they are gone */
body.desk-simple:not(.simple-has-orders) #tabOrders { display: none !important; }

/* plain-word glosses — visible only on the simple desk; every line is a
   true statement about THIS sim, not marketing */
.simple-gloss {
  display: none;
  font-family: var(--mono);
  font-size: var(--t-fine);
  font-weight: 600;
  letter-spacing: 0.04em;
  line-height: 1.45;
  color: var(--muted);
  margin: 3px 0 0;
}
body.desk-simple .simple-gloss { display: block; }

/* SIMPLE / PRO switch — lives in the ticket's panel head */
.ticket-mode { display: inline-flex; border: 1px solid var(--muted); flex: none; }
.tmode-btn {
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.12em;
  padding: 3px 8px;
  min-height: 24px;
  color: var(--muted);
}
.tmode-btn.is-on { background: var(--ink); color: var(--paper); }
.tmode-btn:not(.is-on):hover { color: var(--ink); }

/* first-contact coach tags — three numbered paper slips, JS-positioned,
   shown once (simple desk, no history), gone forever on first touch.
   Paper artifacts like receipts: fixed ink, both themes. */
.coach-tag {
  position: fixed;
  z-index: 120; /* over chrome + grain, under the gate (150) and palette */
  /* pure annotation — a tag must NEVER eat a tap meant for the control it
     points at (tag 3 sits over PLACE). First interaction anywhere retires
     the set; the document-level listener in awake.js owns that. */
  pointer-events: none;
  display: flex;
  align-items: center;
  gap: 7px;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1.35;
  background: var(--receipt-paper);
  color: #141312;
  border: 1px solid #141312;
  box-shadow: 3px 3px 0 rgba(20, 19, 18, 0.55);
  padding: 7px 10px;
  max-width: 250px;
  text-align: left;
}
.coach-tag em {
  font-style: normal;
  flex: none;
  background: #d9e8cf;
  border: 1px solid #141312;
  padding: 0 5px;
  min-height: 18px;
  display: inline-flex;
  align-items: center;
}
.coach-tag:nth-child(odd) { transform: rotate(-1deg); }
.coach-tag:nth-child(even) { transform: rotate(0.8deg); }
@media (prefers-reduced-motion: no-preference) {
  .coach-tag { animation: coachIn 0.3s cubic-bezier(0.2, 0.9, 0.3, 1) both; }
  .coach-tag:nth-child(2) { animation-delay: 0.12s; }
  .coach-tag:nth-child(3) { animation-delay: 0.24s; }
  @keyframes coachIn {
    from { opacity: 0; transform: translateY(-8px); }
    to { opacity: 1; }
  }
}

/* the cover sheet says everything the intro banner says — while the gate is
   open the banner is duplication cutting ACROSS the paper. It returns for
   the signed-in first visit the moment the gate closes. */
#gate:not([hidden]) ~ .intro-banner { display: none !important; }


/* ============================================================
   MARS FOLD v41 — cover sheet fit + contrast
   ============================================================ */
/* B1: the cover grew past short laptops (897px card vs a 720px viewport)
   and .gate is a FIXED inert overlay — without its own scroll the CREATE
   button is simply unreachable. Scroll the gate itself; top-anchor with
   breathing room so the masthead never clips. */
.gate {
  overflow-y: auto;
  align-items: start;
  justify-items: center;
  padding-top: 28px;
  padding-bottom: 28px;
}
@media (max-height: 840px) {
  /* short screens: tighten the sheet before anything has to scroll */
  .cover-spec { row-gap: 4px; }
  .gate-card.cover-sheet { padding-top: 14px; padding-bottom: 14px; }
}
/* M3: the spec rows are wrapped in divs — make the wrappers transparent to
   the grid so dt/dd land label-left / value-right, the receipt grammar the
   block was written to match */
.cover-spec > div { display: contents; }
/* M5: the re-pin resolves the card's OWN outer shadow to paper-ink =
   near-black on the dark veil. The offset plate is depth, not information —
   theme it explicitly instead of through the re-pinned token. */
.gate-card.cover-sheet { box-shadow: 8px 8px 0 rgba(20, 19, 18, 0.85); }
html[data-theme="ink"] .gate-card.cover-sheet { box-shadow: 8px 8px 0 rgba(0, 0, 0, 0.7); }
/* M7: CREATE stays the loud block, but when SIGN IN is the active radio the
   loud block dims so "where am I" stays answerable at a glance */
#modeSignUp:not(.is-on) { opacity: 0.82; }
