/* ============================================================================
   desktop.css — >=1024px only, loaded behind a media attribute.

   Not the mobile column centred in a wide window: a different arrangement.

   LEFT SIDEBAR, not top nav. Vertical space is the scarce resource — the
   trade table is the point of desktop and a top bar taxes ~56px off every
   screen — while horizontal space is abundant here and free at ultrawide.
   The sidebar also holds seven controls without cramming, and a screen edge
   is an infinitely tall mouse target.

   SPLIT WIDTHS. At 1024 with a 240px sidebar there would be 784px of content,
   and a 440px form would leave 344px of "table", which is not a table. So the
   sidebar collapses to a 64px rail below 1280px, giving 520px of table at the
   narrowest desktop. The form panel is drag-resizable 340–560px.
   ========================================================================== */

@media (min-width: 1024px) {
  body {
    padding-bottom: 0;
    display: grid;
    grid-template-columns: var(--rail, 240px) minmax(0, 1fr);
    min-height: 100vh;
  }

  /* mobile chrome retires */
  #tabbar { display: none; }
  #topbar { display: none; }

  /* ---------- sidebar ---------- */

  #sidebar {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 16px 10px;
    border-right: 1px solid var(--border);
    background: var(--surface-1);
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
  }

  /* ---------- the wordmark ----------
     A two-line lockup, not two stacked words. What makes it read as one mark:

     1. SCALE CONTRAST. Line 1 is 3x line 2. Anything closer and they compete.
     2. LIGHT ON ONE LINE ONLY. The name carries the backlight; the descriptor
        is flat. Glowing both would flatten the hierarchy the scale sets up.
     3. OPTICAL WIDTH MATCH. Line 2's tracking is tuned so both lines are the
        same width: measured, not guessed. "Lewgpt" at 30px inks 96.94px, and
        "Trading Journal" inks 76.5px untracked over 15 tracking cells, so
        (96.94 - 76.5) / 15 / 8.5px = 0.1603em. Re-derive it if either string
        or the font stack changes — it is specific to both.
     4. CENTRED ON ONE AXIS. Because the widths match exactly, centring aligns
        BOTH edges at once — the pair reads as a justified block rather than a
        heading with a caption beneath it. Equal widths are what make centring
        work here; without the match it would just be two centred strings. */
  #sidebar .brand {
    display: block;
    /* 13px below leaves ~13px of air to the rule against ~10.5px between the
       lines — more space outside the pair than inside it, which is what keeps
       them reading as one mark now that the internal gap has opened up. */
    padding: 2px 10px 13px;
    border-bottom: 1px solid var(--border-lit);
    margin-bottom: 12px;
  }
  #sidebar .brand-mark { display: none; }   /* collapsed rail only */
  /* CENTRED. The width match earns its keep here: two lines of identical ink
     centred on the same axis align on BOTH edges at once, so the mark reads as
     a single justified block rather than a heading with a caption under it. */
  #sidebar .brand-lines { display: flex; flex-direction: column; align-items: center; }

  #sidebar .brand-name {
    font: 600 30px/0.95 var(--sans);
    letter-spacing: -0.018em;
    color: var(--text-primary);
    text-shadow: var(--glow-soft);
  }
  #sidebar .brand-sub {
    font-size: 8.5px;
    font-weight: 500;
    line-height: 1.1;
    text-transform: uppercase;
    letter-spacing: 0.1603em;
    /* NO trailing-cell compensation. Blink already trims the cell after the
       last letter from the box — measured: the border box and the ink are both
       96.94px — so the negative margin this used to carry was a second
       correction for a problem already solved, and it shunted the line 0.68px
       off the axis. Harmless while left-aligned, visible once centred.
       (WebKit does include that cell; the residual there is 0.68px, which is
       below anything the eye resolves, and the sidebar is desktop-only.)

       The gap is 17px, not the 10px it looks like it should be: "Lewgpt"
       carries descenders that hang 5.5px below the line box, so the margin has
       to clear the g and p rather than the baseline to leave ~11px of actual
       air. */
    margin-top: 17px;
    color: var(--text-muted);
    text-shadow: none;
  }

  #sidebar .navbtn {
    appearance: none;
    display: flex;
    align-items: center;
    gap: 11px;
    width: 100%;
    background: none;
    border: 1px solid transparent;
    border-radius: 8px;
    color: var(--text-muted);
    font: 14px var(--sans);
    padding: 9px 10px;
    cursor: pointer;
    text-align: left;
    transition: color 140ms ease, background 140ms ease, border-color 140ms ease;
  }
  #sidebar .navbtn .ico { font-size: 16px; width: 18px; text-align: center; flex: 0 0 auto; }
  #sidebar .navbtn .key {
    margin-left: auto;
    font: 10px var(--mono);
    color: var(--text-dim);
  }
  #sidebar .navbtn:hover { color: var(--text-secondary); background: var(--surface-2); }
  #sidebar .navbtn.active {
    color: var(--text-primary);
    background: var(--surface-3);
    border-color: var(--border-lit);
    box-shadow: var(--glow-tight);
  }

  #sidebar .spacer { flex: 1; }
  #sidebar .sb-group { padding: 10px 10px 4px; }
  #sidebar .sb-label {
    font-size: 9.5px;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-dim);
    margin-bottom: 6px;
  }
  #sidebar #system-switcher { font-size: 13px; padding: 8px 9px; }
  #sidebar .sys-line { display: flex; align-items: center; gap: 6px; margin-top: 7px; }
  #sidebar #sync-chip { max-width: none; width: 100%; text-align: center; }
  #sidebar .newsys {
    width: 100%;
    margin-top: 7px;
    font-size: 12.5px;
    padding: 8px;
  }

  /* collapsed rail below 1280 so the split keeps a usable table */
  @media (max-width: 1279px) {
    body { --rail: 64px; }
    #sidebar { padding: 16px 8px; align-items: center; }
    #sidebar .navbtn span:not(.ico),
    #sidebar .sb-label,
    #sidebar .newsys span { display: none; }

    /* The lockup cannot survive 64px, so the mark stands in for it — the same
       book and pencil as the app icon, which is what makes the rail read as
       the same product rather than an unlabelled strip of buttons. */
    #sidebar .brand {
      padding: 0 0 12px;
      display: flex;
      justify-content: center;
      border-bottom: 1px solid var(--border-lit);
      margin-bottom: 10px;
      width: 100%;
    }
    #sidebar .brand-lines { display: none; }
    #sidebar .brand-mark {
      display: block;
      width: 26px;
      height: 26px;
      color: var(--text-primary);
      filter: drop-shadow(0 0 10px rgba(198, 214, 235, 0.28));
    }
    #sidebar .navbtn { justify-content: center; padding: 11px 0; }
    #sidebar .sb-group { padding: 8px 0 4px; width: 100%; }
    #sidebar #system-switcher { font-size: 0; padding: 8px 4px; }
    #sidebar #sync-chip { font-size: 0; padding: 6px; }
    #sidebar #sync-chip::after { content: "◈"; font-size: 12px; }
  }

  /* ---------- content ---------- */

  #view {
    max-width: none;
    width: 100%;
    padding: 0;
    display: block;
  }

  /* Prose and stat grids stay capped — that is what §5.5's ~1600px is for:
     stopping lines running absurdly long.
     The class goes on #view ITSELF (main.js toggles it there), so the old
     child selector `#view > .pane-single` matched nothing and every non-split
     desktop view — Stats, Settings, Goals — ran flush against the sidebar and
     the window edge with no padding at all. */
  #view.pane-single {
    max-width: 1600px;
    margin: 0 auto;
    padding: 22px 26px 40px;
  }

  /* ---------- split: trades left, form docked right ---------- */

  /* FULL WIDTH, no cap.
     The 1600px cap this used to carry left dead black space to the right of
     the form panel on anything wider — 80px at 1920, and more beyond — with
     the docked panel floating short of the window edge. A docked panel is
     chrome; it terminates the layout, so it has to reach the edge.
     The reading-width argument the cap was protecting does not apply here
     anyway: the table sheds and adds COLUMNS by measured width rather than
     stretching a fixed set, so extra width buys more of the twenty-eight
     columns instead of a wider gap between asset and running R. The prose and
     stat pages keep their cap — see #view.pane-single, where it is centred and
     therefore never lopsided. */
  .split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto var(--form-w, 440px);
    height: 100vh;
    width: 100%;
    overflow: hidden;          /* a panel must never widen the page */
  }
  /* THE PANELS ARE SEALED. `overflow-y: auto` scrolls them and clips them
     visually, but on its own it did NOT stop their content contributing to the
     ROOT's scrollable overflow: a long entry form (3119px in the live panel)
     gave the page a 1884px scroll region containing nothing at all, so
     scrolling slid the entire app off the top and left you looking at the
     black root background. Every ancestor measured 900px; only the root
     disagreed.

     `contain: layout` is the fix and the honest description of the intent —
     these are independent regions, and nothing inside one has any business
     affecting layout outside it. Layout containment only; NOT paint or size,
     which would clip the sticky savebar's gradient and break the auto-height
     the grid row depends on.

     Applies to both panels and therefore to all five log modes. Backtest never
     showed the symptom only because its form is short enough that the phantom
     region stayed under the viewport height — the same leak was there. */
  .split > .split-list,
  .split > .split-form { contain: layout; }

  .split > .split-list {
    min-width: 0;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 20px 22px 30px;
  }
  .split > .split-form {
    border-left: 1px solid var(--border);
    background: var(--surface-1);
    overflow-y: auto;
    overflow-x: hidden;
    padding: 16px 18px 40px;
    min-width: 0;
    /* The panel is drag-resizable 340–560px, so its contents have to respond
       to the PANEL's width, not the viewport's. A container query is the only
       thing that reads the right number here. */
    container-type: inline-size;
  }

  /* A datetime-local with step="1" renders "06/08/2026 00:00:00" plus a picker
     icon and has a UA minimum width to match — two side by side simply do not
     fit a 440px panel, so paired rows stack instead of overflowing. */
  @container (max-width: 520px) {
    .split-form .row2 { grid-template-columns: 1fr; }
    .split-form .row3 { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  }
  @container (max-width: 380px) {
    .split-form .row3 { grid-template-columns: 1fr; }
  }

  /* Belt and braces: inputs must be allowed to shrink inside a grid cell,
     which they are not by default. */
  .split-form input,
  .split-form select,
  .split-form textarea { min-width: 0; max-width: 100%; }
  .split-form .savebar {
    position: sticky;
    bottom: 0;
    background: linear-gradient(transparent, var(--surface-1) 40%);
    padding: 12px 0 8px;
  }
  .split-form #sizing-card { top: 0; }

  /* drag handle between the two */
  .split-grip {
    width: 5px;
    cursor: col-resize;
    background: transparent;
    position: relative;
  }
  .split-grip::after {
    content: "";
    position: absolute;
    inset: 0 2px;
    background: var(--border);
    transition: background 140ms ease, box-shadow 140ms ease;
  }
  .split-grip:hover::after { background: var(--glow); box-shadow: var(--glow-tight); }

  /* ---------- the real table ---------- */

  /* `clip`, not `hidden`. Both round the table's corners, but `hidden` makes
     this a scroll container, and a sticky element binds to the nearest
     scrollport — so the sticky column headers were binding to a box that never
     scrolls and could therefore never stick. `clip` clips without creating a
     scrollport, so the headers bind to .split-list, which is what actually
     scrolls. Same trap, same fix, as the `html { overflow-x: clip }` note in
     app.css. */
  .dt-wrap { border: 1px solid var(--border); border-radius: var(--radius); overflow: clip; }
  table.dt {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: 12.5px;
    table-layout: fixed;
  }
  table.dt th {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--surface-2);
    color: var(--text-muted);
    font: 600 9.5px var(--mono);
    text-transform: uppercase;
    letter-spacing: 0.07em;
    text-align: right;
    padding: 8px 9px;
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
    user-select: none;
    cursor: pointer;
    /* NO `position: relative` here. This block already declares
       `position: sticky` above, and a second position declaration in the same
       rule silently won — so the header had never actually stuck, and scrolling
       a long table lost the column names. The `relative` was only ever there to
       give the absolutely positioned resize grip a containing block, and a
       sticky box is a positioned box, so it does that job already. */
  }
  table.dt th.num { text-align: right; }
  table.dt th.txt { text-align: left; }
  table.dt th:hover { color: var(--text-secondary); }
  table.dt th .sortmark { color: var(--text-primary); margin-left: 3px; }
  table.dt th .grip {
    position: absolute;
    right: 0; top: 0; bottom: 0;
    width: 6px;
    cursor: col-resize;
  }
  table.dt th .grip:hover { background: var(--glow); }

  table.dt td {
    padding: 0 9px;
    height: 30px;                 /* dense: a mouse is precise */
    border-bottom: 1px solid color-mix(in srgb, var(--border) 50%, transparent);
    text-align: right;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-variant-numeric: tabular-nums;
    color: var(--text-secondary);
  }
  table.dt td.txt { text-align: left; }
  table.dt td.strong { color: var(--text-primary); }
  table.dt tbody tr { cursor: pointer; }
  table.dt tbody tr:hover td { background: var(--surface-2); }

  /* loss rows recede at chrome level; figures keep full luminance */
  table.dt tbody tr.is-loss td { background: #060608; }
  table.dt tbody tr.is-loss:hover td { background: #0C0C10; }
  table.dt tbody tr.is-win td { box-shadow: inset 2px 0 0 -1px color-mix(in srgb, var(--win) 45%, transparent); }

  table.dt tbody tr.selected td {
    background: var(--surface-3);
    box-shadow: inset 0 0 0 1px var(--border-lit);
  }
  table.dt tbody tr.cursor td { box-shadow: inset 0 0 0 1px var(--glow); }
  table.dt .r-cell { font-weight: 600; }
  table.dt .r-cell.pos { color: var(--win); }
  table.dt .r-cell.neg { color: var(--loss); }

  .dt-toolbar {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: 10px;
  }
  .dt-toolbar .grow { flex: 1; }
  /* same (0,1,1) base-rule problem as .filterbar — see app.css */
  .dt-toolbar select,
  .dt-toolbar input[type="date"] { width: auto; }
  .dt-toolbar input[type="date"] { width: 142px; }
  .dt-bulk {
    display: flex;
    gap: 8px;
    align-items: center;
    padding: 8px 12px;
    margin-bottom: 8px;
    background: var(--surface-2);
    border: 1px solid var(--border-lit);
    border-radius: 8px;
    font-size: 13px;
    box-shadow: var(--glow-tight);
  }

  .dt-footer {
    position: sticky;
    bottom: 0;
    background: var(--surface-2);
    border-top: 1px solid var(--border);
    padding: 9px 12px;
    font: 12.5px var(--mono);
    display: flex;
    gap: 18px;
    align-items: center;
  }
  .dt-footer .spacer { flex: 1; }

  /* ---------- stats grid ---------- */

  .stat-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
  .chart-card { margin-bottom: 12px; }
  .kv { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  details { padding: 0 16px; }

  /* two-up charts on very wide screens, full width below */
  @media (min-width: 1500px) {
    .charts-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; }
    .charts-grid > .chart-card:first-child { grid-column: 1 / -1; }
  }

  /* ---------- shortcut cheatsheet ---------- */

  .keys-sheet {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 7px 16px;
    font-size: 13px;
    align-items: center;
  }
  .keys-sheet kbd {
    font: 11px var(--mono);
    background: var(--surface-3);
    border: 1px solid var(--border-lit);
    border-radius: 5px;
    padding: 3px 7px;
    color: var(--text-primary);
    white-space: nowrap;
  }
  .keys-sheet .grp {
    grid-column: 1 / -1;
    font-size: 9.5px;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-dim);
    margin-top: 8px;
  }

  .modal-back { align-items: center; }
  .modal { border-radius: 14px; max-width: 620px; max-height: 82vh; }
  .savebar { bottom: 0; }
  #toast-host { bottom: 22px; }

  /* The sheet puts the week and its rewards side by side; so does this, once
     there is room for both without either becoming a column of slivers. */
  .goals-split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(300px, 380px);
    gap: 22px;
    align-items: start;
  }

  /* ---------- Goal Crushers, desktop ---------- */

  /* These pages fill the width. The original complaint was not that the table
     was too wide — it was that #view had NO PADDING on desktop (the
     `#view.pane-single` selector above was never matching), so the first and
     last columns ran into the sidebar and the window edge. With the padding
     restored, full width is what was wanted; capping it to a reading column
     just wasted the other half of the screen.
     Rows are given a little more height so a wide row is still easy to track
     across, and the range column absorbs the slack rather than every column
     stretching equally. */
  .goals-weeks { margin-bottom: 12px; }
  .goals-weeks table.bd { table-layout: auto; }
  .goals-weeks table.bd th,
  .goals-weeks table.bd td { padding: 8px 10px; white-space: nowrap; }
  .goals-weeks table.bd th:first-child,
  .goals-weeks table.bd td:first-child { padding-left: 0; }
  .goals-weeks table.bd th:last-child,
  .goals-weeks table.bd td:last-child { padding-right: 0; }
  .goals-weeks table.bd th:nth-child(2),
  .goals-weeks table.bd td:nth-child(2) { width: 100%; text-align: left; }
  /* A striped row is what makes a wide table readable left to right. */
  .goals-weeks table.bd tbody tr:nth-child(even),
  .goals-weeks table.bd tr:nth-child(even) { background: color-mix(in srgb, var(--surface-1) 60%, transparent); }
  .goals-weeks table.bd tr:hover { background: var(--surface-2); }

  /* Progress spreads its tiles across the width; the chart follows. */
  .goals-progress .stat-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .goals-progress canvas.chart { height: 300px; }

  /* Setup is a form, so it reads in two columns rather than one long ribbon
     of full-width inputs. */
  .goals-setup { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 22px; align-items: start; }
  .goals-setup > div > h2.section:first-child { margin-top: 0; }

  /* Five daily tasks plus the score have to fit one screen without scrolling,
     so the whole week view is compacted on desktop where the pointer is
     precise and 40px touch targets are not needed. */
  .goals-split .task-card { padding: 6px 10px; margin-bottom: 6px; }
  .goals-split .task-top { gap: 8px; }
  .goals-split .task-top input { padding: 5px 8px; font-size: 14px; }
  .goals-split .day-row { gap: 4px; margin-top: 6px; }
  .goals-split .day-box {
    min-height: 28px;
    padding: 5px 0;
    font-size: 11px;
    border-radius: 6px;
  }
  .goals-split .day-box.wide { margin-top: 6px; font-size: 13px; }
  .goals-split .stepper { gap: 8px; margin-top: 6px; }
  .goals-split .stepper button { min-width: 38px; padding: 4px 0; font-size: 16px; }
  .goals-split .stepper-val { font-size: 17px; }
  /* The Options block is the tallest thing in a card when it is CLOSED — the
     shared `details summary` rule gives it 12px of padding top and bottom, so
     a collapsed row that should be one line was costing 52px. Five of those
     is most of a screen. */
  .goals-split .task-more { margin: 3px 0 0; }
  .goals-split .task-more summary { font-size: 11px; padding: 2px 0; }
  .goals-split .task-more .row3 { margin-top: 6px; }
  .goals-split .task-more label.field { margin-bottom: 4px; }
  /* Title and week picker share a row here; stacked they cost 103px of the
     one screen the week is supposed to fit into. */
  .goals-head {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 9px 14px;
  }
  .goals-head .trade-head { flex: 1; min-width: 0; margin: 0; }
  .goals-head select { margin-top: 0; max-width: 300px; }

  .goals-split h2.section { margin: 8px 0 4px; }
  .goals-split label.field { margin-bottom: 8px; }
  .goals-split .goal-total { padding: 7px 14px; margin-top: 6px; }
  /* Two lines of focus is plenty when the whole week has to fit one screen. */
  .goals-split textarea { min-height: 0; height: 52px; }
  .goals-split .goal-pct { font-size: 28px; }
  .goals-split .trade-actions { margin-top: 8px; }

  /* ---------- MMA/EOD, desktop ---------- */

  /* The date nav is a control, not a banner: it shrinks to its content and
     lets the day label sit beside it rather than stretching across 1600px. */
  .review-head { flex-direction: row; align-items: center; justify-content: space-between; gap: 16px; }
  .review-nav { flex: 0 0 auto; }
  .review-nav input.review-date { flex: 0 0 auto; width: 190px; }

  /* Two columns, so a full morning read fits one screen. The fields are short
     and stacking them would leave half the width empty — the same mistake the
     Goals pages made before they were widened.
     Everything spans by default and only cards take a column, which keeps the
     rule true for sections added later without revisiting this list. */
  .review-body {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 0 24px;
    align-items: start;
  }
  .review-body > * { grid-column: 1 / -1; }
  .review-body > .card { grid-column: auto; margin-bottom: 10px; }
  .review-body > h2.section { margin: 16px 0 6px; }
  .review-body > h2.section:first-child { margin-top: 0; }
  .review-body > textarea { min-height: 0; height: 84px; }

  /* Today's trades read as a list, not a stack of cards a column wide. */
  .review-trades { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }

  .review-body .field-card,
  .review-body .watch-row,
  .review-body .mark-row,
  .review-body .passed-row { padding: 10px 12px; }
}

@media (min-width: 1024px) {
  /* ---------- draggable column headers (amendment 39) ---------- */
  table.dt thead th { cursor: grab; }
  table.dt thead th.dragging { opacity: 0.4; cursor: grabbing; }
  /* Which side the column lands on, shown while dragging. Inset shadows
     rather than borders: a border would change the header's width mid-drag
     and shift every column after it. */
  table.dt thead th.drop-before { box-shadow: inset 2px 0 0 var(--text-primary); }
  table.dt thead th.drop-after { box-shadow: inset -2px 0 0 var(--text-primary); }
  /* The resize grip keeps its own cursor — the two gestures start on the
     same element and must not look like one another. */
  table.dt thead th .grip { cursor: col-resize; }

  /* ---------- scrollbars, hidden (desktop only) ----------
     Requested outright: the owner knows which surfaces scroll and does not
     want the tracks. Two properties because the standard one and the WebKit
     one cover different engines, and both are needed on Chrome for Windows.

     SCROLLING ITSELF IS UNTOUCHED — wheel, trackpad, keyboard, drag-select
     autoscroll and programmatic scrollTop all behave exactly as before. Only
     the painted track and thumb go. Applied to the app's own regions rather
     than with a bare `*`, so nothing leaks into a native control's internals.

     Deliberately NOT in app.css: on a phone the overlay scrollbar is already
     transient, and it is the only cue a region is scrollable under a thumb. */
  html, body,
  #view, #sidebar,
  .split-list, .split-form, .dt-wrap, .tbl-scroll, .modal, .filterbar,
  textarea, select {
    scrollbar-width: none;            /* Firefox, and Chrome 121+ */
    -ms-overflow-style: none;         /* legacy Edge */
  }
  html::-webkit-scrollbar, body::-webkit-scrollbar,
  #view::-webkit-scrollbar, #sidebar::-webkit-scrollbar,
  .split-list::-webkit-scrollbar, .split-form::-webkit-scrollbar,
  .dt-wrap::-webkit-scrollbar, .tbl-scroll::-webkit-scrollbar,
  .modal::-webkit-scrollbar, .filterbar::-webkit-scrollbar,
  textarea::-webkit-scrollbar, select::-webkit-scrollbar {
    width: 0;
    height: 0;
    display: none;
  }

  /* ---------- breakdown tables: one column grid for all of them ----------
     Nine separate <table>s stacked down the Stats page, each previously
     auto-sizing its own first column to its widest label. "BTC" gave a narrow
     one and "unknown · insufficient sample" a wide one, so n / win % / exp R /
     Σ R landed at a different x in every card and the page read as a pile of
     unrelated tables rather than one report.

     Fixed layout with matching widths puts every figure on the same four
     verticals, so the eye can run straight down a column and compare sessions
     against weekdays against directions. Percentages rather than pixels so it
     holds at any panel width, and a min-width so the shared .tbl-scroll takes
     over instead of crushing the numbers when the pane is narrow. */
  table.bd.bd-breakdown {
    table-layout: fixed;
    min-width: 460px;
  }
  table.bd.bd-breakdown th:first-child,
  table.bd.bd-breakdown td:first-child { width: 40%; }
  table.bd.bd-breakdown th:not(:first-child),
  table.bd.bd-breakdown td:not(:first-child) { width: 15%; }
  /* A long label truncates rather than wrapping to a second line, which would
     make one row taller than the rest and break the run down the column. */
  table.bd.bd-breakdown td:first-child {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}
