/* CoinQuant — instrument-panel aesthetic.
   Dark by default (this is a tool people stare at for hours), light available.
   Numbers are tabular monospace everywhere so columns line up and a changed
   digit is visible without re-reading the row.

   One rule governs the whole sheet: the screen states facts, it does not
   teach. Anything that used to be a paragraph of explanation is now a "?"
   button (.q) that drops a question into the conversation, because the
   assistant is on every page and a paragraph in a template cannot be argued
   with when it goes stale. */

:root {
  --bg:        #0a0d13;
  --surface:   #11151e;
  --surface-2: #161b26;
  --surface-3: #1b2130;
  --line:      #232a38;
  --line-soft: #1a202b;
  --text:      #e6eaf2;
  --muted:     #8290a8;
  --faint:     #5b6579;
  --accent:    #e0a83b;
  --accent-dim:#8a6721;
  --on-accent: #17120a;
  --pos:       #46b96a;
  --neg:       #e05a48;
  --info:      #4d8ed6;

  /* One spacing rhythm for the whole product. Before this every template
     invented its own margin inline, which is why nothing lined up. */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px; --s5: 24px; --s6: 36px;

  --radius:    10px;
  --radius-sm: 6px;
  --radius-lg: 14px;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Helvetica, Arial, sans-serif;
  /* The two page trunks. Everything centred on a page - the header included -
     has to share one of these, or nothing lines up. */
  --page-max:  1180px;   /* one-column pages: projects, account */
  --shell-max: 1560px;   /* two-column pages: workspace, report, landing */
  --head-h:    54px;
  --shadow: 0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.25);
  --shadow-sm: 0 1px 2px rgba(0,0,0,.3);
}

@media (prefers-color-scheme: light) {
  :root {
    --bg:        #f6f7f9;
    --surface:   #ffffff;
    --surface-2: #f2f4f7;
    --surface-3: #e9edf3;
    --line:      #dde2ea;
    --line-soft: #eceff4;
    --text:      #10141c;
    --muted:     #5d6779;
    --faint:     #8b95a6;
    --accent:    #a9791a;
    --accent-dim:#d9bb7d;
    --on-accent: #ffffff;
    --pos:       #2f9350;
    --neg:       #c9402c;
    --shadow: 0 1px 2px rgba(16,20,28,.05), 0 8px 24px rgba(16,20,28,.06);
    --shadow-sm: 0 1px 2px rgba(16,20,28,.06);
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }
a:hover { color: var(--accent); }

.num { font-family: var(--mono); font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.pos { color: var(--pos); }
.neg { color: var(--neg); }
.muted { color: var(--muted); }
.faint { color: var(--faint); }
.small { font-size: 13px; }
.tiny  { font-size: 12px; }
.spacer { flex: 1; }
.is-hidden { display: none; }

/* ---------------------------------------------------------------- layout */
.wrap { max-width: var(--page-max); margin: 0 auto; padding: 0 var(--s5); }
.wrap-narrow { max-width: 420px; margin: 0 auto; padding: 0 var(--s5); }

header.top {
  border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  backdrop-filter: blur(10px);
  position: sticky; top: 0; z-index: 40;
}
header.top .inner {
  display: flex; align-items: center; gap: var(--s5);
  height: var(--head-h); max-width: var(--page-max); margin: 0 auto; padding: 0 var(--s5);
}
.brand { display: flex; align-items: center; gap: 9px; font-weight: 620; letter-spacing: -.01em; }
.brand:hover { color: var(--text); }
.brand .mark {
  width: 17px; height: 17px; border-radius: 5px;
  background: linear-gradient(140deg, var(--accent), var(--accent-dim));
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.14);
}
.nav-links { display: flex; gap: var(--s3); align-items: center; font-size: 14px; color: var(--muted); }
.nav-links > a { padding: 4px 2px; }
.lang { display: flex; border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden; }
.lang a { padding: 3px 8px; font-size: 11px; color: var(--muted); font-family: var(--mono); }
.lang a.on { background: var(--surface-2); color: var(--text); }

/* The account menu. A popover rather than five items in the bar: the address,
   the plan and the way out are things you need twice a week, and they were
   costing header width every second of every session. */
.menu { position: relative; }
.menu > summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; gap: 7px;
  padding: 4px 8px; border: 1px solid var(--line); border-radius: 999px;
  color: var(--muted); font-size: 13px;
}
.menu > summary::-webkit-details-marker { display: none; }
.menu > summary:hover { border-color: var(--faint); color: var(--text); }
.menu[open] > summary { border-color: var(--faint); color: var(--text); }
.menu .avatar {
  width: 20px; height: 20px; border-radius: 50%; flex: none;
  display: grid; place-items: center; font-size: 11px; font-weight: 650;
  background: var(--surface-3); color: var(--muted); text-transform: uppercase;
}
.menu-body {
  position: absolute; right: 0; top: calc(100% + 8px); min-width: 232px; z-index: 50;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: var(--s2);
}
.menu-body .who { padding: var(--s2) var(--s3) var(--s3); border-bottom: 1px solid var(--line-soft); }
.menu-body a {
  display: flex; align-items: center; gap: var(--s2);
  padding: 8px var(--s3); border-radius: var(--radius-sm); font-size: 14px; color: var(--muted);
}
.menu-body a:hover { background: var(--surface-2); color: var(--text); }

main { padding: 28px 0 56px; }
body:has(.shell) main { padding: 0; }

h1 { font-size: 25px; font-weight: 650; letter-spacing: -.02em; margin: 0 0 var(--s1); }
h2 { font-size: 16px; font-weight: 620; letter-spacing: -.01em; margin: 0 0 var(--s3); }
h3 { font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .07em;
     color: var(--muted); margin: 0 0 var(--s2); }

.page-head { margin-bottom: var(--s5); display: flex; align-items: flex-start; gap: var(--s4); flex-wrap: wrap; }

/* ---------------------------------------------------------------- cards */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--s4) 18px;
}
.card + .card { margin-top: var(--s4); }
.card-head { display: flex; align-items: center; gap: var(--s2); margin-bottom: var(--s3); }
.card-head h2 { margin: 0; }
.grid { display: grid; gap: var(--s4); }
.grid-2 { grid-template-columns: 1fr 1fr; }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.split { display: grid; grid-template-columns: 1.4fr 1fr; gap: var(--s4); }
@media (max-width: 980px) {
  .grid-2, .grid-3, .split { grid-template-columns: 1fr; }
}

/* A card that folds. Used for everything a user needs occasionally - the
   examples, the run history, the roadmap - so the panel shows the work and
   not the furniture. */
details.fold > summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; gap: var(--s2);
  font-size: 14px; font-weight: 560; color: var(--text);
}
details.fold > summary::-webkit-details-marker { display: none; }
details.fold > summary::after {
  content: ""; margin-left: auto; width: 6px; height: 6px; flex: none;
  border-right: 1.5px solid var(--faint); border-bottom: 1.5px solid var(--faint);
  transform: rotate(45deg) translate(-2px, -2px); transition: transform .15s;
}
details.fold[open] > summary::after { transform: rotate(-135deg) translate(-1px, -1px); }
details.fold > summary:hover { color: var(--accent); }
details.fold[open] > summary { margin-bottom: var(--s3); }
/* A fold inside a card is a sub-heading, not a heading: JSON, "More", "All
   runs". Written out because the element+class selector above would otherwise
   outrank the .small/.muted utilities on the same tag. */
details.fold > summary.small { font-size: 12.5px; font-weight: 550; color: var(--muted); }
details.fold > summary.small:hover { color: var(--accent); }

/* ---------------------------------------------------------------- forms */
label { display: block; font-size: 11px; color: var(--muted); margin-bottom: 5px;
        text-transform: uppercase; letter-spacing: .05em; font-weight: 600; }
input, select, textarea {
  width: 100%; padding: 8px 10px;
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  font-family: var(--sans); font-size: 14px; outline: none;
}
input.num, select { font-family: var(--mono); }
input:focus, select:focus, textarea:focus {
  border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
textarea { min-height: 90px; resize: vertical; line-height: 1.5; font-size: 14.5px; }
.field { margin-bottom: var(--s3); }
.field:last-child { margin-bottom: 0; }
.field-row { display: grid; gap: var(--s2); }
/* Label on the left, its "?" on the right, on one line. The question mark is
   part of the field, not a footnote under it. */
.field-head { display: flex; align-items: center; gap: var(--s2); margin-bottom: 5px; }
.field-head label { margin: 0; }

button, .btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 8px 14px; border-radius: var(--radius-sm);
  border: 1px solid var(--line); background: var(--surface-2); color: var(--text);
  font-family: var(--sans); font-size: 14px; font-weight: 550; cursor: pointer;
  transition: background .12s, border-color .12s, color .12s;
}
button:hover, .btn:hover { background: var(--surface-3); border-color: var(--faint); color: var(--text); }
button:focus-visible, .btn:focus-visible, .q:focus-visible {
  outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 30%, transparent);
}
.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 620; }
.btn-primary:hover { background: color-mix(in srgb, var(--accent) 86%, #fff); border-color: var(--accent); color: var(--on-accent); }
.btn-ghost { background: transparent; }
.btn-sm { padding: 5px 11px; font-size: 13px; }
button[disabled], .btn[disabled] { opacity: .45; cursor: not-allowed; }
button[disabled]:hover { background: var(--surface-2); border-color: var(--line); }

/* The "?" button. Everything the interface used to explain in a paragraph is
   one of these: it drops a written question into the message box and lets the
   user decide whether to ask it. Nothing is sent by clicking. */
.q {
  width: 17px; height: 17px; padding: 0; flex: none;
  border-radius: 50%; border: 1px solid var(--line); background: transparent;
  color: var(--faint); font-size: 10.5px; font-weight: 700; line-height: 1;
  display: inline-grid; place-items: center; cursor: pointer;
}
.q:hover { color: var(--on-accent); background: var(--accent); border-color: var(--accent); }

/* ---------------------------------------------------------------- verdict */
.verdict {
  border-radius: var(--radius); padding: 18px 20px;
  border: 1px solid var(--line); background: var(--surface);
  display: flex; gap: var(--s5); align-items: flex-start; flex-wrap: wrap;
  position: relative; overflow: hidden;
}
.verdict::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--vc);
}
.verdict .vtext { flex: 1 1 320px; }
.verdict .vhead { display: flex; align-items: center; gap: var(--s2); }
.verdict .vtitle { font-size: 20px; font-weight: 660; letter-spacing: -.02em; color: var(--vc); }
.verdict .vhint { color: var(--muted); font-size: 13.5px; margin-top: var(--s1); max-width: 62ch; }
.v-broken       { --vc: var(--neg); }
.v-insufficient { --vc: var(--faint); }
.v-no_edge      { --vc: var(--muted); }
.v-not_confirmed{ --vc: var(--accent); }
.v-fragile      { --vc: #d5813f; }
.v-passed       { --vc: var(--pos); }

.reasons { margin: var(--s3) 0 0; padding: 0; list-style: none; }
.reasons li {
  font-size: 13px; color: var(--muted); padding: 4px 0 4px var(--s4); position: relative;
}
.reasons li::before { content: "—"; position: absolute; left: 0; color: var(--faint); }

/* The four numbers a verdict is about, inside the verdict card. Reading the
   conclusion and the evidence should not require scrolling between them. */
.kpi-wrap { flex: 0 0 auto; }
.kpi { display: grid; grid-template-columns: repeat(2, minmax(84px, 1fr)); gap: var(--s3) var(--s5); }
.kpi .k { font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.kpi .v { font-family: var(--mono); font-size: 19px; font-weight: 560; letter-spacing: -.02em; margin-top: 1px; }

/* ------------------------------------------------------------- status bar */
/* Cost mode, holdout state and trial count: three facts that decide how much
   the page below is worth. One row of chips, never a paragraph. */
.statusbar {
  display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap;
  margin-bottom: var(--s3);
}
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px; border-radius: 999px; border: 1px solid var(--line);
  background: var(--surface); color: var(--muted); font-size: 12.5px; white-space: nowrap;
}
.chip .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }
.chip-bad { color: var(--neg); border-color: color-mix(in srgb, var(--neg) 45%, var(--line));
            background: color-mix(in srgb, var(--neg) 8%, var(--surface)); }
.chip-ok  { color: var(--muted); }
.chip-open { color: var(--accent); border-color: var(--accent-dim); }
.chip-act { padding: 0; border: 0; background: none; }

/* ---------------------------------------------------------------- checks */
.checks { display: flex; flex-direction: column; gap: 1px; background: var(--line-soft);
          border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.check { display: flex; align-items: center; gap: var(--s3); padding: 9px 13px; background: var(--surface); }
.check .ic { width: 15px; height: 15px; border-radius: 50%; flex: none;
             display: grid; place-items: center; font-size: 9.5px; font-weight: 700; }
.check.pass .ic { background: color-mix(in srgb, var(--pos) 18%, transparent); color: var(--pos); }
.check.fail .ic { background: color-mix(in srgb, var(--neg) 18%, transparent); color: var(--neg); }
.check.skip .ic { background: var(--surface-2); color: var(--faint); }
.check .cname { flex: 1; font-size: 13.5px; }
.check .cdetail { font-family: var(--mono); font-size: 12px; color: var(--muted); text-align: right; }

/* ---------------------------------------------------------------- metrics */
.metrics { width: 100%; border-collapse: collapse; }
.metrics th { text-align: right; font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
              color: var(--muted); font-weight: 600; padding: 0 0 var(--s2); }
.metrics th:first-child { text-align: left; }
.metrics td { padding: 6px 0; border-top: 1px solid var(--line-soft);
              font-family: var(--mono); font-size: 13.5px; text-align: right; }
.metrics td:first-child { font-family: var(--sans); color: var(--muted); font-size: 13px; text-align: left; }
.metrics tr:hover td { background: color-mix(in srgb, var(--surface-2) 60%, transparent); }
.col-oos { color: var(--text); }
.col-is  { color: var(--muted); }

.stat-row { display: flex; gap: var(--s5); flex-wrap: wrap; }
.stat { min-width: 88px; }
.stat .k { font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.stat .v { font-family: var(--mono); font-size: 18px; font-weight: 560; letter-spacing: -.02em; margin-top: 2px; }

/* ---------------------------------------------------------------- charts */
.chart { width: 100%; height: auto; display: block; }
.chart .grid { stroke: var(--line-soft); stroke-width: 1; }
.chart .zero { stroke: var(--faint); stroke-width: 1; stroke-dasharray: 3 3; }
.chart .axis-y { fill: var(--faint); font-size: 10px; font-family: var(--mono); text-anchor: end; }
.chart .axis-x { fill: var(--faint); font-size: 10px; font-family: var(--mono); text-anchor: middle; }
.chart .axis-x.val { fill: var(--muted); font-size: 10.5px; }
.chart .series { fill: none; stroke-width: 1.7; stroke-linejoin: round; stroke-linecap: round; }
.chart.equity.up   .series { stroke: var(--pos); }
.chart.equity.down .series { stroke: var(--neg); }
.chart.equity.up   .fill-top    { stop-color: var(--pos); stop-opacity: .16; }
.chart.equity.down .fill-top    { stop-color: var(--neg); stop-opacity: .16; }
.fill-bottom { stop-color: var(--pos); stop-opacity: 0; }
.chart.equity.down .fill-bottom { stop-color: var(--neg); stop-opacity: 0; }
.chart .split-line { stroke: var(--accent); stroke-width: 1; stroke-dasharray: 4 3; }
.chart .oos-band { fill: var(--accent); opacity: .045; }
.chart .split-label { fill: var(--accent); font-size: 10px; font-family: var(--mono); font-weight: 700; }
.chart .dd-fill { fill: var(--neg); opacity: .17; }
.chart .dd-line { fill: none; stroke: var(--neg); stroke-width: 1.2; }
.chart .bar-pos { fill: var(--pos); opacity: .85; }
.chart .bar-neg { fill: var(--neg); opacity: .85; }
.chart-empty { color: var(--faint); font-size: 13px; padding: 40px; text-align: center; }

/* ---------------------------------------------------------------- notes */
.note {
  border-left: 2px solid var(--line); padding: var(--s2) 0 var(--s2) var(--s3);
  color: var(--muted); font-size: 12.5px; line-height: 1.55;
}
.note-warn { border-left-color: var(--accent); }
.note-bad  { border-left-color: var(--neg); }
.banner {
  border: 1px solid var(--line); border-left: 3px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 6%, var(--surface));
  border-radius: var(--radius-sm); padding: 11px 14px; font-size: 13.5px; color: var(--text);
  display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap;
}
.banner.bad { border-left-color: var(--neg); background: color-mix(in srgb, var(--neg) 7%, var(--surface)); }
.banner.ok { border-color: var(--line); border-left-color: var(--line); color: var(--muted); }

/* ---------------------------------------------------------------- lists */
.list { display: flex; flex-direction: column; gap: 1px; background: var(--line-soft);
        border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.list-item { display: flex; align-items: center; gap: var(--s3); padding: 10px var(--s3);
             background: var(--surface); transition: background .1s; }
.list-item:hover { background: var(--surface-2); }
.list-item .title { font-weight: 560; }

.pill { font-family: var(--mono); font-size: 11px; padding: 2px 8px; border-radius: 999px;
        border: 1px solid var(--line); color: var(--muted); white-space: nowrap; }
.pill.v-passed { color: var(--pos); border-color: color-mix(in srgb, var(--pos) 40%, var(--line)); }
.pill.v-no_edge { color: var(--muted); }
.pill.v-fragile { color: #d5813f; border-color: color-mix(in srgb, #d5813f 40%, var(--line)); }
.pill.v-not_confirmed { color: var(--accent); border-color: var(--accent-dim); }
.pill.v-broken { color: var(--neg); border-color: color-mix(in srgb, var(--neg) 40%, var(--line)); }
.pill-tier { background: var(--surface-2); border: 1px solid var(--line); color: var(--muted); }

.tag {
  display: inline-block; font-size: 10.5px; font-family: var(--mono);
  padding: 1px 6px; border-radius: 4px; border: 1px solid var(--line);
  color: var(--muted); vertical-align: middle;
}
.tag-basic { border-color: var(--line); }
.tag-intermediate { border-color: var(--info); color: var(--info); }
.tag-advanced { border-color: var(--accent); color: var(--accent); }

/* ==========================================================================
   Data Explorer

   The coverage strip is the one graphic on the site that can lie, so it is
   built not to. Each segment is a run of consecutive periods in one state and
   grows in proportion to how many periods it spans - three days scattered
   across two months come out as three slivers totalling 4.9% of the bar, which
   is what they are. Marks at fixed size, evenly spaced, would have read as
   "we have this instrument".

   Three colours for three states, none of them green or red: how complete is
   complete enough depends on the strategy about to stand on the data, and the
   palette must not answer that question on the user's behalf.
   ========================================================================== */
.cov {
  display: flex; height: 12px; width: 100%; overflow: hidden;
  border-radius: 3px; background: var(--surface-3);
  border: 1px solid var(--line);
}
/* A held period narrower than one pixel would disappear entirely, which
   overstates emptiness as badly as a fixed-size dot overstates presence. One
   pixel on a 1000px bar is a tenth of a percentage point; that is the size of
   the lie, and it is the smaller of the two available. */
.cov-seg { min-width: 0; }
.cov-held, .cov-thin { min-width: 1px; }
.cov-held { background: var(--info); }
.cov-thin { background: var(--accent); }
.cov-gap  { background: transparent; }
.cov-legend { display: flex; align-items: center; gap: var(--s3); margin-top: 5px; }
.cov-key {
  display: inline-block; width: 9px; height: 9px; border-radius: 2px;
  border: 1px solid var(--line); margin-right: 5px; vertical-align: -1px;
}
/* Under-filled, wherever it is written as text rather than drawn. */
.thin { color: var(--accent); }

/* Missing and under-filled periods are listed in full rather than summarised:
   "58 gaps" is the headline, and the 58 dates are what makes it checkable. */
.period-list { display: flex; flex-wrap: wrap; gap: 4px 6px; }
.period-list span {
  padding: 1px 6px; border-radius: 4px;
  background: var(--surface-2); border: 1px solid var(--line-soft); color: var(--muted);
}

.filter-row { display: flex; gap: var(--s3); align-items: flex-end; flex-wrap: wrap;
              margin-bottom: var(--s4); }
.stream-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--s3); }
.data-table td, .data-table th { padding-right: var(--s3); }
.data-table td:last-child, .data-table th:last-child { padding-right: 0; }
.data-table td:first-child { color: var(--text); }
.data-table .tag { margin: 1px 3px 1px 0; }

pre.code {
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: var(--s3); overflow: auto; font-family: var(--mono); font-size: 12px;
  line-height: 1.5; color: var(--muted); max-height: 340px; margin: 0;
}

/* The strategy, as the engine will run it. The one place on the workspace
   where the user can check what the assistant actually did. */
.strategy-view { font-family: var(--mono); font-size: 12.5px; line-height: 1.7; }
.strategy-view .kw { color: var(--accent); }
.strategy-view .row { display: flex; gap: var(--s2); padding: 3px 0; border-bottom: 1px solid var(--line-soft); }
.strategy-view .row:last-child { border-bottom: 0; }
.strategy-view .k { color: var(--muted); min-width: 104px; flex: none; }

.spinner {
  width: 15px; height: 15px; border: 2px solid var(--line);
  border-top-color: var(--accent); border-radius: 50%;
  animation: spin .7s linear infinite; display: inline-block; vertical-align: -2px;
}
@keyframes spin { to { transform: rotate(360deg); } }

footer.foot { border-top: 1px solid var(--line); margin-top: var(--s6); padding: var(--s4) 0 var(--s5);
              color: var(--faint); font-size: 11.5px; }
footer.foot .wrap { display: flex; gap: var(--s3); flex-wrap: wrap; align-items: baseline; }
/* The footer shares whichever trunk the page above it uses, or its first line
   starts 160px to the left of everything else. */
body:has(.shell) footer.foot .wrap { max-width: var(--shell-max); }

/* ---------------------------------------------------------------- landing */
.hero { padding: 40px 0 var(--s5); }
.hero h1 { font-size: 38px; line-height: 1.12; letter-spacing: -.03em; max-width: 17ch; }
.hero p.lede { font-size: 16.5px; color: var(--muted); max-width: 56ch; margin: var(--s4) 0 var(--s5); }
.feat { display: grid; gap: var(--s4); grid-template-columns: repeat(3, 1fr); margin-top: var(--s6); }
@media (max-width: 900px) { .feat { grid-template-columns: 1fr; } .hero h1 { font-size: 29px; } }
.feat .f h4 { margin: 0 0 var(--s1); font-size: 14px; font-weight: 600; }
.feat .f p { margin: 0; color: var(--muted); font-size: 13px; }
.feat .f .n { font-family: var(--mono); color: var(--accent); font-size: 11.5px; }
.signup-card { border-color: var(--accent-dim); }

/* ==========================================================================
   The shell: conversation on one side, whatever the page is about on the
   other. One layout for every screen the assistant appears on, because the
   assistant is not a feature of one page - it is where the user asks
   questions, and the questions do not stop when the backtest starts.

   .shell        the workspace. The chat is the wide column; the panel beside
                 it is the audit trail. Both columns scroll independently and
                 the run buttons never leave the screen, so the tool behaves
                 like an instrument panel rather than like a document.
   .shell-rail   the report and the landing page. The right column is dense
                 reading, so the chat narrows to a rail beside it.
   ========================================================================== */
.shell {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 380px;
  gap: 18px;
  max-width: var(--shell-max);
  margin: 0 auto;
  padding: 18px var(--s5) var(--s5);
  align-items: start;
}
/* The header is centred on its own maximum, and the two-column pages are wider
   than the one-column ones. Left alone, the logo lands 160px to the right of
   where the conversation begins and nothing on the page shares a left edge. */
body:has(.shell) header.top .inner { max-width: var(--shell-max); }
@media (min-width: 1360px) {
  .shell { grid-template-columns: minmax(0, 1fr) 440px; gap: 22px; }
}

.shell-rail { grid-template-columns: 370px minmax(0, 1fr); }
@media (min-width: 1360px) {
  .shell-rail { grid-template-columns: 410px minmax(0, 1fr); gap: 24px; }
}

.ws-chat {
  position: sticky;
  top: 18px;
  display: flex;
  flex-direction: column;
  height: calc(100vh - var(--head-h) - 36px);
  min-height: 430px;
}
.ws-chat-rail { height: calc(100vh - var(--head-h) - 36px); min-height: 380px; }
.ws-chat-rail .bubble { font-size: 13.5px; padding: 9px 12px; }
.ws-chat-rail .transcript { padding: var(--s3); }

/* The landing column grows with its contents instead of being pinned to the
   viewport: the sign-up card appears underneath the conversation partway
   through, and a fixed-height column would push it off the bottom edge at
   exactly the moment it is meant to be read. */
.ws-chat-demo { position: static; height: auto; min-height: 0; }
.ws-chat-demo .transcript { flex: none; min-height: 280px; max-height: 44vh; }

.ws-head { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; margin-bottom: var(--s2); min-height: 26px; }
.ws-head h1 { margin: 0; font-size: 19px; }
.ws-head .back { color: var(--faint); font-size: 13px; }
.ws-head .back:hover { color: var(--accent); }

.transcript {
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--s4);
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  scroll-behavior: smooth;
}

/* Capped in characters as well as in percent. On a wide monitor the chat
   column is over a thousand pixels, and a bubble that fills it is a
   150-character line - unreadable in the way a wall of text is unreadable. */
.msg { display: flex; flex-direction: column; gap: 6px; max-width: min(88%, 74ch); }
.msg-user { align-self: flex-end; align-items: flex-end; }
.msg-assistant, .msg-system { align-self: flex-start; }
.msg-system { max-width: 100%; }

.bubble {
  padding: 10px 13px;
  border-radius: 12px;
  line-height: 1.55;
  white-space: pre-wrap;
  word-wrap: break-word;
  font-size: 14.5px;
}
.msg-user .bubble { background: var(--accent); color: var(--on-accent); border-bottom-right-radius: 4px; }
.msg-assistant .bubble { background: var(--surface-2); border: 1px solid var(--line-soft); border-bottom-left-radius: 4px; }
.msg-system .bubble {
  background: transparent; border: 1px dashed var(--line);
  color: var(--muted); font-size: 13px; padding: 8px 12px;
}

/* What an assistant turn actually changed. Always rendered, never collapsed:
   an action the user did not notice is an action they cannot undo. */
.act {
  font-size: 12.5px; padding: 7px 11px; border-radius: 8px;
  border-left: 3px solid var(--line); background: var(--surface-2);
}
.act-ok { border-left-color: var(--pos); }
.act-warn { border-left-color: var(--accent); }
.act a { color: var(--info); }
.act ul.blocking { margin: var(--s2) 0 6px; padding-left: 18px; }
.act ul.blocking li { margin-bottom: 5px; }
/* Spec-derived summary inside an assistant turn. Deliberately plain and
   slightly cramped: it is a receipt, not a headline. */
.act ul.applied { margin: 6px 0; padding-left: var(--s4); list-style: none; }
.act ul.applied li { margin-bottom: 3px; font-family: var(--mono); font-size: 11.5px; color: var(--text); }
.act ul.applied li::before { content: "· "; color: var(--faint); }

.composer { display: flex; gap: var(--s2); margin-top: var(--s3); align-items: flex-end; }
.composer textarea {
  flex: 1; resize: none; min-height: 44px; max-height: 200px;
  padding: 10px 12px; border-radius: var(--radius-sm);
  border: 1px solid var(--line); background: var(--surface); color: var(--text);
  font-family: var(--sans); font-size: 14.5px; line-height: 1.5;
}
.composer textarea:focus { outline: none; border-color: var(--accent-dim); box-shadow: none; }
/* A question dropped in by a "?" button should be visibly waiting to be sent,
   not look like something that already happened. */
.composer textarea.filled { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent); }

/* Suggested replies. A button fills the message box and nothing else - reading
   what an option says must not be the same act as choosing it. */
.choices { display: flex; flex-wrap: wrap; gap: 6px; }
.choices .choice { font-size: 12.5px; padding: 5px 10px; text-align: left; }

/* ------------------------------------------------------- workspace panel */
/* Same height as the conversation, its own scroll, and the two buttons that
   spend money pinned underneath it. Before this the run button lived at the
   bottom of a ten-field form, one screen below the fold. */
.ws-panel {
  position: sticky;
  top: 18px;
  display: flex;
  flex-direction: column;
  height: calc(100vh - var(--head-h) - 36px);
  min-height: 430px;
}
.ws-scroll {
  flex: 1; overflow-y: auto; overscroll-behavior: contain;
  display: flex; flex-direction: column; gap: var(--s3);
  padding-right: var(--s2);
}
.ws-scroll .card { margin: 0; }
.ws-actions {
  flex: none; display: flex; gap: var(--s2);
  padding-top: var(--s3); margin-top: var(--s3); border-top: 1px solid var(--line);
}
.ws-actions .btn-primary { flex: 2; }
.ws-actions .btn-ghost { flex: 1; }

/* Thin scrollbars: two independently scrolling columns with system-width bars
   would spend 30px of a 380px panel on chrome. */
.ws-scroll, .transcript { scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
.ws-scroll::-webkit-scrollbar, .transcript::-webkit-scrollbar { width: 8px; }
.ws-scroll::-webkit-scrollbar-thumb, .transcript::-webkit-scrollbar-thumb {
  background: var(--line); border-radius: 4px;
}

/* Below this the two columns would each be too narrow to use, so they stack.
   Which one goes first depends on what the page is for: on the workspace the
   chat leads and the panel follows, and on a report the report leads - being
   made to scroll past a conversation to reach the verdict would be its own
   small insult. Neither is hidden in a drawer: an audit trail you have to open
   is no audit trail. */
@media (max-width: 1040px) {
  .shell, .shell-rail { grid-template-columns: minmax(0, 1fr); }
  .ws-chat, .ws-panel { position: static; height: auto; min-height: 0; }
  .transcript { max-height: 58vh; }
  .ws-scroll { overflow: visible; padding-right: 0; }
  .ws-actions { position: sticky; bottom: 0; z-index: 10;
                background: color-mix(in srgb, var(--bg) 88%, transparent);
                backdrop-filter: blur(8px); padding-bottom: var(--s2); }
  .shell-rail .ws-chat { order: 2; }
  .shell-rail .shell-main { order: 1; }
}

/* On a phone the bar has to fit in 375px: the plan label folds into the
   avatar, the gaps halve, and "Projects" stays because it is the only way back
   that is not inside a menu. */
@media (max-width: 640px) {
  header.top .inner { gap: var(--s3); padding: 0 var(--s3); }
  .nav-links { gap: var(--s2); }
  .menu > summary .tiny { display: none; }
  .wrap, .wrap-narrow { padding: 0 var(--s3); }
  .shell, .shell-rail { padding: var(--s3); }
  .card { padding: var(--s3); }
  h1 { font-size: 21px; }
  .hero { padding: var(--s5) 0; }
  .kpi { grid-template-columns: repeat(2, minmax(70px, 1fr)); gap: var(--s2) var(--s4); }
  .stat-row { gap: var(--s4); }
}

/* --------------------------------------------------------------- report */
.holdout {
  display: flex; gap: var(--s4); align-items: center; justify-content: space-between;
  flex-wrap: wrap; border: 1px solid var(--line); border-left: 3px solid var(--info);
  border-radius: var(--radius); background: var(--surface); padding: var(--s3) var(--s4);
  margin-bottom: var(--s3);
}
.holdout.opened { border-left-color: var(--accent); }
.holdout-title { font-weight: 600; font-size: 14px; }
.holdout form { margin: 0; flex-shrink: 0; }

.locked { border: 1px dashed var(--line); border-radius: var(--radius-sm);
          padding: var(--s3) var(--s4); background: var(--surface-2); }
.lock-title { font-weight: 600; margin-bottom: 6px; font-size: 14px; }

/* Progress ---------------------------------------------------------------- */
.progress { height: 5px; background: var(--surface-2); border-radius: 3px; overflow: hidden;
            max-width: 380px; margin: 0 auto; }
.progress-bar { height: 100%; background: var(--accent); transition: width .4s ease; width: 0; }

/* Plans table ------------------------------------------------------------- */
table.plans th { text-align: center; padding-bottom: var(--s2); }
table.plans td:not(:first-child) { text-align: center; }

/* ==========================================================================
   Market Replay

   A trading screen, and the layout follows what a person actually looks at
   between two clicks: the chart and the book on the left, the ticket and the
   account on the right, the clock above both. The ladder is the one element
   here with a rule behind it rather than a taste - the size bar behind each
   rung is scaled against the largest level *currently displayed*, so the
   shape of the visible book is honest even though the numbers beside it are
   the fact.
   ========================================================================== */
.rp-page { max-width: var(--shell-max); margin: 0 auto; padding: 18px var(--s5) var(--s5); }
body:has(.rp-page) header.top .inner { max-width: var(--shell-max); }
body:has(.rp-page) footer.foot .wrap { max-width: var(--shell-max); }

.rp-transport { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap;
                padding: var(--s3) var(--s4); margin-bottom: var(--s3); }
.rp-transport form { margin: 0; }
.rp-step { display: flex; gap: 4px; }
.rp-play { display: flex; align-items: center; gap: var(--s2); }
.rp-play label { margin: 0; }

.rp-body { display: grid; grid-template-columns: minmax(0, 1fr) 360px; gap: var(--s3); align-items: start; }
@media (max-width: 1180px) { .rp-body { grid-template-columns: minmax(0, 1fr); } }
.rp-side { display: flex; flex-direction: column; gap: var(--s3); }
.rp-account { display: flex; flex-direction: column; gap: var(--s3); }
.rp-account .card, .rp-side .card { margin: 0; }

/* The clock is the largest thing on the screen on purpose: every other number
   here is "as of" it. */
.rp-strip { display: flex; align-items: center; gap: var(--s4); flex-wrap: wrap;
            background: var(--surface); border: 1px solid var(--line);
            border-radius: var(--radius); padding: var(--s3) var(--s4); }
.rp-clock { font-size: 25px; font-weight: 600; letter-spacing: -.02em; }
.rp-strip-grid { display: flex; gap: var(--s5); flex-wrap: wrap; }
.rp-strip-grid .k { display: block; font-size: 10px; text-transform: uppercase;
                    letter-spacing: .06em; color: var(--muted); }
.rp-strip-grid .v { font-size: 15px; font-weight: 550; }

.rp-cols { display: grid; grid-template-columns: minmax(0, 1fr) 250px 190px;
           gap: var(--s3); margin-top: var(--s3); align-items: start; }
@media (max-width: 1400px) { .rp-cols { grid-template-columns: minmax(0, 1fr) 230px; }
                             .rp-cols .rp-tape { grid-column: 1 / -1; } }
@media (max-width: 760px) { .rp-cols { grid-template-columns: minmax(0, 1fr); } }
.rp-cols .card { margin: 0; }

/* ---- the ladder ---- */
.ladder { display: flex; flex-direction: column; font-family: var(--mono); font-size: 12px; }
.rung { position: relative; display: grid; grid-template-columns: 1fr 1fr 42px;
        gap: var(--s2); padding: 2px 5px; align-items: center; }
.rung .bar { position: absolute; right: 0; top: 1px; bottom: 1px; border-radius: 2px; z-index: 0; }
.rung .lp, .rung .ls, .rung .lm { position: relative; z-index: 1; }
.rung .ls { text-align: right; color: var(--muted); }
.rung .lm { text-align: right; color: var(--accent); font-size: 11px; }
.rung.ask .bar { background: color-mix(in srgb, var(--neg) 16%, transparent); }
.rung.ask .lp { color: var(--neg); }
.rung.bid .bar { background: color-mix(in srgb, var(--pos) 16%, transparent); }
.rung.bid .lp { color: var(--pos); }
.rung.mid-row { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
                padding: 4px 5px; margin: 2px 0; }
.rung.mid-row .lp { font-size: 13.5px; font-weight: 600; }
.rung.mid-row .ls { text-align: right; }

/* ---- the tape ---- */
.tape { display: flex; flex-direction: column; font-family: var(--mono); font-size: 11.5px;
        max-height: 320px; overflow-y: auto; scrollbar-width: thin; }
.print { display: grid; grid-template-columns: 62px 1fr 1fr; gap: 6px; padding: 1px 0; }
.print .p { text-align: right; }
.print .s { text-align: right; color: var(--muted); }
.print.buy .p { color: var(--pos); }
.print.sell .p { color: var(--neg); }
/* Stacked on a phone, the tape is no longer a column of its own, and a
   capped box with its own scrollbar in the middle of a page swallows the
   wheel: the page stops moving and the reader thinks it is stuck. */
@media (max-width: 1400px) { .tape { max-height: none; } }

/* ---- candles ---- */
.chart .cndl-up { fill: var(--pos); stroke: var(--pos); }
.chart .cndl-dn { fill: var(--neg); stroke: var(--neg); }
.chart .wick { stroke-width: 1; }
.chart .mid-line { stroke: var(--accent); stroke-width: 1; stroke-dasharray: 3 3; }
.chart .mid-tag { fill: var(--accent); }
.chart .fill-buy { fill: var(--info); stroke: var(--bg); stroke-width: 1; }
.chart .fill-sell { fill: var(--accent); stroke: var(--bg); stroke-width: 1; }

/* ---- the ticket ---- */
.rp-pricehints { display: flex; gap: 4px; margin-top: 5px; }
.rp-check { display: flex; align-items: center; gap: 7px; font-size: 12.5px;
            color: var(--muted); letter-spacing: 0; font-weight: 500; }
.rp-sides { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s2); margin-top: var(--s3); }
.btn-buy { background: color-mix(in srgb, var(--pos) 20%, var(--surface-2));
           border-color: color-mix(in srgb, var(--pos) 45%, var(--line)); color: var(--pos); font-weight: 620; }
.btn-buy:hover { background: color-mix(in srgb, var(--pos) 30%, var(--surface-2)); color: var(--pos); }
.btn-sell { background: color-mix(in srgb, var(--neg) 20%, var(--surface-2));
            border-color: color-mix(in srgb, var(--neg) 45%, var(--line)); color: var(--neg); font-weight: 620; }
.btn-sell:hover { background: color-mix(in srgb, var(--neg) 30%, var(--surface-2)); color: var(--neg); }

/* ---- what the venue answered ---- */
.rp-log { display: flex; flex-direction: column; gap: 3px; font-size: 12.5px; }
.rp-log > div { display: flex; gap: var(--s2); align-items: baseline;
                padding: 3px 0 3px var(--s2); border-left: 2px solid var(--line); }
.rp-log > div.ok { border-left-color: var(--pos); }
.rp-log > div.bad { border-left-color: var(--neg); color: var(--muted); }

/* --- results and fill detail -------------------------------------------- */
/* A wide table scrolls inside its own card rather than pushing the page
   sideways; the fills table grows a column per markout horizon. */
.rp-scroll { overflow: auto; }
.rp-scroll table { width: 100%; }
/* The level we were resting on, and the prints that worked off the queue in
   front of us. Both are "this row is the answer to the question you opened
   this page with", so they share one accent. */
.rung.mine { outline: 1px solid var(--accent); outline-offset: -1px; }
tr.hi td { color: var(--accent); }


/* --- pasted configs ------------------------------------------------------ */
/* A JSON config is read by column as much as by line - a misplaced brace is
   found by indentation - so it gets a monospace box that does not wrap. */
.code-area {
  width: 100%; font-family: var(--mono, ui-monospace, SFMono-Regular, monospace);
  font-size: .82rem; line-height: 1.5; white-space: pre; overflow-wrap: normal;
  overflow-x: auto; tab-size: 2;
}
.code-block {
  font-family: var(--mono, ui-monospace, SFMono-Regular, monospace);
  font-size: .82rem; white-space: pre-wrap; overflow-x: auto;
}

/* A multi-select of days needs to show enough rows to pick a range without
   scrolling inside a four-line box. */
.day-pick { width: 100%; min-height: 14rem; font-size: .85rem; }
.day-pick optgroup { font-style: normal; }

/* --- run chart -----------------------------------------------------------
   The interactive one. Everything here is inert until runchart.js adds
   `.live`, so a page without JavaScript shows the <noscript> SVG and none of
   the controls that would do nothing. */
.runchart .rc-bar,
.runchart .rc-canvas-wrap { display: none; }
.runchart.live .rc-bar,
.runchart.live .rc-canvas-wrap { display: block; }

.runchart.live .rc-bar {
  display: flex; align-items: center; gap: var(--s2);
  margin-bottom: var(--s2); flex-wrap: wrap;
}
.rc-tf { display: flex; gap: 2px; }
.rc-tf-btn { min-width: 2.4rem; }
.rc-tf-btn.on {
  border-color: var(--accent); color: var(--accent);
}
.rc-readout { color: var(--text); white-space: nowrap; }
.rc-sep { color: var(--faint); margin: 0 .45rem; }
.rc-canvas-wrap { width: 100%; }
.runchart canvas {
  display: block; width: 100%; cursor: crosshair;
  touch-action: none;   /* the wheel handler owns zooming */
}
.runchart canvas.dragging { cursor: grabbing; }

/* --- the Origami+ assistant --------------------------------------------- */
/* Two speakers, told apart by indentation and a rule rather than by colour:
   the page already spends colour on gains and losses, and a chat bubble that
   is green means something here. */
.chat-turn { padding: var(--s3) 0; border-top: 1px solid var(--line); }
.chat-turn:first-of-type { border-top: 0; }
.chat-you { padding-left: 0; }
.chat-bot { padding-left: var(--s4); border-left: 2px solid var(--line);
            margin-left: 2px; }
