:root{
  --bg:#0a0c11;
  --bg-deep:#070910;
  --panel:#101319;
  --panel-hi:#151922;
  --panel-head:#131720;
  --line:#212636;
  --line-soft:#191d28;
  --txt:#e4e8f0;
  --dim:#828a9c;
  --dimmer:#5b6274;
  --green:#33d17a;--green-dim:#123023;
  --red:#ff5d5d;--red-dim:#331a1d;
  --amber:#ffb84d;--amber-dim:#33270f;
  --blue:#5b8cff;--blue-dim:#141d33;
  --radius:6px;
  --shadow:0 1px 2px rgba(0,0,0,.45);
  --mono:"SF Mono",Consolas,"Cascadia Mono","Roboto Mono",monospace;
  --sans:-apple-system,"Segoe UI",Inter,system-ui,sans-serif;
  --topbar-h:46px;
  --rail-w:390px;
}
*{box-sizing:border-box;margin:0}
html,body{height:100%}
body{
  background:var(--bg);color:var(--txt);
  font:13px/1.45 var(--sans);
  font-variant-numeric:tabular-nums;
  display:flex;flex-direction:column;overflow:hidden;
}
::-webkit-scrollbar{width:9px;height:9px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:#242a3a;border-radius:5px}
::-webkit-scrollbar-thumb:hover{background:#333b50}

/* top bar */
.topbar{
  height:var(--topbar-h);flex:0 0 auto;
  display:flex;align-items:center;gap:10px;
  padding:0 14px;background:var(--bg-deep);
  border-bottom:1px solid var(--line);
  box-shadow:0 1px 0 rgba(0,0,0,.5);
}
.brand{display:flex;align-items:center;gap:8px;font-size:13px;font-weight:700;letter-spacing:.02em}
.brand .mark{
  width:20px;height:20px;border-radius:5px;display:grid;place-items:center;
  background:linear-gradient(140deg,var(--blue),#2f4fb0);
  color:#fff;font-size:11px;font-weight:800;font-family:var(--mono);
}
.brand .sub{color:var(--dimmer);font-weight:600;font-size:10.5px;
  text-transform:uppercase;letter-spacing:.12em;padding-left:2px}
.spacer{flex:1}
.clock{font-family:var(--mono);font-size:12.5px;color:var(--dim);letter-spacing:.02em}
.clock b{color:var(--txt);font-weight:600}
.navlink{
  color:var(--dim);text-decoration:none;font-size:11.5px;font-weight:600;
  padding:5px 10px;border-radius:var(--radius);border:1px solid transparent;
  text-transform:uppercase;letter-spacing:.06em;
}
.navlink:hover{color:var(--txt);background:var(--panel-hi);border-color:var(--line)}
.vsep{width:1px;height:20px;background:var(--line)}

/* workspace */
.workspace{
  flex:1 1 auto;min-height:0;
  display:grid;grid-template-columns:minmax(0,1fr);
}
.workspace.single{grid-template-columns:minmax(0,1fr)}
.col{min-width:0;overflow-y:auto;padding:12px 14px 20px}
/* strategy ticket, shown as a modal */
.modal{position:fixed;inset:0;z-index:50;background:rgba(0,0,0,.6);
       display:flex;justify-content:center;align-items:flex-start;
       padding:22px 14px;overflow-y:auto}
.modal[hidden]{display:none}
.modal>.rail{width:min(var(--rail-w),100%);background:var(--bg-deep);
             border:1px solid var(--line);border-radius:10px;
             padding:12px 14px 16px;max-height:calc(100vh - 44px);overflow-y:auto;
             box-shadow:0 18px 50px rgba(0,0,0,.6)}

/* headings */
h2,.sechead{
  font-size:10.5px;color:var(--dimmer);font-weight:700;
  text-transform:uppercase;letter-spacing:.11em;
}
.sechead{display:flex;align-items:center;gap:8px;margin:2px 0 8px}
.sechead .rule{flex:1;height:1px;background:var(--line-soft)}
h2{margin:14px 0 7px}

/* panels */
.panel{
  background:var(--panel);border:1px solid var(--line);
  border-radius:var(--radius);margin-bottom:12px;box-shadow:var(--shadow);
}
.panel>.head{
  display:flex;align-items:center;gap:8px;
  padding:8px 12px;border-bottom:1px solid var(--line-soft);
  background:var(--panel-head);border-radius:var(--radius) var(--radius) 0 0;
}
.panel>.head .title{font-size:10.5px;font-weight:700;color:var(--dim);
  text-transform:uppercase;letter-spacing:.11em}
.panel>.body{padding:11px 12px}
.panel>.body.flush{padding:0}
.panel h2:first-child{margin-top:0}
.panel.pad{padding:11px 12px}

/* status pills */
.badge{
  padding:3px 9px;border-radius:4px;font-size:10.5px;font-weight:700;
  background:var(--panel-hi);color:var(--dim);border:1px solid var(--line);
  letter-spacing:.06em;text-transform:uppercase;white-space:nowrap;
}
.ok{background:var(--green-dim);color:var(--green);border-color:#22513a}
.bad{background:var(--red-dim);color:var(--red);border-color:#54282c}
.warn{background:var(--amber-dim);color:var(--amber);border-color:#5a4318}
.tag{
  padding:2px 7px;border-radius:3px;font-size:10.5px;font-weight:700;
  font-family:var(--mono);letter-spacing:.04em;
  background:var(--panel-hi);border:1px solid var(--line);color:var(--dim);
}
.tag.buy{color:var(--green);border-color:#22513a;background:var(--green-dim)}
.tag.sell{color:var(--red);border-color:#54282c;background:var(--red-dim)}
.tag.live{color:var(--amber);border-color:#5a4318;background:var(--amber-dim)}
.tag.paper{color:var(--blue);border-color:#2b3d6b;background:var(--blue-dim)}

/* summary strip */
.tape{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(118px,1fr));
  gap:1px;background:var(--line);border:1px solid var(--line);
  border-radius:var(--radius);overflow:hidden;margin-bottom:12px;
}
.tape .cell{background:var(--panel);padding:8px 11px}
.tape .cell b{
  display:block;font-size:9.5px;color:var(--dimmer);font-weight:700;
  text-transform:uppercase;letter-spacing:.09em;margin-bottom:3px;
}
.tape .cell span{font-family:var(--mono);font-size:15px;font-weight:600;letter-spacing:-.01em}

/* rows and grids */
.row{display:flex;gap:7px;flex-wrap:wrap;align-items:center}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(124px,1fr));gap:1px;
      background:var(--line-soft);border-top:1px solid var(--line-soft);
      border-bottom:1px solid var(--line-soft)}
.kv{padding:6px 11px;background:var(--panel);font-family:var(--mono);font-size:12.5px}
.kv.big{padding:9px 11px;font-size:17px;font-weight:600;letter-spacing:-.01em}
.kv.big>b{font-size:10px;color:var(--dim)}
.kv b{display:block;font-size:9.5px;color:var(--dimmer);font-weight:700;
      font-family:var(--sans);text-transform:uppercase;letter-spacing:.09em;margin-bottom:2px}

/* tables */
table{border-collapse:collapse;width:100%;font-size:12px;font-family:var(--mono)}
th,td{padding:5px 11px;text-align:left;border-bottom:1px solid var(--line-soft);white-space:nowrap}
th{color:var(--dimmer);font-weight:700;font-size:9.5px;text-transform:uppercase;
   letter-spacing:.09em;font-family:var(--sans);background:var(--panel-head);
   position:sticky;top:0;z-index:1}
tr:hover td{background:var(--panel-hi)}
tr:last-child td{border-bottom:none}
td.num,th.num{text-align:right}
/* a heading that sorts its column, and the one currently sorting it */
th.sortable{cursor:pointer;user-select:none}
th.sortable:hover{color:var(--txt)}
th.sorted{color:var(--blue)}
/* a link in a cell is a row that opens something, not prose: it reads as the
   value it stands for until it is hovered */
td a{color:inherit;text-decoration:none;border-bottom:1px dotted var(--line)}
/* the sign-in and password pages' small links: not the browser's default blue */
.foot a{color:var(--blue)}
td a:hover{color:var(--blue);border-bottom-color:var(--blue)}
/* let the last column absorb slack so numeric columns stay grouped */
#detailbody th:last-child,#detailbody td:last-child{width:100%}
.tblwrap{overflow-x:auto}

/* controls */
input,select,button{
  background:#0c0f16;border:1px solid var(--line);color:var(--txt);
  border-radius:var(--radius);padding:6px 9px;font-size:12.5px;
  font-family:inherit;transition:border-color .12s,background .12s,box-shadow .12s;
}
input,select{width:100%}
/* a tick is not a field: full width made every checkbox fill its row and
   pushed the label it belongs to onto the next line */
input[type=checkbox],input[type=radio]{width:auto;margin:0;flex:none}
input[type=number]{font-family:var(--mono)}
input:focus,select:focus{outline:none;border-color:var(--blue);box-shadow:0 0 0 2px var(--blue-dim)}
input::placeholder{color:#4c5365}
button{cursor:pointer;font-weight:600;font-size:11.5px;letter-spacing:.02em;color:var(--dim)}
button:hover{border-color:#38405a;background:var(--panel-hi);color:var(--txt)}
button:active{transform:translateY(1px)}
button.sm{padding:4px 8px;font-size:10.5px}
button.danger{border-color:#4a2529;color:var(--red)}
button.danger:hover{background:var(--red-dim);border-color:#6b3238;color:var(--red)}
button.primary{border-color:#2c4587;color:#cddcff;background:#16213c}
button.primary:hover{background:#1c2c53;border-color:#3d5cad;color:#fff}
button.ghost{background:transparent}
label{font-size:10.5px;color:var(--dim);display:block;margin-bottom:3px;
      font-weight:600;text-transform:uppercase;letter-spacing:.05em}
input.locked{background:var(--panel-hi);color:var(--dim);cursor:not-allowed;border-style:dashed}

fieldset{border:none;padding:0;margin:0 0 14px}
fieldset legend{
  font-size:10.5px;color:var(--dimmer);font-weight:700;padding:0;margin-bottom:7px;
  text-transform:uppercase;letter-spacing:.11em;
}
.form-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));
           gap:9px;align-items:end}
.form-grid.narrow{grid-template-columns:repeat(auto-fill,minmax(180px,240px))}
.form-grid .wide{grid-column:1/-1}

.days{display:flex;flex-wrap:wrap;gap:4px}
.days label{
  font-size:11px;color:var(--dim);display:inline-flex;align-items:center;gap:5px;
  padding:4px 8px;border-radius:4px;cursor:pointer;margin:0;border:1px solid var(--line);
  text-transform:none;letter-spacing:0;font-weight:600;
}
.days label:hover{background:var(--panel-hi);color:var(--txt)}
.days input{width:auto;margin:0}
/* one pickable row: the tick, the name and the detail all on the same line */
.pick{display:flex;align-items:center;gap:8px;padding:4px 0;cursor:pointer;
      font-size:12.5px;min-width:0}
.pick:hover{color:var(--txt)}
.pick b{font-family:var(--mono);white-space:nowrap}
.pick .hint{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* strategy cards */
/* as many cards per row as the window fits, one per row on a narrow one,
   and never wider than a phone screen narrower than one card */
#strategies{display:grid;gap:10px;
            grid-template-columns:repeat(auto-fill,minmax(min(310px,100%),1fr))}
#strategies .empty{grid-column:1/-1}
/* the sechead is a row of controls, so the sort picker sizes to its text
   rather than taking the full width every other select does */
#cardsort,#basketfilter{width:auto;max-width:210px;padding:4px 8px;font-size:10.5px}

/* a basket: one heading, and its own grid of cards under it. The board is a
   grid, so a section has to span every column to hold a grid of its own. */
.basket{grid-column:1/-1;min-width:0}
.basket .bhead{display:flex;align-items:center;gap:8px;cursor:pointer;
               padding:5px 2px;margin:2px 0 8px;user-select:none;
               border-bottom:1px solid var(--line-soft)}
.basket .bhead:hover .bname{color:var(--txt)}
.basket .bhead .rule{flex:1;height:1px;background:var(--line-soft)}
.basket .bhead .caret{color:var(--dimmer);font-size:10px;width:10px}
.basket .bname{font-size:11px;font-weight:700;letter-spacing:.06em;
               text-transform:uppercase;color:var(--dim)}
.basket .bhead .kv{display:flex;align-items:center;gap:5px;font-size:11px;
                   font-family:var(--mono);color:var(--dim);
                   border:0;padding:0;background:none}
.basket .bhead .kv b{font-family:var(--sans);font-size:9.5px;font-weight:700;
                     text-transform:uppercase;letter-spacing:.05em;
                     color:var(--dimmer)}
/* the cards of one basket, laid out exactly like the ungrouped board */
.basket .bcards{display:grid;gap:10px;margin-bottom:16px;
                grid-template-columns:repeat(auto-fill,minmax(min(310px,100%),1fr))}
.basket .bcards .empty{grid-column:1/-1}
.basket.shut .bhead{margin-bottom:2px;border-bottom-color:transparent}
.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
      box-shadow:var(--shadow);min-width:0}
/* four headline cells, always a tidy 2x2 whatever the card is wide */
.card .grid{grid-template-columns:repeat(2,minmax(0,1fr))}
/* right and bottom edges carry the P&L colour, so a card is fenced off from
   the one beside it and the one under it. The left edge stays for live/error. */
.card.up{border-right:3px solid var(--green);border-bottom:3px solid var(--green)}
.card.down{border-right:3px solid var(--red);border-bottom:3px solid var(--red)}
.card.is-live{border-left:2px solid var(--amber)}
.card.is-error{border-left:2px solid var(--red)}
.card>.head{display:flex;align-items:center;gap:7px;padding:8px 11px;
            background:var(--panel-head);border-bottom:1px solid var(--line-soft);
            border-radius:var(--radius) var(--radius) 0 0;flex-wrap:wrap}

/* per-card action menu (the kebab) */
.card .menu{position:relative}
.card .menu>summary{list-style:none;cursor:pointer;user-select:none;
                    padding:0 6px;border-radius:5px;color:var(--dim);
                    font-size:16px;line-height:18px}
.card .menu>summary::-webkit-details-marker{display:none}
.card .menu>summary:hover{color:var(--txt);background:var(--panel-hi)}
.card .menu-items{position:absolute;left:0;top:24px;z-index:20;min-width:152px;
                  display:flex;flex-direction:column;padding:4px;
                  background:var(--panel);border:1px solid var(--line);
                  border-radius:8px;box-shadow:0 12px 30px rgba(0,0,0,.55)}
.card .menu-items button{background:none;border:0;cursor:pointer;text-align:left;
                         padding:6px 9px;border-radius:5px;font-size:12px;
                         font-family:var(--sans);color:var(--txt)}
.card .menu-items button:hover{background:var(--panel-hi)}
.card .menu-items button.danger{color:var(--red)}
.card .menu-items hr{border:0;border-top:1px solid var(--line-soft);margin:4px 2px}
/* the grip: the only part of the card that starts a drag, so selecting text
   and opening the menu still work everywhere else */
.card .drag{cursor:grab;color:var(--dimmer);font-size:11px;line-height:1;
            padding:2px 1px;user-select:none}
.card .drag:hover{color:var(--txt)}
.card .drag:active{cursor:grabbing}
.card .sym{font-family:var(--mono);font-size:14.5px;font-weight:700;letter-spacing:-.01em;
           flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.notice{padding:6px 11px;font-size:11.5px;font-weight:600;
        background:var(--amber-dim);color:var(--amber);border-bottom:1px solid var(--line-soft)}

/* state and pnl */
.pnl-pos{color:var(--green)} .pnl-neg{color:var(--red)}
.state{font-weight:700;font-size:10.5px;display:inline-flex;align-items:center;gap:5px;
       letter-spacing:.06em;text-transform:uppercase;font-family:var(--sans)}
.state::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;flex:0 0 auto}
.state-ACTIVE{color:var(--green)}
.state-ACTIVE::before{animation:pulse 2s infinite}
.state-CLOSED,.state-CREATED{color:var(--dim)}
.state-MIXED{color:var(--amber)}
.state-ERROR,.state-RECONCILIATION_REQUIRED,.state-BROKER_DISCONNECTED{color:var(--red)}
.state-WAITING_FOR_OPENING_PRICE,.state-SCHEDULED,.state-PAUSED,
.state-MAX_DEPTH_REACHED,.state-CLOSING{color:var(--amber)}
@keyframes pulse{
  0%{box-shadow:0 0 0 0 rgba(51,209,122,.5)}
  70%{box-shadow:0 0 0 5px rgba(51,209,122,0)}
  100%{box-shadow:0 0 0 0 rgba(51,209,122,0)}
}
@media (prefers-reduced-motion:reduce){.state-ACTIVE::before{animation:none}}

/* misc */
.muted{color:var(--dim);font-size:11.5px}
.hint{color:var(--dimmer);font-size:11px;line-height:1.4}
.err{color:var(--amber);font-size:11.5px;font-family:var(--mono)}
.empty{padding:26px 14px;text-align:center;color:var(--dimmer);font-size:12px;
       border:1px dashed var(--line);border-radius:var(--radius)}
#msg{font-size:12px;font-weight:600;color:var(--amber)}
#msg:not(:empty){padding:7px 11px;background:var(--amber-dim);border:1px solid #5a4318;
                 border-radius:var(--radius);margin-bottom:11px}
.scroll{max-height:260px;overflow:auto}
.formactions{
  position:sticky;bottom:0;background:var(--bg-deep);
  border-top:1px solid var(--line);padding:10px 0 2px;margin-top:4px;
  display:flex;gap:7px;z-index:5;
}
.formactions button{flex:1}
.switch{font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}
.switch.on{color:var(--green)} .switch.off{color:var(--red)}
.halt{border-color:#54282c;background:linear-gradient(var(--red-dim),var(--panel))}

/* the trader's log: a bar at the foot of the page that rolls up to half the
   screen. A flex child of body, so it pushes the board up rather than
   covering it; sticky keeps it on screen where the page itself scrolls. */
.logdock{flex:0 0 auto;position:sticky;bottom:0;z-index:40;
         background:var(--bg-deep);border-top:1px solid var(--line)}
.logdock>.loghead{padding:4px 14px;display:flex;justify-content:space-between}
.logdock:not(.open) #logexport{display:none}
.logdock #logbtn::after{content:" \25B2"}
.logdock.open #logbtn::after{content:" \25BC"}
.logdock>.logbody{height:0;overflow:auto;transition:height .2s ease}
.logdock.open>.logbody{height:50vh}
/* the message wraps and takes the slack; the other columns stay one line */
.logdock td:last-child{width:100%;white-space:normal;overflow-wrap:anywhere}
@media (prefers-reduced-motion:reduce){.logdock>.logbody{transition:none}}

@media (max-width:1180px){
  body{overflow:auto;height:auto;min-height:100%}
  .workspace{grid-template-columns:minmax(0,1fr)}
  .col{overflow:visible}
}

/* phone. The top bar stays pinned and keeps the status badges on the first
   row and the clock, Problems and KILL ALL on the second; the page links and
   the account controls (.inmenu) fold behind the menu button. The spacer is
   the row break. Modals become full-screen sheets. */
.menubtn{display:none}
@media (max-width:640px){
  html{-webkit-text-size-adjust:100%}
  .topbar{height:auto;flex-wrap:wrap;gap:6px 8px;padding:8px 12px;
          position:sticky;top:0;z-index:30}
  .topbar>*{order:2}
  /* the mark alone: font-size 0 drops the bare "Scalper" text node */
  .topbar>.brand{font-size:0;gap:0}
  .topbar>.badge{padding:2px 6px;font-size:9.5px;letter-spacing:.03em}
  /* KILL ALL at the far edge, a thumb's width from Problems */
  .topbar>.killall{margin-left:auto}
  .topbar>.brand,.topbar>.badge,.topbar>.menubtn{order:0}
  .topbar>.menubtn{display:block;margin-left:auto;font-size:16px;padding:4px 11px}
  .topbar>.spacer{order:1;flex:1 0 100%}
  .topbar>.vsep{display:none}
  /* the page name stays, except where status badges need the row */
  .topbar:has(>.badge) .brand .sub{display:none}
  .topbar>.navlink,.topbar>.inmenu{order:3;display:none}
  body.navopen .topbar>.navlink,body.navopen .topbar>.inmenu{display:block}
  .topbar>.navlink{border-color:var(--line);padding:8px 12px}

  .col{padding:10px 10px 24px}
  .sechead,.panel>.head{flex-wrap:wrap}
  /* iOS zooms the page into any focused field whose text is under 16px */
  input,select,#cardsort,#basketfilter{font-size:16px}
  button{min-height:34px}
  button.sm{min-height:30px;padding:5px 10px}
  .card .menu>summary{padding:4px 10px;font-size:18px}
  /* opens leftward: from mid-card a left-anchored menu runs off the screen */
  .card .menu-items{left:auto;right:0}
  .card .menu-items button{padding:9px 11px;font-size:13px}

  .modal{padding:0}
  .modal>.rail{width:100%;height:100%;max-height:none;border:0;border-radius:0;
               padding:0 12px 16px}
  /* the sheet's title row carries its close button, so it never scrolls away */
  .modal>.rail>.sechead:first-child{position:sticky;top:0;z-index:6;margin:0 0 8px;
               padding:12px 0 8px;background:var(--bg-deep)}
  /* sticky stops at the sheet's 16px bottom padding; reach past it so the
     form does not show through underneath Save */
  .modal .formactions{bottom:-16px;padding-bottom:14px}
  .logdock>.loghead{padding:4px 10px}
  .logdock th,.logdock td{padding:5px 6px}
}
/* a drag grip needs a mouse; the sort picker still orders the board */
@media (hover:none){.card .drag{display:none}}

/* roles. The server is what enforces every permission (scalper/auth.py); these
   two rules only keep a page from offering controls that would answer 403.
   Both fail closed: until /api/me sets data-role, neither group is shown. */
body:not([data-role=admin]) [data-perm=admin]{display:none !important}
body:not([data-role=admin]):not([data-role=trader]) [data-perm=trade]{display:none !important}
/* a trader's own account only: an admin sets it per account in Accounts */
body:not([data-role=trader]) [data-perm=trader]{display:none !important}

/* the special-session exchange picker: a native disclosure used as a
   multi-pick dropdown, so no click-outside handler and no library */
.exsel{position:relative}
.exsel>summary{
  cursor:pointer;list-style:none;padding:4px 8px;min-width:120px;
  border:1px solid var(--line);border-radius:var(--radius);
  background:var(--panel-hi);color:var(--txt);
}
.exsel>summary::-webkit-details-marker{display:none}
.exsel-menu{
  position:absolute;z-index:20;margin-top:2px;padding:6px;min-width:120px;
  display:flex;flex-direction:column;gap:4px;
  border:1px solid var(--line);border-radius:var(--radius);
  background:var(--panel);box-shadow:var(--shadow);
}
.exsel-menu label{display:flex;gap:6px;align-items:center;cursor:pointer}
