/* tradinghub.cc — live trade tape + liquidations sidebar (Crypto terminal panel) */

/* ---------- Bloomberg/Aggr-style flat redesign ----------
   Retargets the shared color tokens for everything under .live-term only
   (custom properties cascade to every descendant that reads var(--line)
   etc.), and kills border-radius across the panel. Circular status dots
   are restored to round further down so they still read as indicator
   lights rather than tiny squares. No markup, IDs or classes changed. */
.live-term{
  --void: #000000;
  --panel: #090909;
  --panel-hover: #121212;
  --surface-header: #1A1A1A;
  --line: #1A1A1A;
  --line-soft: #141414;
  --ink: #CCCCCC;
  --mute: #8F8F8F;
  --mute-dim: #5A5A5A;
  --signal: #FFC857;
  --signal-soft: rgba(255,200,87,0.12);
  --pulse: #00FF88;
  --pulse-soft: rgba(0,255,136,0.12);
  --danger: #FF4D4D;
  --danger-soft: rgba(255,77,77,0.12);
  --exch-binance: #4CC2FF;
  --exch-bybit: #35D0A7;
  background:var(--void);
}
.live-term, .live-term *{ border-radius:0 !important; }
.live-term .term-identity-bar__dot,
.live-term .live-tape-idle__dot,
.live-term .dot{ border-radius:50% !important; }

.live-term{
  /* Balanced default: terminal (main) and Live Chart (side) split the
     available width roughly evenly and stay responsive across desktop
     resolutions. --live-side-w is only set (as a fixed px value) once a
     user drags the gutter or has a saved width in layout-persistence.js —
     until then the "1fr" fallback keeps both columns equal. */
  display:grid;
  /* Two-panel layout: Volume (trade tape + Whales + Market Overview,
     under the TRADINGHUB TERMINAL header) on the left, resizable via the
     gutter, and Chart (Live Chart + the rest of the widget stack) on the
     right. */
  grid-template-columns:minmax(0,1fr) 6px minmax(0,var(--live-side-w,1fr));
  gap:0;
  align-items:start;
  /* the ~160px accounts for the identity bar + asset/exchange selectors +
     toolbar + heatmap strip above the tape list, so the tape list itself
     (not just this outer container) clears 70% of the viewport height */
  min-height:calc(70vh + 160px);
}
@media (max-width:980px){
  .live-term{ grid-template-columns:1fr; min-height:0; }
  .live-term__gutter{ display:none; }
}

/* ---------- resizable sidebar gutter (drag to resize, remembered) ---------- */
.live-term__gutter{
  align-self:stretch;
  width:6px;
  margin:0 -3px;
  cursor:col-resize;
  position:relative;
  z-index:3;
  background:transparent;
  touch-action:none;
}
.live-term__gutter::after{
  content:''; position:absolute; top:0; bottom:0; left:2px; width:1px;
  background:var(--line);
}
.live-term__gutter:hover::after,
.live-term__gutter--active::after{ left:1px; width:3px; background:var(--signal); }
.live-term--fullscreen .live-term__gutter{ align-self:stretch; }

/* ---------- sidebar panel drag-to-reorder ---------- */
.panel-drag-handle{
  flex:none; color:var(--mute-dim); font-size:14.5px; line-height:1;
  margin-right:2px; user-select:none;
  cursor:grab;
}
.panel-drag-handle:active{ cursor:grabbing; }
.live-term__side .widget-card--drag-ghost{ opacity:.35; }
.live-term__side .widget-card--drag-over{ box-shadow:inset 0 2px 0 var(--signal); }

.live-term__main{
  min-width:0;
  display:flex; flex-direction:column;
  position:relative;
  background:var(--void);
  border:1px solid var(--line);
  /* Auto-height, not fixed: this panel now also carries Whales + Market
     Overview·Statistics below the tape, so it needs to grow to fit them
     instead of clipping them off — the tape itself keeps a bounded,
     independently-scrollable box via .live-term__tape-frame below. */
  height:auto;
}
.live-term__tape-frame{
  display:flex; flex-direction:column;
  min-width:0;
  overflow:hidden;
  /* Fixed, not just inherited from the grid's min-height: the grid uses
     align-items:start (so the shorter sidebar column isn't stretched
     into a lot of empty space), which means this box was otherwise sized
     purely by its own content — as trade rows streamed in/out, or just
     changed height (large-trade rows get extra padding), it visibly grew
     and shrank. With an explicit height here, .live-tape below (flex:1)
     has something definite to size against and scrolls inside a constant
     box instead. Matches the same 70vh+160px the grid's min-height
     already targets, so nothing shifts on first load either. */
  height:calc(70vh + 160px);
}

/* ---------- terminal identity bar ---------- */
.term-identity-bar{
  display:flex; align-items:center; gap:10px;
  padding:4px 10px;
  background:var(--surface-header);
  border-bottom:1px solid var(--line);
  font-family:var(--font-mono);
  overflow-x:auto;
  white-space:nowrap;
}
.term-identity-bar__brand{
  font-size:12.5px; font-weight:700; letter-spacing:.06em;
  color:var(--signal);
  flex:none;
}
.term-identity-bar__brand span{ color:var(--ink); font-weight:600; }
.term-identity-bar__version{ color:var(--mute-dim) !important; font-weight:500 !important; }
.term-identity-bar__sep{
  flex:none; width:1px; align-self:stretch; background:var(--line-soft);
}
.term-identity-bar__item{
  display:flex; align-items:baseline; gap:5px;
  font-size:12px; letter-spacing:.04em;
  flex:none;
}
.term-identity-bar__label{ color:var(--mute-dim); text-transform:uppercase; }
.term-identity-bar__value{
  color:var(--ink); font-weight:600; font-variant-numeric:tabular-nums;
}
.term-identity-bar__value.term-identity--good{ color:var(--pulse); }
.term-identity-bar__value.term-identity--warn{ color:var(--ink); }
.term-identity-bar__value.term-identity--bad{ color:var(--danger); }
.term-identity-bar__dot{
  width:6px; height:6px; border-radius:50%; flex:none;
  background:var(--mute-dim);
}
.term-identity-bar__dot--live{ background:var(--pulse); box-shadow:0 0 6px rgba(0,255,136,.6); }
.term-identity-bar__dot--reconnecting{ background:var(--ink); }
.term-identity-bar__dot--offline{ background:var(--danger); }
@media (max-width:640px){
  .term-identity-bar__item:not(#term-identity-ws){ display:none; }
  /* mobile-only: drop "v1.0" (saves width) and shrink the bar itself
     ~20% shorter (padding + font-size) — desktop is untouched. The
     WS status stays exactly as-is: small colored dot + LIVE/RECONNECTING/
     OFFLINE text via #term-identity-ws. */
  .term-identity-bar__version{ display:none; }
  .term-identity-bar{ padding:3px 10px; }
  .term-identity-bar__brand{ font-size:11.5px; }
  .term-identity-bar__item{ font-size:11px; }
}

/* ---------- local + UTC clock (identity bar, upper-right) ---------- */
.term-clock-chip{
  display:flex; align-items:baseline; gap:8px;
  margin-left:auto; padding:2px 10px;
  border:1px solid var(--line);
  background:var(--panel);
  font-family:var(--font-mono); font-size:12px; letter-spacing:.04em;
  flex:none; white-space:nowrap;
}
.term-clock-chip__item{ display:flex; align-items:baseline; gap:5px; }
.term-clock-chip__label{ color:var(--mute-dim); text-transform:uppercase; }
.term-clock-chip__value{ color:var(--ink); font-weight:700; font-variant-numeric:tabular-nums; }
.term-clock-chip__sep{
  width:1px; align-self:stretch; background:var(--line-soft); flex:none;
}
@media (max-width:820px){ .term-clock-chip__label{ display:none; } }
@media (max-width:640px){ .term-clock-chip{ display:none; } }

/* Desktop-only: shrink the whole identity-bar row (CONNECTED/LATENCY/WS
   plus the UTC/LOCAL clock chip on its right) — mobile keeps its own
   sizing from the max-width:640px rules above, untouched. */
@media (min-width:641px){
  .term-identity-bar{ padding:2px 10px; gap:8px; }
  .term-identity-bar__item{ font-size:11px; }
  .term-identity-bar__brand{ font-size:11.5px; }
  .term-clock-chip{ padding:1px 8px; gap:6px; font-size:11px; }
}

/* ---------- asset selector ---------- */
.asset-select{
  display:flex; align-items:center; gap:0; flex-wrap:wrap;
  padding:6px 10px;
  border-bottom:1px solid var(--line);
  background:var(--panel);
}
.asset-pill{
  font-family:var(--font-mono);
  font-size:13px; font-weight:600;
  letter-spacing:.03em;
  color:var(--mute);
  background:transparent;
  border:1px solid var(--line);
  margin-right:-1px;
  padding:4px 12px;
  cursor:pointer;
  display:inline-flex; align-items:baseline; gap:7px;
  transition:color .15s ease, border-color .15s ease, background .15s ease;
}
.asset-pill:hover{ color:var(--ink); border-color:var(--mute-dim); }
.asset-pill--active{
  color:#000000;
  background:var(--signal);
  border-color:var(--signal);
}
.asset-pill__chg{
  font-size:12px; font-weight:600;
  font-variant-numeric:tabular-nums;
  color:var(--mute-dim);
}
.asset-pill__chg--up{ color:var(--pulse); }
.asset-pill__chg--down{ color:var(--danger); }
.asset-pill--active .asset-pill__chg--up{ color:#0a5c30; }
.asset-pill--active .asset-pill__chg--down{ color:#7a1518; }

/* Market Display Mode: "Both" stacks label above price+change on each pill */
.asset-select--stacked .asset-pill{
  flex-direction:column; align-items:flex-start; gap:2px;
  padding:5px 12px 6px;
}
.asset-select--stacked .asset-pill__chg{ font-size:12px; }

/* Phones: smaller text/padding, and the 3 pills now split the row equally
   (flex:1) instead of scrolling — always one static line, no sideways
   sliding, no wrap. min-width:0 + ellipsis on the label/change text is
   just a safety net if a future 4th asset or a long negative % ever makes
   things too tight; the sizing below is chosen to fit comfortably as-is. */
@media (max-width:640px){
  .asset-select{
    padding:4px 4px;
    flex-wrap:nowrap;
  }
  .asset-pill{
    flex:1 1 0; min-width:0;
    font-size:10.5px;
    padding:5px 4px;
    gap:4px;
    justify-content:center;
    overflow:hidden;
  }
  .asset-pill__label{
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0;
  }
  .asset-pill__chg{ font-size:10px; flex:none; }
  .asset-select--stacked .asset-pill{ padding:4px 4px 5px; }
}

/* ---------- exchange toggles + tape toolbar, combined into one row ----------
   Was two full-width bars stacked on top of each other (exch-select, then
   tape-toolbar) — same content, just sharing a single border-bottom/background
   now so Settings/Cluster/Pause/Clear/Fullscreen sit inline with Binance/
   Bybit/OKX instead of costing an extra row. flex-wrap lets the toolbar drop
   to its own line on narrow phones if the two groups don't both fit. */
.exch-toolbar-row{
  display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:4px 10px;
  border-bottom:1px solid var(--line);
  background:var(--panel);
}
.exch-toolbar-row .exch-select,
.exch-toolbar-row .tape-toolbar{
  border-bottom:none; background:transparent;
}
.exch-toolbar-row .exch-select{ padding-right:0; }
.exch-toolbar-row .tape-toolbar{ padding-left:0; }
/* Desktop: the collapsible wrapper is transparent to layout so
   .exch-select/.tape-toolbar behave exactly as if they were direct
   children of .exch-toolbar-row, same as before this wrapper existed. */
.exch-toolbar-row__collapsible{ display:contents; }
.exch-toolbar-row__toggle{ display:none; }
@media (max-width:640px){
  /* Collapsed by default on phones — hidden until the "More" bar
     (below) is tapped, to save vertical space. Full-width slim bar with
     a visible label + chevron so it actually reads as tappable, instead
     of a small icon-only button that's easy to miss. */
  .exch-toolbar-row__collapsible{
    display:none;
    width:100%;
    flex-wrap:wrap; align-items:center; gap:4px 10px;
  }
  .exch-toolbar-row__collapsible--open{ display:flex; }
  .exch-toolbar-row__toggle{
    display:flex; align-items:center; justify-content:center; gap:6px;
    width:100%;
    padding:4px 8px;
    font-family:var(--font-mono); font-size:11px; font-weight:600;
    letter-spacing:.04em; text-transform:uppercase;
    color:var(--mute);
    background:transparent;
    border:none;
    cursor:pointer;
  }
  .exch-toolbar-row__toggle-chevron{ font-size:10px; line-height:1; transition:transform .15s ease; }
  .exch-toolbar-row__toggle[aria-expanded="true"]{ color:var(--signal); }
  .exch-toolbar-row__toggle[aria-expanded="true"] .exch-toolbar-row__toggle-chevron{ transform:rotate(180deg); }
}
/* ---------- exchange toggle chips ---------- */
.exch-select{
  display:flex; align-items:center; gap:14px; flex-wrap:wrap;
  padding:5px 10px;
  border-bottom:1px solid var(--line);
  background:var(--panel);
}
.exch-pill{
  display:flex; align-items:center; gap:6px;
  font-family:var(--font-mono); font-size:12px; font-weight:600;
  letter-spacing:.03em;
  color:var(--mute-dim);
  background:transparent;
  border:none;
  padding:2px 0;
  cursor:pointer;
  opacity:.55;
  transition:opacity .15s ease, color .15s ease;
}
.exch-pill:hover{ opacity:.8; }
.exch-pill--active{ opacity:1; color:var(--ink); }
.exch-pill__dot{ width:13px; height:13px; border-radius:4px !important; flex:none; display:inline-flex; overflow:hidden; }
.exch-pill__dot svg{ display:block; }

/* ---------- Fáza 2: tape toolbar (font size, stored rows, pause, clear, fullscreen) ---------- */
.tape-toolbar{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  padding:5px 10px;
  border-bottom:1px solid var(--line);
  background:var(--panel);
}
.tape-toolbar__group{ display:flex; align-items:center; gap:6px; }
.tape-toolbar__group--right{ margin-left:auto; gap:8px; }
.tape-toolbar__label{
  font-family:var(--font-mono); font-size:11px; text-transform:uppercase; letter-spacing:.06em;
  color:var(--mute-dim);
}
.tape-toolbar__select{
  font-family:var(--font-mono); font-size:12px;
  background:var(--void); color:var(--ink);
  border:1px solid var(--line);
  padding:2px 5px; cursor:pointer;
}
.toolbar-btn{
  display:inline-flex; align-items:center; gap:5px;
  font-family:var(--font-mono); font-size:12px; font-weight:600;
  letter-spacing:.02em;
  color:var(--mute);
  background:transparent;
  border:1px solid var(--line);
  padding:3px 8px;
  cursor:pointer;
  transition:color .15s ease, border-color .15s ease, background .15s ease;
}
.toolbar-btn:hover{ color:var(--ink); border-color:var(--mute-dim); }
.toolbar-btn:disabled{ opacity:.35; cursor:default; }
.toolbar-btn:disabled:hover{ color:var(--mute); border-color:var(--line); }
.toolbar-btn--sq{ padding:3px 7px; }
/* Subtle outline+tint instead of a solid, glowing gold fill — same
   language already used for .liq-filter--active/.whale-tab--active
   below, just applied consistently to toolbar buttons (Cluster, Pause,
   chart-type toggles, etc.) so "active" reads as a quiet state change
   rather than a bright illuminated control. */
.toolbar-btn--active{ color:var(--signal); background:var(--signal-soft); border-color:var(--signal); }
.toolbar-btn--active:hover{ color:var(--signal); background:rgba(255,200,87,.2); }
.toolbar-btn--active:active{ background:rgba(255,200,87,.28); }
.toolbar-btn:not(.toolbar-btn--active):active{ background:var(--panel-hover); }
.toolbar-btn__icon{ font-size:13.5px; line-height:1; }
@media (max-width:640px){
  .toolbar-btn__label{ display:none; }
  .toolbar-btn{ padding:5px 8px; min-width:36px; min-height:36px; justify-content:center; }
  .toolbar-btn--sq{ min-width:36px; }
  .exch-pill{ padding:8px 4px; min-height:32px; }
}

/* live-term--paused: subtle cue that the tape is frozen while connections stay live */
.live-term--paused .live-tape{ opacity:.6; }

/* fullscreen mode: fill the viewport and let the tape column claim the extra height.
   Both panels are given an explicit height + their own overflow so they scroll
   independently (Trade Tape on the left, sidebar cards on the right) instead of
   the browser's default :fullscreen overflow:auto turning the whole grid into a
   single page-level scroll surface, which is what made the sidebar uncrollable. */
.live-term--fullscreen{
  background:var(--panel);
  padding:12px;
  height:100vh;
  overflow:hidden;
}
.live-term--fullscreen .live-term__main{
  min-height:0; height:100%;
  overflow-y:auto; -webkit-overflow-scrolling:touch;
}
.live-term--fullscreen .live-term__side{
  height:100%; min-height:0;
  overflow-y:auto; -webkit-overflow-scrolling:touch;
}
:fullscreen.live-term{ min-height:100vh; overflow:hidden; }
@media (max-width:980px){
  /* below the breakpoint the tape/sidebar stack in a single column (same
     rule the base .live-term already applies) — let that stack scroll as
     one unit instead of fighting it for a fixed height, same tradeoff
     Immersive Mode makes at this breakpoint. */
  .live-term--fullscreen{ overflow-y:auto; }
  .live-term--fullscreen .live-term__main{ height:auto; overflow-y:visible; }
  .live-term--fullscreen .live-term__side{ height:auto; overflow-y:visible; }
  /* :fullscreen.live-term (higher specificity, above) sets overflow:hidden
     unconditionally — override it here for the native Fullscreen API case
     specifically, or the phone can enter fullscreen but never scroll. */
  :fullscreen.live-term.live-term--fullscreen{ overflow-y:auto; overflow-x:hidden; }
}

/* ---------- Fáza 3: sound alerts popover ---------- */
.sound-control{ position:relative; }
.sound-panel{
  position:absolute; top:calc(100% + 8px); right:0; z-index:20;
  width:240px;
  background:var(--panel); border:1px solid var(--line); border-radius:10px;
  
  padding:12px;
  font-family:var(--font-mono);
}
.sound-panel__head{
  display:flex; align-items:center; justify-content:space-between; gap:8px;
  margin-bottom:10px; padding-bottom:8px;
  border-bottom:1px solid var(--line-soft);
}
.sound-panel__head strong{ font-size:13.5px; color:var(--ink); }
.sound-panel__master{ display:flex; align-items:center; gap:5px; font-size:12px; color:var(--mute); cursor:pointer; }
.sound-panel__profile-row{
  display:flex; align-items:center; justify-content:space-between; gap:8px;
  padding:2px 0 10px; margin-bottom:6px;
  border-bottom:1px solid var(--line-soft);
}
.sound-panel__profile-row label{ font-size:12.5px; color:var(--mute); flex:none; }
.sound-panel__profile-row select{
  flex:1; font-family:var(--font-mono); font-size:12.5px;
  background:var(--void); color:var(--ink);
  border:1px solid var(--line); border-radius:5px;
  padding:3px 6px; cursor:pointer;
}
.sound-panel__volume-row{
  display:flex; align-items:center; gap:8px;
  padding:2px 0 10px;
  margin-bottom:6px;
  border-bottom:1px solid var(--line-soft);
}
.sound-panel__volume-row label{ font-size:12.5px; color:var(--mute); flex:none; }
.sound-panel__volume-row input[type="range"]{
  flex:1; accent-color:var(--signal); cursor:pointer;
}
.sound-panel__volume-value{
  font-size:12px; color:var(--mute-dim); flex:none; min-width:32px; text-align:right;
}
.sound-panel__row{
  display:flex; align-items:center; justify-content:space-between; gap:8px;
  padding:5px 0;
}
.sound-panel__profile{ display:flex; align-items:center; gap:6px; font-size:13px; color:var(--ink); cursor:pointer; }
.sound-panel__profile input{ accent-color:var(--signal); }
.sound-panel__row select{
  font-family:var(--font-mono); font-size:12px;
  background:var(--void); color:var(--ink);
  border:1px solid var(--line); border-radius:5px;
  padding:2px 5px; cursor:pointer;
}
.sound-panel__test{
  width:100%; margin-top:8px;
  font-family:var(--font-mono); font-size:12.5px; font-weight:600;
  color:var(--ink); background:var(--panel, #12151C);
  border:1px solid var(--line); border-radius:6px;
  padding:6px; cursor:pointer;
}
.sound-panel__test:hover{ border-color:var(--mute-dim); }
.sound-panel__hint{
  margin:8px 0 0; font-size:11.5px; line-height:1.4; color:var(--mute-dim);
}

/* ---------- Settings popover (Display + Filters + Sound, consolidated) ---------- */
.filter-control{ position:relative; }
.filter-panel{
  position:absolute; top:calc(100% + 8px); left:0; z-index:20;
  width:200px;
  background:var(--panel); border:1px solid var(--line); border-radius:10px;
  
  padding:12px;
  font-family:var(--font-mono);
}
/* Settings is always a fixed, centered modal dialog — on desktop AND
   mobile — rather than a popover anchored under the toolbar button.
   Being `position:fixed` means its position is purely viewport-relative:
   it can't drift, and it doesn't care where the button that opened it
   lives, whether that's a cramped mobile toolbar or a wide desktop one.
   Previously this centered treatment only kicked in above a min-width
   breakpoint, with a separate anchored-popover styling below it — that
   in-between anchored state (position:absolute, relative to the toolbar
   button) is what let the panel appear to drift/slide as the page
   reflowed from incoming trades. Making it unconditional removes that
   anchored state entirely.
   Centered with `inset:0` + `margin:auto` rather than the more common
   `top/left:50%` + `translate(-50%,-50%)` trick: auto-margins let the
   browser's own fixed-positioning layout center the box in the actual
   viewport directly, with no percentage-of-viewport / transform math for
   anything to go subtly wrong in. */
.filter-panel--settings{
  position:fixed;
  inset:0; margin:auto;
  display:flex; flex-direction:column;
  width:min(760px, calc(100vw - 32px));
  height:fit-content;
  max-width:none;
  max-height:calc(100vh - 64px);
  overflow-y:auto; overscroll-behavior:contain;
  padding:16px 18px 18px;
  box-sizing:border-box;
  box-shadow:0 24px 64px rgba(0,0,0,.5), 0 2px 8px rgba(0,0,0,.3);
  z-index:200;
}
/* position:fixed above has the same specificity as the browser's default
   [hidden]{display:none} rule, but author CSS always wins that tie — so
   without this, the panel would render open (dead center, backdrop and
   all) on page load, before the Settings button is ever clicked. */
.filter-panel--settings[hidden]{ display:none; }
/* Smooth open/close: the panel already toggles the [hidden] attribute in
   JS (trade-tape.js), which is instant with no transition surface — add
   a fade+scale driven by an "is-open" class that JS applies a frame after
   removing [hidden] (and removes a frame before restoring [hidden]), so
   the transition below actually has something to animate between.
   Centering here comes from inset:0+margin:auto above, so the animation
   only needs to scale — no translate offset to keep in sync with it. */
.filter-panel--settings{
  opacity:0;
  transform:scale(.97);
  transition:opacity .16s ease, transform .16s ease;
}
.filter-panel--settings.filter-panel--open{
  opacity:1;
  transform:scale(1);
}
.filter-panel__head{
  display:flex; align-items:center; justify-content:space-between;
  margin:-16px -18px 10px;
  padding:14px 18px 10px;
  background:var(--surface-header);
  border-bottom:1px solid var(--line);
  /* Settings can grow tall enough to scroll (many categories expanded at
     once, especially Notifications) — keep the head (and its close
     button) pinned to the top of that scroll instead of it disappearing
     upward, which on a phone meant scrolling all the way back up just to
     find the way to close the dialog. */
  position:sticky; top:-16px; z-index:2;
}
.filter-panel__head strong{ font-size:13.5px; color:var(--ink); }
.filter-panel__close{
  display:inline-flex; /* Settings is always the modal treatment now */
  align-items:center; justify-content:center;
  width:24px; height:24px; padding:0;
  background:none; border:none; border-radius:6px;
  color:var(--mute-dim); font-size:13.5px; cursor:pointer;
  transition:color .15s ease, background .15s ease;
}
.filter-panel__close:hover{ color:var(--ink); background:rgba(255,255,255,0.06); }
.filter-panel__group{ padding:6px 0; border-bottom:1px solid var(--line-soft); }
.filter-panel__group:last-child{ border-bottom:none; padding-bottom:0; }
.filter-panel__group-label{
  display:block; font-size:11.5px; text-transform:uppercase; letter-spacing:.05em;
  color:var(--mute-dim); margin-bottom:5px;
}
.filter-panel__radio, .filter-panel__checkbox{
  display:flex; align-items:center; gap:6px;
  font-size:13px; color:var(--ink); cursor:pointer;
  padding:2px 0;
}
.filter-panel__radio input, .filter-panel__checkbox input{ accent-color:var(--signal); }
.settings-checkbox{ margin-top:2px; }
.settings-row{
  display:flex; align-items:center; justify-content:space-between; gap:8px;
  padding:4px 0;
}
.settings-row__label{ font-size:13px; color:var(--ink); }
.settings-row__control--buttons{ display:flex; gap:6px; }
.settings-row__select{
  font-family:var(--font-mono); font-size:12.5px;
  background:var(--void); color:var(--ink);
  border:1px solid var(--line); border-radius:5px;
  padding:3px 6px; cursor:pointer;
}
/* ---------- Settings categories: collapsible accordion ---------- */
.settings-categories{ display:flex; flex-direction:column; }
.settings-category{ border-bottom:1px solid var(--line-soft); }
.settings-category:last-child{ border-bottom:none; }
.settings-category__header{
  width:100%; display:flex; align-items:center; gap:8px;
  background:none; border:none; margin:0;
  font-family:var(--font-mono); text-align:left; cursor:pointer;
  padding:9px 2px;
  -webkit-tap-highlight-color:transparent;
}
.settings-category__title{
  flex:1; font-size:12px; text-transform:uppercase; letter-spacing:.05em;
  color:var(--mute-dim);
}
.settings-category__header--open .settings-category__title{ color:var(--ink); }
.settings-category__chevron{
  font-size:11.5px; line-height:1; color:var(--mute-dim);
  transition:transform .15s ease;
}
.settings-category__header--open .settings-category__chevron{ transform:rotate(180deg); color:var(--mute); }
.settings-category__body{ padding:0 2px 10px; }
.settings-category__body[hidden]{ display:none; }
.settings-category__hint{
  font-size:12px; line-height:1.4; color:var(--mute-dim);
  margin:0 0 6px;
}
.settings-subgroup{ padding:4px 0; }
.settings-subgroup .filter-panel__group-label{ margin-bottom:5px; }
.settings-reset-btn{
  width:100%; margin-top:2px;
  font-family:var(--font-mono); font-size:12.5px; font-weight:600;
  color:var(--danger); background:var(--panel, #12151C);
  border:1px solid var(--danger); border-radius:6px;
  padding:7px; cursor:pointer;
  transition:background .12s ease, color .12s ease;
}
.settings-reset-btn:hover{ background:var(--danger); color:var(--void, #0a0b0d); }
.settings-reset-btn:disabled{ opacity:.6; cursor:default; background:var(--panel, #12151C); color:var(--danger); }
.settings-category__header:hover .settings-category__title{ color:var(--ink); }

/* Settings dialog chrome: applies at every width now that the panel is
   always the fixed centered modal (previously gated to min-width:981px,
   with mobile relying on a different, anchored-popover layout). Categories
   lay out in an auto-fit grid — the number of columns grows with the
   panel's own width, not a fixed 2-per-row — so the more room a screen
   has, the shorter (not scrollier) the panel gets; on narrow phones the
   grid naturally collapses to one column. A generous max-height +
   overflow-y:auto is kept purely as a last-resort safety net for very
   short/zoomed-in viewports; in normal use it should never be needed. */
.filter-panel--settings .settings-categories{
  display:grid;
  grid-template-columns:repeat(auto-fit, minmax(220px, 1fr));
  gap:2px 20px;
  align-items:start;
}
.filter-panel--settings .settings-category{
  box-sizing:border-box;
  min-width:0;
}
/* Notifications (sound) has the most controls (profile, volume,
   per-type thresholds, test button) — give it the full width instead
   of squeezing it into one grid cell. */
.filter-panel--settings .settings-category--wide{
  grid-column:1 / -1;
}
/* A translucent backdrop behind the centered dialog: dims the terminal
   so the modal reads clearly as modal, and doubles as a big, obvious
   click target to dismiss it (clicks bubble to the existing document
   click-to-close listener in trade-tape.js — no extra JS needed). */
.filter-panel__backdrop{
  position:fixed; inset:0; z-index:199;
  background:rgba(4,6,10,.6);
  opacity:0; pointer-events:none;
  transition:opacity .16s ease;
}
.filter-panel__backdrop--open{ opacity:1; pointer-events:auto; }
/* Bigger tap targets on the category headers themselves at narrower
   widths, since these are the primary touch controls for showing/hiding
   a whole group. */
@media (max-width:980px){
  .settings-category__header{ padding:11px 2px; }
}
/* Phone-width touch targets: rows/checkboxes/radios/selects get more
   height and breathing room than the desktop density above, since a
   fingertip needs more room than a mouse cursor. Scoped to the settings
   dialog specifically so the compact trade-tape filter popovers
   elsewhere keep their tighter desktop sizing. */
@media (max-width:600px){
  .filter-panel--settings .filter-panel__radio,
  .filter-panel--settings .filter-panel__checkbox{
    padding:7px 0; font-size:14px; gap:9px;
  }
  .filter-panel--settings .filter-panel__radio input,
  .filter-panel--settings .filter-panel__checkbox input{
    width:18px; height:18px;
  }
  .filter-panel--settings .settings-row{ padding:7px 0; }
  .filter-panel--settings .settings-row__select,
  .filter-panel--settings select{
    padding:6px 8px; font-size:13.5px;
  }
  .filter-panel--settings .settings-row__control--buttons .toolbar-btn{
    padding:6px 12px;
  }
}
/* Sound now lives inline inside Settings instead of its own popover —
   same markup/ids as before, just without the floating position and
   its own trigger button (see sound.js: btn is optional there now). */
.sound-panel--inline{
  position:static; width:auto; border:none; border-radius:0; padding:0;
}
.sound-panel--inline .sound-panel__head{ border-bottom:none; padding-bottom:2px; margin-bottom:6px; justify-content:flex-start; }
.sound-panel--divider{ margin-top:12px; padding-top:12px; border-top:1px solid var(--line-soft); }


/* ---------- Fáza 3: recent-trades heatmap strip ---------- */
.tape-heatmap{
  display:flex; align-items:stretch; gap:1px;
  height:20px;
  padding:0 12px;
  background:var(--void);
  border-bottom:1px solid var(--line-soft);
}
.tape-heatmap__cell{ flex:1 1 0; min-width:2px; border-radius:1px; margin:3px 0; }
.tape-heatmap__cell--buy{ background:var(--pulse); }
.tape-heatmap__cell--sell{ background:var(--danger); }
.tape-heatmap__cell--tier1{ opacity:.35; }
.tape-heatmap__cell--tier2{ opacity:.6; }
.tape-heatmap__cell--tier3{ opacity:.85; }
.tape-heatmap__cell--tier4{ opacity:1; }

/* ---------- Fáza 3: biggest-trade-in-5m highlight ---------- */
.tape-row--biggest{
  outline:1px solid var(--signal);
  outline-offset:-1px;
  box-shadow:inset 0 0 0 1px rgba(245,166,35,.25);
  /* the row element is newly created in the DOM whenever a trade becomes
     the biggest-in-5m (see tapeRowSignature/buildTapeRowEl in trade-tape.js),
     so a plain CSS entrance animation fires automatically the moment it's
     inserted — no JS timing hooks needed. Kept short and understated: a
     quick opacity/lift, not a flashy pop. */
  animation:tapeRowBiggestIn .35s ease-out;
}
@keyframes tapeRowBiggestIn{
  from{ opacity:0; transform:translateY(-3px); }
  to{ opacity:1; transform:translateY(0); }
}
@media (prefers-reduced-motion: reduce){
  .tape-row--biggest{ animation:none; }
}
.tape-row__crown{ flex:none; font-size:12.5px; line-height:1; margin-right:-4px; }

/* ---------- Prompt 8: chart+terminal sync — "just landed" row flash ----------
   A brief neutral flash (not tinted per side — buy/sell color already comes
   from the row's own background/text) applied only to a row's very first
   paint, both here on the trade tape and on the liquidations sidebar rows
   further down. Matches the terminal request literally: ~300ms. */
.tape-row--flash-in,
.liq-sidebar__row--flash-in{ animation:rowFlashIn .3s ease-out; }
@keyframes rowFlashIn{
  from{ box-shadow:inset 0 0 0 999px rgba(255,255,255,.18); }
  to{ box-shadow:inset 0 0 0 999px rgba(255,255,255,0); }
}
@media (prefers-reduced-motion: reduce){
  .tape-row--flash-in,
  .liq-sidebar__row--flash-in{ animation:none; }
}

/* ---------- Fáza 3: order flow (buy/sell ratio) card ----------
   Same overlay-bar pattern as .liq-multi-row__bar / .whale-stats__bar: the
   Buy/Sell % legend sits on top of the bar itself (pinned to its two ends)
   instead of on its own line underneath, so all three widgets share one
   visual language for red/green ratio bars. */
.orderflow-ratio-bar-wrap{ position:relative; }
/* Low-sample state: the buy/sell % legend can look 100%-confident off a
   single trade, same as it would off hundreds. Dim it and dash the bar
   outline so a thin sample reads as "noisy", not "settled". The title
   attribute (set in JS) carries the actual trade count on hover/focus. */
.orderflow-ratio-bar-wrap--low-sample .orderflow-ratio-bar{ opacity:.55; }
.orderflow-ratio-bar-wrap--low-sample .orderflow-ratio-bar{
  outline:1px dashed var(--line); outline-offset:2px;
}
.orderflow-ratio-bar-wrap--low-sample .orderflow-ratio-legend__buy,
.orderflow-ratio-bar-wrap--low-sample .orderflow-ratio-legend__sell{ opacity:.75; }
.orderflow-ratio-bar{
  display:flex; height:16px; border-radius:5px; overflow:hidden;
  background:var(--line-soft);
}
.orderflow-ratio-bar__buy{ background:var(--pulse); transition:width .3s ease; }
.orderflow-ratio-bar__sell{ background:var(--danger); transition:width .3s ease; }
.orderflow-ratio-legend{
  position:absolute; inset:0;
  display:flex; justify-content:space-between; align-items:center;
  padding:0 7px;
  font-family:var(--font-mono); font-size:12px;
  pointer-events:none;
}
.orderflow-ratio-legend__buy,
.orderflow-ratio-legend__sell{
  color:#fff; font-weight:700; text-shadow:0 1px 2px rgba(0,0,0,.55);
  white-space:nowrap;
}
.orderflow-ratio-legend b{ font-weight:700; }
/* Compact "last 60 seconds" readout: one line instead of a 2x2 grid under
   its own "Last 60 seconds" heading — cuts the card's height by close to
   half versus the old layout. Sell vol is dropped here since it's already
   implied by the ratio bar/legend directly above. */
.orderflow-60s{
  margin-top:8px; padding-top:8px;
  border-top:1px solid var(--line-soft);
}
.orderflow-60s--compact{
  display:flex; align-items:baseline; justify-content:center; flex-wrap:wrap; gap:5px;
  font-family:var(--font-mono); font-size:13px; color:var(--mute-dim);
}
.orderflow-60s-stat b{ font-size:14.5px; font-weight:700; color:var(--ink); }
.orderflow-60s-sep{ color:var(--line); }
/* Explicit window marker so this row is never mistaken for part of the
   "last 5m" tag in the card head — it's a different, shorter window. */
.orderflow-60s-window{
  display:inline-block; padding:1px 5px; margin-right:2px;
  border:1px solid var(--line); border-radius:3px;
  font-size:10px; font-weight:700; letter-spacing:.02em;
  color:var(--mute-dim); cursor:help;
}

/* ---------- Fáza 3: market stats card (volume / OI / funding / long-short) ---------- */
.mstat-row{
  display:flex; justify-content:space-between; align-items:center;
  padding:6px 0;
  font-family:var(--font-mono); font-size:13.5px;
  border-bottom:1px solid var(--line-soft);
}
.mstat-row:last-child{ border-bottom:none; }
.mstat-label{ color:var(--mute-dim); display:inline-flex; align-items:center; }
.mstat-value{ color:var(--ink); font-weight:600; }

/* Market Pulse column: keep the labels (1m/5m/15m Buy/Sell, Dominant side)
   visible next to the values so the numbers are self-explanatory. */
.marketpulse-card .mstat-value{ text-align:right; }

/* ---------- compact metric tooltips ----------
   Small ⓘ trigger next to a label or value that isn't self-explanatory
   (Order Flow scoring, the various "Volume" figures, funding/OI/long-short,
   cluster counts on the tape, etc). The actual bubble is one shared
   floating element (see metric-tooltips.js) so it's never clipped by a
   card's own layout — this just styles the small trigger itself and, on
   real hover-capable desktop pointers, reveals the bubble without needing
   a click; touch devices always use tap (handled in JS) so there's no
   double-tap-to-click quirk. */
.metric-tip{
  display:inline-flex; align-items:center; justify-content:center;
  width:13px; height:13px; margin-left:5px;
  border-radius:50%; border:1px solid var(--line); background:none;
  color:var(--mute-dim); font-family:var(--font-mono); font-size:10.5px; line-height:1;
  cursor:help; flex-shrink:0; padding:0; vertical-align:middle;
  transition:color .15s ease, border-color .15s ease;
}
.metric-tip:hover, .metric-tip:focus-visible, .metric-tip--open{
  color:var(--signal); border-color:var(--signal); outline:none;
}
/* Mobile: keep the glyph's small inline size (it sits mid-sentence next to
   labels like "Open interest") but give it a real ~32px tap target via an
   invisible expanded hit-area, instead of enlarging the visible dot. */
@media (max-width:760px){
  .metric-tip{ position:relative; }
  .metric-tip::after{
    content:''; position:absolute; top:50%; left:50%;
    transform:translate(-50%,-50%); width:32px; height:32px;
  }
}
.metric-tip-bubble{
  position:absolute; z-index:130; display:none;
  background:var(--panel); border:1px solid var(--line); border-radius:var(--radius-sm);
  padding:8px 10px; box-shadow:0 10px 30px rgba(0,0,0,.45);
  font-family:var(--font-mono); font-size:12.5px; line-height:1.5; color:var(--mute);
}
.metric-tip-bubble.open{ display:block; }

/* ---------- Prompt 9: Market Pulse card ---------- */
.tag--pos{ color:var(--pulse); border-color:rgba(0,255,136,.35); background:rgba(0,255,136,.08); }
.tag--neg{ color:var(--danger); border-color:rgba(255,77,77,.35); background:rgba(255,77,77,.08); }
/* Smoother "feel" when a tag flips direction (e.g. the live chart's price
   tag going from pos to neg on a tick) instead of an instant hard swap. */
.tag--pos, .tag--neg{ transition:background .2s ease, border-color .2s ease, color .2s ease; }

/* ---------- Prompt 10: Order Flow Score card ----------
   Redesigned for a faster read than the old -100..+100 gauge: a headline
   ("Buy Pressure" / "Sell Pressure"), the buy/sell split as two big
   numbers, a simple two-color bar for the same split, then the numeric
   score and its Bullish/Bearish/Neutral label — everything a trader needs
   in one glance, top to bottom, no gauge math required. */
.ofscore-pressure{ text-align:center; margin-bottom:2px; }
.ofscore-pressure__label{
  font-size:12.5px; font-weight:700; color:var(--mute-dim);
  text-transform:uppercase; letter-spacing:.05em;
  margin-bottom:4px;
}
.ofscore-pressure__label.pos{ color:var(--pulse); }
.ofscore-pressure__label.neg{ color:var(--danger); }
.ofscore-pressure__ratio{
  font-family:var(--font-mono); font-size:25px; font-weight:700;
  line-height:1.1; margin-bottom:7px;
}
.ofscore-pressure__buy{ color:var(--pulse); }
.ofscore-pressure__sell{ color:var(--danger); }
.ofscore-pressure__sep{ color:var(--mute-dim); font-weight:400; margin:0 2px; }
.ofscore-pressure__bar{
  display:flex; height:10px; border-radius:5px; overflow:hidden;
  background:var(--line-soft);
  margin-bottom:10px;
}
.ofscore-pressure__bar-buy{ background:var(--pulse); transition:width .3s ease; }
.ofscore-pressure__bar-sell{ background:var(--danger); transition:width .3s ease; }
.ofscore-value{
  font-family:var(--font-mono); font-size:28px; font-weight:700;
  text-align:center; color:var(--ink); line-height:1.1;
}
.ofscore-value.pos{ color:var(--pulse); }
.ofscore-value.neg{ color:var(--danger); }
.ofscore-label{
  text-align:center; font-size:12.5px; color:var(--mute-dim);
  text-transform:uppercase; letter-spacing:.04em;
  margin-top:2px; margin-bottom:10px;
}

/* Exchange marks: small rounded-square icon tiles (each SVG paints its own
   brand-accurate background + mark) instead of the old flat 3-letter text
   badges — so an exchange is tellable apart by its tile at a glance. */
.tape-row__exch, .liq-sidebar__exch, .whale-exch{
  flex:none;
  display:inline-flex; align-items:center; justify-content:center;
  border-radius:6px; overflow:hidden;
  box-shadow:0 0 0 1px rgba(255,255,255,0.06);
}
.tape-row__exch{ width:18px; height:18px; }
.liq-sidebar__exch{ width:17px; height:17px; }
.whale-exch{ width:17px; height:17px; }
.tape-row__exch svg, .liq-sidebar__exch svg, .whale-exch svg{ display:block; }

/* ---------- trade tape rows ---------- */
.live-tape{
  flex:1; min-height:0;
  overflow-y:auto;
  padding:4px 0;
  /* very low-contrast scanline texture so the space below the last trade
     (or under the "Waiting for new trades…" indicator on a quiet market)
     reads as intentional terminal surface rather than dead black space.
     Deliberately faint — it should not compete with trade row data. */
  background-image:repeating-linear-gradient(
    0deg,
    rgba(255,255,255,0.018) 0px,
    rgba(255,255,255,0.018) 1px,
    transparent 1px,
    transparent 3px
  );
}
.live-tape__empty{
  padding:40px 16px; text-align:center;
  color:var(--mute-dim); font-size:14.5px;
  display:flex; flex-direction:column; align-items:center; gap:10px;
}
.live-tape__empty-icon{
  font-size:26px; line-height:1; opacity:.35;
}
.live-tape__empty-title{
  font-family:var(--font-mono); font-size:14px; font-weight:700;
  color:var(--mute); letter-spacing:.02em;
}
.live-tape__empty-sub{
  font-size:12.5px; color:var(--mute-dim); max-width:280px;
}
/* Loading variant: a slow pulse on the icon signals "still working on it"
   without implying anything is broken. */
.live-tape__empty--loading .live-tape__empty-icon{
  animation:th-empty-pulse 1.6s ease-in-out infinite;
}
@keyframes th-empty-pulse{
  0%, 100%{ opacity:.25; }
  50%{ opacity:.55; }
}
/* Unavailable variant: static (no pulse) plus an amber accent on the title
   so it visibly reads as a different state from "still loading". */
.live-tape__empty--unavailable .live-tape__empty-title{ color:var(--signal); }
.live-tape__empty--unavailable .live-tape__empty-icon{ opacity:.3; }
/* ---------- idle-state indicator ----------
   Sits at the bottom of the tape panel (not inside the virtualized row
   list — it's a sibling of #live-tape-list, so it's never touched by that
   list's own render/spacer logic). Anchored to the panel rather than the
   scrolling list, so it always reads as "part of the empty space below
   the last trade" whether that gap is small or (during a quiet market)
   fills most of the ~70vh panel. Hidden by default; trade-tape.js adds
   .live-tape-idle--visible once a while has passed with no new prints,
   and removes it the moment the next trade arrives. */
.live-tape-idle{
  position:absolute; left:50%; bottom:16px; transform:translateX(-50%);
  display:flex; align-items:center; gap:7px;
  padding:6px 14px;
  font-family:var(--font-mono); font-size:12.5px; color:var(--mute-dim);
  background:rgba(11,11,11,0.7); border:1px solid var(--line);
  opacity:0; pointer-events:none;
  transition:opacity .4s ease;
  z-index:2;
}
.live-tape-idle--visible{ opacity:1; }
.live-tape-idle__dot{
  width:6px; height:6px; flex:none;
  background:var(--signal);
  animation:liveTapeIdlePulse 1.6s ease-in-out infinite;
}
@keyframes liveTapeIdlePulse{
  0%, 100%{ opacity:.35; transform:scale(.85); }
  50%{ opacity:1; transform:scale(1.15); }
}
@media (prefers-reduced-motion: reduce){
  .live-tape-idle__dot{ animation:none; }
}
.tape-row{
  display:flex; align-items:center; gap:8px;
  padding:1.5px 10px;
  font-family:var(--font-mono); font-size:var(--tape-fs, 11px);
  line-height:1.3;
  border-bottom:1px solid rgba(255,255,255,0.03);
  border-left:2px solid transparent;
}
.tape-row--buy{ background:rgba(0,255,136,.06); }
.tape-row--sell{ background:rgba(255,77,77,.06); }
.tape-row.tape-tier-2{ background-color:rgba(0,255,136,.12); }
.tape-row.tape-tier-2.tape-row--sell{ background-color:rgba(255,77,77,.12); }
.tape-row.tape-tier-3{ font-weight:700; padding-top:5px; padding-bottom:5px; background-color:rgba(0,255,136,.2); }
.tape-row.tape-tier-3.tape-row--sell{ background-color:rgba(255,77,77,.2); }
.tape-row.tape-tier-4{ font-weight:800; padding-top:6px; padding-bottom:6px; background-color:rgba(0,255,136,.32); }
.tape-row.tape-tier-4.tape-row--sell{ background-color:rgba(255,77,77,.32); }

/* ---------- outsized-print highlight hierarchy ($100K / $500K / $1M) ----------
   Layered on top of the buy/sell tint above via a left accent bar + faint
   wash, so direction stays legible while size still stands out. Escalates
   via border thickness + glow within the amber family, not by switching
   to --danger red on the top tier — a big *buy* print (green wash) getting
   a red border/value would read as a sell it isn't. Direction stays the
   tape's own job (background tint, ▲/▼ side glyph, price colour); this
   hierarchy is purely "how big", so it never touches red/green. */
.tape-row.tape-hl-1{ border-left-color:rgba(255,200,87,.55); box-shadow:inset 4px 0 10px -8px rgba(255,200,87,.6); }
.tape-row.tape-hl-2{ border-left-color:var(--signal); background-image:linear-gradient(90deg, rgba(255,200,87,.14), rgba(255,200,87,.05) 60%); }
.tape-row.tape-hl-3{
  border-left-width:4px;
  border-left-color:var(--signal);
  background-image:linear-gradient(90deg, rgba(255,200,87,.26), rgba(255,200,87,.07) 65%);
  box-shadow:inset 0 0 0 1px rgba(255,200,87,.3);
  font-weight:800;
}
.tape-row.tape-hl-3 .tape-row__value{ color:var(--signal); }

/* ---------- Settings: Terminal — Highlight whale trades toggles ----------
   trade-tape.js always computes tape-hl-1/2/3 for every row; these shell
   modifiers (flipped by settings-extras.js) neutralize a tier's accent
   without touching the size-based tape-tier-N bolding above, which is a
   separate always-on density cue. th-hl-off is the master "Highlight whale
   trades" switch; th-hl-N-off are the individual >100k/>500k/>1M toggles. */
.th-hl-off .tape-row.tape-hl-1,
.th-hl-off .tape-row.tape-hl-2,
.th-hl-off .tape-row.tape-hl-3,
.th-hl-1-off .tape-row.tape-hl-1,
.th-hl-2-off .tape-row.tape-hl-2,
.th-hl-3-off .tape-row.tape-hl-3{
  border-left-color:transparent; box-shadow:none; background-image:none;
}
.th-hl-off .tape-row.tape-hl-3 .tape-row__value,
.th-hl-3-off .tape-row.tape-hl-3 .tape-row__value{ color:inherit; }

/* ---------- Settings: Terminal — Show volumes toggle ---------- */
.th-hide-volumes .tape-row__value{ display:none; }

.tape-row__side{ flex:none; width:12px; text-align:center; font-size:11.5px; }
.tape-row--buy .tape-row__side{ color:var(--pulse); }
.tape-row--sell .tape-row__side{ color:var(--danger); }
.tape-row__price{ flex:none; width:90px; color:var(--ink); font-variant-numeric:tabular-nums; }
.tape-row--buy .tape-row__price{ color:var(--pulse); }
.tape-row--sell .tape-row__price{ color:var(--danger); }
.tape-row__qty{ flex:1; min-width:0; color:var(--mute); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.tape-row__value{ flex:none; width:72px; text-align:right; color:var(--ink); font-weight:600; }
.tape-row__time{ flex:none; width:66px; text-align:right; color:var(--mute-dim); font-size:12.5px; white-space:nowrap; }
.tape-row__cluster{
  flex:none; font-size:11.5px; font-weight:700;
  color:#000000; background:var(--pulse);
  border-radius:999px; padding:1px 6px; line-height:1.4;
  cursor:help;
}
.tape-row--sell .tape-row__cluster{ background:var(--danger); color:#fff; }

/* ---------- Tape modes: Compact / Normal / Large / Whales only ----------
   Normal = the base .tape-row rule above, no class needed. Compact/Large
   only change row density (padding/gap/font); the tier-based padding bumps
   above (tape-tier-3/4) still apply on top of whichever density is active.
   Whales-only doesn't change row layout — the filtering that keeps only
   $100k+ prints happens in trade-tape.js's render() — this just adds a
   small accent so it's visually obvious the mode is active even before any
   trade has arrived. */
.tape-mode--compact .tape-row{ padding-top:1px; padding-bottom:1px; gap:8px; font-size:var(--tape-fs, 10px); }
.tape-mode--compact .tape-row.tape-tier-3{ padding-top:3px; padding-bottom:3px; }
.tape-mode--compact .tape-row.tape-tier-4{ padding-top:4px; padding-bottom:4px; }

.tape-mode--large .tape-row{ padding-top:8px; padding-bottom:8px; gap:12px; font-size:var(--tape-fs, 14px); }
.tape-mode--large .tape-row.tape-tier-3{ padding-top:11px; padding-bottom:11px; }
.tape-mode--large .tape-row.tape-tier-4{ padding-top:14px; padding-bottom:14px; }
.tape-mode--large .tape-row__value{ width:88px; }

.tape-mode--whales .live-tape{ border-top:2px solid var(--signal); }
.tape-mode--whales .tape-row{ border-left:2px solid rgba(255,200,87,.4); }

/* ---------- terminal typography + density pass ----------
   IBM Plex Mono everywhere inside the sidebar (headers were inheriting the
   site's display font), and tighter card padding so the 2-column grid
   above reads as dense/information-rich rather than airy. */
.live-term__side .widget-card{
  background:transparent;
  border:none;
  border-bottom:1px solid var(--line);
  padding:8px 10px;
}
.live-term__side .widget-card:last-child{ border-bottom:none; }
.live-term__side .widget-card__head{ margin-bottom:6px; }
.live-term__side .widget-card__head h4{
  font-family:var(--font-mono); font-size:12.5px; font-weight:700;
  text-transform:uppercase; letter-spacing:.07em; color:var(--mute);
}
.live-term__side .mstat-row{ padding:2px 0; font-size:12.5px; }

/* ---------- sidebar: single-column stack ----------
   Was a 2-column dense grid pairing narrow stat cards side by side
   (Whale Tracker | Market Overview, Statistics | Watchlist, etc.); now that
   Whale Tracker and Market Overview·Statistics have moved out into the
   Volume panel (.live-term__main), Squeeze Detector is the only card here that
   was ever narrow enough to pair — with nothing left to pair it with, a
   2-column grid just leaves an empty half-width gap next to it, so this
   drops to a plain single-column stack instead. */
.live-term__side{
  min-width:0;
  display:grid;
  grid-template-columns:1fr;
  gap:0; align-content:start;
  border-left:1px solid var(--line);
  background:var(--void);
  position:relative;
  /* ---------- scroll-boundary fades ----------
     A soft inset shadow at the top/bottom edges hints that the card list
     continues beyond view. Lives on the container's own box (not a scrolled
     child), so it stays anchored at the edges whether the sidebar scrolls
     independently (fullscreen, via overflow-y:auto) or the whole page
     scrolls past it below the 980px breakpoint — and it never covers or
     intercepts clicks on the cards underneath. */
  box-shadow:
    inset 0 24px 16px -16px rgba(0,0,0,.55),
    inset 0 -24px 16px -16px rgba(0,0,0,.55);
}
.live-term__side .widget-card{ min-width:0; }
/* ---------- customizable dashboard: hidden widgets ----------
   display:none (not visibility/opacity) so the stack immediately closes the
   gap left behind — no manual reflow needed. The card stays in the DOM and
   keeps receiving live updates underneath; only its box is pulled from the
   layout. */
.live-term__side .widget-card.widget-card--hidden,
.live-term__side .wc-split-col.widget-card--hidden{ display:none !important; }
/* Order book depth heatmap + Liquidations ticker: same toggle mechanism as
   the sidebar widgets above, but these two cards sit outside #live-term-side
   (they're full-width cards further down the Crypto panel), so they need
   their own (unscoped) display:none rule. */
.dom-heatmap-card.widget-card--hidden,
.liq-ticker-card.widget-card--hidden{ display:none !important; }
/* ---------- Volume panel: Whales + Market Overview·Statistics ----------
   Live directly inside .live-term__main, below the trade tape — under the
   TRADINGHUB TERMINAL header, in the same bordered panel, not a separate
   column. No drag handle (not part of the right sidebar's reorder set). */
.live-term__main .whale-card,
.live-term__main .mktoverview-card{
  background:transparent;
  border:none;
  border-top:1px solid var(--line);
  padding:8px 10px;
  min-width:0;
  flex:none;
}
.live-term__main .widget-card__head{ margin-bottom:6px; }
.live-term__main .whale-card .widget-card__head h4,
.live-term__main .mktoverview-card .widget-card__head h4{
  font-family:var(--font-mono); font-size:12.5px; font-weight:700;
  text-transform:uppercase; letter-spacing:.07em; color:var(--mute);
}
.live-term__main .mktoverview-card .mstat-row{ padding:2px 0; font-size:12.5px; }

.liq-sidebar{ display:flex; flex-direction:column; }
.liq-sidebar .widget-card__body{ display:flex; flex-direction:column; min-height:0; flex:1; }
.liq-sidebar__src{
  font-family:var(--font-mono); font-size:11.5px; font-weight:500;
  color:var(--mute-dim); text-transform:uppercase; letter-spacing:.05em;
  margin-left:8px;
}

/* ---------- Liquidations: stats summary ---------- */
.liq-stats{ padding-bottom:10px; margin-bottom:8px; border-bottom:1px solid var(--line-soft); }

/* ---------- Liquidations: all timeframes at once (15m/30m/1h/4h) ----------
   Every window renders as its own block — window label on top, then
   Long/Short side by side as value-over-label pairs — separated from the
   next window by a dashed divider. No Total figure and no filter row;
   the feed below always shows everything. */
.liq-multi{ display:flex; flex-direction:column; }
.liq-multi-block{
  padding:7px 0;
  border-bottom:1px dashed var(--line-soft);
}
.liq-multi-block:first-child{ padding-top:0; }
.liq-multi-block:last-child{ padding-bottom:0; border-bottom:none; }
.liq-multi-block__win{
  display:block;
  font-family:var(--font-mono); font-size:11.5px; font-weight:700; letter-spacing:.03em;
  color:var(--mute-dim); text-transform:uppercase;
  margin-bottom:5px;
}
.liq-multi-block__sides{
  display:flex; align-items:stretch; gap:8px;
}
.liq-multi-block__side{
  flex:1 1 0; min-width:0;
  display:flex; flex-direction:column; align-items:center; gap:1px;
}
.liq-multi-block__value{
  font-family:var(--font-mono); font-size:19px; font-weight:800;
  color:var(--ink); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:100%;
  line-height:1.15;
}
.liq-multi-block__label{
  font-family:var(--font-mono); font-size:10px; font-weight:600; letter-spacing:.06em;
  color:var(--mute-dim);
}
.liq-multi-block__side--long .liq-multi-block__value{ color:var(--danger); }
.liq-multi-block__side--short .liq-multi-block__value{ color:var(--pulse); }
@media (max-width:640px){
  .liq-multi-block__value{ font-size:17px; }
}

/* ---------- Squeeze Detector card ----------
   Longs/Shorts destroyed reuses the same two-column stat pattern as
   .liq-multi-block above (long = --danger, short = --pulse — same colors,
   since a short liquidation is what feeds a bullish squeeze). The verdict
   line below escalates LOW/MEDIUM/HIGH via weight/glow within the same
   directional color rather than switching hue, same convention as the
   tape's outsized-print highlight tiers. */
.squeeze-destroyed{
  display:flex; align-items:stretch; gap:8px;
  padding-bottom:9px; margin-bottom:9px;
  border-bottom:1px dashed var(--line-soft);
}
.squeeze-destroyed__col{
  flex:1 1 0; min-width:0;
  display:flex; flex-direction:column; align-items:center; gap:1px;
}
.squeeze-destroyed__value{
  font-family:var(--font-mono); font-size:19px; font-weight:800;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:100%;
  line-height:1.15;
}
.squeeze-destroyed__col--long .squeeze-destroyed__value{ color:var(--danger); }
.squeeze-destroyed__col--short .squeeze-destroyed__value{ color:var(--pulse); }
.squeeze-destroyed__label{
  font-family:var(--font-mono); font-size:10px; font-weight:600; letter-spacing:.06em;
  color:var(--mute-dim); text-transform:uppercase;
}
.squeeze-verdict{
  display:flex; flex-direction:column; align-items:center; gap:3px;
  padding:4px 0 9px;
}
.squeeze-verdict__label{
  font-family:var(--font-mono); font-size:16px; font-weight:800; letter-spacing:.03em;
  color:var(--ink);
}
.squeeze-verdict__label.pos{ color:var(--pulse); }
.squeeze-verdict__label.neg{ color:var(--danger); }
.squeeze-verdict__level{
  font-family:var(--font-mono); font-size:11px; font-weight:700; letter-spacing:.08em;
  padding:1px 8px; border-radius:3px; border:1px solid var(--line);
  color:var(--mute-dim);
}
.squeeze-verdict__level:empty{ display:none; }
.squeeze-verdict__level--low.pos{ color:var(--pulse); border-color:rgba(0,255,136,.3); background:rgba(0,255,136,.06); }
.squeeze-verdict__level--low.neg{ color:var(--danger); border-color:rgba(255,77,77,.3); background:rgba(255,77,77,.06); }
.squeeze-verdict__level--medium.pos{ color:var(--pulse); border-color:rgba(0,255,136,.45); background:rgba(0,255,136,.12); font-weight:800; }
.squeeze-verdict__level--medium.neg{ color:var(--danger); border-color:rgba(255,77,77,.45); background:rgba(255,77,77,.12); font-weight:800; }
.squeeze-verdict__level--high.pos{
  color:var(--pulse); border-color:var(--pulse); background:rgba(0,255,136,.18); font-weight:800;
  box-shadow:0 0 10px rgba(0,255,136,.25);
}
.squeeze-verdict__level--high.neg{
  color:var(--danger); border-color:var(--danger); background:rgba(255,77,77,.18); font-weight:800;
  box-shadow:0 0 10px rgba(255,77,77,.25);
}
.squeeze-factors{
  display:flex; align-items:center; justify-content:center; flex-wrap:wrap;
  gap:5px 10px;
  font-family:var(--font-mono); font-size:11px; color:var(--mute-dim);
}

.liq-sidebar__head-row{
  display:flex; align-items:center; gap:6px;
  padding:4px 6px 8px;
  font-family:var(--font-mono); font-size:11.5px; text-transform:uppercase; letter-spacing:.05em;
  color:var(--mute-dim);
  border-bottom:1px solid var(--line-soft);
}
.liq-sidebar__head-row span:nth-child(1){ flex:none; width:22px; }
.liq-sidebar__head-row span:nth-child(2){ flex:none; width:44px; }
.liq-sidebar__head-row span:nth-child(3){ flex:none; width:50px; }
.liq-sidebar__head-row span:nth-child(4){ flex:1; }
.liq-sidebar__head-row span:nth-child(5){ flex:none; width:64px; }
.liq-sidebar__head-row .ta-r{ text-align:right; }

.liq-sidebar__list{
  list-style:none; margin:0; padding:0;
  flex:1; min-height:0; overflow-y:auto;
  max-height:400px;
}
.liq-sidebar__empty{
  padding:20px 8px; text-align:center;
  color:var(--mute-dim); font-size:13.5px; list-style:none;
}
.liq-sidebar__row{
  display:flex; align-items:center; gap:6px;
  padding:6px;
  font-family:var(--font-mono); font-size:13px;
  border-bottom:1px solid rgba(255,255,255,0.03);
}
.liq-sidebar__row--long{ background:rgba(255,77,77,.10); }
.liq-sidebar__row--short{ background:rgba(0,255,136,.10); }
.liq-sidebar__sym{ flex:none; width:44px; font-weight:700; color:var(--ink); }
.liq-sidebar__side{ flex:none; width:50px; font-size:12px; white-space:nowrap; }
.liq-sidebar__row--long .liq-sidebar__side{ color:var(--danger); }
.liq-sidebar__row--short .liq-sidebar__side{ color:var(--pulse); }
.liq-sidebar__usd{ flex:1; text-align:right; font-weight:700; color:var(--ink); }
.liq-sidebar__time{ flex:none; width:64px; text-align:right; color:var(--mute-dim); font-size:12px; white-space:nowrap; }

/* ---------- unusually-large liquidation highlighting ----------
   Same three tiers as the trade tape's highlightTier() ($100k/$500k/$1M),
   layered as an inset ring on top of the long/short background tint so
   both signals stay visible at once. Escalates via ring thickness/
   brightness within the amber family, not by switching to red/green — a
   big *short* liquidation (green row) ringed in --danger would read as a
   sell signal it isn't, so size stays on its own amber channel. */
.liq-sidebar__row--tier1{ box-shadow:inset 0 0 0 1px rgba(255,200,87,.35); }
.liq-sidebar__row--tier2{ box-shadow:inset 0 0 0 1px rgba(255,159,10,.55); }
.liq-sidebar__row--tier3{ box-shadow:inset 0 0 0 2px rgba(255,159,10,.9); }
.liq-sidebar__row--tier2 .liq-sidebar__usd,
.liq-sidebar__row--tier3 .liq-sidebar__usd{ color:var(--signal); }

/* thin scrollbars to match the rest of the terminal */
.live-tape, .liq-sidebar__list, .live-term__side{ scrollbar-width:thin; scrollbar-color:var(--line) transparent; }
.live-tape::-webkit-scrollbar, .liq-sidebar__list::-webkit-scrollbar, .live-term__side::-webkit-scrollbar{ width:6px; }
.live-tape::-webkit-scrollbar-thumb, .liq-sidebar__list::-webkit-scrollbar-thumb, .live-term__side::-webkit-scrollbar-thumb{ background:var(--line); border-radius:3px; }

/* ---------- Prompt 11: Whale Tracker card ---------- */

/* ---------- Whale Tracker: stats summary ---------- */
.whale-stats{ padding-bottom:8px; margin-bottom:8px; border-bottom:1px solid var(--line-soft); }
.whale-stats__row{ display:flex; gap:10px; }
.whale-stats__item{ flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; font-family:var(--font-mono); }
.whale-stats__label{ font-size:11.5px; color:var(--mute-dim); text-transform:uppercase; letter-spacing:.04em; }
.whale-stats__value{ font-size:14.5px; font-weight:700; color:var(--ink); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }

/* Empty state: no whale trades recorded yet for this asset — collapse the
   whole card to one short line instead of showing an empty stats row,
   empty filter tabs and an empty list stacked on top of each other. */
.whale-card--empty .widget-card__head{ margin-bottom:2px; }
.whale-card--empty .widget-card__body{
  height:auto; padding-top:0; padding-bottom:0;
}
.whale-empty-msg{
  font-family:var(--font-mono); font-size:13.5px; color:var(--mute-dim);
  line-height:1.3;
}
.whale-empty-msg[hidden]{ display:none; }

.whale-tabs{ display:flex; flex-wrap:wrap; gap:5px; margin-bottom:8px; }
.whale-tab{
  flex:1 1 auto; padding:5px 6px;
  font-family:var(--font-mono); font-size:12px; font-weight:600;
  color:var(--mute-dim); background:var(--void);
  border:1px solid var(--line); border-radius:6px;
  cursor:pointer; transition:color .15s ease, border-color .15s ease, background .15s ease;
  white-space:nowrap;
}
.whale-tab:hover{ color:var(--ink); }
.whale-tab--active{ color:var(--ink); border-color:var(--signal); background:rgba(255,255,255,0.04); }
.whale-head-row{
  display:flex; align-items:center; gap:6px;
  padding:4px 6px 8px;
  font-family:var(--font-mono); font-size:11.5px; text-transform:uppercase; letter-spacing:.05em;
  color:var(--mute-dim);
  border-bottom:1px solid var(--line-soft);
}
.whale-head-row span:nth-child(1){ flex:none; width:26px; }
.whale-head-row span:nth-child(2){ flex:none; width:36px; }
.whale-head-row span:nth-child(3){ flex:none; width:54px; }
.whale-head-row span:nth-child(4){ flex:1; }
.whale-head-row span:nth-child(5){ flex:none; width:64px; }
.whale-head-row .ta-r{ text-align:right; }
.whale-list{
  list-style:none; margin:0; padding:0;
  max-height:340px; overflow-y:auto;
  scrollbar-width:thin; scrollbar-color:var(--line) transparent;
}
.whale-list::-webkit-scrollbar{ width:6px; }
.whale-list::-webkit-scrollbar-thumb{ background:var(--line); border-radius:3px; }
.whale-empty{
  padding:20px 8px; text-align:center;
  color:var(--mute-dim); font-size:13.5px; list-style:none;
}
.whale-row{
  display:flex; align-items:center; gap:6px;
  padding:6px;
  font-family:var(--font-mono); font-size:13px;
  border-bottom:1px solid rgba(255,255,255,0.03);
}
.whale-row--buy{ background:rgba(0,255,136,.10); }
.whale-row--sell{ background:rgba(255,77,77,.10); }
.whale-pair{ flex:none; width:36px; font-weight:700; color:var(--ink); }
.whale-side{ flex:none; width:54px; font-size:12px; white-space:nowrap; }
.whale-row--buy .whale-side{ color:var(--pulse); }
.whale-row--sell .whale-side{ color:var(--danger); }
.whale-value{ flex:1; text-align:right; font-weight:700; color:var(--ink); }
.whale-time{ flex:none; width:64px; text-align:right; color:var(--mute-dim); font-size:12px; white-space:nowrap; }

/* ---------- unusually-large whale trade highlighting ----------
   Same three tiers as the trade tape's highlightTier() ($100k/$500k/$1M).
   Escalates via ring thickness/brightness within the amber family, not by
   switching to red/green — direction is already shown by the row's own
   buy/sell tint (.whale-row--buy/--sell above), so a size-based ring in
   --danger would silently repaint a *buy* row red once it got big enough. */
.whale-row--tier1{ box-shadow:inset 0 0 0 1px rgba(255,200,87,.35); }
.whale-row--tier2{ box-shadow:inset 0 0 0 1px rgba(255,159,10,.55); }
.whale-row--tier3{ box-shadow:inset 0 0 0 2px rgba(255,159,10,.9); }
.whale-row--tier2 .whale-value,
.whale-row--tier3 .whale-value{ color:var(--signal); }

/* ---------- big-trade flash (flash-effects.js) ----------
   A brief pulse across the whole live-tape panel on $100k+/$500k+/$1M+
   prints, so a whale trade registers even if you're not staring at the
   tape row itself. Buy = green tint, sell = red tint; intensity and
   duration scale with size. Border-box only (box-shadow), so it never
   shifts layout. */
.live-term--flash-buy{ --flash-rgb: 0,255,136; }
.live-term--flash-sell{ --flash-rgb: 255,77,77; }
.live-term--flash-t1{ animation: liveTermFlash .5s ease-out; }
.live-term--flash-t2{ animation: liveTermFlash .7s ease-out; }
.live-term--flash-t3{ animation: liveTermFlashBig 1s ease-out; }
@keyframes liveTermFlash{
  0%{ box-shadow: inset 0 0 0 1px rgba(var(--flash-rgb,0,255,136),.5), 0 0 26px -4px rgba(var(--flash-rgb,0,255,136),.4); }
  100%{ box-shadow: inset 0 0 0 1px rgba(var(--flash-rgb,0,255,136),0), 0 0 26px -4px rgba(var(--flash-rgb,0,255,136),0); }
}
@keyframes liveTermFlashBig{
  0%{ box-shadow: inset 0 0 0 2px rgba(var(--flash-rgb,0,255,136),.85), 0 0 46px -2px rgba(var(--flash-rgb,0,255,136),.55); }
  55%{ box-shadow: inset 0 0 0 1px rgba(var(--flash-rgb,0,255,136),.4), 0 0 32px -4px rgba(var(--flash-rgb,0,255,136),.32); }
  100%{ box-shadow: inset 0 0 0 1px rgba(var(--flash-rgb,0,255,136),0), 0 0 26px -4px rgba(var(--flash-rgb,0,255,136),0); }
}
@media (prefers-reduced-motion: reduce){
  .live-term--flash-t1, .live-term--flash-t2, .live-term--flash-t3{ animation:none; }
  .livechart-price--flash-up, .livechart-price--flash-down{ animation:none; }
}

/* ---------- Live Chart widget ---------- */
.livechart-card .widget-card__body{ padding-top:2px; }
/* Brief wash of color on the header price tag for a live tick — the
   underlying .tag--pos/.tag--neg background shows again once the
   animation ends (animations don't persist past their keyframes unless
   given fill-mode:forwards, which this deliberately omits). */
@keyframes livechartPriceFlashUp{ 0%{ background:rgba(0,255,136,.38); } 100%{ background:transparent; } }
@keyframes livechartPriceFlashDown{ 0%{ background:rgba(255,77,77,.38); } 100%{ background:transparent; } }
.livechart-price--flash-up{ animation:livechartPriceFlashUp .5s ease-out; }
.livechart-price--flash-down{ animation:livechartPriceFlashDown .5s ease-out; }
.livechart-toolbar{
  display:flex; align-items:center; flex-wrap:wrap; gap:6px 8px;
  margin-bottom:8px;
}
.livechart-toolbar .tape-toolbar__group{ display:flex; align-items:center; gap:4px; }
.livechart-toolbar .tape-toolbar__select{ padding:3px 5px; }
#livechart-type-group{ gap:2px; }
#livechart-type-group .toolbar-btn{ padding:3px 8px; }
/* ---------- mobile overflow ("More") for the secondary chart toolbar
   controls: Indicators, Live/Replay, trendline, h-line, v-line, share,
   fullscreen. Desktop: the wrapper/panel are transparent to layout
   (display:contents) so every button still renders inline exactly as
   before this wrapper existed, and the "More" button itself stays
   hidden. Below the breakpoint the buttons collapse into a popover so
   the main row only shows Symbol/Timeframe/Chart type — see
   wireLiveChartOverflowToggle() in core.js. Styled to match the
   terminal's own "More" toggle (.exch-toolbar-row__toggle above) —
   transparent/borderless, uppercase mono label + chevron that flips
   and turns signal-colored when open — instead of looking like a
   square icon button, so both "More" controls in the terminal read as
   the same control. */
.livechart-overflow{ display:contents; }
.livechart-overflow-btn{ display:none; }
.livechart-overflow-panel{ display:contents; }
@media (max-width:640px){
  /* .livechart-overflow's immediate parent (.tape-toolbar__group--right)
     is otherwise sized to its content and pinned right via margin-left:
     auto — .livechart-overflow's own width:100% below was only ever
     100% of that narrow parent, not of the toolbar row, so the button
     stayed hugging the right edge instead of becoming its own row. */
  .livechart-toolbar .tape-toolbar__group--right{
    width:100%;
    margin-left:0;
  }
  .livechart-overflow{
    display:flex; position:relative;
    width:100%;
    margin-left:0;
    margin-top:4px;
    /* Full-width bar of its own, same as .exch-toolbar-row__toggle above —
       a border-top here reads as the same "separate control" cue the
       terminal's toggle gets from its container's border-bottom, without
       relying on being squeezed against the chart-type icon group. */
    border-left:none;
    border-top:1px solid var(--line);
    padding-left:0;
    padding-top:4px;
  }
  .livechart-overflow-btn{
    display:flex; align-items:center; justify-content:center; gap:6px;
    width:100%;
    padding:4px 8px;
    font-family:var(--font-mono); font-size:11px; font-weight:600;
    letter-spacing:.04em; text-transform:uppercase;
    color:var(--mute);
    background:transparent;
    border:none;
    cursor:pointer;
  }
  .livechart-overflow-btn:hover{ color:var(--ink); }
  .livechart-overflow-btn__chevron{ font-size:10px; line-height:1; transition:transform .15s ease; }
  .livechart-overflow-btn[aria-expanded="true"]{ color:var(--signal); }
  .livechart-overflow-btn[aria-expanded="true"] .livechart-overflow-btn__chevron{ transform:rotate(180deg); }
  .livechart-overflow-panel{
    display:none;
    position:absolute; top:calc(100% + 6px); right:0; z-index:30;
    flex-direction:column; align-items:stretch; gap:4px;
    width:200px;
    background:var(--panel); border:1px solid var(--line); border-radius:10px;
    padding:8px;
    box-shadow:0 10px 28px rgba(0,0,0,.4);
  }
  .livechart-overflow-panel:not([hidden]){ display:flex; }
  .livechart-overflow-panel .toolbar-btn{
    width:100%; justify-content:flex-start;
  }
  .livechart-overflow-panel .toolbar-btn__label{ display:inline; }
  .livechart-overflow-panel .filter-control.livechart-indicator-control{ width:100%; }
  .livechart-overflow-panel .filter-control.livechart-indicator-control > .toolbar-btn{ width:100%; }
  .livechart-overflow-panel .livechart-indicator-panel{
    position:static; width:100%; margin-top:4px;
  }
}
.livechart-indicator-control{ position:relative; }
.livechart-indicator-panel{
  width:190px;
  top:calc(100% + 6px); right:0; left:auto;
}
.livechart-indicator-panel .filter-panel__checkbox{ cursor:pointer; }
/* Oscillator/volume rows get a second control — a small pill that flips
   between "Pane" (own strip below the chart, the long-standing behavior)
   and "Chart" (drawn as a translucent band directly inside the price
   chart). Kept compact since it sits inline with an already-narrow
   checkbox label. */
.livechart-indicator-panel .filter-panel__row{
  display:flex; align-items:center; justify-content:space-between; gap:6px;
}
.livechart-indicator-panel .filter-panel__row .filter-panel__checkbox{ flex:1; min-width:0; }
.livechart-ind-place{
  flex:none; border:1px solid var(--line-soft); background:transparent;
  color:var(--mute-dim); font-size:10.5px; line-height:1;
  padding:3px 7px; border-radius:20px; cursor:pointer;
  transition:color .15s ease, border-color .15s ease, background .15s ease;
}
.livechart-ind-place:hover{ color:var(--ink); border-color:var(--mute-dim); }
.livechart-ind-place[data-placement="overlay"]{
  color:var(--void); background:var(--signal); border-color:var(--signal);
}
/* Replay mode is a UI state, not a market signal, so it uses the shared
   .toolbar-btn--active amber styling (see line ~293) instead of red —
   red is reserved for price/trade direction elsewhere in the terminal. */

/* ---------- Replay Mode: compact scrub/play bar ---------- */
.livechart-replay-bar{
  display:flex; align-items:center; gap:6px;
  margin-bottom:8px;
  padding:4px 8px;
  background:var(--signal-soft);
  border:1px solid rgba(255,200,87,.35);
  border-radius:6px;
}
.livechart-replay-bar[hidden]{ display:none; }
.livechart-replay-bar .toolbar-btn--sq{ padding:2px 7px; font-size:12.5px; flex:0 0 auto; }
.livechart-replay-slider{
  flex:1; min-width:0;
  accent-color:var(--signal);
  height:4px;
  cursor:pointer;
}
.livechart-replay-time{
  font-family:var(--font-mono); font-size:11.5px; color:var(--mute);
  white-space:nowrap;
}
.livechart-replay-speed{ padding:2px 4px; font-size:12.5px; flex:0 0 auto; }

.chart-share-modal{
  position:fixed; inset:0; z-index:970;
  display:none; align-items:center; justify-content:center;
  padding:20px;
}
.chart-share-modal.open{ display:flex; }
.chart-share-modal__backdrop{
  position:absolute; inset:0;
  background:rgba(3,3,3,0.78); backdrop-filter:blur(4px);
}
html.chart-share-lock{ overflow:hidden; }
.chart-share-modal__panel{
  position:relative; width:100%; max-width:480px; max-height:88vh;
  background:var(--panel); border:1px solid var(--line);
  box-shadow:0 24px 70px rgba(0,0,0,.55);
  display:flex; flex-direction:column; gap:10px;
  padding:16px; overflow-y:auto;
}
.chart-share-modal__close{
  position:absolute; top:8px; right:8px; width:28px; height:28px;
  display:flex; align-items:center; justify-content:center;
  background:transparent; border:1px solid var(--line); color:var(--mute);
  font-size:18px; line-height:1; cursor:pointer;
}
.chart-share-modal__close:hover{ color:var(--ink); border-color:var(--mute-dim); }
.chart-share-modal__preview{
  border:1px solid var(--line); background:var(--void);
  display:flex; align-items:center; justify-content:center; overflow:hidden;
}
.chart-share-modal__img{ display:block; width:100%; height:auto; }
.chart-share-modal__label{
  font:600 11px var(--font-mono); color:var(--mute); text-transform:uppercase; letter-spacing:.04em;
}
.chart-share-modal__input{
  width:100%; padding:9px 10px; font:14px var(--font-body); color:var(--ink);
  background:var(--panel-hover); border:1px solid var(--line); border-radius:var(--radius-sm);
}
.chart-share-modal__input:focus{ outline:none; border-color:var(--signal); }
.chart-share-modal__actions{ display:flex; gap:8px; margin-top:2px; }
.chart-share-modal__btn{
  flex:1; padding:10px 12px; font:600 13px var(--font-mono); cursor:pointer;
  background:var(--panel-hover); border:1px solid var(--line); color:var(--ink);
  transition:border-color .15s ease, color .15s ease;
}
.chart-share-modal__btn:hover{ border-color:var(--mute-dim); }
.chart-share-modal__btn--primary{
  background:var(--signal-soft); border-color:var(--signal); color:var(--signal);
}
.chart-share-modal__btn--primary:hover{ background:var(--signal); color:var(--void); }
.chart-share-modal__status{
  font:600 12px var(--font-mono); color:var(--pulse); margin:0; text-align:center;
}
.chart-share-modal__status--error{ color:var(--danger); }
.chart-share-modal__hint{
  font:12px var(--font-body); color:var(--mute-dim); margin:0; line-height:1.4;
}
@media (max-width:520px){
  .chart-share-modal{ padding:0; align-items:flex-end; }
  .chart-share-modal__panel{ max-width:none; max-height:92vh; border-left:0; border-right:0; border-bottom:0; }
}

/* Stats strip under the chart header — 24h high, low, current price + %
   change, volume, and open interest, readable at a glance without needing
   to check the separate Market Overview card. Spread lives as a small
   overlay on the chart itself (see .livechart-chart-spread below). */
.livechart-ticker{
  margin-bottom:6px;
  padding:5px 8px 4px;
  background:var(--void);
  border:1px solid var(--line-soft);
  border-radius:6px;
}
.livechart-ticker__stats{
  display:flex; align-items:stretch;
  gap:1px;
  background:var(--line-soft);
  border:1px solid var(--line-soft);
  border-radius:5px;
  overflow:hidden;
}
/* Wraps the 24H+Low cells and the Vol+OI cells so they can be relocated
   as a unit onto the chart overlay on mobile (see wireLiveChartMobileStats
   in core.js) without disturbing desktop layout — display:contents makes
   the wrapper invisible to layout, so its .livechart-ticker__stat children
   act as direct flex items of .livechart-ticker__stats, same as if there
   were no wrapper at all. */
.livechart-ticker__extra{ display:contents; }
.livechart-ticker__stat{
  flex:1; min-width:0;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:1px;
  padding:3px 3px;
  background:var(--panel, #12151C);
}
.livechart-ticker__stat-label{
  font-size:11px; text-transform:uppercase; letter-spacing:.06em;
  color:var(--mute-dim);
  white-space:nowrap;
  display:inline-flex; align-items:center;
}
.livechart-ticker__stat-value{
  font-family:var(--font-mono); font-size:14px; font-weight:600;
  color:var(--ink);
  white-space:nowrap;
}
/* The 24H/Low cells double as a compact range read, same red/green
   convention the rest of the terminal uses for high/low reference points. */
.livechart-ticker__stat:nth-child(1) .livechart-ticker__stat-value{ color:var(--pulse); }
.livechart-ticker__stat:nth-child(2) .livechart-ticker__stat-value{ color:var(--danger); }
/* The PRICE cell reads as too cramped at the base 1px stat gap — give it
   a bit more room between the label and the value than the other
   (deliberately tight) ticker cells, in both the stacked (default) and
   inline (mobile, see below) layouts. */
.livechart-ticker__stat--price{ gap:6px; }
/* Price + % change cell — same font-mono treatment as the other stat
   values, just two spans side by side instead of one. */
.livechart-ticker__pricechg{
  display:flex; align-items:baseline; gap:7px; min-width:0;
}
.livechart-ticker__stat--price .livechart-ticker__price{
  font-family:var(--font-mono); font-size:14px; font-weight:600;
  line-height:1.1; color:var(--ink); white-space:nowrap;
}
.livechart-ticker__price.pos{ color:var(--pulse); }
.livechart-ticker__price.neg{ color:var(--danger); }
.livechart-ticker__stat--price .livechart-ticker__change{
  font-family:var(--font-mono); font-size:11px; font-weight:600;
  color:var(--mute-dim); white-space:nowrap;
}
.livechart-ticker__change.pos{ color:var(--pulse); }
.livechart-ticker__change.neg{ color:var(--danger); }

/* On phones, 24H/Low/Vol/OI move onto the chart itself (see
   #livechart-chart-stats below and wireLiveChartMobileStats in core.js) —
   the ticker row is left holding just Price+change, so it can breathe
   instead of squeezing 5 cells into one line. */
@media (max-width:640px){
  .livechart-ticker{ margin-bottom:4px; padding:4px 8px; }
  .livechart-ticker__stats{ display:flex; }
  /* Safety net: if JS hasn't relocated them yet (or is unavailable),
     hide 24H/Low/Vol/OI here rather than let them crowd the row —
     they belong on the chart overlay at this width, not in the ticker. */
  .livechart-ticker__extra{ display:none; }
  .livechart-ticker__stat--price{
    flex:1; width:100%;
    flex-direction:row; align-items:baseline; justify-content:center;
    gap:8px;
  }
  .livechart-ticker__stat--price .livechart-ticker__stat-label{ font-size:10px; }
  .livechart-ticker__pricechg{ gap:6px; }
  .livechart-ticker__stat--price .livechart-ticker__price{ font-size:15px; }
  .livechart-ticker__stat--price .livechart-ticker__change{ font-size:11px; }
}

/* ---------- thin stats strip: 24H / Low / Vol / OI (mobile only) ----------
   Relocated here from the ticker row by wireLiveChartMobileStats() in
   core.js. No longer an on-chart overlay — it now sits in normal flow
   right under the toolbar (below the "More" button on phones), as its
   own thin full-width strip above the canvas. Kept at the same small
   type size the values already rendered at on the chart overlay, just
   moved off the canvas so it doesn't cover price action; hairline
   top/bottom rules mark it as its own compact row without spending
   more than a couple of pixels of padding on it. */
.livechart-chart-stats{
  display:none;
}
@media (max-width:640px){
  .livechart-chart-stats{
    display:flex;
    flex-direction:row;
    align-items:baseline;
    justify-content:center;
    flex-wrap:wrap;
    gap:2px 14px;
    padding:3px 0;
    margin:-2px 0 6px;
    border-top:1px solid var(--line);
    border-bottom:1px solid var(--line);
  }
}
/* display:contents so all four stats become direct children of the strip
   above (24H, Low, Vol, OI each their own item) instead of two grouped
   pairs — keeps them flowing as one single-line row. */
.livechart-chart-stats .livechart-ticker__extra{
  display:contents;
}
.livechart-chart-stats .livechart-ticker__stat{
  display:flex; flex-direction:row; align-items:baseline; gap:3px;
  padding:0; background:transparent;
}
.livechart-chart-stats .livechart-ticker__stat-label{
  font-size:6.5px; color:var(--mute-dim);
}
.livechart-chart-stats .livechart-ticker__stat-value{
  font-size:7.5px; color:var(--ink); font-family:var(--font-mono);
}
.livechart-chart-stats .livechart-ticker__stat:nth-child(1) .livechart-ticker__stat-value,
.livechart-chart-stats #livechart-ticker-high{ color:var(--pulse); }
.livechart-chart-stats #livechart-ticker-low{ color:var(--danger); }
.livechart-chart-stats .metric-tip{ display:none; }

@media (max-width:360px){
  .livechart-ticker__stat-label{ font-size:8.5px; }
  .livechart-ticker__stat-value,
  .livechart-ticker__stat--price .livechart-ticker__price{ font-size:10.5px; }
}

.livechart-canvas-wrap{
  position:relative;
  height:267px; /* was 220px, then 270px, then 297px (+10%) — reduced back down ~10% */
  background:var(--void);
  border:1px solid var(--line-soft);
  overflow:hidden;
}
.livechart-canvas-wrap canvas{
  display:block; width:100%; height:100%;
  cursor:crosshair;
  /* The chart handles its own drag-to-pan and pinch-to-zoom (live-chart.js);
     without this the browser also tries to scroll/zoom the page for the
     same touch gestures, fighting the chart for them. */
  touch-action:none;
}
/* ---------- resizable chart height (drag to resize, remembered) ---------- */
.livechart-resize-handle{
  position:absolute; left:0; right:0; bottom:0; height:7px;
  cursor:row-resize;
  z-index:3;
  touch-action:none;
}
.livechart-resize-handle::after{
  content:''; position:absolute; left:0; right:0; bottom:2px; height:1px;
  background:var(--line-soft);
}
.livechart-resize-handle:hover::after,
.livechart-resize-handle--active::after{ bottom:1px; height:3px; background:var(--signal); }
.livechart-card:fullscreen .livechart-resize-handle,
.livechart-card--fullscreen .livechart-resize-handle{ display:none; }
/* ---------- top-left overlay: OHLC legend + spread readout ----------
   Legend and spread readout are stacked in one flex column so the spread
   always sits right after however many lines the legend takes, including
   when the legend (BTC/USDT · 15m + O/H/L/C) wraps to two lines on narrow
   phones — no hardcoded offset that could fall out of sync. */
.livechart-topleft-overlay{
  position:absolute; top:6px; left:8px; z-index:2;
  display:flex; flex-direction:column; gap:3px;
  pointer-events:none;
}
.livechart-legend{
  display:flex; flex-wrap:wrap; gap:2px 10px;
  font-family:var(--font-mono); font-size:11.5px; color:var(--mute);
  text-shadow:0 1px 2px rgba(0,0,0,.8);
}
/* Mobile: the O/H/L/C strip is otherwise a single unwrapped-looking row
   that runs straight into the shaded price-axis panel on the right (it
   already wraps via flex-wrap, but with no right boundary it wraps far
   too late, right at the axis). Stopping it short of the axis makes it
   wrap onto a second line while there's still room, instead of visually
   colliding with the price labels. 24H/Low/Vol/OI no longer render on
   the chart itself below 640px (moved into the thin .livechart-chart-stats
   strip under the toolbar instead), so this only needs to clear the
   price-axis gutter (56px on narrow phones — see chartPadR in
   live-chart.js) plus a small gap. */
@media (max-width:640px){
  .livechart-topleft-overlay{ right:62px; }
}
.livechart-legend b{ font-weight:700; }
.livechart-legend .pos{ color:var(--pulse); }
.livechart-legend .neg{ color:var(--danger); }
/* Small "Spread x.xx%" readout, now just the next flex item after the
   legend instead of an absolutely-positioned sibling. */
.livechart-chart-spread{
  font-family:var(--font-mono); font-size:10.5px; color:var(--mute-dim);
  text-shadow:0 1px 2px rgba(0,0,0,.8);
}
.livechart-chart-spread span{ color:var(--ink); font-weight:700; }
.livechart-marker-legend{
  position:absolute; bottom:14px; left:8px; z-index:2;
  display:flex; flex-wrap:wrap; gap:2px 9px;
  font-family:var(--font-mono); font-size:10.5px; font-weight:700; letter-spacing:.02em;
  pointer-events:none;
  text-shadow:0 1px 2px rgba(0,0,0,.85);
}
.livechart-marker-legend .lcml-item--buy{ color:var(--pulse); }
.livechart-marker-legend .lcml-item--sell{ color:var(--danger); }
.livechart-marker-legend .lcml-item--whale{ color:var(--signal); }
.livechart-marker-legend .lcml-item--liq{ color:var(--ink); }
.livechart-loading{
  position:absolute; inset:0; z-index:3;
  display:flex; align-items:center; justify-content:center;
  font-family:var(--font-mono); font-size:12.5px; color:var(--mute-dim);
  background:rgba(5,5,5,.5);
  transition:opacity .2s ease;
}
.livechart-loading[hidden]{ display:none; }
.livechart-subpane{
  position:relative;
  height:64px; /* fallback for before JS applies the persisted/dragged height */
  margin-top:4px;
  background:var(--void);
  border:1px solid var(--line-soft);
  overflow:hidden;
}
.livechart-subpane canvas{ display:block; width:100%; height:100%; }
.livechart-subpane__label{
  position:absolute; top:3px; left:6px; z-index:2;
  font-family:var(--font-mono); font-size:10.5px; text-transform:uppercase; letter-spacing:.05em;
  color:var(--mute-dim);
  pointer-events:none;
}
/* ---------- resizable subpane height (volume/RSI/MACD/Stoch/ATR — drag to
   resize, remembered, all panes share one height) ---------- */
.livechart-subpane-resize-handle{
  position:absolute; left:0; right:0; bottom:0; height:7px;
  cursor:row-resize;
  z-index:3;
  touch-action:none;
}
.livechart-subpane-resize-handle::after{
  content:''; position:absolute; left:0; right:0; bottom:2px; height:1px;
  background:var(--line-soft);
}
.livechart-subpane-resize-handle:hover::after,
.livechart-subpane-resize-handle--active::after{ bottom:1px; height:3px; background:var(--signal); }

/* Safety net: whatever goes fullscreen on this site should never fall back
   to the browser's own white default — same principle as the ticker bar
   above (hidden/clipped unless a specific rule below opens it up). */
:fullscreen{ background:var(--void); }
::backdrop{ background:var(--void); }

/* fullscreen: the card itself becomes the fullscreen element and grows to
   fill the viewport, same convention as .live-term--fullscreen for the tape */
.livechart-card:fullscreen,
.livechart-card.livechart-card--fullscreen{
  background:var(--panel); padding:12px; height:100vh;
  display:flex; flex-direction:column;
  overflow:hidden;
}
.livechart-card:fullscreen .livechart-canvas-wrap,
.livechart-card--fullscreen .livechart-canvas-wrap{ flex:1; height:auto; min-height:0; }

/* ---------- price alerts ---------- */
/* Lives as a sibling of .livechart-canvas-wrap now (see core.js), not
   inside it — that wrap clips with `overflow:hidden`, which used to slice
   the popover in half whenever its real rendered height exceeded the
   wrap's remaining space. It's `position:absolute` against `.livechart-card`
   (see the `position:relative` rule added below) rather than
   `position:fixed` against the viewport — fixed let it drift away from the
   chart entirely. Anchoring to the card keeps it fully visible AND visually
   attached to the widget it belongs to; see positionAlarmPopover in
   live-chart.js for the clamping math. */
.livechart-card{ position:relative; }
.alarm-popover{
  position:absolute; z-index:50;
  min-width:252px; max-width:280px;
  max-height:calc(100vh - 16px); overflow-y:auto;
  background:var(--panel, #101010); border:1px solid var(--line-soft);
  border-radius:8px;
  padding:12px 14px 14px;
  box-shadow:0 10px 28px rgba(0,0,0,.55);
  font-family:var(--font-mono); font-size:11.5px; color:var(--ink);
}
.alarm-popover[hidden]{ display:none; }

.alarm-popover__header{
  display:flex; align-items:center; justify-content:space-between;
  margin-bottom:10px; padding-bottom:9px;
  border-bottom:1px solid var(--line-soft);
}
.alarm-popover__title{ font-size:12px; font-weight:700; letter-spacing:.02em; color:var(--ink); }
.alarm-popover__close{
  width:20px; height:20px; padding:0; margin:-2px -2px 0 0;
  display:flex; align-items:center; justify-content:center;
  background:transparent; border:none; border-radius:4px;
  color:var(--mute-dim); font-size:16px; line-height:1; cursor:pointer;
}
.alarm-popover__close:hover{ background:var(--void); color:var(--ink); }

.alarm-popover__field{ margin-bottom:12px; }
.alarm-popover__field:last-of-type{ margin-bottom:0; }
.alarm-popover__field > label,
.alarm-popover__field-label{
  display:block; margin-bottom:6px;
  font-size:10px; text-transform:uppercase; letter-spacing:.06em;
  color:var(--mute-dim);
}
.alarm-popover__price-wrap{
  display:flex; align-items:stretch;
  border:1px solid var(--line-soft); border-radius:5px;
  background:var(--void); overflow:hidden;
}
.alarm-popover__price-wrap:focus-within{ border-color:var(--signal); }
.alarm-popover__price-input{
  flex:1 1 auto; min-width:0;
  background:transparent; border:none;
  color:var(--ink); font-family:var(--font-mono); font-size:12.5px; font-weight:600;
  padding:7px 8px;
}
.alarm-popover__price-input:focus{ outline:none; }
.alarm-popover__price-suffix{
  flex:0 0 auto; align-self:center;
  padding:0 9px; color:var(--mute-dim); font-size:10.5px; font-weight:700; letter-spacing:.03em;
  border-left:1px solid var(--line-soft);
}

.alarm-popover__options{ display:flex; flex-direction:column; gap:6px; }
.alarm-popover__option{
  display:flex; align-items:flex-start; gap:8px;
  padding:7px 8px; border:1px solid var(--line-soft); border-radius:5px;
  cursor:pointer; transition:border-color .12s ease, background .12s ease;
}
.alarm-popover__option:hover{ border-color:var(--mute-dim); }
.alarm-popover__option:has(input:checked){
  border-color:var(--signal); background:var(--signal-soft);
}
.alarm-popover__option input{ margin-top:2px; accent-color:var(--signal); flex:0 0 auto; }
.alarm-popover__option-text{ display:flex; flex-direction:column; gap:1px; line-height:1.3; }
.alarm-popover__option-text strong{ font-size:11.5px; font-weight:600; color:var(--ink); }
.alarm-popover__option-text small{ font-size:10px; color:var(--mute-dim); }

.alarm-popover__actions{ display:flex; gap:8px; margin-top:12px; }
.alarm-popover__btn{
  flex:1 1 0; padding:7px 8px;
  background:var(--void); border:1px solid var(--line-soft); border-radius:5px;
  color:var(--ink); font-family:var(--font-mono); font-size:11px; font-weight:600; cursor:pointer;
  transition:border-color .12s ease, opacity .12s ease;
}
.alarm-popover__btn:hover{ border-color:var(--mute-dim); }
.alarm-popover__btn--primary{ background:var(--signal); color:var(--void); border-color:var(--signal); }
.alarm-popover__btn--primary:hover{ opacity:.9; }

.alarm-toast-stack{
  position:absolute; top:8px; right:8px; z-index:6;
  display:flex; flex-direction:column; gap:6px;
  pointer-events:none;
  max-width:min(260px, 70%);
}
.alarm-toast{
  background:rgba(10,10,10,.92); border:1px solid var(--signal);
  border-radius:5px; padding:7px 10px;
  font-family:var(--font-mono); font-size:11px; color:var(--ink);
  box-shadow:0 4px 14px rgba(0,0,0,.5);
  animation:alarm-toast-in .18s ease-out;
}
.alarm-toast b{ color:var(--signal); }
@keyframes alarm-toast-in{ from{ opacity:0; transform:translateY(-6px); } to{ opacity:1; transform:translateY(0); } }
@media (prefers-reduced-motion: reduce){ .alarm-toast{ animation:none; } }

/* Brief whole-chart wash when an alarm fires, same technique as the price-tag flash */
.livechart-canvas-wrap.livechart-canvas-wrap--alarm-flash{ animation:alarm-flash-wash .9s ease-out; }
@keyframes alarm-flash-wash{
  0%{ box-shadow: inset 0 0 0 2px var(--signal); }
  100%{ box-shadow: inset 0 0 0 2px transparent; }
}
@media (prefers-reduced-motion: reduce){ .livechart-canvas-wrap.livechart-canvas-wrap--alarm-flash{ animation:none; } }
.livechart-card:fullscreen .widget-card__body,
.livechart-card--fullscreen .widget-card__body{ flex:1; min-height:0; display:flex; flex-direction:column; }

@media (max-width:640px){
  .livechart-toolbar .tape-toolbar__label{ display:none; }
  /* ~10% shorter than the 267px desktop/default height — phones don't
     have the vertical room to spare, and the chart stays perfectly
     readable smaller. Only the *default* changes; the resize handle
     still drags freely from here exactly as before. */
  .livechart-canvas-wrap{ height:240px; }
  /* "Live Chart" header + drag handle costs a whole row of vertical
     space that's more valuable given to the chart itself on phones.
     Safe to drop entirely here: the handle only supports HTML5
     drag-and-drop (dragstart in layout-persistence.js), which has no
     touch equivalent, so it isn't a working control on mobile anyway. */
  .live-term__side .livechart-card .widget-card__head{ display:none; }
}

/* ============================================================
   Mobile default layout
   Placed at the end of the stylesheet on purpose: several of these
   rules share a selector with an earlier, unconditional rule (e.g.
   .live-term__side's display:grid, .live-tape's flex:1), and at equal
   specificity the later declaration in the file wins whenever both
   apply — so this block needs to come last to reliably override them
   below the breakpoint, without touching the desktop rules themselves.
   ============================================================ */
@media (max-width:980px){
  .live-term{ overflow-x:hidden; }

  /* ---------- reorder: Live Chart first, trade tape second,
     Liquidations third, everything else after ----------
     .live-term__side is only ever a wrapper for the sidebar cards —
     giving it display:contents unwraps it so those cards become direct
     items of the .live-term grid alongside .live-term__main, which lets
     `order` interleave them instead of the whole sidebar always trailing
     the tape as one block. Every descendant selector still matches
     (e.g. ".live-term__side .widget-card"): display:contents only drops
     the wrapper's own box — its border-left/background/scroll-fade
     shadow no longer render — it stays in the DOM. Drag-to-reorder
     (layout-persistence.js) still works exactly as before; it reorders
     the underlying DOM/localStorage, it just no longer changes what's
     drawn here, since this fixed order is the point of a "default"
     mobile layout. */
  .live-term__side{ display:contents; }
  .livechart-card{ order:1; }
  .live-term__main{ order:2; }
  .liq-sidebar{ order:3; }
  .squeeze-card{ order:4; }
  .orderflow-card{ order:5; }
  .pulseflow-card{ order:6; }

  /* ---------- 30 trade rows by default ----------
     The tape used to stretch (flex:1) to fit however many rows were
     currently rendered — easily 1000px+ tall — forcing a long scroll
     before reaching Live Chart/Liquidations below it. A default .tape-row
     (12px text, 1.3 line-height, 1.5px top/bottom padding, 1px border)
     is ~20px tall, so 30 rows is ~600px: fixing .live-tape's height there
     shows 30 rows by default, with the rest reachable by scrolling inside
     the tape itself — same as it already works on desktop, just bounded
     by row count instead of viewport height. The 80vh ceiling only kicks
     in on short/landscape phones — tall enough on ordinary portrait
     phones that it doesn't clip the 30-row target. Live updates,
     clustering, filters, pause/clear, etc. are untouched — this only
     changes how tall the scroll area is. */
  .live-term__main{ height:auto; }
  .live-term__tape-frame{ height:auto; }
  .live-tape{ flex:none; height:600px; max-height:80vh; }

  /* ---------- readability on small screens ---------- */
  .live-term__side .widget-card{ padding:10px 12px; }
  .live-term__side .widget-card__head{ margin-bottom:8px; }
  .live-term__side .widget-card__head h4{ font-size:13px; }
  .live-term__side .mstat-row{ padding:4px 0; font-size:13px; }
  .liq-sidebar__row, .whale-row{ padding:6px 6px; }

  /* ---------- mobile-only: compress Liquidations + Whales, less visual
     noise (fewer dividers, tighter spacing) — desktop stays untouched. ---------- */
  .liq-stats{ padding-bottom:8px; margin-bottom:6px; }
  .liq-multi{ display:grid; grid-template-columns:1fr 1fr; gap:8px 14px; }
  .liq-multi-block{ padding:0; border-bottom:none; }
  .liq-multi-block__win{ margin-bottom:3px; }
  .liq-sidebar__head-row{ padding:4px 6px 6px; }
  .whale-head-row{ padding:4px 6px 6px; }
  .whale-stats{ margin-bottom:6px; }
  .whale-tabs{ margin-bottom:6px; }

  /* ---------- chart: stay inside the card on mobile ----------
     This used to break the canvas out of the card's own left/right
     padding with a negative margin so candles ran edge-to-edge. That
     made the panel read as oversized/"wide" on phones instead of a
     compact, contained widget like its neighbors — reverted. The wrap
     now keeps its normal border on all four sides, same as desktop,
     just at the smaller mobile chart height set above. */
}

/* ============================================================
   VISUAL PRIORITY — 3-tier hierarchy
   ------------------------------------------------------------
   Everything under .live-term used to read at the same visual
   weight (same background, same border, same header treatment)
   regardless of how important the panel actually is. That forces
   the eye to scan the whole terminal instead of landing on the
   thing that matters most.

   Three tiers, same content/layout — only background depth,
   border weight and header opacity move:

     HIGH   — Terminal (trade tape) + Live Chart
              the two panels the terminal is actually "for"
     MEDIUM — Buy/Sell, Liquidations
              secondary, glanceable order-flow signals
     LOW    — Market Pulse, Whales, Market Overview/Statistics
              supporting context, read on demand not at a glance
   ============================================================ */

/* ---- HIGH: Terminal (trade tape) ---- */
.live-term__main{
  background:var(--panel-hover);
  border-top:2px solid var(--signal);
}
.term-identity-bar{ opacity:1; }

/* ---- HIGH: Live Chart ---- */
.live-term__side .livechart-card{
  background:var(--panel-hover);
  border:1px solid var(--line);
  border-top:2px solid var(--signal);
  padding:10px 12px 8px;
}
.live-term__side .livechart-card:fullscreen,
.live-term__side .livechart-card.livechart-card--fullscreen{
  border-top:2px solid var(--signal);
}
.live-term__side .livechart-card .widget-card__head{ opacity:1; }
.live-term__side .livechart-card .widget-card__head h4{ color:var(--ink); }
/* Unlike the other panel heads, the Live Chart head has no trailing
   .tag element to balance the drag handle against justify-content:
   space-between, so the title drifts to the right. Mirror the handle's
   width with an invisible spacer so the title sits centered like every
   other panel. */
.live-term__side .livechart-card .widget-card__head::after{
  content:"⠿";
  flex:none; font-size:14.5px; line-height:1; margin-left:2px;
  visibility:hidden; pointer-events:none;
}

/* ---- DESKTOP ONLY: Live Chart loses its header entirely ----
   PC-only removal of the Live Chart panel's header (drag handle +
   wrapper). display:none collapses the element completely, so none of
   its padding/margin/min-height (including the negative-margin bleed
   and background/border-bottom from the shared .widget-card__head base
   rule) is left behind — the chart content starts right at the card's
   own top padding, with no empty gap where the header used to be.
   Scoped to min-width:981px to exactly complement the mobile layout
   switch at max-width:980px used everywhere else in this file, so the
   mobile Live Chart (which already hides this same header below 640px
   via the max-width:640px rule further up) is completely untouched. */
@media (min-width:981px){
  .live-term__side .livechart-card .widget-card__head{ display:none; }
}

/* ---- MEDIUM: Buy/Sell + Liquidations ---- */
.live-term__side .orderflow-card,
.live-term__side .liq-sidebar{
  background:var(--panel);
  border-bottom:1px solid var(--line);
}
.live-term__side .orderflow-card .widget-card__head,
.live-term__side .liq-sidebar .widget-card__head{ opacity:.85; }

/* ---- LOW: Market Pulse, Whales, Market Overview/Statistics ---- */
.live-term__side .pulseflow-card,
.live-term__main .whale-card,
.live-term__main .mktoverview-card{
  background:transparent;
  border-bottom:1px solid var(--line-soft);
}
.live-term__side .pulseflow-card .widget-card__head,
.live-term__main .whale-card .widget-card__head,
.live-term__main .mktoverview-card .widget-card__head{ opacity:.65; }

/* Drag-reordering swaps a card's position in the DOM, not which panel
   it represents — keep the tier rules keyed to the panel classes above
   (unaffected by order) rather than nth-child, so re-ordering a widget
   never silently changes its priority tier. */
