
/* =====================================================================
   GRID OVERFLOW GUARD — the right-hand card was running off the screen
   ---------------------------------------------------------------------
   A grid item's default is min-width:auto, so `1fr` really behaves as
   minmax(min-content, 1fr). A Chart.js canvas carries an inline pixel
   width, so the moment a chart paints, that pixel width BECOMES the
   column's min-content and the column can never shrink again. The grid
   then measures wider than the page, the second card is pushed past the
   right edge, and .main's 32px right gutter disappears. It never
   self-corrects either: the container can't shrink, so Chart.js's
   resize observer never fires to redraw smaller.

   min-width:0 restores the intended minmax(0,1fr). Capping the canvas at
   100% lets it shrink back so the chart redraws at the correct size.
   Loaded last so it wins over the earlier !important layers.
   ===================================================================== */
.main [style*="display:grid"] > *,
.main [style*="display: grid"] > *,
.main .mob-grid-2 > *,
.main .mob-grid-3 > *,
.main .mob-grid-4 > *,
.main .set-risk-grid > *,
.main .dash-stats > *{
  min-width: 0;
}

/* Same guard by element type, in case a grid's inline style is written
   differently than the attribute selectors above expect. */
.main .section-card{ min-width: 0; }

/* Charts shrink with their column instead of pinning it open. */
.main .chart-container{ min-width: 0; width: 100%; overflow: hidden; }
.main .chart-container > canvas{ max-width: 100% !important; }

/* Wide tables scroll inside their own card rather than stretching the page. */
.main .scrollable-table{ overflow-x: auto; max-width: 100%; }

/* Last line of defence: nothing on a page may widen the document itself. */
.main{ min-width: 0; max-width: 100%; }
.page{ min-width: 0; max-width: 100%; }

/* =====================================================================
   ANALYTICS FULL BLEED — kills the black frame around the page
   ---------------------------------------------------------------------
   .main carries 28px/32px of padding, and the Analytics gradient lives on
   #analyticsPage INSIDE that padding, so the dark body colour showed as a
   band across the top and down both sides, with the page's rounded corners
   floating in the middle of it.

   While Analytics is the active page, .main hands its padding over to the
   page itself. The cards end up in exactly the same place, but the
   gradient now reaches every edge of the content area and fills the full
   viewport height even when the page is short.
   ===================================================================== */
body[data-page="analytics"] .main{ padding: 0 !important; }
body[data-page="analytics"] #analyticsPage{
  padding: 28px 32px !important;
  border-radius: 0 !important;
  min-height: 100vh;
}
@media (max-width: 768px){
  body[data-page="analytics"] #analyticsPage{
    padding: 62px 10px 24px 10px !important;
  }
  /* Mobile bottom nav needs its space reserved inside the page now. */
  body[data-page="analytics"]:has(#tcMobBottomNav:not(.tc-bn-hide)) #analyticsPage{
    padding-bottom: calc(74px + env(safe-area-inset-bottom, 0px)) !important;
  }
}

/* =====================================================================
   PLAYBOOK — NAME FIT
   ---------------------------------------------------------------------
   Long strategy names were being cut off in three places: the card title,
   the "Best playbook" overview tile, and the trade-assign rows. The card
   title is fixed at source (.pbk-card-name above). This block is the
   last-word layer for the rest, and it stops either playbook grid from
   forcing the page wider than the content area.
   ===================================================================== */

/* Grid children default to min-width:auto, which lets a long unbroken name
   push its own column open and drag the whole page past the right edge.
   The earlier global guard only matched inline-style grids, so these two
   class-based grids were never covered. */
.pbk-ov > *,
.pbk-grid > *{ min-width: 0; }

.pbk-root{ max-width: 100%; }
.pbk-ov,
.pbk-grid{ max-width: 100%; }

/* "Best playbook" tile — the value is a strategy name, not a number, so it
   wraps instead of running out of the tile. */
.pbk-ov-card{ min-width: 0; overflow: hidden; }
.pbk-ov-v{ overflow-wrap: anywhere; word-break: break-word; line-height: 1.3; }

/* Header row: the ＋ New Playbook button keeps its own width and the title
   block gives way, so neither one gets clipped on a narrow content area. */
.pbk-top > div:first-child{ min-width: 0; flex: 1 1 320px; }
.pbk-top > .pbk-btn{ flex: 0 0 auto; }

/* A wrapped name makes one card's header taller than its neighbour's, which
   used to knock that card's stats, win-rate bar and footer out of line with
   the rest of the row. The card is now a column and the sparkline is the only
   part that stretches, so everything below it sits on a shared baseline. */
.pbk-card{ display: flex; flex-direction: column; }
.pbk-card-top,
.pbk-stat-row,
.pbk-wrbar,
.pbk-card-foot{ flex: 0 0 auto; }
.pbk-spark{ flex: 1 1 auto; }

/* "Profit factor" wraps to two lines on a narrow card while "Net P&L" stays on
   one, which dropped that column's number a line lower than the other two.
   Two reserved label lines put all three values back on one baseline. */
.pbk-stat-l{ line-height: 1.25; min-height: 2.5em; }

/* =====================================================================
   ROOMS — HOST-SIDE PERFORMANCE
   ---------------------------------------------------------------------
   The Rooms UI itself lives in /tradercab-room.html inside #tcRoomFrame,
   so nothing here can touch how that chat renders. What this block does
   is stop the HOST page from taxing the GPU while the iframe is on
   screen — every effect below is completely hidden behind a full-height
   iframe, yet the compositor was still keeping all of it alive.
   ===================================================================== */

/* body::before is a fixed, perspective-rotated, mask-image grid and
   body::after is an 800x800 fixed radial glow. Both sit behind the
   iframe where not one pixel of either is visible, and both are large
   composited layers the browser keeps re-rasterising. Off while the
   Rooms page is open; back the moment you navigate away. */
body[data-page="rooms"]::before,
body[data-page="rooms"]::after{ display: none !important; }

/* backdrop-filter makes the browser re-read whatever is painted behind
   the element on every frame. On the Rooms page the thing behind the
   sidebar is a static dark background, so the blur costs frames and
   buys nothing. */
body[data-page="rooms"] .sidebar,
body[data-page="rooms"] .sidebar *{
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}

/* A 24px-blur drop shadow on a full-viewport-height element is a large
   soft region the compositor recalculates whenever anything moves. A 1px
   border reads the same at a glance and costs nothing. */
body[data-page="rooms"] #tcRoomFrame{
  box-shadow: none !important;
  border: 1px solid rgba(40,30,70,.75);
}

/* One scroll context, not two. The iframe already fills the content area
   exactly (100vh - 56px inside .main's 28px padding), so any outer scroll
   is a rounding artefact — but a document that can shift even a pixel is
   what makes a flick inside an embedded chat feel like it catches. Desktop
   only: the mobile rule below gives the iframe its own height and the page
   still needs to scroll there. */
@media(min-width:761px){
  body[data-page="rooms"]{ overflow: hidden; }
}
