/* QuadLines dashboard — palette per the reference dataviz instance.
   Roles as CSS custom properties; dark values under both the OS media query
   and the explicit data-theme scope. */

:root {
  color-scheme: light;
  --page:        #f9f9f7;
  --surface:     #fcfcfb;
  --ink:         #0b0b0b;
  --ink-2:       #52514e;
  --muted:       #898781;
  --grid:        #e1e0d9;
  --baseline:    #c3c2b7;
  --border:      rgba(11,11,11,0.10);
  --series-1:    #2a78d6;   /* categorical slot 1 (blue) */
  --pos:         #2a78d6;   /* diverging pole: profit */
  --neg:         #e34948;   /* diverging pole: loss (light) */
  --good:        #0ca30c;
  --warning:     #fab219;
  --serious:     #ec835a;
  --critical:    #d03b3b;
  --delta-good:  #006300;   /* success text on light */
}
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) {
    color-scheme: dark;
    --page:      #0d0d0d;
    --surface:   #1a1a19;
    --ink:       #ffffff;
    --ink-2:     #c3c2b7;
    --muted:     #898781;
    --grid:      #2c2c2a;
    --baseline:  #383835;
    --border:    rgba(255,255,255,0.10);
    --series-1:  #3987e5;
    --pos:       #3987e5;
    --neg:       #e66767;
    --delta-good:#0ca30c;
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --page:      #0d0d0d;
  --surface:   #1a1a19;
  --ink:       #ffffff;
  --ink-2:     #c3c2b7;
  --muted:     #898781;
  --grid:      #2c2c2a;
  --baseline:  #383835;
  --border:    rgba(255,255,255,0.10);
  --series-1:  #3987e5;
  --pos:       #3987e5;
  --neg:       #e66767;
  --delta-good:#0ca30c;
}

* { box-sizing: border-box; }
body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font: 14px/1.45 system-ui, -apple-system, "Segoe UI", sans-serif;
}
h1 { font-size: 18px; margin: 0 0 8px; }
/* Run-log filenames are single unbreakable tokens (…_tf_15_0_200_0_life_0…),
   with no break opportunity for the line breaker — without this they overflow
   the heading and widen the whole page on a phone. */
h2 { font-size: 13px; font-weight: 600; color: var(--ink-2); margin: 0 0 8px;
     text-transform: uppercase; letter-spacing: .04em; overflow-wrap: anywhere; }
.muted { color: var(--muted); font-weight: 400; text-transform: none; letter-spacing: 0; }
.hidden { display: none !important; }

/* -- top bar + tabs -- */
.topbar {
  display: flex; align-items: center; gap: 12px 16px; flex-wrap: wrap;
  padding: 10px 16px; background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 20;
}
.brand { font-weight: 700; font-size: 15px; }
.tick { font-variant-numeric: tabular-nums; color: var(--ink-2); }
.acct { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.badges { display: flex; gap: 6px; flex-wrap: wrap; margin-left: auto; }
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12px; padding: 2px 9px; border-radius: 999px;
  border: 1px solid var(--border); color: var(--ink-2); background: var(--page);
}
.badge .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--muted); }
.badge.ok .dot { background: var(--good); }
.badge.bad .dot { background: var(--critical); }
.badge.warn .dot { background: var(--warning); }

/* Access level of the signed-in key (admin key vs viewer key). */
.role-chip { font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
             padding: 2px 8px; border-radius: 999px; border: 1px solid var(--border);
             color: var(--muted); }
.role-chip.admin { color: var(--series-1); border-color: var(--series-1); }
.role-chip.user { color: var(--warning); border-color: var(--warning); }
.role-chip.denied { color: var(--critical); border-color: var(--critical); }

.tabs { display: flex; gap: 2px; padding: 6px 12px 0; background: var(--surface);
        border-bottom: 1px solid var(--border); position: sticky; top: 45px; z-index: 19;
        overflow-x: auto; scrollbar-width: none; }
.tabs::-webkit-scrollbar { display: none; }
.tabs button {
  border: none; background: none; color: var(--ink-2); padding: 8px 14px;
  font: inherit; cursor: pointer; border-bottom: 2px solid transparent;
  flex: 0 0 auto; white-space: nowrap;
}
.tabs button.active { color: var(--ink); border-bottom-color: var(--series-1); font-weight: 600; }
.tabs button:hover { color: var(--ink); }

/* Unread sign-in count on the Notifications tab. */
.tab-badge {
  display: inline-block; min-width: 16px; margin-left: 6px; padding: 0 5px;
  border-radius: 999px; background: var(--critical); color: #fff;
  font-size: 10px; font-weight: 700; line-height: 16px; text-align: center;
  vertical-align: 1px; font-variant-numeric: tabular-nums;
}

/* -- notifications tab -- */
.ntf-unread { background: color-mix(in srgb, var(--warning) 9%, transparent); }
.ntf-dot {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--warning); margin-right: 7px; vertical-align: 1px;
}
/* Long user-agent strings must not stretch the table on a phone. */
.ellip { display: inline-block; max-width: 22ch; overflow: hidden;
         text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
.warn-note { border-left: 3px solid var(--warning); padding-left: 10px; }
.sub-h2 { margin-top: 22px; }
button.small { padding: 3px 9px; font-size: 12px; }

main { padding: 16px; max-width: 1400px; margin: 0 auto; }

/* -- panels, tiles -- */
.panel {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 8px; padding: 14px; margin-bottom: 16px;
}
.panel-head { display: flex; align-items: center; justify-content: space-between;
              gap: 12px; flex-wrap: wrap; margin-bottom: 8px; }
/* Flex items default to min-width:auto — without this the toolbar half of a
   panel head is sized by its widest child (the log picker) and cannot shrink,
   so nothing inside it can be capped either. */
.panel-head > * { min-width: 0; }
.panel-head h2 { margin: 0; }
.cols { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
/* Grid items default to min-width:auto, i.e. their content's intrinsic width.
   A wide table (open positions / pending orders) therefore pushed its panel
   past the 1fr track and widened the whole page instead of scrolling inside
   its .scroll-x wrapper — which shifted the layout and clipped the panel
   headings off the left edge on narrow screens. */
.cols > * { min-width: 0; }
.cols > .panel { margin-bottom: 0; }
.cols { margin-bottom: 16px; }
.config-cols { grid-template-columns: 290px 1fr; }
.slim { min-width: 0; }
.grow { min-width: 0; }
@media (max-width: 900px) { .cols, .config-cols { grid-template-columns: 1fr; } }

/* One row, whatever the tile count: auto-flow column with 1fr auto-columns
   divides the width evenly instead of wrapping the last tiles onto a second
   row. minmax(0,1fr) (not plain 1fr) lets a column shrink below its content's
   intrinsic width, which is what stops a long sub-line from forcing overflow.
   Phones fall back to a wrapping grid — nine tiles on one row is unreadable
   there (see the max-width: 640px block). */
.tiles { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
         gap: 10px; margin-bottom: 16px; }
.tiles.small { margin: 10px 0; }
.tile {
  background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
  padding: 10px 12px; min-width: 0;
}
.tile .label { font-size: 11px; color: var(--muted); text-transform: uppercase;
               letter-spacing: .05em; }
.tile .value { font-size: 20px; font-weight: 650; margin-top: 2px; }
.tile .sub { font-size: 11px; color: var(--ink-2); }
.tile .value.up { color: var(--delta-good); }
.tile .value.down { color: var(--critical); }
/* Below a wide desktop, a single row squeezes each tile past readability —
   go back to wrapping. */
@media (max-width: 1100px) {
  .tiles { grid-auto-flow: row; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
}

/* -- charts -- */
.chart { width: 100%; height: 340px; }
.chart.short { height: 260px; }
.range-row button, .filter-row button, .filter-row select, .filter-row input,
.form select, .form input, button {
  font: inherit; color: var(--ink); background: var(--page);
  border: 1px solid var(--border); border-radius: 6px; padding: 5px 10px;
}
/* A <select> sizes itself to its widest option, so the log picker's long
   filenames widened the page. Cap it and let the UA ellipsise the label;
   min-width:0 lets it shrink inside the flex toolbars. */
select { max-width: 100%; min-width: 0; }
.range-row { display: flex; gap: 4px; flex-wrap: wrap; min-width: 0; }
.range-row button { cursor: pointer; padding: 3px 10px; font-size: 12px; }
.range-row button.active { background: var(--series-1); color: #fff; border-color: var(--series-1); }
button { cursor: pointer; }
button:hover { border-color: var(--muted); }
button.primary { background: var(--series-1); border-color: var(--series-1); color: #fff; }
button.danger { background: var(--critical); border-color: var(--critical); color: #fff; }
button.ghost { background: none; }
.filter-row { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.filter-row input { min-width: 0; flex: 1 1 120px; max-width: 240px; }
/* Same shrink treatment as the input above, which selects never got: a select
   sizes to its widest option, and the Stats log picker's options are full run
   filenames. Capping it with max-width alone is circular — the percentage
   resolves against a parent the select itself inflated — so the flex item has
   to be allowed to shrink below its intrinsic width. */
.filter-row select { min-width: 0; flex: 0 1 auto; max-width: 100%; }
.chk { display: inline-flex; gap: 4px; align-items: center; color: var(--ink-2); font-size: 12px; }

/* -- tables -- */
.scroll-x { overflow-x: auto; }
table { border-collapse: collapse; width: 100%; font-variant-numeric: tabular-nums; }
th, td { text-align: left; padding: 5px 10px; border-bottom: 1px solid var(--grid);
         white-space: nowrap; font-size: 13px; }
th { color: var(--muted); font-weight: 600; font-size: 11px; text-transform: uppercase;
     letter-spacing: .04em; }
td.num, th.num { text-align: right; }
td.up { color: var(--delta-good); }
td.down { color: var(--critical); }
tr.clickable { cursor: pointer; }
tr.clickable:hover td { background: var(--page); }

.pager { display: flex; gap: 10px; align-items: center; justify-content: flex-end;
         margin-top: 8px; font-size: 12px; }
.pager button { font-size: 12px; padding: 3px 10px; }
.pager button:disabled { opacity: .4; cursor: default; }
.pager select { font-size: 12px; padding: 3px 6px; }

/* -- logs -- */
.log-box {
  background: var(--page); border: 1px solid var(--border); border-radius: 6px;
  font: 12px/1.5 ui-monospace, Consolas, monospace;
  padding: 8px 10px; height: 420px; overflow: auto; white-space: pre;
}
.log-box.small { height: 180px; white-space: pre-wrap; }
.log-line.err { color: var(--critical); }

/* -- services -- */
.note { color: var(--ink-2); background: var(--surface); border: 1px solid var(--border);
        border-left: 3px solid var(--warning); border-radius: 6px; padding: 8px 12px; }
.note.live-note { border-left-color: var(--series-1); margin-top: 8px; }
.svc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; }
.svc-card { background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
            padding: 12px; }
.svc-card .head { display: flex; justify-content: space-between; align-items: center; }
.svc-card .name { font-weight: 600; }
.svc-card .meta { color: var(--muted); font-size: 12px; margin: 6px 0 10px;
                  font-variant-numeric: tabular-nums; }
.svc-card .actions { display: flex; gap: 6px; }
.svc-card .actions button { font-size: 12px; padding: 4px 10px; }

/* -- config -- */
.file-list { display: flex; flex-direction: column; gap: 4px; margin-bottom: 14px; }
.file-list button {
  text-align: left; background: none; border: 1px solid transparent; padding: 6px 8px;
  border-radius: 6px; color: var(--ink);
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  min-width: 0; overflow-wrap: anywhere;
}
.file-list button:hover { background: var(--page); }
.file-list button.active { border-color: var(--series-1); background: var(--page); }
.file-list .tag { font-size: 10px; color: var(--muted); text-transform: uppercase;
                  letter-spacing: .03em; }
.file-list.small button { font-size: 12px; padding: 4px 8px; flex-direction: row;
                          justify-content: space-between; width: 100%; }
#cfg-editor {
  width: 100%; height: 520px; resize: vertical;
  font: 12.5px/1.5 ui-monospace, Consolas, monospace;
  background: var(--page); color: var(--ink);
  border: 1px solid var(--border); border-radius: 6px; padding: 10px;
}
.msg { border-radius: 6px; padding: 6px 10px; margin: 6px 0; font-size: 13px;
       border: 1px solid var(--border); }
.msg.error { border-left: 3px solid var(--critical); }
.msg.warning { border-left: 3px solid var(--warning); }
.msg.ok { border-left: 3px solid var(--good); }

/* -- forms, meters -- */
.form { display: flex; flex-direction: column; gap: 10px; }
.form label { display: flex; flex-direction: column; gap: 4px; color: var(--ink-2); font-size: 12px; }
/* Backtest form: the panel is full width, so lay the fields out on one
   wrapping row with the submit button at the end. */
#bt-form { flex-direction: row; flex-wrap: wrap; align-items: flex-end; gap: 12px; }
#bt-form label { flex: 1 1 170px; min-width: 0; }
#bt-form button[type="submit"] { flex: 0 0 auto; }
#bt-form .note, #bt-form .error-text { flex-basis: 100%; margin: 0; }
#bt-form .note:empty, #bt-form .error-text:empty { display: none; }
/* Artifact links carry the full run-log filename — wrap them as a list of
   pills instead of one overflowing line. */
#bt-artifacts { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0; }
#bt-artifacts a { display: inline-block; max-width: 100%; overflow-wrap: anywhere;
                  padding: 3px 10px; border: 1px solid var(--border);
                  border-radius: 6px; font-size: 12px; text-decoration: none; }
#bt-artifacts a:hover { border-color: var(--series-1); }
.error-text { color: var(--critical); font-size: 13px; min-height: 1em; }
.meter { margin: 8px 0; }
.meter .label { display: flex; justify-content: space-between; font-size: 12px;
                color: var(--ink-2); margin-bottom: 3px; font-variant-numeric: tabular-nums; }
.meter .bar { height: 8px; border-radius: 4px; background: var(--grid); overflow: hidden; }
.meter .fill { height: 100%; border-radius: 4px; background: var(--series-1); }
.meter .fill.warn { background: var(--warning); }
.meter .fill.crit { background: var(--critical); }

/* -- login / modal / toast -- */
.login { position: fixed; inset: 0; background: var(--page); z-index: 100;
         display: flex; align-items: center; justify-content: center; }
.login-card { background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
              padding: 24px; width: min(320px, 92vw);
              display: flex; flex-direction: column; gap: 10px; }
.login-card input { font: inherit; padding: 8px 10px; border: 1px solid var(--border);
                    border-radius: 6px; background: var(--page); color: var(--ink);
                    width: 100%; box-sizing: border-box; }
#login-pw, #login-key-wrap { display: flex; flex-direction: column; gap: 10px; }
.modal { position: fixed; inset: 0; background: rgba(0,0,0,.45); z-index: 90;
         display: flex; align-items: center; justify-content: center; }
.modal-card { background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
              padding: 20px; max-width: min(420px, 92vw); margin: 0 12px; }
.modal-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 14px; }
.toast { position: fixed; bottom: 18px; left: 50%; transform: translateX(-50%);
         background: var(--surface); color: var(--ink); border: 1px solid var(--border);
         border-radius: 8px; padding: 10px 16px; z-index: 95; box-shadow: 0 4px 16px rgba(0,0,0,.2); }
#bt-artifacts a { color: var(--series-1); margin-right: 14px; }

/* -- live chart tab -- */
.lw-stats { display: flex; gap: 16px; align-items: baseline; flex-wrap: wrap;
            font-variant-numeric: tabular-nums; }
.lw-stats b { font-weight: 600; }
.up-text { color: var(--delta-good); }
.down-text { color: var(--critical); }
#lw-wrap { position: relative; }
#lw-chart { height: 68vh; min-height: 380px; }
#lw-legend { position: absolute; top: 8px; left: 10px; z-index: 5;
             background: color-mix(in srgb, var(--surface) 80%, transparent);
             padding: 5px 10px; border-radius: 5px; font-size: 12px; }
#lw-legend .lg { display: inline-block; margin-right: 12px; color: var(--ink-2); }
#lw-legend .lg i { display: inline-block; width: 18px; height: 3px;
                   vertical-align: middle; margin-right: 5px; }
/* Break-valid is a marker, not a line — show its square, not a line swatch. */
#lw-legend .lg i.sq { width: 8px; height: 8px; background: var(--ink);
                      margin-left: 5px; margin-right: 10px; }
/* Status strip under the chart — sits below the time axis rather than over it,
   so hovering never hides the axis labels. */
#lw-ohlc { display: flex; gap: 14px; flex-wrap: wrap; align-items: baseline;
           padding: 5px 10px; margin-top: 4px; font-size: 12.5px;
           border-top: 1px solid var(--border); color: var(--ink-2);
           font-variant-numeric: tabular-nums; min-height: 22px; }
#lw-ohlc .t { color: var(--ink); font-weight: 600; }
#lw-ohlc .k { color: var(--muted); margin-right: 3px; }
#lw-ohlc .x { color: var(--muted); }

#lw-tip { position: absolute; display: none; z-index: 10; pointer-events: none;
          background: var(--surface); border: 1px solid var(--baseline);
          border-radius: 6px; padding: 8px 10px; max-width: min(420px, 86vw);
          box-shadow: 0 4px 14px rgba(0,0,0,.4); font-size: 12.5px; }
#lw-tip .ev { margin: 3px 0; }
#lw-tip .hd { font-weight: 600; }
#lw-tip .entry .hd { color: #ef9a9a; } #lw-tip .entry.buy .hd { color: #80cbc4; }
#lw-tip .tp .hd { color: #26a69a; } #lw-tip .sl .hd { color: #ef5350; }
#lw-tip .exit .hd { color: #ff9800; }
#lw-tip .brk .hd { color: var(--ink); }
#lw-tip .ctx { color: var(--muted); font-size: 11.5px; }

#stats-frame { width: 100%; height: 78vh; border: none; border-radius: 6px;
               background: #fff; }

/* -- mobile -- */
@media (max-width: 640px) {
  /* A wrapping topbar has a variable height, which breaks the tabs' sticky
     offset — keep only the tabs sticky on phones. */
  .topbar { position: static; padding: 8px 10px; gap: 8px 12px; }
  .tabs { top: 0; padding: 4px 6px 0; }
  .tabs button { padding: 8px 10px; }
  .brand { font-size: 14px; }
  .tick { font-size: 12px; }
  .badge { font-size: 11px; padding: 2px 7px; }
  #btn-logout { padding: 3px 8px; font-size: 12px; }

  main { padding: 10px; }
  .panel { padding: 10px; margin-bottom: 10px; }
  .cols, .config-cols { gap: 10px; margin-bottom: 10px; }
  .tiles { grid-auto-flow: row;
           grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 8px; }
  .tile { padding: 8px 10px; }
  .tile .value { font-size: 17px; }

  .chart { height: 260px; }
  .chart.short { height: 220px; }
  #lw-chart { height: 60vh; min-height: 300px; }
  #lw-legend { font-size: 10.5px; padding: 4px 7px; right: 10px; }
  #lw-ohlc { gap: 8px; font-size: 11px; padding: 4px 6px; }
  .lw-stats { gap: 10px; font-size: 12px; }

  .log-box { height: 320px; font-size: 11px; }
  #cfg-editor { height: 55vh; }
  th, td { padding: 5px 7px; font-size: 12px; }
}
/* A rejection that carried no credential at all — a signed-out tab, not an
   attempt on a key. Muted so real key attempts stand out beside it. */
.role-chip.muted-chip { color: var(--muted); border-color: var(--border); }
