/* =============================================================================
   MLB SCHEDULE — THEATER MODE
   =============================================================================
   The wall of live-game tiles: TWO per row, scrolling past that. Tiles are
   bespoke (theaterMLB.js tileHtml/matchupHtml — NOT the game page's at-bat
   card): header with logos/score/inning, PITCHER | count+bases | BATTER |
   last-pitch zone, an ON DECK / LAST PITCH footer, and a RECENT PLAYS rail.

   Two size steps, driven by @container on the TILE's width: the base metrics
   are the big-card scale (founder ask 2026-08-09: +50% card height, content
   scaled with it); the ≤680px step restores the compact scale for narrow
   tiles (small desktop windows), and ≤540px drops the zone panel.

   The --gd-* design tokens and the Inter body font are NOT re-declared here.
   .pbt-overlay is in their declaration lists in mlb-game-detail.css (alongside
   #mlb-game-detail and .pbr-modal, which lives on body for the same reason).
   Two copies of a palette drift; one does not.
   ========================================================================== */

/* The lock MUST include the root element. The viewport takes its overflow from
   the root, and body's only propagates when the root's is `visible` — but
   style.css:120 sets `html,body { overflow-x: hidden }`, which forces html's
   overflow-y to `auto`. A body-only lock is therefore a no-op here, and the
   schedule page kept scrolling behind theater (visible through the nav, which
   is transparent with a backdrop-filter blur).
   No !important needed: `html.pbt-lock` (0,0,1,1) outranks the bare `html`
   (0,0,0,1) on specificity, so load order is irrelevant. */
html.pbt-lock,
body.pbt-lock { overflow: hidden; }

/* Hiding the scrollbar widens the viewport, shifting the still-visible fixed
   nav's right-aligned contents. Hold the gutter open so nothing moves. Applied
   by JS only when a scrollbar was actually present, so short pages don't gain
   a phantom gap. Degrades to the (cosmetic) shift where unsupported. */
html.pbt-lock-gutter { scrollbar-gutter: stable; }

/* Theater fills the viewport BETWEEN the site's two navs — the top nav and
   the bottom page nav (#pb-bottom-nav: Games / Research / Home / My Parlays /
   Pick'em) both stay visible and usable; this is a page mode (with its own
   URL), not a modal.
   --pbt-top / --pbt-bottom are measured from the live bars by theaterMLB.js
   (applyNavOffset) rather than hardcoded: there is no --nav-height variable
   for the top bar and its height is content-driven, and the bottom bar
   carries a safe-area inset and gets `bottom`-nudged by the betting slip.
   z-index 20000 clears every page-level surface that could otherwise poke
   through — the parlay pill (10050), the game/player modal overlays (10000 /
   10001) and #loading-animation (9999). It deliberately does NOT try to beat
   `.landing-nav`, which is `z-index: 2000000000 !important` (cover-page.css)
   and sits above theater by design; the bottom nav (z-index 1200) simply
   isn't overlapped at all. */
.pbt-overlay {
  position: fixed;
  top: var(--pbt-top, 0px);
  left: 0;
  right: 0;
  bottom: var(--pbt-bottom, 0px);
  z-index: 20000;
  display: flex;
  flex-direction: column;
  /* The SITE's page background, not a theater-own shade: themes.css sets
     html/body to --theme-bg-base (#000 on the default teal theme), and a
     hardcoded near-black here read as its own grey page next to it. The var
     also tracks theme switches for free. */
  background: var(--theme-bg-base, #000);
  color: var(--gd-text);
  overscroll-behavior: contain;
}

/* ── top row: ← Schedule, top-left ────────────────────────────────────────
   Deliberately NOT a chrome bar (the old full-width gradient strip existed
   for one right-aligned Close and read as wasted space — founder 2026-08-09):
   transparent, borderless — just the back link on the left and, only while
   games are user-removed, the restore pill on the right. */
.pbt-bar {
  flex: none;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 16px 2px;
}
/* The same back affordance as the game page's "← Schedule" (.mlb-gd-back,
   mlb-game-detail.css:122): teal + 700 on transparent, arrow as an inline
   currentColor svg. Every "go somewhere" link in the MLB surfaces is one
   colour — the --theme-accent-rgb token, never a re-picked hex. */
.pbt-back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 6px;
  background: transparent;
  border: none;
  color: rgba(var(--theme-accent-rgb, 0, 211, 189), .9);
  font-family: var(--gd-font-body, inherit);
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  transition: color .15s ease;
}
.pbt-back:hover { color: rgb(var(--theme-accent-rgb, 0, 211, 189)); }
.pbt-back svg { flex: none; }

/* Every live game is on the wall, so the only absentees are ones the user
   removed. A single restore button keeps removal from being a dead end.
   Rounded-full white-outline pill (founder mock 2026-08-11).
   NOTE: no `display` is set here on purpose — an author `display` would beat
   the UA's `[hidden] { display: none }` and pin the button on screen (that is
   exactly how the old tray panel became a permanent empty capsule). If you add
   one, add `.pbt-restore[hidden] { display: none }` with it. */
.pbt-restore {
  margin-left: auto;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, .75);
  border-radius: 999px;
  color: #fff;
  cursor: pointer;
  font: inherit;
  font-size: .8rem;
  font-weight: 600;
  line-height: 1;
  padding: 8px 14px;
}
.pbt-restore:hover {
  background: rgba(255, 255, 255, .1);
  border-color: #fff;
}

/* ── tiling surface ───────────────────────────────────────────────────────
   Fixed TWO columns; rows are content-sized and the surface scrolls. No JS
   fitter, no CSS zoom — the tiles are fluid. scrollbar-gutter keeps
   clientWidth stable whether or not the wall is tall enough to scroll.

   grid-auto-rows: max-content is LOAD-BEARING, not decoration. The tiles
   carry `overflow: hidden` (rounded-corner clip + the rail), which zeroes a
   grid item's AUTOMATIC MINIMUM SIZE — so with the default `auto` rows in
   this definite-height grid, track maximization stops when the free space
   runs out and every row gets an equal ~1fr-style share instead of its
   content height. Measured: 8 games compressed to 208px tiles (content 304px)
   with the ON DECK footer clipped and nothing to scroll. max-content rows
   size to the tile's real height regardless of the overflow clip; the wall
   then genuinely scrolls — full-height cards beat seeing every game at once. */
.pbt-grid {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-auto-rows: max-content;
  align-content: start;
  gap: 16px;
  padding: 16px;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, .16) transparent;
  scrollbar-gutter: stable;
}
.pbt-grid::-webkit-scrollbar { width: 8px; }
.pbt-grid::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, .16);
  border-radius: 99px;
}

/* ── tile ─────────────────────────────────────────────────────────────────
   container-type makes the @container rules below respond to the TILE's
   width (viewport width says nothing useful — the rail and zone panel crowd
   at ~2x the tile width the viewport query would fire at).
   min-height is the +50% card-height ask: content is scaled up with it, the
   matchup centers into the slack (align-content on .pbt-matchup), and the
   RECENT PLAYS rail — absolute, bottom-pinned — absorbs the rest as more
   visible rows. Content taller than this still wins (max-content rows). */
.pbt-tile {
  min-width: 0;
  min-height: 462px;
  display: flex;
  flex-direction: column;
  /* The game page's own card surface (--gd-surface, the dark navy every
     .pbr-card uses) — the tiles read as the same family of card, and the two
     surfaces can never drift apart. */
  background: var(--gd-surface, #0B0C10);
  border: 1px solid var(--gd-line-strong);
  border-radius: 14px;
  overflow: hidden;
  container-type: inline-size;
}
.pbt-tile.is-final { opacity: .85; }

/* ── tile header: LIVE · logos · score · inning ─────────────────────────── */
.pbt-head {
  flex: none;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 18px;
  border-bottom: 1px solid var(--gd-line);
}
.pbt-live-chip {
  flex: none;
  font-family: var(--gd-font-mono);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .1em;
  color: var(--gd-live);
  border: 1px solid rgba(255, 59, 71, .55);
  border-radius: 7px;
  padding: 4px 10px;
}
.pbt-tile.is-final .pbt-live-chip {
  color: var(--gd-text-2);
  border-color: var(--gd-line-strong);
}
.pbt-mid {
  display: flex;
  align-items: center;
  gap: 18px;
  margin: 0 auto;
  min-width: 0;
}
.pbt-team { display: flex; align-items: center; gap: 10px; min-width: 0; }
.pbt-logo { width: 32px; height: 32px; object-fit: contain; flex: none; }
.pbt-code {
  font-family: var(--gd-font-mono);
  font-size: 16px;
  font-weight: 600;
  letter-spacing: .05em;
  color: var(--gd-text);
}
.pbt-score {
  font-family: var(--gd-font-mono);
  font-size: 26px;
  font-weight: 700;
  color: var(--gd-text);
  font-variant-numeric: tabular-nums;
}
.pbt-score.is-trailing { color: var(--gd-text-3); }
.pbt-inn {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 8px;
  font-family: var(--gd-font-mono);
  font-size: 12.5px;
  letter-spacing: .08em;
  color: var(--gd-text-2);
  white-space: nowrap;
}
.pbt-arr { font-style: normal; font-size: 10px; line-height: 1; }
.pbt-arr.is-top { color: #60A5FA; }
.pbt-arr.is-bot { color: #F5A524; }

/* Red — it removes the game from the wall. */
.pbt-cap-x {
  flex: none;
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--gd-live);
  font-size: 18px;
  line-height: 1;
  padding: 2px 6px;
}
.pbt-cap-x:hover { color: #fff; }

/* ── tile body: main panel + recent-plays rail ──────────────────────────── */
/* Rail at 34%: the matchup row carries visible slack on wide tiles (founder
   2026-08-09), so the RECENT PLAYS rail takes some of it — the avatar +
   stacked-name rows need the width. The ≤800px step gives it back. */
.pbt-body {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(210px, 34%);
}
.pbt-main {
  min-width: 0;
  display: flex;
  flex-direction: column;
  padding: 6px 20px 0;
}

/* ── matchup row: pitcher | count+bases | batter | zone ───────────────────
   align-content centers the (single) row inside whatever height the tile's
   min-height hands this flexible section, so the extra card height reads as
   breathing room around the matchup rather than a gap above the footer. */
.pbt-matchup {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto;
  gap: 10px;
  align-items: start;
  align-content: center;
  padding: 14px 0 16px;
}
.pbt-who {
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 7px;
}
.pbt-eyebrow {
  font-family: var(--gd-font-mono);
  font-size: 11px;
  letter-spacing: .14em;
  color: var(--gd-text-3);
  white-space: nowrap;
}
/* Avatar: initials underneath, headshot layered on top (avatarHtml). The ring
   is inline box-shadow from the painter — team accent per side. */
.pbt-ava {
  position: relative;
  width: 76px;
  height: 76px;
  margin-top: 3px;
  border-radius: 50%;
  background: #1A1D24;
  display: flex;
  align-items: center;
  justify-content: center;
  font: 700 20px/1 var(--gd-font-mono);
  color: #808A9C;
  overflow: hidden;
  flex: none;
}
.pbt-ava img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.pbt-ava--sm { width: 38px; height: 38px; margin-top: 0; font-size: 12px; }
.pbt-nm {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 16px;
  font-weight: 600;
  color: var(--gd-text);
}
.pbt-hand {
  font-family: var(--gd-font-mono);
  font-size: 11.5px;
  letter-spacing: .06em;
  color: var(--gd-text-2);
  min-height: 14px;
}
.pbt-sub {
  font-family: var(--gd-font-mono);
  font-size: 12.5px;
  color: var(--gd-text-3);
}

/* center: COUNT / OUTS over the bases diamond */
.pbt-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding-top: 8px;
}
.pbt-nums { display: flex; gap: 26px; }
.pbt-num { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.pbt-num b {
  font-family: var(--gd-font-mono);
  font-size: 30px;
  font-weight: 700;
  color: var(--gd-text);
  font-variant-numeric: tabular-nums;
}
.pbt-num span {
  font-family: var(--gd-font-mono);
  font-size: 10.5px;
  letter-spacing: .14em;
  color: var(--gd-text-3);
}
/* Bases + zone sizes are FLUID (cqw = 1% of the tile's width), one rule per
   component across every tier — the old fixed px-per-tier ladder meant
   editing the base width silently did nothing whenever a @container override
   was the active one at your window size (founder hit exactly this). To
   resize these now, tune the clamp() preferred/max here and nothing else;
   height follows each svg's viewBox aspect automatically. */
.pbt-bases { width: clamp(92px, 17cqw, 152px); height: auto; display: block; }

/* right edge: the LAST PITCH mini zone */
.pbt-zonebox {
  flex: none;
  width: clamp(96px, 19cqw, 168px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
}
.pbt-zone { line-height: 0; }
.pbt-zone-svg { width: clamp(88px, 18cqw, 160px); height: auto; }
.pbt-zmph {
  font-family: var(--gd-font-mono);
  font-size: 17px;
  font-weight: 700;
  color: var(--gd-text);
}
.pbt-ztype {
  font-family: var(--gd-font-mono);
  font-size: 13px;
  color: var(--gd-text-2);
  min-height: 16px;
}

/* ── footer strip: ON DECK | LAST PITCH ─────────────────────────────────── */
.pbt-foot {
  flex: none;
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-top: 1px solid var(--gd-line);
  margin: 0 -20px;                 /* stretch to the card edges past .pbt-main */
}
.pbt-ondeck,
.pbt-lastp {
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 7px;
  padding: 13px 20px;
}
.pbt-lastp { border-left: 1px solid var(--gd-line); gap: 4px; }
.pbt-od-row { display: flex; align-items: center; gap: 11px; min-width: 0; }
.pbt-od-txt { display: flex; flex-direction: column; min-width: 0; }
.pbt-od-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--gd-text);
}
.pbt-od-avg {
  font-family: var(--gd-font-mono);
  font-size: 11.5px;
  color: var(--gd-text-3);
}
.pbt-lp-mph {
  font-family: var(--gd-font-mono);
  font-size: 16px;
  font-weight: 700;
  color: var(--gd-text);
}
.pbt-lp-type {
  font-family: var(--gd-font-mono);
  font-size: 12.5px;
  color: var(--gd-text-2);
  min-height: 15px;
}

/* ── recent-plays rail ────────────────────────────────────────────────────
   The list is ABSOLUTE inside the rail so its content never sets the tile's
   height — the main panel (and the tile min-height) does. However long the
   game log gets, the rail just scrolls inside whatever height the card has;
   taller cards simply show more rows. */
.pbt-plays {
  position: relative;
  min-height: 0;
  border-left: 1px solid var(--gd-line);
}
.pbt-plays-title {
  height: 40px;
  box-sizing: border-box;
  padding: 14px 14px 0;
  font-family: var(--gd-font-mono);
  font-size: 11px;
  letter-spacing: .14em;
  color: var(--gd-text-3);
}
.pbt-plays-list {
  position: absolute;
  top: 40px;
  bottom: 0;
  left: 0;
  right: 0;
  overflow-y: auto;
  padding: 0 14px 12px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, .14) transparent;
}
.pbt-plays-list::-webkit-scrollbar { width: 6px; }
.pbt-plays-list::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, .14);
  border-radius: 99px;
}
.pbt-pr {
  display: grid;
  /* The result track is CAPPED, not auto: auto tracks max out toward their
     max-content before the 1fr name track sees any space, so at the rail's
     width floor a long unwrapped label ("Swinging Strike", "Fielder's
     Choice") starved the batter name to a one-letter-per-line strip. Capped,
     the label wraps instead and the name keeps a readable share. */
  grid-template-columns: 46px minmax(0, 1fr) minmax(0, 40%);
  gap: 8px;
  align-items: center;
  padding: 8px 0;
  border-bottom: 1px solid var(--gd-line);
}
.pbt-pr:last-child { border-bottom: 0; }
.pbt-pr-ctx {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-family: var(--gd-font-mono);
  font-size: 11px;
  color: var(--gd-text-3);
  white-space: nowrap;
}
.pbt-pr-ctx i { font-style: normal; }
/* Batter cell: headshot + FIRST name stacked over LAST name. Every line
   ellipsizes on its own span — text-overflow can't reach text split into
   anonymous boxes, and mid-word wrapping letter-laddered names at the rail's
   width floor. The ≤800px step hides the avatar and folds the two name spans
   onto one inline line. */
.pbt-pr-who {
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 9px;
}
.pbt-ava--pr { width: 36px; height: 36px; margin-top: 0; font-size: 11px; }
.pbt-pr-names {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.pbt-pr-fn {
  font-size: 11.5px;
  color: var(--gd-text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pbt-pr-ln {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--gd-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Single-word name (no last-name span) reads as the primary line. */
.pbt-pr-fn:only-child {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--gd-text);
}
.pbt-pr-res {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  font-size: 12.5px;
  font-weight: 600;
  text-align: right;
  color: var(--gd-text-2);
}
.pbt-pr-res i {
  font-style: normal;
  font-size: 11px;
  font-weight: 400;
  color: var(--gd-text-3);
}
.pbt-pr-res.is-out { color: #F87171; }
.pbt-pr-res.is-on  { color: #4ADE80; }
.pbt-pr-res.is-xbh { color: #60A5FA; }
.pbt-pr-res.is-hr  { color: #FBBF24; }
/* The in-progress at-bat's row: the "result" is the latest pitch call, dimmer
   than a real outcome so the eye reads it as transient. */
.pbt-pr-res.is-live { font-weight: 500; }
.pbt-pr-empty {
  padding: 12px 0;
  font-family: var(--gd-font-mono);
  font-size: 12px;
  color: var(--gd-text-3);
}

/* ── narrow tiles (container queries — the TILE's width, not the viewport) ─
   Bases/zone WIDTHS are deliberately absent from every step — they're fluid
   (cqw clamps, above) so there is exactly one place to size them. The steps
   only swap typography, spacing and layout form.
   Step 1 (≤800px): the big-screen extras only fit where the matchup row
   genuinely has slack. Below this the chrome, pitcher/batter columns and
   rail go compact (76px avatars in ~70px columns were crushing the names),
   the rail narrows back to 32% and its rows fold to LAST name only, no
   avatar — a folded "First Last" line ellipsizes into uselessness here and
   the surname is the recognizable half. The center components (count /
   bases / zone) HOLD their standard size — this step exists to protect
   them, not shrink them.
   Step 2 (≤680px): the center components step down too — each tile is near
   its ~470px floor.
   Step 3 (≤540px): drop the zone panel (its facts persist in the LAST PITCH
   footer cell) and re-pack the matchup to three columns. */
@container (max-width: 800px) {
  .pbt-head { padding: 10px 14px; gap: 10px; }
  .pbt-live-chip { font-size: 11px; padding: 3px 8px; }
  .pbt-mid { gap: 12px; }
  .pbt-logo { width: 26px; height: 26px; }
  .pbt-code { font-size: 14px; }
  .pbt-score { font-size: 22px; }
  .pbt-inn { font-size: 11.5px; }
  .pbt-cap-x { font-size: 16px; }
  .pbt-body { grid-template-columns: minmax(0, 1fr) minmax(150px, 32%); }
  .pbt-main { padding: 4px 14px 0; }
  .pbt-matchup { gap: 10px; padding: 12px 0 14px; }
  .pbt-eyebrow { font-size: 9.5px; }
  .pbt-who { gap: 5px; }
  .pbt-ava { width: 58px; height: 58px; font-size: 16px; }
  .pbt-ava--sm { width: 30px; height: 30px; font-size: 10px; }
  .pbt-nm { font-size: 13.5px; }
  .pbt-hand { font-size: 10px; min-height: 12px; }
  .pbt-sub { font-size: 10.5px; }
  .pbt-state { gap: 10px; padding-top: 6px; }
  .pbt-nums { gap: 24px; }
  .pbt-num b { font-size: 26px; }
  .pbt-num span { font-size: 10px; }
  .pbt-zonebox { gap: 5px; }
  .pbt-zmph { font-size: 16px; }
  .pbt-ztype { font-size: 12.5px; min-height: 15px; }
  .pbt-foot { margin: 0 -14px; }
  .pbt-ondeck, .pbt-lastp { padding: 10px 14px; gap: 6px; }
  .pbt-lastp { gap: 3px; }
  .pbt-od-row { gap: 9px; }
  .pbt-od-name { font-size: 12px; }
  .pbt-od-avg { font-size: 10px; }
  .pbt-lp-mph { font-size: 13px; }
  .pbt-lp-type { font-size: 10.5px; min-height: 13px; }
  .pbt-plays-title { height: 32px; padding: 12px 12px 0; font-size: 10px; }
  .pbt-plays-list { top: 32px; padding: 0 12px 10px; }
  .pbt-pr { grid-template-columns: 46px minmax(0, 1fr) minmax(0, 45%); gap: 8px; padding: 7px 0; }
  .pbt-pr-ctx { font-size: 9.5px; }
  .pbt-ava--pr { display: none; }
  .pbt-pr-names {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .pbt-pr-fn { display: none; }
  .pbt-pr-fn:only-child { display: inline; font-size: 11.5px; }   /* one-word names keep their span */
  .pbt-pr-ln { display: inline; font-size: 11.5px; }
  .pbt-pr-res { font-size: 11px; }
  .pbt-pr-res i { font-size: 9.5px; }
  .pbt-pr-empty { font-size: 10.5px; }
}
@container (max-width: 680px) {
  .pbt-nums { gap: 18px; }
  .pbt-num b { font-size: 20px; }
  .pbt-num span { font-size: 9px; }
  .pbt-zmph { font-size: 13px; }
  .pbt-ztype { font-size: 10.5px; min-height: 13px; }
}
@container (max-width: 540px) {
  .pbt-zonebox { display: none; }
  .pbt-matchup { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); }
}

/* Centered over the whole overlay, NOT flex-auto-margins: the sibling
   .pbt-grid is flex:1 and flexible lengths resolve before auto margins, so
   margin:auto collapsed to 0 and the message sat pinned to the bottom edge.
   pointer-events:none because inset:0 also spans the Back-button row — it
   must stay clickable through this. And the [hidden] override is LOAD-BEARING
   (same trap as .pbt-restore): the author `display: flex` would otherwise
   beat the UA's `[hidden] { display: none }` and pin the message on screen
   over live tiles. */
.pbt-empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  pointer-events: none;
  color: var(--gd-text-3);
  font-family: var(--gd-font-mono);
  font-size: .85rem;
}
.pbt-empty[hidden] { display: none; }

.pbt-toast {
  position: fixed;
  left: 50%;
  bottom: 28px;
  transform: translateX(-50%);
  z-index: 10001;
  background: #14161C;
  border: 1px solid rgba(255, 255, 255, .14);
  border-radius: 10px;
  color: #e5e7eb;
  font-size: .85rem;
  padding: 10px 16px;
}

/* ── entry point: the dashboard filter bar, immediately left of Home Runs ──
   The button carries .wb-dash-action too, so all of its geometry — padding,
   font, radius, border colour, inline-flex centring — comes from
   schedule-dashboard.css:63 and matches the Home Runs link exactly. Only the
   colour is overridden here: the shared white border, a subtle red wash, and
   the LIVE red (#ef4444 — the red of the live dot and the Live count) on the
   label, because the button only exists while games are live.

   The auto margin moves from .wb-dash-actions ONTO this button so the pair
   travel to the right edge together instead of being pushed to opposite ends.
   Both carrying `margin-left: auto` would split the slack between them.

   These rules must out-order .wb-dash-action's (identical specificity, later
   wins) — mlb-theater.css is loaded after schedule-dashboard.css in
   index.html.

   The `[hidden]` override below is LOAD-BEARING, not insurance: borrowing
   .wb-dash-action also inherits its `display: inline-flex`
   (schedule-dashboard.css:172), which beats the UA's `[hidden] { display:none }`
   — without the override the button could never hide, and it is hidden whenever
   nothing is live. `.pbt-open[hidden]` (0,0,2,0) out-specifies it. */
.pbt-open {
  margin-left: auto;
  background: rgba(239, 68, 68, .10);
  color: #ef4444;
  cursor: pointer;
  font-weight: 600;
}
.pbt-open:hover {
  background: rgba(239, 68, 68, .18);
  border-color: rgba(239, 68, 68, .45);
  color: #ef4444;
}
/* :not([hidden]) is load-bearing: the button is INSERTED on every MLB
   schedule:ready but VISIBLE only with 2+ live games, and the `+` combinator
   matches on DOM adjacency, not visibility — a bare `.pbt-open +` would strip
   the actions slot's own `margin-left: auto` (its right-edge alignment) all
   day while the hidden button pushes nothing. */
.pbt-open:not([hidden]) + .wb-dash-actions { margin-left: 0; }
.pbt-open[hidden] { display: none; }

/* ── HARD mobile exclusion ────────────────────────────────────────────────
   The schedule dashboard this launches from is desktop-only, and four-across
   tile content in a phone column is unreadable — theaterMLB.js refuses to
   open below 1001px (a narrow deep link bounces to /mlb/schedule) and closes
   on resize; this is the backstop for the frame before the matchMedia
   listener fires. */
@media (max-width: 1000px) {
  .pbt-open,
  .pbt-overlay { display: none !important; }
}
