* { box-sizing: border-box; }

/* Scrollbars, drawn by us on every platform.
   `color-scheme: dark` (tokens.css) already stops them being white, but the
   width and the chrome around them still differ per OS, so the bar itself is
   spelled out: a thin thumb on no track at all. The standard properties cover
   Firefox and current Chromium; the ::-webkit- rules cover everything older,
   and both say the same thing. */
* { scrollbar-width: thin; scrollbar-color: var(--scroll-thumb) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track, ::-webkit-scrollbar-corner { background: transparent; }
::-webkit-scrollbar-thumb {
  /* The transparent border is the padding: it keeps the visible thumb narrow
     while the grab area stays the full ten pixels. */
  background: var(--scroll-thumb); background-clip: padding-box;
  border: 2px solid transparent; border-radius: 6px;
}
::-webkit-scrollbar-thumb:hover { background: var(--scroll-thumb-hover); background-clip: padding-box; }

html { background: var(--ground); }
body {
  margin: 0; background: var(--ground); color: var(--ink);
  font-family: var(--mono); font-size: 12px; font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased; padding: 0 18px 28px;
}
a { color: var(--info); text-decoration: none; }
:focus-visible { outline: 2px solid var(--info); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }
[hidden] { display: none !important; }

.lbl { font-size: 10px; letter-spacing: 1.2px; color: var(--ink-3); text-transform: uppercase; }
.num { text-align: right; }
.pos { color: var(--pos); } .neg { color: var(--neg); } .warn { color: var(--warn); } .info { color: var(--info); }
.muted { color: var(--ink-2); } .faint { color: var(--ink-3); }
.ell { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.panel {
  position: relative;
  background: var(--panel); border: 1px solid var(--rule); border-radius: 4px;
  box-shadow: 0 1px 0 rgba(255,255,255,.02); min-width: 0;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.panel:hover { border-color: var(--rule-strong); }
.btn {
  padding: 6px 12px; border: 1px solid var(--rule-strong); border-radius: 2px; background: none;
  color: var(--ink-2); font: inherit; letter-spacing: .8px; cursor: pointer; white-space: nowrap;
}
.btn:hover { color: var(--ink); border-color: var(--ink-3); }
.btn-sm { padding: 3px 9px; font-size: 11px; }
.btn-pos { border-color: var(--pos); color: var(--pos); }
.btn-pos:hover { background: var(--pos-dim); border-color: var(--pos); color: var(--ink); }
.chip {
  padding: 4px 10px; border: 1px solid var(--rule); border-radius: 2px; color: var(--ink-3);
  letter-spacing: .6px; background: none; font: inherit; cursor: pointer;
}
.chip:hover { border-color: var(--rule-strong); color: var(--ink); }
.chip[aria-pressed="true"] { border-color: var(--rule-strong); color: var(--ink); background: var(--raised); }
.dot { width: 6px; height: 6px; border-radius: 50%; display: inline-block; }
input, select {
  background: var(--ground); border: 1px solid var(--rule); border-radius: 2px; color: var(--ink);
  font: inherit; padding: 3px 7px;
}
input:focus, select:focus { outline: none; border-color: var(--rule-strong); }

/* ───── sticky header + tabs ───── */
.sticky-top { position: sticky; top: 0; z-index: 40; background: var(--ground); padding-top: 8px; }
.strip { display: flex; align-items: stretch; border: 1px solid var(--rule); background: var(--panel); border-radius: 3px; }
.strip-brand { display: flex; align-items: center; gap: 8px; padding: 6px 14px; border-right: 1px solid var(--rule); }
.brand-name { font-weight: 700; letter-spacing: 1.6px; }
.strip-ops { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 14px; padding: 6px 14px; flex: 1; min-width: 0; }
.strip-ops .state { display: flex; align-items: center; gap: 6px; }
.tabs { display: flex; align-items: center; border-bottom: 1px solid var(--rule); margin-top: var(--gap); overflow-x: auto; }
main { padding-top: var(--gap); }
.empty { padding: 16px; color: var(--ink-3); }

/* ───── toasts ───── */
.toasts { position: fixed; right: 16px; bottom: 16px; z-index: 90; display: flex; flex-direction: column; gap: 8px; align-items: flex-end; }
.toast { background: var(--panel); border: 1px solid var(--rule-strong); border-left: 2px solid var(--info); border-radius: 2px; padding: 9px 14px; font-size: 11px; max-width: 380px; }
.toast.t-pos { border-left-color: var(--pos); } .toast.t-neg { border-left-color: var(--neg); } .toast.t-warn { border-left-color: var(--warn); }

/* ───── alert banner ───── */
.alert-banner {
  position: fixed; top: 14px; left: 50%; transform: translateX(-50%); z-index: 100;
  display: flex; align-items: center; gap: 14px; background: var(--panel);
  border: 1px solid var(--rule-strong); border-left: 3px solid var(--pos);
  border-radius: 3px; padding: 8px 14px; font-size: 11px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, .6); max-width: calc(100vw - 32px);
  animation: banner-drop .15s ease-out;
}
@keyframes banner-drop {
  from { opacity: 0; transform: translate(-50%, -8px); }
  to { opacity: 1; transform: translate(-50%, 0); }
}
.al-banner-head { display: flex; align-items: center; gap: 6px; }
.al-banner-icon { font-size: 13px; line-height: 1; }
.al-banner-content { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.al-banner-desc { color: var(--ink); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 480px; }
.al-banner-hint { font-size: 10px; }
.al-banner-actions { display: flex; align-items: center; gap: 8px; margin-left: auto; flex-shrink: 0; }

/* ───── the desk ───── */
/* The desk is exactly as tall as the window leaves room for. `min-height`
   alone was a floor, not a ceiling: a block with more rows than fit stretched
   its panel — and with it the whole desk — down the page, instead of scrolling
   inside its own body. A block may fill the desk; it may not grow past it. */
.workspace { display: flex; align-items: stretch; width: 100%; height: var(--deck-viewport-h); overflow: auto; }
/* One per desk. The inactive ones stay in the DOM, mounted and live, so that
   switching back is a rebuild of boxes rather than of every data source. */
.ws-desk { display: flex; align-items: stretch; flex: 1 1 0; min-width: 0; }
.ws-split { display: flex; min-width: 0; }
.ws-row { flex-direction: row; align-items: stretch; }
.ws-col { flex-direction: column; align-items: stretch; min-width: 0; }
.ws-row > [data-panel], .ws-row > .ws-split { min-width: 0; }
[data-panel] {
  position: relative; display: flex; flex-direction: column; min-height: 120px;
  overflow: hidden;
}
[data-panel].context-hover { outline: 1px solid var(--info-dim); outline-offset: -1px; }
.panel-head {
  position: relative; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-height: 34px;
  padding: 6px 42px 6px 10px; border-bottom: 1px solid var(--rule); background: var(--raised);
}
.block-sym-host { display: inline-flex; align-items: center; }
.block-sym { border: 0; background: none; color: var(--ink); font: inherit; font-size: 10px; letter-spacing: .8px; padding: 2px 4px; border-radius: 2px; cursor: text; }
.block-sym:hover:not(:disabled) { background: var(--raised); }
.block-sym:disabled { color: var(--ink-2); cursor: default; }
.block-sym-input { background: var(--raised); border: 1px solid var(--info); border-radius: 2px; color: var(--ink); font: inherit; font-size: 10px; letter-spacing: .8px; padding: 1px 4px; }
/* The channel link sits where the focus box used to: same size as the ⌘K
   button beside it, so the strip keeps one rhythm. */
.tg-link { text-decoration: none; letter-spacing: .3px; white-space: nowrap; }
.tg-link:hover { border-color: var(--info); color: var(--info); }

.block-title.has-about { cursor: help; text-decoration: underline dotted color-mix(in srgb, var(--ink-3) 60%, transparent); text-underline-offset: 3px; }
/* What the block is, drawn by us: the native tooltip waits a second, vanishes
   on its own and loses the line break. */
.block-about {
  position: fixed; z-index: 90; max-width: min(380px, calc(100vw - 16px));
  padding: 7px 9px; border: 1px solid var(--rule-strong); border-radius: 3px;
  background: var(--panel); box-shadow: 0 12px 32px rgba(0,0,0,.55);
  color: var(--ink-2); font-size: 10.5px; line-height: 1.45; pointer-events: none;
}
.block-about div + div { margin-top: 4px; }
.block-about-name { color: var(--ink); font-size: 10px; letter-spacing: 1px; text-transform: uppercase; }
.panel-head .grip { cursor: grab; color: var(--rule-strong); letter-spacing: -1px; padding: 0 2px; user-select: none; order: -1; }
.panel-head .grip:hover { color: var(--ink-2); }
.panel-head .grip:active { cursor: grabbing; }
.block-params { display: flex; gap: 6px; align-items: center; }
.block-params input, .block-params select { padding: 2px 6px; font-size: 11px; }
.block-params .follow { padding: 1px 6px; font-size: 11px; }
.block-context-links { display: inline-flex; align-items: center; gap: 3px; }
.context-link-trigger.is-local { min-width: 0; color: var(--ink-3); }
.context-link-trigger.is-local:hover { color: var(--info); }
.context-link-trigger {
  min-width: 43px; padding: 2px 5px; border: 1px solid var(--rule); border-radius: 2px;
  background: none; color: var(--info); font: inherit; font-size: 9px; letter-spacing: .4px;
  cursor: pointer; white-space: nowrap;
}
.context-link-trigger:hover, .context-link-trigger[aria-expanded="true"], .context-link-trigger.context-hover { border-color: var(--info); color: var(--ink); background: var(--raised); }
.context-link-swap { min-width: 28px; padding: 2px 4px; border: 1px solid var(--rule); border-radius: 2px; background: none; color: var(--warn); font: inherit; font-size: 12px; cursor: pointer; }
.context-link-swap:hover, .context-link-swap:focus-visible { border-color: var(--warn); color: var(--ink); background: var(--raised); outline: none; }
.context-menu {
  position: fixed; z-index: 78; width: min(280px, calc(100vw - 16px)); max-height: min(520px, calc(100vh - 24px));
  overflow-y: auto; padding: 7px; border: 1px solid var(--rule-strong); border-radius: 3px;
  background: var(--panel); box-shadow: 0 16px 48px rgba(0,0,0,.58); color: var(--ink-2); font-size: 11px;
}
.context-menu-title { padding: 3px 5px 7px; color: var(--ink); font-size: 10px; letter-spacing: 1px; text-transform: uppercase; }
.context-menu-channels { display: flex; flex-direction: column; gap: 2px; }
.context-menu-option {
  display: flex; width: 100%; padding: 6px 7px; border: 1px solid transparent; border-radius: 2px;
  background: none; color: var(--ink-2); font: inherit; text-align: left; cursor: pointer;
}
.context-menu-option:hover, .context-menu-option:focus-visible, .context-menu-option.active { border-color: var(--info-dim); background: var(--raised); color: var(--ink); outline: none; }
.context-menu-new { margin-top: 3px; border-top: 1px solid var(--rule); border-radius: 0; color: var(--pos); }
.context-menu-manual { display: flex; gap: 5px; margin: 7px 0; padding-top: 7px; border-top: 1px solid var(--rule); }
.context-menu-channel-input, .context-menu-scope, .context-menu-token, .context-menu-mode { width: 100%; min-width: 0; padding: 4px 5px; font: inherit; font-size: 10px; }
.context-menu-channel-input { flex: 1; }
.context-menu-manual .chip { white-space: nowrap; }
.context-menu-hint { padding: 8px 5px 3px; color: var(--ink-3); font-size: 10px; }
.context-menu-scope, .context-menu-token { display: block; margin: 6px 0; }
.context-menu-scope-label { margin: 7px 0; padding: 5px 6px; border: 1px solid var(--rule); color: var(--ink-2); font-size: 10px; }
.context-menu-advanced { margin: 7px 0; border-top: 1px solid var(--rule); padding-top: 5px; }
.context-menu-advanced summary { color: var(--ink-3); cursor: pointer; font-size: 10px; }
.context-menu-mode { margin-top: 6px; }
.context-menu-apply { width: 100%; color: var(--info); }
.block-status { margin-left: auto; font-size: 10px; }
.block-close { order: 99; position: absolute; top: 5px; right: 8px; z-index: 1; padding: 2px 8px; }
.panel-body { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 8px 10px; }
.notes-text { width: 100%; height: 100%; min-height: 90px; resize: none; border: 0; background: transparent; color: var(--ink); font: inherit; line-height: 1.5; }
.notes-text:focus { outline: none; }
[data-panel].dragging { opacity: .4; }
/* Where the dragged block will land. A fixed overlay above every panel: an
   inset border on the target is hidden by the panel head and by the root-drop
   strips, which is precisely where a drop hint has to be readable. */
.ws-drop-preview {
  position: fixed; z-index: 72; pointer-events: none;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--pos); border-radius: 3px;
  background: color-mix(in srgb, var(--pos) 13%, transparent);
  font-size: 10px; letter-spacing: 1.4px; text-transform: uppercase; color: var(--pos);
  transition: left .07s ease, top .07s ease, width .07s ease, height .07s ease;
}
.ws-drop-preview.drop-above { border-top-width: 3px; }
.ws-drop-preview.drop-below { border-bottom-width: 3px; }
.ws-drop-preview.drop-left { border-left-width: 3px; }
.ws-drop-preview.drop-right { border-right-width: 3px; }
.ws-drop-preview.drop-root { border-width: 2px; border-style: dashed; }
.ws-gap { flex: 0 0 var(--gap); align-self: stretch; position: relative; touch-action: none; z-index: 2; }
.ws-gap-row { min-width: var(--gap); cursor: col-resize; }
.ws-gap-col { min-height: var(--gap); cursor: row-resize; }
.ws-gap::before { content: ''; position: absolute; background: var(--rule); }
.ws-gap-row::before { top: 0; bottom: 0; left: 50%; width: 1px; transform: translateX(-50%); }
.ws-gap-col::before { left: 0; right: 0; top: 50%; height: 1px; transform: translateY(-50%); }
.ws-gap:hover::before { background: var(--pos); width: 3px; }
.ws-gap-col:hover::before { width: auto; height: 3px; }
body.resizing { user-select: none; cursor: col-resize; }
body.resizing-row { user-select: none; cursor: row-resize; }
.ws-edges { position: fixed; inset: 0; z-index: 70; pointer-events: none; }
/* Root-drop strips live in the page margins, not over the desk: at 54px tall
   and inset 12px the bottom one sat on top of the bottom row's own drop zone,
   so a block could never be attached below the panel it covered. */
.ws-edge {
  position: absolute; left: 0; right: 0; height: 26px; pointer-events: auto;
  display: flex; align-items: center; justify-content: center;
  border: 1px dashed var(--rule-strong); border-radius: 3px; background: rgba(13,15,19,.96);
  font-size: 10px; letter-spacing: 1.2px; text-transform: uppercase; color: var(--ink-3);
}
.ws-edge[data-edge="top"] { top: 0; } .ws-edge[data-edge="bottom"] { bottom: 1px; }
.ws-edge.edge-armed { border-color: var(--pos); border-style: solid; color: var(--pos); background: color-mix(in srgb, var(--pos) 16%, rgba(13,15,19,.96)); }
.desk-tabs { display: flex; align-items: stretch; gap: 4px; padding: 0 6px 0 14px; }
.desk-menu-sym { width: 100%; margin: 2px 0 6px; font-size: 11px; }
.desk-menu-about { padding: 0 8px 6px; font-size: 10px; line-height: 1.35; }
/* A saved template sits on one row with its rename/delete buttons, so the
   name stays clickable and the two small actions never eat the click. */
.desk-menu-row { display: flex; align-items: stretch; gap: 2px; }
.desk-menu-row .desk-menu-item { flex: 1 1 auto; min-width: 0; }
.desk-menu-act {
  flex: 0 0 auto; width: 22px; border: 0; border-radius: 2px; background: none;
  color: var(--ink-3); font: inherit; font-size: 11px; cursor: pointer;
}
.desk-menu-act:hover { background: var(--raised); color: var(--ink); }
.desk-menu-mine:empty { display: none; }
.desk-tab { display: flex; align-items: center; border-bottom: 2px solid transparent; margin-bottom: -1px; }
.desk-tab.active { border-bottom-color: var(--pos); }
.desk-name { background: none; border: 0; font: inherit; letter-spacing: 1.1px; color: var(--ink-3); cursor: pointer; padding: 9px 6px 9px 9px; text-transform: uppercase; white-space: nowrap; }
.desk-tab.active .desk-name { color: var(--ink); font-weight: 700; }
.desk-close { background: none; border: 0; font: inherit; font-size: 10px; color: var(--rule-strong); cursor: pointer; padding: 9px 8px 9px 2px; }
.desk-close:hover { color: var(--neg); }
.desk-add { background: none; border: 1px solid var(--rule); border-radius: 2px; color: var(--ink-3); font: inherit; cursor: pointer; padding: 2px 9px; align-self: center; margin-left: 4px; }
.desk-add:hover { border-color: var(--pos); color: var(--pos); }
.palette-blocks { position: relative; display: flex; align-items: center; gap: 5px; margin-left: auto; padding: 0 10px; }
/* Quick add: the blocks this browser uses most, left of the group menus and
   separated from them so the two kinds of button do not read as one row. */
/* Five quick buttons plus three menus outgrow a narrow header. The quick bar
   is the half that yields: it shrinks and scrolls inside itself so the group
   menus never get pushed out of reach. */
.palette-quick { display: inline-flex; align-items: center; gap: 5px; min-width: 0; max-width: min(38vw, 420px); flex: 0 1 auto; overflow-x: auto; scrollbar-width: none; margin-right: 4px; padding-right: 8px; border-right: 1px solid var(--rule); }
.palette-quick::-webkit-scrollbar { display: none; }
.block-quick {
  padding: 4px 8px; border: 1px solid var(--rule-soft); border-radius: 2px; background: var(--raised);
  color: var(--ink-2); font: inherit; font-size: 10px; letter-spacing: .8px; cursor: pointer; white-space: nowrap;
}
.block-quick:hover { border-color: var(--pos); color: var(--ink); }
.block-menu-trigger {
  display: inline-flex; align-items: center; gap: 5px; flex: 0 0 auto; padding: 4px 8px; border: 1px solid var(--rule);
  border-radius: 2px; background: none; color: var(--ink-2); font: inherit; font-size: 10px;
  letter-spacing: .8px; cursor: pointer; white-space: nowrap;
}
.block-menu-trigger:hover, .block-menu-trigger[aria-expanded="true"] { border-color: var(--pos); color: var(--ink); background: var(--raised); }
.block-menu-caret { margin-left: 2px; color: var(--ink-3); font-size: 11px; transition: transform .15s ease; }
.block-menu-trigger[aria-expanded="true"] .block-menu-caret { transform: rotate(180deg); }
.block-menu {
  position: fixed; z-index: 75; width: min(284px, calc(100vw - 16px)); max-height: min(520px, calc(100vh - 80px));
  overflow-y: auto; padding: 5px; border: 1px solid var(--rule-strong); border-radius: 3px;
  background: var(--panel); box-shadow: 0 16px 48px rgba(0,0,0,.58);
}
.block-menu-group + .block-menu-group { border-top: 1px solid var(--rule); margin-top: 5px; padding-top: 5px; }
.block-menu-label { padding: 5px 9px 4px; color: var(--ink-3); font-size: 9px; font-weight: 700; letter-spacing: 1.2px; text-transform: uppercase; }
/* Is this block still being fed? Green while data arrives at the block's own
   rhythm, amber when it has gone quiet for three of its own beats. Hidden
   entirely for blocks with no feed — Notes, the catalogue — because a dot
   there would report health nobody measured. */
.block-pulse {
  width: 6px; height: 6px; border-radius: 50%; flex: 0 0 auto;
  background: var(--pos); margin: 0 2px;
  transition: background .3s ease;
}
.block-pulse.is-stale { background: var(--warn); }
@media (prefers-reduced-motion: reduce) { .block-pulse { transition: none; } }

.block-menu-item {
  display: flex; align-items: center; gap: 10px; width: 100%; padding: 7px 9px; border: 0;
  border-left: 2px solid transparent; border-radius: 1px; background: none; color: var(--ink-2);
  font: inherit; text-align: left; cursor: pointer;
}
.block-menu-item:hover, .block-menu-item:focus-visible { background: var(--raised); border-left-color: var(--pos); color: var(--ink); outline: 0; }
.block-menu-hint { margin-left: auto; color: var(--ink-3); font-size: 9px; }
/* Between the phone breakpoint and a full desk the header row is the tight
   one: the quick bar gives up width first and scrolls what does not fit. */
@media (max-width: 1180px) { .palette-quick { max-width: min(26vw, 210px); } }
@media (max-width: 760px) {
  .tabs { flex-wrap: wrap; overflow-x: visible; }
  .workspace, .ws-split { flex-direction: column; }
  /* Stacked on a phone the blocks are meant to run past the fold. */
  .workspace { height: auto; min-height: var(--deck-viewport-h); overflow: visible; }
  .ws-split { gap: var(--gap); min-width: 0 !important; min-height: 0 !important; }
  .ws-split > [data-panel], .ws-split > .ws-split, .workspace > [data-panel], .workspace > .ws-split {
    flex: 0 0 auto !important; width: 100%; min-width: 0 !important;
  }
  [data-panel] { min-width: 0 !important; }
  .ws-gap { display: none; }
  .palette-blocks { flex-basis: 100%; justify-content: flex-end; margin-left: 0; padding: 4px 6px; border-top: 1px solid var(--rule); }
}

/* A funding rate the hub did not collect, filled from the aggregator. Small
   and quiet, but never absent: second-hand must not look first-hand. */
.fx-src { margin-left: 5px; padding: 0 3px; border: 1px solid var(--rule-strong); border-radius: 2px; color: var(--ink-3); font-size: 9px; cursor: help; }
/* A row priced in something other than what was asked for. */
.fx-src.warn { border-color: var(--warn); color: var(--warn); }

/* A venue row that can be carried into the Watchlist, and the Watchlist while
   something is being carried over it. */
/* Token watch: one token across every venue we can price. */
.tw-head { display: flex; align-items: baseline; gap: 10px; padding: 0 0 6px; }

.tbl tr.is-focus td { background: color-mix(in srgb, var(--info) 14%, transparent); }
.wl-drop-cell { width: 18px; padding-left: 0 !important; padding-right: 4px !important; text-align: right; }
.wl-x { border: 0; background: none; color: var(--ink-3); font: inherit; font-size: 10px; line-height: 1; padding: 2px; cursor: pointer; opacity: 0; transition: opacity .12s ease; }
.tbl tr:hover .wl-x, .wl-x:focus-visible { opacity: 1; }
.wl-x:hover { color: var(--neg); }
.drag-link { cursor: grab; -webkit-user-drag: element; }
.drag-link:active { cursor: grabbing; }
/* Which port a carried group would land on, drawn over the target panel. */
.link-drop-zone {
  position: absolute; top: 0; bottom: 0; z-index: 6; pointer-events: none;
  display: flex; align-items: center; justify-content: center;
  border: 1px dashed var(--info); border-radius: 3px;
  background: color-mix(in srgb, var(--info) 14%, transparent);
}
.link-drop-zone span {
  padding: 4px 9px; border: 1px solid var(--info); border-radius: 3px;
  background: var(--panel); box-shadow: 0 4px 14px rgba(0,0,0,.5);
  color: var(--ink); font-size: 11px; letter-spacing: .8px; text-transform: uppercase; white-space: nowrap;
}

.drag-venue { cursor: grab; user-select: none; -webkit-user-drag: element; }
.drag-venue * { user-select: none; }
.drag-venue:active { cursor: grabbing; }
.panel-body.drop-market { position: relative; outline: 1px dashed var(--pos); outline-offset: -3px; background: color-mix(in srgb, var(--pos) 6%, transparent); }
/* The Spread chart has two places to put a market, so it shows both and lights
   the one the pointer is over. */
.sc-drop { position: absolute; inset: 0; z-index: 5; display: flex; pointer-events: none; }
.sc-drop-half { flex: 1 1 50%; display: flex; align-items: center; justify-content: center; border: 1px dashed var(--rule-strong); color: var(--ink-3); font-size: 11px; letter-spacing: .08em; text-transform: uppercase; }
.sc-drop-half.is-active { border-color: var(--pos); color: var(--ink); background: color-mix(in srgb, var(--pos) 12%, transparent); }

/* ───── ⌘K palette ───── */
.overlay { position: fixed; inset: 0; z-index: 80; background: rgba(0,0,0,.55); display: flex; align-items: flex-start; justify-content: center; padding-top: 12vh; }
.palette-box { width: 100%; max-width: 620px; background: var(--panel); border: 1px solid var(--rule-strong); border-radius: 3px; box-shadow: 0 18px 60px rgba(0,0,0,.6); display: flex; flex-direction: column; max-height: 76vh; }
.palette-box > input { background: none; border: 0; border-bottom: 1px solid var(--rule); color: var(--ink); font: inherit; font-size: 14px; padding: 13px 16px; }
.palette-box > input:focus { outline: none; }
.palette-list { overflow-y: auto; }
.pal-item { display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px 16px; border: 0; border-left: 2px solid transparent; background: none; color: var(--ink-2); font: inherit; text-align: left; cursor: pointer; }
.pal-item .pal-kind { font-size: 10px; color: var(--ink-3); letter-spacing: 1px; width: 62px; flex: 0 0 auto; }
.pal-item .pal-hint { margin-left: auto; font-size: 10px; color: var(--ink-3); }
.pal-item[aria-selected="true"] { background: var(--raised); color: var(--ink); border-left-color: var(--pos); }
.pal-empty { padding: 16px; color: var(--ink-3); }

/* ───── screener table ───── */
.tbl-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 4px; }
/* The screener's own search box: it filters in place, so it sits in the table
   head rather than among the block params, which remount on change. */
.tbl-q { width: 88px; padding: 1px 5px; font-size: 10.5px; background: var(--raised); border: 1px solid var(--rule); border-radius: 2px; color: var(--ink); }
.tbl-q::placeholder { color: var(--ink-3); }
/* The column everything is read by — sorted on, filtered by, grouped on. */
.tbl th.is-window { color: var(--ink); }
.tbl td.is-window { font-weight: 600; }
.tbl-chips { display: flex; gap: 5px; flex-wrap: wrap; margin-bottom: 6px; }
.tbl-chips .chip { font-size: 10px; padding: 2px 7px; cursor: default; }
.tbl-wrap { overflow: auto; }
.tbl { border-collapse: collapse; width: 100%; font-size: 11.5px; }
.tbl th { text-align: left; font-size: 9.5px; letter-spacing: 1px; text-transform: uppercase; color: var(--ink-3); font-weight: 500; padding: 4px 8px; border-bottom: 1px solid var(--rule-strong); white-space: nowrap; position: sticky; top: 0; background: var(--panel); }
.tbl th.num { text-align: right; }
.tbl td { padding: 3px 8px; border-bottom: 1px solid var(--rule-soft); white-space: nowrap; }
.tbl tr:hover td { background: var(--raised); }
.tbl tr.is-focus td { background: var(--raised); box-shadow: inset 2px 0 0 var(--pos); }

/* Open interest: the change columns, and the movers table. */
.oi-note { padding: 4px 10px; font-size: 10.5px; }
.oi-note:empty { display: none; }
.oi-tbl td, .oi-movers td { font-variant-numeric: tabular-nums; }
/* The column the table is ranked by, so the order is never a mystery. */
.tbl th.is-sorted { color: var(--ink); border-bottom-color: var(--info); }
/* A header that sorts is a control, and has to look like one — but a table
   head is not a place for a button's chrome. */
.tbl th > .th-sort { background: none; border: 0; padding: 0; margin: 0; font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit; cursor: pointer; }
.tbl th > .th-sort:hover { color: var(--ink); }
.tbl th.num > .th-sort { width: 100%; text-align: right; }
.oi-movers td.is-sorted { box-shadow: inset 0 -1px 0 color-mix(in srgb, var(--info) 45%, transparent); }
.oi-mover-row { cursor: pointer; }
.oi-mover-row.is-picked td { background: color-mix(in srgb, var(--info) 12%, transparent); }
.oi-coin { font-weight: 600; letter-spacing: .3px; }

/* The catalogue: the block palette, left open on the desk. */
.cat-search { width: calc(100% - 20px); margin: 8px 10px 4px; font-size: 11px; }
.cat-list { padding-bottom: 6px; }
/* Auto layout, not fixed: a fixed share gave "Ratio" the same width as
   "Ліквідність" and took it out of the summary, which is the column doing the
   explaining. The outer two hug their content instead and the summary keeps
   whatever the panel has left. */
.cat-tbl { width: 100%; }
.cat-tbl th:nth-child(1), .cat-tbl td:nth-child(1) { width: 1%; white-space: nowrap; }
.cat-tbl th:nth-child(3), .cat-tbl td:nth-child(3) { width: 1%; white-space: nowrap; text-align: right; }
.cat-tbl td:nth-child(2) { max-width: 0; }
/* A group heading is a row, not a table of its own: the columns have to keep
   lining up across the whole catalogue. */
.cat-group td {
  padding-top: 10px; color: var(--ink-3); font-size: 9px; letter-spacing: .8px;
  text-transform: uppercase; border-bottom: 1px solid var(--rule);
}
.cat-row { cursor: pointer; border-left: 2px solid transparent; }
.cat-row:hover, .cat-row:focus-visible { background: var(--raised); border-left-color: var(--info); outline: none; }
.cat-name { font-size: 11.5px; }
/* The summary is the wide column and the one that can outgrow it; clipping it
   is better than a row that grows to three lines, and the title carries the
   whole text. */
.cat-about { font-size: 10px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cat-here { color: var(--ink-3); font-size: 9px; letter-spacing: .6px; text-transform: uppercase; }
.cat-row.is-here .cat-name { color: var(--ink-2); }

/* Ліквідність: a book whose rows are distances, not prices. */
/* The ladder keeps one width and sits in the middle of whatever panel it is
   given, the way the Order book does: past a point a wider panel only pushes
   the numbers apart, and a price ladder is read as a column, not a row. */
/* The two sides split the height and the mid sits between them, so the spread
   line holds the middle of the panel at any height — the Order book rule. */
[data-panel][data-type="liquidity"] .panel-body { display: flex; flex-direction: column; overflow: hidden; min-height: 0; }
[data-panel][data-type="liquidity"] .lq-side { flex: 1 1 0; min-height: 0; overflow-y: auto; }
[data-panel][data-type="liquidity"] .lq-asks { justify-content: flex-end; }
[data-panel][data-type="liquidity"] .lq-bids { justify-content: flex-start; }
[data-panel][data-type="liquidity"] .lq-head,
[data-panel][data-type="liquidity"] .lq-mid,
[data-panel][data-type="liquidity"] .mp { flex: 0 0 auto; }
.lq-side { display: flex; flex-direction: column; }
.lq-row { flex: 0 0 auto; }
.lq-head, .lq-side, .lq-mid { width: 100%; max-width: 660px; margin-inline: auto; }
.lq-head, .lq-row {
  /* Fractional, so the columns scale together instead of the bar eating every
     spare pixel. The last column is the order marker — a fixed sliver, so the
     ladder does not shift when it appears. */
  display: grid; grid-template-columns: 58px 1fr 1.15fr 1.5fr 12px;
  gap: 8px; align-items: center; padding: 2px 10px;
}
.lq-head { padding-top: 6px; padding-bottom: 4px; border-bottom: 1px solid var(--rule-strong); cursor: help; }
.lq-row { position: relative; font-size: 11.5px; font-variant-numeric: tabular-nums; }
.lq-row:hover { background: var(--raised); }
.lq-ask .lq-pct { color: var(--neg); }
.lq-bid .lq-pct { color: var(--pos); }
.lq-bar-cell { display: block; height: 7px; border-radius: 1px; background: var(--rule-soft); overflow: hidden; }
.lq-bar { display: block; height: 100%; background: var(--rule-strong); }
.lq-ask .lq-bar { background: color-mix(in srgb, var(--neg) 55%, transparent); }
.lq-bid .lq-bar { background: color-mix(in srgb, var(--pos) 55%, transparent); }
/* The row for the size being considered: it is the answer, so it reads louder
   than the ladder it sits in. */
.lq-row.is-order { background: color-mix(in srgb, var(--info) 13%, transparent); box-shadow: inset 2px 0 0 var(--info); }
.lq-row.is-order .lq-pct { color: var(--info); font-weight: 600; }
.lq-order-tag { color: var(--info); font-size: 9.5px; line-height: 1; }
.lq-mid {
  /* `auto` on the sides, not 0: this rule sits after the one that centres the
     ladder, and a shorthand margin would quietly undo it. */
  display: flex; justify-content: space-between; gap: 8px; margin: 3px auto;
  padding: 3px 10px; border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule);
  background: var(--raised); font-size: 12px; font-variant-numeric: tabular-nums;
}
.sym-btn { background: none; border: 0; color: var(--ink); font: inherit; cursor: pointer; padding: 0; }
.sym-btn:hover { color: var(--info); }
.sym-btn.is-picked { color: var(--info); font-weight: 600; }
.badge { font-size: 10px; padding: 1px 6px; border-radius: 2px; border: 1px solid var(--rule-strong); }
.badge.info { border-color: var(--info-dim); } .badge.warn { border-color: var(--warn-dim); } .badge.pos { border-color: var(--pos-dim); } .badge.neg { border-color: var(--neg-dim); }

/* ───── order book ───── */
[data-panel][data-type="orderbook"] .panel-body { display: flex; flex-direction: column; overflow: hidden; min-height: 0; }
[data-panel][data-type="orderbook"] .ob-cols { flex: 0 0 auto; }
[data-panel][data-type="orderbook"] .ob-side { flex: 1 1 0; min-height: 0; overflow: hidden; }
[data-panel][data-type="orderbook"] .ob-asks { justify-content: flex-end; }
[data-panel][data-type="orderbook"] .ob-bids { justify-content: flex-start; }
.ob-cols { display: grid; grid-template-columns: 1.2fr 1fr 1fr; gap: 6px; padding: 0 4px 4px; }
.ob-side { display: flex; flex-direction: column; }
.ob-row { display: grid; grid-template-columns: 1.2fr 1fr 1fr; gap: 6px; padding: 1px 4px; font-size: 11.5px; position: relative; flex: 0 0 auto; }
.ob-row::before { content: ''; position: absolute; inset: 0; left: auto; right: 0; width: var(--fill, 0); opacity: .12; }
.ob-row.neg::before { background: var(--neg); }
.ob-row.pos::before { background: var(--pos); }
.ob-price { display: flex; align-items: baseline; gap: 4px; min-width: 0; white-space: nowrap; }
.ob-price-value { overflow: hidden; text-overflow: ellipsis; }
.ob-offset { color: var(--ink-3); font-size: 9px; letter-spacing: 0; }
.ob-mid { display: flex; justify-content: space-between; align-items: baseline; flex: 0 0 auto; padding: 4px 4px; border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); margin: 3px 0; font-size: 13px; }

/* ───── pair book ───── */
.pb-grid { display: grid; grid-template-columns: 1fr 90px 1fr; gap: 8px; align-items: start; }
.pb-col .ob-row { grid-template-columns: 1.4fr 1fr; }
.pb-mid { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; padding-top: 40px; font-size: 13px; font-weight: 700; }

/* ───── candles ───── */
.chart-host { width: 100%; height: 100%; min-width: 0; min-height: 220px; overflow: hidden; }
[data-panel][data-type="candles"] .panel-body { display: flex; flex-direction: column; padding: 0; overflow: hidden; min-height: 0; }
[data-panel][data-type="candles"] .chart-host { flex: 1 1 0; height: auto; min-height: 0; }
[data-panel][data-type="candles"] { min-height: 280px; }
.mkt-picker { position: relative; z-index: 3; padding: 6px 8px 0; }
.mkt-picker-bar { display: flex; align-items: center; gap: 7px; min-width: 0; padding: 4px 7px; border: 1px solid var(--rule); border-radius: 3px; background: var(--ground); }
.mkt-picker-icon { color: var(--ink-3); font-size: 16px; line-height: 1; }
.mkt-picker-input { min-width: 90px; flex: 1 1 140px; padding: 2px 0; border: 0; background: transparent; font: inherit; font-size: 12px; color: var(--ink); }
.mkt-picker-input:focus { outline: none; }
.mkt-picker-selected { margin-left: auto; overflow: hidden; color: var(--ink-3); font-size: 10px; text-overflow: ellipsis; white-space: nowrap; }
.mkt-picker-results { position: absolute; top: calc(100% - 1px); left: 8px; right: 8px; max-height: 250px; overflow-y: auto; border: 1px solid var(--rule-strong); border-radius: 0 0 3px 3px; background: var(--panel); box-shadow: 0 12px 28px rgba(0,0,0,.42); }
.mkt-row { display: grid; grid-template-columns: 1.1fr 1fr .9fr 1.2fr; gap: 8px; width: 100%; padding: 7px 9px; border: 0; border-bottom: 1px solid var(--rule-soft); background: transparent; color: var(--ink-2); font: inherit; font-size: 11px; text-align: left; cursor: pointer; }
.mkt-row:last-child { border-bottom: 0; }
.mkt-row:hover, .mkt-row:focus-visible { background: var(--raised); color: var(--ink); outline: none; }
.mkt-row.is-unavailable { opacity: .42; cursor: not-allowed; }
.mkt-row.is-unavailable:hover { background: transparent; }
.mkt-row-symbol { color: var(--ink); font-weight: 600; }
.mkt-row-name { color: var(--info); }
.mkt-row-type { color: var(--pos); font-size: 10px; }
.mkt-row-native { overflow: hidden; color: var(--ink-3); text-overflow: ellipsis; white-space: nowrap; }
.mkt-picker-empty { padding: 10px; color: var(--ink-3); font-size: 11px; }
.mkt-picker-bar { flex-wrap: wrap; }
.mkt-picker-chips { display: contents; }
.mkt-chip { display: inline-flex; align-items: center; gap: 4px; padding: 1px 3px 1px 6px; border: 1px solid var(--rule-strong); border-radius: 2px; background: var(--raised); color: var(--ink); font-size: 10px; letter-spacing: .03em; }
.mkt-chip-x { padding: 0 3px; border: 0; background: transparent; color: var(--ink-3); font: inherit; font-size: 12px; line-height: 1; cursor: pointer; }
.mkt-chip-x:hover, .mkt-chip-x:focus-visible { color: var(--neg); outline: none; }

/* ───── spread chart ───── */
.sc-legend { display: flex; gap: 5px; flex-wrap: wrap; padding: 4px 6px; }
.sc-legend .chip { font-size: 10px; padding: 1px 6px; }
.sc-meta { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 14px; padding: 6px 10px; border-bottom: 1px solid var(--rule); font-size: 11px; }
.sc-pairname { color: var(--ink); font-weight: 500; }
.sc-in, .sc-out { font-size: 13px; font-weight: 500; }
.sc-fund { white-space: nowrap; font-variant-numeric: tabular-nums; }
.sc-context-side.context-hover { background: var(--raised); border-radius: 2px; outline: 1px solid var(--info); outline-offset: 2px; }
.sc-status:empty { display: none; }
.sc-ranges { display: flex; gap: 2px; margin-left: auto; }
.sc-ranges .chip { padding: 2px 6px; }
[data-panel][data-type="spread-chart"] .panel-body { padding: 0; display: flex; flex-direction: column; }

/* ───── trades ───── */
[data-panel][data-type="trades"] .panel-body { display: flex; flex-direction: column; overflow: hidden; min-height: 0; height: 0; }
.tr-flow { display: flex; gap: 12px; padding: 0 4px 6px; text-transform: none; letter-spacing: 0; font-size: 11px; }
.tr-table-wrap { flex: 1 1 0; min-height: 0; overflow: auto; overflow-anchor: none; }
.tr-tbl { width: 100%; }
.tr-tbl td { padding: 1px 6px; font-size: 11px; }
.tr-big td { font-weight: 700; }

/* ───── alerts ───── */
[data-panel][data-type="alerts"] .panel-body { display: flex; flex-direction: column; overflow: hidden; min-height: 0; }
[data-panel][data-type="alerts"] .tbl-head { flex-shrink: 0; }
.al-list { display: flex; flex-direction: column; gap: 6px; flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding-right: 4px; }
.al-item { border-left: 2px solid var(--rule-strong); padding: 4px 8px; }
.al-meta { display: flex; gap: 8px; align-items: center; font-size: 10.5px; margin-bottom: 2px; }
.al-meta .chip { font-size: 9.5px; padding: 0 6px; cursor: default; }
.al-text { white-space: pre-wrap; font-size: 11.5px; line-height: 1.45; overflow-wrap: anywhere; }
.al-text a { overflow-wrap: anywhere; }
.al-meta .chip.neg { color: var(--neg); border-color: var(--neg-dim); }

/* The «+ alert» control: a native popover enters the top layer so panel
   overflow and stacking contexts cannot clip or cover its choices. */
.al-menu-wrap { position: relative; display: inline-flex; }
.al-menu {
  position: fixed; inset: auto; margin: 0; min-width: 246px; max-width: calc(100vw - 16px);
  max-height: calc(100vh - 16px); overflow-y: auto;
  display: flex; flex-direction: column; gap: 1px; padding: 5px;
  background: var(--panel); border: 1px solid var(--rule-strong); border-radius: 3px;
  box-shadow: 0 8px 22px rgba(0, 0, 0, .55);
}
/* Author display:flex overrides the browser's hidden popover state. */
.al-menu:not(:popover-open) { display: none; }
.al-menu.is-asking { width: 320px; max-width: calc(100vw - 16px); }
.al-menu button {
  display: block; width: 100%; text-align: left; padding: 6px 8px;
  background: none; border: 0; border-radius: 2px; color: var(--ink); font: inherit; cursor: pointer;
}
.al-menu button:hover { background: var(--raised); }
.al-menu .hint { display: block; margin-top: 2px; color: var(--ink-3); font-size: 10px; }
.al-menu button.back { color: var(--ink-3); border-bottom: 1px solid var(--rule); border-radius: 0; margin-bottom: 3px; }
.al-menu button:disabled { color: var(--ink-3); cursor: default; }
.al-menu .already { float: right; color: var(--pos); font-size: 10px; letter-spacing: .4px; }
.al-menu .note { padding: 6px 8px; font-size: 11px; line-height: 1.4; }
.al-menu .note.warn { color: var(--warn); }
.al-menu .note.neg { color: var(--neg); }
.al-menu .note.ok { color: var(--pos); }
/* The one question a menu asks: which coin. It sits in the menu, so the field
   has to look like the rows above it rather than like a form. */
.al-menu .al-ask { display: flex; align-items: center; gap: 6px; padding: 6px 8px; }
.al-menu .al-ask span { color: var(--ink-3); font-size: 10px; letter-spacing: .4px; text-transform: uppercase; }
.al-menu .al-ask input { flex: 1 1 auto; min-width: 0; }
.al-menu .al-ask input::placeholder { color: var(--ink-3); opacity: 1; }
.al-menu .al-ask button {
  width: auto; flex: 0 0 auto; padding: 4px 10px;
  background: var(--raised); border: 1px solid var(--rule-strong); border-radius: 3px;
}
.al-menu > .hint { padding: 0 8px 4px; color: var(--ink-3); font-size: 10px; }

/* A button that is only an icon: square, and the glyph centred rather than
   sitting on a text baseline that does not exist. */
.icon-btn { display: inline-flex; align-items: center; justify-content: center; padding: 2px 8px; }
.icon-btn svg { display: block; }

/* Settings: one panel for what is true of the whole deck. */
.set-box {
  width: min(560px, 94vw); max-height: 86vh; overflow: auto;
  background: var(--panel); border: 1px solid var(--rule-strong); border-radius: 4px;
  padding: 14px 16px 16px; display: flex; flex-direction: column; gap: 14px;
}
.set-head { display: flex; align-items: baseline; gap: 10px; }
.set-head .btn { margin-left: auto; }
.set-section { display: flex; flex-direction: column; gap: 6px; }
.set-section .lbl { margin-bottom: 2px; }
.set-row {
  display: grid; grid-template-columns: 1fr auto; gap: 12px; align-items: center;
  padding: 4px 0; border-bottom: 1px solid var(--rule-soft);
}
.set-row:last-child { border-bottom: 0; }
.set-label { display: flex; flex-direction: column; }
.set-hint { color: var(--ink-3); font-size: 10px; margin-top: 2px; }
.set-row input[type="text"] { width: 240px; }
.set-row input.set-time { width: 64px; text-align: center; }
.set-row input.set-num { width: 80px; text-align: right; }
.set-pair { display: inline-flex; align-items: center; gap: 6px; color: var(--ink-3); }
.set-actions { display: flex; align-items: center; gap: 10px; margin-top: 4px; }
.set-status { font-size: 11px; }
.set-foot { display: flex; align-items: center; gap: 12px; }

/* Compact density: the same deck with less air, for a screen that has to hold
   four more rows. Only paddings and leading — never the font size, which is
   what makes a table unreadable rather than dense. */
:root[data-density="compact"] .tbl th, :root[data-density="compact"] .tbl td { padding-top: 1px; padding-bottom: 1px; }
:root[data-density="compact"] .panel-body { padding: 5px 7px; }
:root[data-density="compact"] .al-item { padding-top: 2px; padding-bottom: 2px; }
:root[data-density="compact"] .nw-row, :root[data-density="compact"] .ix-row { line-height: 1.25; }

/* Networks: deposit/withdrawal status per chain, grouped by exchange */
.nw-head { display: flex; align-items: baseline; gap: 10px; padding: 7px 9px; border-bottom: 1px solid var(--rule); }
.nw-title { color: var(--ink); font-weight: 600; }
.nw-counts { margin-left: auto; color: var(--ink-2); font-size: 11px; white-space: nowrap; }
.nw-age { margin-left: auto; font-size: 10px; }
.nw-venue-head .nw-note + .nw-counts, .nw-venue-head .nw-counts { margin-left: auto; }
.nw-body { overflow-y: auto; }
.nw-venue { margin-bottom: 6px; }
.nw-venue:last-child { margin-bottom: 0; }
.nw-venue-head { display: flex; align-items: baseline; gap: 8px; padding: 5px 9px 5px 7px; border-left: 2px solid var(--info); background: var(--raised); font-size: 11px; }
.nw-venue-head b { letter-spacing: .04em; text-transform: uppercase; }
.nw-cols, .nw-row { display: grid; grid-template-columns: minmax(64px, 1.3fr) 40px 40px minmax(56px, 1fr) 46px minmax(74px, 1.2fr); gap: 6px; align-items: center; padding: 4px 9px; }
.nw-cols { position: sticky; top: 0; z-index: 1; padding-left: 21px; border-bottom: 1px solid var(--rule); background: var(--panel); font-size: 10px; }
.nw-row { position: relative; font-size: 11px; border-bottom: 1px solid var(--rule-soft); padding-left: 21px; }
.nw-row::before { content: ''; position: absolute; left: 10px; top: 0; bottom: 0; border-left: 1px solid var(--rule); }
.nw-venue .nw-row:last-child::before { bottom: 50%; }
.nw-row:last-child { border-bottom: 0; }
.nw-row:hover { background: var(--raised); }
.nw-net { overflow: hidden; color: var(--ink); text-overflow: ellipsis; white-space: nowrap; }
.nw-cell { display: inline-flex; align-items: center; gap: 4px; }
.nw-flag { font-size: 11px; }
.nw-fee { color: var(--ink-2); }
.nw-link { color: var(--ink-3); text-decoration: none; font-size: 10px; }
.nw-link:hover { color: var(--info); }
.nw-contract { padding: 0; border: 0; background: transparent; color: var(--ink-3); font: inherit; font-size: 10px; cursor: pointer; }
.nw-contract:hover { color: var(--ink); text-decoration: underline dotted; }
.nw-contract.is-copied { color: var(--pos); }
.nw-contract-cell { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nw-note { margin-left: auto; padding: 0 4px; border: 1px solid var(--rule-strong); border-radius: 2px; color: var(--warn); font-size: 9px; white-space: nowrap; cursor: help; }
.nw-muted { display: flex; flex-wrap: wrap; gap: 4px 14px; padding: 8px 9px; font-size: 10px; }
.nw-muted-item { color: var(--ink-3); white-space: nowrap; }
.nw-pending { color: var(--ink-3); font-size: 12px; }

/* Index prices: one card per venue, its basket indented under it. The weight
   bar behind a row is the fastest read — one exchange at 45% is a different
   index from five at 20%. */
.ix-head { display: flex; align-items: baseline; gap: 10px; padding: 7px 9px; border-bottom: 1px solid var(--rule); }
.ix-title { color: var(--ink); font-weight: 600; }
.ix-band { margin-left: auto; padding: 0 4px; border: 1px solid var(--rule-strong); border-radius: 2px; color: var(--ink-2); font-size: 10px; white-space: nowrap; cursor: help; }
.ix-band.warn { border-color: var(--warn); color: var(--warn); }
.ix-body { overflow-y: auto; }
.ix-venue { margin-bottom: 6px; }
.ix-venue:last-child { margin-bottom: 0; }
.ix-venue-head { display: flex; align-items: baseline; gap: 8px; padding: 5px 9px 5px 7px; border-left: 2px solid var(--info); background: var(--raised); font-size: 11px; }
.ix-venue-head b { letter-spacing: .04em; text-transform: uppercase; }
.ix-index { color: var(--ink); font-size: 12px; }
.ix-symbol { margin-left: auto; font-size: 10px; }
.ix-note { padding: 0 4px; border: 1px solid var(--rule-strong); border-radius: 2px; color: var(--ink-3); font-size: 9px; white-space: nowrap; cursor: help; }
.ix-row { position: relative; display: grid; grid-template-columns: minmax(80px, 1.4fr) 52px minmax(70px, 1fr) 70px; gap: 6px; align-items: center; padding: 4px 9px 4px 21px; font-size: 11px; border-bottom: 1px solid var(--rule-soft); }
.ix-row::before { content: ''; position: absolute; left: 10px; top: 0; bottom: 0; border-left: 1px solid var(--rule); }
.ix-venue .ix-row:last-child::before { bottom: 50%; }
.ix-row::after { content: ''; position: absolute; left: 21px; right: 9px; bottom: 0; height: 2px; width: var(--w, 0); background: var(--info); opacity: .35; }
.ix-row:last-child { border-bottom: 0; }
.ix-row:hover { background: var(--raised); }
.ix-src { overflow: hidden; color: var(--ink); text-overflow: ellipsis; white-space: nowrap; }
.ix-weight { color: var(--ink-2); }
.ix-muted { display: flex; flex-wrap: wrap; gap: 4px 14px; padding: 8px 9px; font-size: 10px; }

/* DEX chart: one token on one chain, addressed by contract rather than by
   exchange ticker, so the picker is a paste box instead of a search. */
[data-panel][data-type="dex-chart"] .panel-body { display: flex; flex-direction: column; padding: 0; overflow: hidden; min-height: 0; }
/* The address is typed once, the numbers are read constantly: the input keeps
   a fixed slice and the stats take what is left, wrapping rather than eating
   the box you paste into. */
.dx-head { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; padding: 6px 10px; border-bottom: 1px solid var(--rule); }
.dx-addr { flex: 0 1 200px; min-width: 96px; font-size: 11px; }
.dx-title { flex: 0 0 auto; white-space: nowrap; font-size: 10px; letter-spacing: .8px; }
.dx-chains { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 6px 10px; border-bottom: 1px solid var(--rule); }
.dx-stats { flex: 1 1 140px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 10px; letter-spacing: .4px; }

/* Ratio: two markets divided by each other, so the heading carries the reading
   and the chart is one line. */
[data-panel][data-type="pair-ratio"] .panel-body { display: flex; flex-direction: column; padding: 0; overflow: hidden; min-height: 0; }
.pr-head { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; padding: 6px 10px; border-bottom: 1px solid var(--rule); }
.pr-title { font-size: 11px; letter-spacing: .6px; }
.pr-range { font-size: 10px; letter-spacing: .4px; }

/* ───── usage (admin) block ─────
   Three tiers: the pulse (now), the browsers (who), the load (how hard).
   Hairlines, not cards; the desk's mono and tabular numbers throughout. */
.usage { container-type: inline-size; display: flex; flex-direction: column; gap: 14px; }
.usage-gate { display: flex; flex-direction: column; gap: 6px; padding: 12px 4px; }
.usage-gate-title { font-size: 10px; letter-spacing: 1.2px; color: var(--ink-3); text-transform: uppercase; }
.usage-gate code { align-self: flex-start; background: var(--raised); border: 1px solid var(--rule); border-radius: 2px; padding: 3px 8px; color: var(--ink); }

/* pulse */
.usage-pulse { display: grid; grid-template-columns: minmax(180px, 1fr) minmax(160px, 1.4fr); gap: 8px 18px; align-items: end; padding-bottom: 12px; border-bottom: 1px solid var(--rule); }
.usage-pulse-now { display: grid; grid-template-columns: auto auto 1fr; grid-template-rows: auto auto; column-gap: 8px; align-items: baseline; }
.usage-live { width: 8px; height: 8px; border-radius: 50%; background: var(--pos); box-shadow: 0 0 0 0 color-mix(in srgb, var(--pos) 45%, transparent); align-self: center; animation: usage-pulse 2.4s ease-out infinite; }
@keyframes usage-pulse { 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--pos) 45%, transparent); } 70% { box-shadow: 0 0 0 7px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } }
@media (prefers-reduced-motion: reduce) { .usage-live { animation: none; } }
.usage-pulse-n { font-size: 34px; font-weight: 500; line-height: 1; color: var(--ink); letter-spacing: -.5px; }
.usage-pulse-l { color: var(--ink-2); letter-spacing: .6px; }
.usage-pulse-sub { grid-column: 2 / 4; }
.usage-pulse-ts { grid-column: 2 / 4; font-size: 10px; }
.usage-pulse-chart { display: flex; flex-direction: column; gap: 2px; }
.usage-spark { width: 100%; height: 48px; display: block; }
.usage-axis { display: flex; justify-content: space-between; font-size: 10px; letter-spacing: .4px; }

/* tiers */
.usage-tier { display: flex; flex-direction: column; gap: 10px; }
.usage-tier + .usage-tier { padding-top: 12px; border-top: 1px solid var(--rule); }
.usage-tier-head { display: flex; align-items: baseline; gap: 10px; }

/* KPIs: a row of numbers separated by hairlines, wrapping as the block narrows */
.usage-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); row-gap: 10px; }
.usage-kpi { padding: 0 10px; border-left: 1px solid var(--rule); min-width: 0; display: grid; grid-template-rows: 24px auto auto; align-content: start; }
.usage-kpi .lbl { align-self: end; line-height: 12px; }
.usage-kpi:first-child { padding-left: 0; border-left: 0; }
.usage-kpi-v { font-size: 20px; line-height: 1.15; color: var(--ink); margin-top: 3px; font-variant-numeric: tabular-nums; }
.usage-kpi-sub { font-size: 10px; min-height: 12px; }

/* 30-day bars: bottom-aligned, quiet days as a hairline mark */
.usage-days { display: flex; flex-direction: column; gap: 4px; }
.usage-bars { display: flex; align-items: flex-end; gap: 2px; height: 36px; border-bottom: 1px solid var(--rule); }
.usage-bars i { flex: 1; background: var(--info); border-radius: 1px 1px 0 0; min-width: 2px; opacity: .85; }
.usage-bars i.is-zero { background: var(--rule-strong); opacity: 1; }
.usage-bars i:last-child { background: var(--pos); opacity: 1; }

/* horizontal bars: label · track · number */
.usage-hbars { display: flex; flex-direction: column; gap: 4px; }
.usage-hbar { display: grid; grid-template-columns: minmax(80px, 1fr) minmax(60px, 1.2fr) 44px; gap: 8px; align-items: center; font-size: 11px; }
.usage-hbar-track { height: 6px; background: var(--raised); border-radius: 1px; overflow: hidden; }
.usage-hbar-track i { display: block; height: 100%; border-radius: 1px; }
.usage-hbar-n { color: var(--ink); font-variant-numeric: tabular-nums; }

/* load */
.usage-load { display: grid; grid-template-columns: minmax(150px, 1fr) minmax(160px, 1.6fr); gap: 8px 18px; align-items: end; }
.usage-load-main { display: flex; flex-direction: column; gap: 8px; }
.usage-load-main .usage-kpi { padding-left: 0; border-left: 0; }
.usage-load-main .usage-kpi-v { font-size: 26px; }
.usage-pills { display: flex; flex-wrap: wrap; gap: 4px; }
.usage-pill { padding: 1px 7px; border: 1px solid var(--rule); border-radius: 2px; font-size: 10px; letter-spacing: .5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.usage-pill.is-warn { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 45%, var(--rule)); background: var(--warn-dim); }
.usage-pill.is-neg { color: var(--neg); border-color: color-mix(in srgb, var(--neg) 45%, var(--rule)); background: var(--neg-dim); }
.usage-load-chart { display: flex; flex-direction: column; gap: 2px; }
.usage-stack { display: flex; height: 8px; gap: 1px; border-radius: 1px; overflow: hidden; background: var(--raised); }
.usage-stack i { display: block; height: 100%; min-width: 1px; }
.usage-legend { display: flex; flex-wrap: wrap; gap: 4px 14px; font-size: 11px; color: var(--ink-2); }
.usage-legend-i { display: inline-flex; align-items: center; gap: 5px; }
.usage-legend-i i { width: 7px; height: 7px; border-radius: 1px; display: inline-block; }
.usage-legend-i b { font-weight: 500; color: var(--ink); font-variant-numeric: tabular-nums; }
.usage-ips, .usage-open { display: flex; flex-direction: column; gap: 6px; }

@container (max-width: 520px) {
  .usage-pulse, .usage-load { grid-template-columns: 1fr; }
  .usage-kpis { grid-template-columns: repeat(auto-fit, minmax(80px, 1fr)); }
}
.account-control { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.account-name { max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.account-button:focus-visible { outline: 2px solid var(--accent, #60a5fa); outline-offset: 2px; }
/* A session that ran out: the button is what fixes it, so the button carries it. */
.account-button.is-expired { border-color: var(--warn); color: var(--warn); }
@media (max-width: 600px) { .account-control { max-width: 100%; } }

/* The rate reticks every second and steps between one and three digits. A slot
   as wide as the widest of them stops the whole strip — the login button, the
   clock, everything to its right — from sliding under it. */
#ws-rate .strip-count { display: inline-block; min-width: 3ch; text-align: right; font-variant-numeric: tabular-nums; }
