*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html {
  /* Hover/tap tooltips (.card-tooltip-wrap etc) are visibility:hidden when
     closed, but a hidden element still keeps its layout box, and that box
     is positioned via `left:50%` BEFORE the centering `transform:
     translateX(-50%)` is applied -- transforms don't count toward
     scrollable overflow, so a tooltip anchored near a viewport edge keeps
     quietly widening the page even while invisible. overflow-x:hidden
     doesn't affect any visible in-flow content, only clips this kind of
     off-screen invisible box. */
  overflow-x: hidden;
  /* The app is dark everywhere, but a dark background doesn't tell the
     browser that: without this the chrome it draws itself stays light
     (scrollbars, the date picker's calendar, checkbox internals). */
  color-scheme: dark;
  /* body's own background only ever covers body's box. When the viewport is
     briefly taller than that (address-bar collapse, phone rotation) html's
     background shows through at the edges -- give it the same slate as
     body's so that gap reads as background, not a white bar. */
  background: #07090a;
}

:root {
  --bg-deep:      #0d0c1a;
  --bg-mid:       #181530;
  --bg-warm:      #261c2e;
  --panel:        #211e36;
  --panel-2:      #2a2545;
  --panel-border: #4a3f6e;
  /* --panel/--panel-2, barely transparent, for the top-level panel surfaces:
     the map scroll behind the page (.map-bg) still tints them, but not enough
     for the parchment's bright band to change a panel's own background part
     way across it. At 65% the filter row straddled that band and read as two
     different panels; the map is meant to be the page's field, not something
     the reader has to look through to read a number. */
  --panel-glass:   rgba(33, 30, 54, 0.94);
  --panel-2-glass: rgba(42, 37, 69, 0.94);
  --hairline:     #3a3460;
  --gold:         #e0c468;
  --gold-bright:  #f3d98a;
  --gold-glow:    rgba(224, 196, 104, 0.35);
  --teal:         #6fd6c6;
  --ember:        #d97a3a;
  --text:         #e6e2f2;
  --text-dim:     #a8a2c4;
  /* The type scale: font-sizes outside the phone @media blocks should be one
     of these, so text at the same level reads the same size page to page.
     xs: tags, counts, uppercase labels. sm: secondary text, descriptions.
     md: names and primary text. lg/xl: headline numbers and titles. */
  --fs-xs: 0.8125rem;
  --fs-sm: 0.875rem;
  --fs-md: 1rem;
  --fs-lg: 1.5rem;
  --fs-xl: 2rem;
}

body {
  font-family: "Segoe UI", system-ui, sans-serif;
  color: var(--text);
  padding: 2rem;
  min-height: 100vh;
  /* Own stacking context so .map-bg and body::before (negative z-index,
     below) stack under body's content but above html's background, not
     under html's too. */
  position: relative;
  z-index: 0;
  /* The map-screen slate as baked into the scroll's edges (darkened with
     it), so the page beyond the scroll's width matches seamlessly. */
  background: #07090a;
}
/* The act-map parchment scroll (baked, darkened, by
   tools/bake_map_background.py), pinned behind the page like the map screen.
   .map-bg (in run.py's page markup) is panned top-to-bottom as the page
   scrolls by js/map-bg.js. Fixed elements rather than
   background-attachment:fixed, which iOS Safari ignores. It's the viewport's width up to 1400px, but at
   least 1.5 screens tall, so on a phone (where the full width would be barely
   a screen tall) it crops the slate at its sides and still has room to pan. */
.map-bg {
  position: fixed;
  top: 0;
  left: 50%;
  z-index: -2;
  pointer-events: none;
  width: max(min(1400px, 100%), calc(150vh * 1400 / 2971));
  width: max(min(1400px, 100%), calc(150lvh * 1400 / 2971));
  aspect-ratio: 1400 / 2971;
  background: url(/ui_icons/map_scroll.webp) 0 0 / 100% 100% no-repeat;
  transform: translate3d(-50%, 0, 0);
  will-change: transform;
}
/* A vignette easing the scroll's edges into the slate; it never moves. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(ellipse at 50% 40%, transparent 50%, rgba(10, 12, 14, 0.55) 100%);
}

h1 {
  font-size: var(--fs-xl);
  font-weight: 700;
  letter-spacing: .02em;
  margin-bottom: 0.25rem;
  background: linear-gradient(180deg, var(--gold-bright) 0%, var(--gold) 60%, #c9a04e 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  text-shadow: 0 0 18px var(--gold-glow);
  display: inline-block;
}
.subtitle { color: var(--text-dim); margin-bottom: 2rem; font-size: var(--fs-md); }

/* ---- Summary stat cards ---- */
/* Was flex-wrap with flex:0 0 auto cards, so each card sized to its own
   label/value/sub content -- rows never lined up column-to-column, and a
   card with a longer sub (Time Played, Best Win %) ballooned wider
   than its neighbors for no reason. A grid of equal-width tracks fixes both:
   every card is the same width, and one wrapping to a second row still lines
   up under the column above it. minmax(220px, 1fr): wide enough that none of
   the nine cards' content wraps awkwardly, narrow enough to fit 4-5 per row
   on a laptop-width screen. Fixed counts that divide the nine cards evenly
   (5 + 4, then 3 + 3 + 3) rather than auto-fit, which left 7 + a lonely 2
   on wide screens and 4 + 4 + 1 at 1280px. */
.cards {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 1rem;
  margin-bottom: 2.5rem;
}
@media (max-width: 1200px) {
  .cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* The dashboard's summary row is 8 cards, not 9,
   so four across divides it into 4 + 4 with no ragged edge. Keyed off the id
   rather than .cards because .cards is shared with the finder's 6-card grid
   (players.css .site-cards) and the Personal Bests row, both of which need
   their own counts. */
#summary-cards { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* Each summary card is a bar: label left, value right, one line instead of the
   stacked three. Eight short facts cost 187px of the fold stacked and 107px
   like this, and the numbers line up into a readable column down the page.
   The secondary detail that used to sit under the value is on data-tip now.

   Only above 1250px. A bar needs room for its label and value on one line --
   the longest label is "Elites/Bosses Defeated", ~165px -- and below that the
   label wraps and drags its value out of line with the cards beside it. Narrower
   screens keep the stacked card, which needs no such room. */
@media (min-width: 1251px) {
  #summary-cards .card {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.55rem 0.9rem;
  }
  #summary-cards .card .label { margin: 0; }
  #summary-cards .card .value { line-height: 1; }
}

/* Personal bests: force 5 equal columns so tiles never leave an orphan.
   minmax(0, 1fr), not bare 1fr -- bare 1fr is minmax(auto, 1fr), so a
   column holding a wide character panel refuses to shrink below that
   content's width and blows the grid out past the viewport instead of
   letting the panel's own content wrap (see the mobile override below,
   and .grid-2/.grid-4 further down, for the same fix). */
#personal-bests-cards {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
}
/* Most Picked/Best Win % card & relic rows: same hover-tooltip anchoring as
   the deck/relic tiles they borrow buildCardTooltip/buildRelicTooltip from
   (.card-tooltip-wrap / .relic-tooltip-wrap below), just on a row-shaped
   wrapper instead of a square tile. */
.fav-item {
  position: relative;
  z-index: 1;
}
.fav-item:hover {
  z-index: 100;
}
.fav-item:hover .card-tooltip-wrap,
.fav-item:hover .relic-tooltip-wrap,
.fav-item:focus-within .card-tooltip-wrap,
.fav-item:focus-within .relic-tooltip-wrap {
  visibility: visible;
}
/* Card Stats table: the card art beside each name (62px-wide thumbnails). */
/* Card Stats: the table at a snug width, and on wide screens the full card of
   the row under the pointer in the space beside it (previewCard). */
.cards-split { display: flex; gap: 1.5rem; align-items: stretch; }
.cards-list { flex: 0 1 1040px; min-width: 0; max-height: min(70vh, 720px); overflow-y: auto; }
.cards-preview { display: none; flex: 1 1 0; min-width: 0; align-items: center; justify-content: flex-start; padding-left: 1.5rem; }
.cards-preview .cardface, .cards-preview .card-tooltip { width: min(360px, 100%) !important; max-height: min(70vh, 720px); object-fit: contain; }
#cards-tbody tr.cards-current td { background: rgba(255,255,255,.06); }
@media (min-width: 1420px) { .cards-preview { display: flex; } }
/* Seed Data, same idea: a snug list, and the picked seed's deck and relics
   beside it (previewSeed) instead of under its row. */
.seeds-list { flex: 1 1 auto; min-width: 0; }
.seeds-preview { display: none; }
@media (min-width: 1100px) {
  .seeds-list { flex: 0 1 auto; max-width: 60%; max-height: min(70vh, 720px); overflow-y: auto; position: sticky; top: 1rem; align-self: flex-start; }
  #seeds-table { width: auto; }
  #seeds-table .seed-expand-arrow { display: none; }
  #seeds-tbody tr.seed-current td { background: rgba(255,255,255,.06); }
  .seeds-preview { display: block; flex: 1 1 0; min-width: 0; align-self: flex-start; }
  /* Smaller tiles than under a row: the whole deck should fit beside the list. */
  .seeds-preview .seed-detail-panel { padding-top: 0; }
}
/* Cards and Seeds: the column headings stay put while the rows scroll.
   box-shadow, not a border: a collapsed border stays behind when the cell sticks. */
#cards-table-main thead, #seeds-table thead { position: sticky; top: 0; z-index: 2; }
#cards-table-main thead th, #seeds-table thead th { background: var(--panel-2); border-bottom: 0; box-shadow: inset 0 -2px 0 var(--hairline); }
.cards-thumb-wrap { display: inline-block; vertical-align: middle; margin-right: 10px; line-height: 0; }
.cards-hi { font-size: var(--fs-md); }
.cards-thumb { width: 44px; height: 33px; object-fit: contain; border-radius: 4px; vertical-align: middle; }
.fav-item-face {
  flex: 0 0 auto;
}
.card {
  flex: 0 0 auto;
  background: linear-gradient(165deg, var(--panel-2-glass) 0%, var(--panel-glass) 100%);
  border: 1px solid var(--panel-border);
  border-top-color: var(--gold-glow);
  border-radius: 10px;
  padding: 0.6rem 1rem;
  box-shadow: 0 4px 18px rgba(0,0,0,0.35), inset 0 1px 0 rgba(255,255,255,0.03);
}
.card .label { font-size: var(--fs-sm); color: var(--text-dim); text-transform: uppercase; letter-spacing: .06em; }
.card .value { font-size: var(--fs-lg); font-weight: 700; color: var(--gold); line-height: 1.2; text-shadow: 0 0 10px var(--gold-glow); }
.card .sub   { font-size: var(--fs-sm); color: var(--text-dim); margin-top: 0.1rem; }

/* Personal Bests stat values that link to the run behind them (see
   statLink() in dashboard.js) — gold on hover, matching every other
   interactive-text affordance in the app. */
.pb-stat-link:hover { color: var(--gold) !important; }
/* ---- Ascension Tracker (Overview) ---- */
/* One card per character, solo over multiplayer. auto-fit so a player with
   two characters gets two wide cards and a phone gets one or two per row. */
#asc-tracker-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0.75rem;
}
.asc-card {
  background: rgba(255,255,255,0.04);
  border-top: 3px solid var(--panel-border);
  border-radius: 8px;
  padding: 0.7rem 0.8rem;
  min-width: 0;
}
.asc-name { font-size: var(--fs-sm); font-weight: 600; color: var(--text); }
.asc-mode { margin-top: 0.5rem; }
.asc-mode + .asc-mode { border-top: 1px solid var(--panel-border); margin-top: 0.65rem; padding-top: 0.6rem; }
.asc-mode-label { font-size: var(--fs-xs); color: var(--text-dim); text-transform: uppercase; letter-spacing: .07em; }
.asc-big { font-size: var(--fs-xl); font-weight: 700; line-height: 1.1; }
.asc-big.asc-none { color: var(--text-dim) !important; opacity: 0.6; }
.asc-sub { font-size: var(--fs-sm); color: var(--text-dim); }
.asc-pips { display: flex; gap: 2px; margin: 0.5rem 0 0.45rem; }
.asc-pip { flex: 1; height: 6px; border-radius: 3px; background: rgba(255,255,255,0.1); }
.asc-now { font-size: var(--fs-sm); color: var(--text); opacity: 0.85; }
/* Title and caption left, three headline numbers right. */
.asc-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem 2rem; flex-wrap: wrap; }
.asc-stats { display: flex; gap: 1.75rem; margin-bottom: 0.9rem; }
.asc-stats div { font-size: var(--fs-sm); color: var(--text-dim); }
.asc-stats b { display: block; font-size: var(--fs-lg); line-height: 1.2; color: var(--gold); }

/* ---- Fight lanes (Overview): win rate, HP entering, damage taken ---- */
.fl-legend { font-size: var(--fs-sm); color: var(--text-dim); margin-bottom: 0.25rem; }
.fl-legend i { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin: 0 5px 0 12px; }
.fl-legend i:first-child { margin-left: 0; }
.fl-won  { background: #5cba7d; }
.fl-lost { background: #e05c5c; }
/* Elites left, bosses right, a row per act. */
.fl-groups { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.25rem 2.5rem; }
.fl-section { font-size: var(--fs-xs); letter-spacing: 0.07em; text-transform: uppercase; color: var(--gold); margin: 0.75rem 0 0.4rem; }
.fl-rows { display: grid; grid-template-columns: 26px 9.5rem minmax(0, 1fr); gap: 0.35rem 0.6rem; align-items: center; font-size: var(--fs-sm); }
.fl-rows img { width: 26px; height: 26px; object-fit: contain; }
/* The lane stops short of the edge to leave room for the value text. */
.fl-lane { position: relative; height: 18px; margin-right: 6.5rem; background: linear-gradient(rgba(255,255,255,0.08), rgba(255,255,255,0.08)) 0 8px / 100% 2px no-repeat; }
.fl-line { position: absolute; top: 6px; height: 6px; border-radius: 3px; background: linear-gradient(90deg, #5cba7d, #e05c5c); }
.fl-line-rev { background: linear-gradient(90deg, #e05c5c, #5cba7d); }
.fl-dot { position: absolute; top: 3px; width: 12px; height: 12px; border-radius: 50%; transform: translateX(-6px); }
.fl-value { position: absolute; top: 1px; font-size: var(--fs-xs); color: #bcbcd0; white-space: nowrap; }
.fl-fill { position: absolute; left: 0; top: 4px; height: 10px; border-radius: 3px; min-width: 2px; }
.fl-band { position: absolute; top: 6px; height: 6px; border-radius: 3px; background: #5cba7d; }
.fl-low { background: var(--panel); box-shadow: inset 0 0 0 2px #5cba7d; }
.fl-axis { height: 14px; background: none; font-size: var(--fs-xs); color: var(--text-dim); }
.fl-axis span { position: absolute; transform: translateX(-50%); }
/* Character lanes (Time Played, Cards & Relics): character, two lanes. */
.re-rows { display: grid; grid-template-columns: 7rem minmax(0, 1fr) minmax(0, 1fr); gap: 0.35rem 2.5rem; align-items: center; font-size: var(--fs-sm); }
.re-rows .fl-section { margin: 0.5rem 0 0.1rem; }
.re-rows .fl-lane { margin-right: 4.5rem; }
.re-rows .fl-section .fl-legend { margin-left: 1rem; letter-spacing: 0; text-transform: none; }
.re-ring { background: var(--panel); box-shadow: inset 0 0 0 2px #bcbcd0; }
.re-dot  { background: #bcbcd0; }
@media (max-width: 900px) { .fl-groups { grid-template-columns: minmax(0, 1fr); } }
/* Phones: the name sits over a full-width lane, so the lane has room to show
   differences. Axis labels thin to 0 / mid / max. */
@media (max-width: 700px) {
  .fl-rows { grid-template-columns: 26px minmax(0, 1fr); row-gap: 0.1rem; }
  .fl-rows > span { display: none; }
  .fl-rows .fl-lane { grid-column: 1 / -1; margin-bottom: 0.45rem; }
  .fl-rows .fl-axis { margin-bottom: 0; }
  .fl-axis span:nth-child(2), .fl-axis span:nth-child(4) { display: none; }
  .re-rows { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 1rem; }
  .re-rows > span { display: none; }
  .re-rows > div:not(.fl-section):not(.fl-lane) { grid-column: 1 / -1; margin-top: 0.3rem; }
  .re-rows .fl-lane { margin-right: 5.2rem; }
  /* The key drops under its lane title: beside it, it wraps mid-key. */
  .re-rows .fl-section .fl-legend { display: block; margin: 0.15rem 0 0; font-size: 0.68rem; white-space: nowrap; }
}

/* ---- Chart layout grids ---- */
.grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
  margin-bottom: 2rem;
}
.grid-4 {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  gap: 1.5rem;
  margin-bottom: 2rem;
}
.grid-4.grid-3 { grid-template-columns: 1fr 1fr 1fr; }
.grid-1 { margin-bottom: 2rem; }


.chart-box {
  background: linear-gradient(165deg, var(--panel-2-glass) 0%, var(--panel-glass) 100%);
  border: 1px solid var(--panel-border);
  border-top-color: var(--gold-glow);
  border-radius: 10px;
  padding: 1.25rem;
  box-shadow: 0 4px 18px rgba(0,0,0,0.35), inset 0 1px 0 rgba(255,255,255,0.03);
  /* Grid items default to min-width:auto and refuse to shrink below their
     content, which lets a wide pivot table push the whole page wider instead
     of scrolling inside .pivot-wrap. */
  min-width: 0;
}
.chart-box h2 { font-size: var(--fs-md); color: var(--text); margin-bottom: 1rem; }
/* One-line "how to read this" under a heading whose cells aren't self-explanatory. */
.chart-box h2:has(+ .chart-caption) { margin-bottom: 0.25rem; }
.chart-caption { font-size: var(--fs-sm); color: var(--text-dim); margin-bottom: 0.9rem; }

/* 300px: room for a plot after the --fs-sm axis labels and legend. */
.chart-wrap { position: relative; height: 300px; }

/* Act Boss Defeated, by Rest Site Choices: a Heal and a Smith chart share one
   half-width box, a little shorter so the box stays level with its neighbour
   once the Heal/Smith labels are added. Stacked on phones (below). */
.rest-act-pair { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0.75rem; }
.rest-act-pair h3 { font-size: var(--fs-sm); color: var(--text-dim); text-align: center; margin-bottom: 0.3rem; }
.rest-act-pair .chart-wrap { height: 276px; }
@media (max-width: 700px) {
  .rest-act-pair { grid-template-columns: minmax(0, 1fr); }
}

/* A default OS/browser scrollbar (thin, gray, sometimes overlay-hidden until
   hover) gives no visible cue that a pivot table has more columns off to the
   right (notably the ALL rollup column) — style it to be unmistakably always
   visible instead. */
/* overflow-x:auto below already clips the wide pivot table visually at any
   viewport width -- no horizontal page scrollbar appears and .pivot-wrap's
   own rect fits the viewport -- but document.documentElement.scrollWidth
   still grows to the UNCLIPPED table width anyway (a Chromium quirk: a
   descendant scroll container's full content size leaks into the page's
   reported scrollWidth even though it's genuinely clipped on screen).
   contain:paint makes that containment authoritative instead of just
   visual, which is the only thing that actually brings scrollWidth back
   down. Safe here since overflow-x:auto already stops anything from
   visibly escaping this box in either axis. */
.pivot-wrap {
  overflow-x: auto;
  contain: paint;
  scrollbar-width: auto;
  scrollbar-color: var(--gold) var(--panel-2);
}
.pivot-wrap::-webkit-scrollbar { height: 10px; }
.pivot-wrap::-webkit-scrollbar-track { background: var(--panel-2); border-radius: 5px; }
.pivot-wrap::-webkit-scrollbar-thumb { background: var(--gold); border-radius: 5px; }
.pivot-wrap::-webkit-scrollbar-thumb:hover { background: var(--gold-bright); }

/* ---- Pivot tables ---- */
.pivot {
  border-collapse: collapse;
  font-size: var(--fs-sm);
  min-width: 100%;
}
.pivot th {
  padding: 0.5rem 0.9rem;
  color: var(--text-dim);
  font-weight: 600;
  font-size: var(--fs-sm);
  text-transform: uppercase;
  letter-spacing: .05em;
  border-bottom: 2px solid var(--hairline);
  white-space: nowrap;
  text-align: center;
}
.pivot th.char-head { text-align: left; }
.pivot td.char-name {
  padding: 0 1rem 0 0.25rem;
  font-weight: 600;
  white-space: nowrap;
  border-right: 1px solid var(--hairline);
}
.pivot td.char-name .dot {
  display: inline-block;
  width: 8px; height: 8px;
  border-radius: 50%;
  margin-right: 8px;
  vertical-align: middle;
}
.pivot td.cell {
  text-align: center;
  padding: 0.3rem 0.5rem;
  border: 1px solid #0a0916;
  min-width: 72px;
  vertical-align: middle;
  transition: filter .1s;
}
.pivot td.cell:hover { filter: brightness(1.25); cursor: default; }
.pivot td.cell .pct  { font-weight: 700; font-size: var(--fs-md); line-height: 1.2; }
.pivot td.cell .meta { font-size: var(--fs-sm); color: rgba(255,255,255,.72); margin-top: 1px; }
.pivot td.cell.empty { color: #4a4570; background: var(--panel); }
.pivot tr.total-row td { border-top: 2px solid var(--hairline); }
.pivot td.act-header {
  padding: 0.5rem 0.25rem 0.2rem;
  font-size: var(--fs-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--gold);
  border-top: 2px solid var(--hairline);
}
.pivot tr.total-row td.char-name { color: var(--gold); }
.pivot td.cell.all-col { border-left: 2px solid var(--hairline); }

/* ---- Filter bar ---- */
.filter-bar {
  background: linear-gradient(165deg, var(--panel-2-glass) 0%, var(--panel-glass) 100%);
  border: 1px solid var(--panel-border);
  border-top-color: var(--gold-glow);
  border-radius: 10px;
  padding: 0.75rem 1.25rem;
  margin-bottom: 1.5rem;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  box-shadow: 0 4px 18px rgba(0,0,0,0.35), inset 0 1px 0 rgba(255,255,255,0.03);
}
.filter-bar-2row {
  flex-direction: column;
  align-items: stretch;
  gap: 0.5rem;
}
.filter-bar-2row .filter-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
}
/* The one-line summary the filter rows collapse behind. This used to be
   phone-only, but the rows cost the top third of every page at any width, and
   the summary doubles as a readable statement of the current filter state.
   Scoped to .filter-bar-2row, the only bar that has a summary button -- the
   Card Stats bar is a plain .filter-bar and must keep its rows visible. */
.filter-bar-2row .filter-summary {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0;
  background: none;
  border: 0;
  color: var(--text);
  font: inherit;
  font-size: var(--fs-sm);
  text-align: left;
  cursor: pointer;
}
.filter-bar-2row .filter-summary:hover .filter-summary-caret { color: var(--text); }
.filter-bar-2row .filter-summary-text {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.filter-bar-2row .filter-summary-caret { color: var(--text-dim); transition: transform 0.15s; }
.filter-bar-2row:not(.expanded) .filter-row { display: none; }
.filter-bar-2row.expanded .filter-summary {
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--hairline);
}
.filter-bar-2row.expanded .filter-summary-caret { transform: rotate(180deg); }
.filter-bar-2row .filter-row + .filter-row {
  padding-top: 0.5rem;
  border-top: 1px solid var(--hairline);
}
.filter-bar .filter-label {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: .06em;
  white-space: nowrap;
  margin-right: 0.25rem;
}
.filter-bar label {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-size: var(--fs-sm);
  color: var(--text);
  cursor: pointer;
  padding: 0.25rem 0.6rem;
  border-radius: 5px;
  border: 1px solid transparent;
  transition: background .15s, border-color .15s;
  user-select: none;
}
.filter-bar label:hover { background: rgba(255,255,255,0.05); }
.filter-bar label.checked { border-color: var(--gold-glow); background: rgba(224,196,104,0.12); color: var(--gold); }
.filter-bar input[type=checkbox] { accent-color: var(--gold); width: 14px; height: 14px; cursor: pointer; }
.filter-bar .sep { width: 1px; height: 20px; background: var(--hairline); margin: 0 0.25rem; }
.filter-bar .filter-group {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.6rem;
  border: 1px solid var(--hairline);
  border-radius: 8px;
  background: rgba(0,0,0,0.18);
}
.filter-bar .toggle-btn {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  background: none;
  border: 1px solid var(--hairline);
  border-radius: 4px;
  padding: 0.2rem 0.5rem;
  cursor: pointer;
  transition: color .15s, border-color .15s;
}
.filter-bar .toggle-btn:hover { color: var(--gold); border-color: var(--gold); }

/* "Save as default" is the one action here worth reaching for, unlike the
   purely-corrective Reset — give it a permanent gold tint (not just on
   hover) so it reads as the primary action, plus a quick pop on click for
   tactile save confirmation beyond the small status text next to it. */
.filter-bar .toggle-btn-primary {
  color: var(--gold);
  border-color: color-mix(in srgb, var(--gold) 55%, transparent);
  background: rgba(224,196,104,0.08);
}
.filter-bar .toggle-btn-primary:hover {
  background: rgba(224,196,104,0.16);
  box-shadow: 0 0 10px var(--gold-glow);
}
@keyframes toggle-btn-pop {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.12); box-shadow: 0 0 12px var(--gold-glow); }
  100% { transform: scale(1); }
}
.filter-bar .toggle-btn-primary.pop { animation: toggle-btn-pop 0.32s ease; }
.filter-bar input[type=date] {
  background: rgba(0,0,0,0.25);
  border: 1px solid var(--hairline);
  border-radius: 4px;
  color: var(--text);
  padding: 0.2rem 0.6rem;
  font-size: var(--fs-sm);
  font-family: inherit;
  cursor: pointer;
}
/* The control is drawn by the browser in its dark scheme now (html's
   color-scheme), so the indicator already comes out light; the invert that
   used to brighten it would darken it straight back onto the dark input. */
.filter-bar input[type=date]::-webkit-calendar-picker-indicator { cursor: pointer; }

/* ---- Page tabs ---- */
.page-tabs {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
}
.page-tab {
  font-size: var(--fs-sm);
  font-family: inherit;
  font-weight: 600;
  color: var(--text-dim);
  background: var(--panel);
  border: 1px solid var(--hairline);
  border-radius: 6px;
  padding: 0.4rem 1.1rem;
  cursor: pointer;
  transition: color .15s, border-color .15s, background .15s, box-shadow .15s;
}
.page-tab:hover { color: var(--gold); border-color: var(--gold-glow); }
.page-tab.active {
  color: var(--gold-bright);
  border-color: var(--gold);
  background: linear-gradient(165deg, rgba(224,196,104,0.16), rgba(224,196,104,0.04));
  box-shadow: 0 0 14px var(--gold-glow);
}

/* ---- Character selector buttons ---- */
.char-btn {
  font-size: var(--fs-sm);
  font-family: inherit;
  font-weight: 600;
  color: var(--text-dim);
  background: none;
  border: 1px solid var(--hairline);
  border-radius: 5px;
  padding: 0.25rem 0.7rem;
  cursor: pointer;
  transition: color .15s, border-color .15s, background .15s, box-shadow .15s;
}
.char-btn:hover { color: var(--char-color, var(--gold)); border-color: var(--char-color, var(--gold)); }
.char-btn.active {
  color: var(--char-color, var(--gold));
  border-color: var(--char-color, var(--gold));
  background: rgba(255,255,255,0.06);
  box-shadow: 0 0 10px color-mix(in srgb, var(--char-color, var(--gold)) 45%, transparent);
}
.char-btn:disabled { color: #4a4570; border-color: var(--hairline); cursor: not-allowed; }



/* ---- Seeds page ---- */
.seed-show-more {
  font-size: var(--fs-sm);
  font-family: inherit;
  font-weight: 600;
  color: var(--text-dim);
  background: none;
  border: 1px solid var(--hairline);
  border-radius: 5px;
  padding: 0.3rem 0.9rem;
  margin: 0 0.3rem;
  cursor: pointer;
  transition: color .15s, border-color .15s;
}
.seed-show-more:hover { color: var(--gold); border-color: var(--gold); }

.seeds-search-area {
  display: flex;
  gap: 1.5rem;
  flex-wrap: wrap;
  align-items: flex-start;
  margin-top: 0.75rem;
}

.seeds-search-col {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  /* Capped, so "Clear all" lands just after the two inputs instead of being
     pushed to the far right of the row by two flex: 1 columns that grow. */
  flex: 1 1 240px;
  min-width: 220px;
  max-width: 380px;
}

/* Nothing has been searched for yet, so the matched-items column would be a
   blank ~40% of the table, squeezing the four columns that do have data.
   Keyed off a class seeds.js sets; only the header cell and the seed rows,
   not the expanded detail rows (which span the whole table). */
#seeds-table.no-search thead th:last-child,
#seeds-table.no-search tr.seed-row > td:last-child { display: none; }

.seeds-search-label {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: .06em;
}

.seeds-typeahead-wrap {
  position: relative;
}

.seeds-input {
  width: 100%;
  background: rgba(0,0,0,0.25);
  border: 1px solid var(--hairline);
  border-radius: 6px;
  color: var(--text);
  padding: 0.35rem 0.75rem;
  font-size: var(--fs-sm);
  font-family: inherit;
  outline: none;
  transition: border-color .15s;
}
.seeds-input:focus { border-color: var(--gold); }

.seeds-dropdown {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  background: var(--panel-2);
  border: 1px solid var(--panel-border);
  border-radius: 6px;
  z-index: 50;
  max-height: 220px;
  overflow-y: auto;
  box-shadow: 0 4px 16px rgba(0,0,0,0.5);
}

.seeds-dropdown-item {
  padding: 0.4rem 0.75rem;
  font-size: var(--fs-sm);
  color: var(--text);
  cursor: pointer;
  transition: background .1s;
}
.seeds-dropdown-item:hover { background: rgba(255,255,255,0.06); color: var(--gold); }

.filter-dropdown-wrap { position: relative; }
.filter-dropdown-panel {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  background: var(--panel-2);
  border: 1px solid var(--panel-border);
  border-radius: 6px;
  z-index: 50;
  min-width: 160px;
  max-height: 260px;
  display: flex;
  flex-direction: column;
  box-shadow: 0 4px 16px rgba(0,0,0,0.5);
  padding: 0.4rem;
}
.filter-dropdown-actions {
  display: flex;
  gap: 0.3rem;
  flex: 0 0 auto;
}
.filter-dropdown-actions .toggle-btn { flex: 1 1 0; margin: 0; }
.filter-dropdown-scroll {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  overflow-y: auto;
  min-height: 0;
}
.filter-dropdown-panel label {
  display: flex;
  width: 100%;
  margin: 0;
}
.filter-dropdown-panel .sep {
  width: auto;
  height: 1px;
  margin: 0.3rem 0;
  flex: 0 0 auto;
}

.seeds-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  min-height: 1.8rem;
}

.seeds-chip {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  background: rgba(224,196,104,0.1);
  border: 1px solid var(--gold-glow);
  border-radius: 5px;
  padding: 0.2rem 0.5rem;
  font-size: var(--fs-sm);
  color: var(--text);
}

.seeds-chip-label { color: var(--text); }

.seeds-chip-qty {
  display: flex;
  align-items: center;
  gap: 0.2rem;
}

.seeds-chip-min {
  font-size: var(--fs-sm);
  color: var(--gold);
  min-width: 1.8rem;
  text-align: center;
}

.seeds-chip-adj {
  background: none;
  border: 1px solid var(--panel-border);
  border-radius: 3px;
  color: var(--text-dim);
  cursor: pointer;
  font-size: var(--fs-sm);
  line-height: 1;
  padding: 0 0.3rem;
  transition: color .1s, border-color .1s;
}
.seeds-chip-adj:hover { color: var(--gold); border-color: var(--gold); }
.seeds-chip-adj:disabled { color: #4a4570; border-color: var(--hairline); cursor: default; }
.seeds-chip-qty-label { font-size: var(--fs-xs); color: var(--text-dim); text-transform: uppercase; letter-spacing: .04em; }

.seeds-chip-remove {
  background: none;
  border: none;
  color: #7a7398;
  cursor: pointer;
  font-size: var(--fs-md);
  line-height: 1;
  padding: 0 0.1rem;
  transition: color .1s;
}
.seeds-chip-remove:hover { color: #e05c5c; }

.seed-row:hover { background: rgba(255,255,255,0.04); }

.seed-detail-panel {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1rem 1.25rem;
}

.seed-detail-section {
  width: 100%;
}

.seed-detail-label {
  font-size: var(--fs-xs);
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: .06em;
  margin-bottom: 0.5rem;
}

/* One card type per block, as on Run History. */
.seed-detail-cards { display: block; }

.seed-match-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-bottom: 3px;
}

.seed-loc-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
}

.seed-loc-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  border: 1px solid;
  border-radius: 4px;
  padding: 0.1rem 0.4rem;
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: default;
  white-space: nowrap;
}

/* =========================================================================
   Run Detail page
   ========================================================================= */

#detail-layout {
  display: grid;
  /* minmax(0, ...): a bare 1fr never shrinks below its content, and a drawn
     chart canvas is content, so narrowing the window (or zooming in) left
     the timeline as wide as before, clipped off the right edge. */
  grid-template-columns: var(--run-list-width, 230px) minmax(0, 1fr);
  gap: 1.5rem;
  align-items: start;
}
/* A "Modded" tag in the run list needs the room: 316px fits the widest row
   (Necrobinder, A10, tag, two-digit month and day) beside a scrollbar. A
   variable, so the phone layout's single column still wins. */
#detail-layout:has(.detail-run-item .run-modded-tag) { --run-list-width: 316px; }

/* ---- Run list (left column) ---- */

#detail-run-list {
  background: linear-gradient(165deg, var(--panel-2-glass) 0%, var(--panel-glass) 100%);
  border: 1px solid var(--panel-border);
  border-top-color: var(--gold-glow);
  border-radius: 8px;
  max-height: 70vh;
  overflow-y: auto;
  box-shadow: 0 4px 18px rgba(0,0,0,0.35), inset 0 1px 0 rgba(255,255,255,0.03);
}

.detail-run-item {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.45rem 0.75rem;
  cursor: pointer;
  border-bottom: 1px solid var(--hairline);
  font-size: var(--fs-sm);
  white-space: nowrap;
  overflow: hidden;
  transition: background 0.1s;
}
.detail-run-item:last-child { border-bottom: none; }
.detail-run-item:hover { background: rgba(255,255,255,0.05); }
.detail-run-item.active { background: rgba(224,196,104,0.1); border-left: 3px solid var(--gold); padding-left: calc(0.75rem - 3px); }

.detail-run-header-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0.75rem;
  font-size: var(--fs-sm);
  color: var(--text-dim);
  border-bottom: 1px solid var(--hairline);
  position: sticky;
  top: 0;
  background: var(--panel-2);
}
.detail-run-char { font-weight: 600; }
.detail-run-asc  { font-size: var(--fs-sm); }
.detail-run-won  { font-weight: 700; font-size: var(--fs-sm); }
.detail-run-floor { font-size: var(--fs-sm); }
.detail-run-date  { font-size: var(--fs-sm); margin-left: auto; }

/* "Modded": on a run the game mod reported loaded mods for, in the run list
   and the run header. The mod list is its data-tip. */
.run-modded-tag {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  line-height: 1.5;
  padding: 0 0.3rem;
  color: var(--ember);
  border: 1px solid var(--ember);
  border-radius: 3px;
}

/* ---- Run header ---- */

.run-copy-link {
  font: inherit;
  font-size: var(--fs-sm);
  color: var(--gold);
  background: none;
  border: 1px solid var(--gold);
  border-radius: 4px;
  padding: 0.2rem 0.5rem;
  cursor: pointer;
  transition: color .15s, border-color .15s, background .15s;
}
.run-copy-link:hover { color: var(--gold-bright); border-color: var(--gold-bright); background: var(--gold-glow); }

.detail-run-header-bar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  padding: 0.75rem 0 0.5rem;
  font-size: var(--fs-md);
}

.rh-date { color: #8a8aa0; font-size: var(--fs-sm); }
.rh-seed { color: #8a8aa0; font-size: var(--fs-sm); font-family: monospace; }

.detail-run-headline-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  padding-bottom: 0.6rem;
}

.run-headline-stat {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.05rem;
}

.run-headline-value {
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--text);
  line-height: 1;
}

.run-headline-label {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.detail-run-header-stats {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem 0.75rem;
  padding-bottom: 0.75rem;
  margin-bottom: 1rem;
  border-bottom: 1px solid var(--hairline);
  font-size: var(--fs-sm);
}

.run-header-stat-divider {
  width: 1px;
  height: 14px;
  background: var(--hairline);
  flex-shrink: 0;
}

/* The secondary stat tail (fight/event counts, buys, damage/heal totals)
   collapses into a disclosure under the headline stats; when open the body
   restores the same wrapped chip layout it had as a flat row. */
.run-detail-stats { flex-basis: 100%; }
.run-detail-stats > summary {
  cursor: pointer;
  user-select: none;
  color: var(--text-dim);
  font-size: var(--fs-sm);
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}
.run-detail-stats > summary:hover { color: var(--text); }
.run-detail-stats > summary:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
  border-radius: 3px;
}
.run-detail-stats-body {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem 0.75rem;
  padding-top: 0.55rem;
}
.run-detail-stats[open] > summary { margin-bottom: 0.1rem; }

/* ---- Placeholder ---- */

.detail-placeholder {
  color: var(--text-dim);
  font-size: var(--fs-md);
  padding: 2rem;
  text-align: center;
}

/* ---- Timeline acts ---- */

.timeline-legend {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  margin-bottom: 0.7rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1rem;
  align-items: center;
}

.timeline-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  white-space: nowrap;
}

.timeline-act {
  margin-bottom: 1rem;
}

.timeline-act-header {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin-bottom: 0.4rem;
}

.timeline-act-label {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  flex-shrink: 0;
}

.timeline-act-counts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
}

.act-count-pill {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  background: var(--panel);
  border: 1px solid var(--hairline);
  border-radius: 3px;
  padding: 0.05rem 0.35rem;
  white-space: nowrap;
}

.timeline-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

/* ---- Node cards ---- */

/* 100px wide: room for an HP reading at --fs-md, so the floor timeline reads
   at the same scale as the relic tiles above it. */
.node-card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100px;
  padding: 0.45rem 0.3rem 0.4rem;
  background: linear-gradient(165deg, var(--panel-2-glass), var(--panel-glass));
  border: 1px solid var(--hairline);
  border-radius: 6px;
  cursor: default;
  font-size: var(--fs-sm);
  user-select: none;
  transition: border-color .12s, box-shadow .12s;
}
.node-card:hover { border-color: var(--gold); box-shadow: 0 0 10px var(--gold-glow); z-index: 10; }

.node-card.node-type-elite  { border-color: #6a3a1e; }
.node-card.node-type-boss   { border-color: #6a1e3a; }
.node-card.node-type-rest_site { border-color: #1e3a6a; }

/* A chart's heading with a small switch at its right, e.g. Deck by Floor's
   Rarity / Type. */
.chart-box-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 1rem;
}
.chart-box-head h2 { margin-bottom: 0; }
.chart-toggle { display: inline-flex; gap: 0.35rem; }
.chart-toggle .toggle-btn {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  background: none;
  border: 1px solid var(--hairline);
  border-radius: 4px;
  padding: 0.2rem 0.5rem;
  cursor: pointer;
  transition: color .15s, border-color .15s;
}
.chart-toggle .toggle-btn:hover { color: var(--gold); border-color: var(--gold); }
.chart-toggle .toggle-btn[aria-pressed="true"] {
  color: var(--gold);
  border-color: color-mix(in srgb, var(--gold) 55%, transparent);
  background: rgba(224,196,104,0.08);
}

.chart-vline-legend {
  display: flex;
  gap: 1rem;
  justify-content: flex-end;
  padding: 0 0.25rem 0.4rem;
}

.vline-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: var(--fs-sm);
  color: var(--text-dim);
}

.vline-legend-line {
  display: inline-block;
  width: 18px;
  height: 0;
  border-top: 1px dashed #ffffff44;
  flex-shrink: 0;
}

.node-floor {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  line-height: 1;
  margin-bottom: 2px;
}

.node-icon {
  font-size: var(--fs-lg);
  line-height: 1.3;
  display: flex;
  align-items: center;
  justify-content: center;
}
.node-icon-img {
  width: 36px;
  height: 36px;
  object-fit: contain;
  image-rendering: pixelated;
}

.node-hp {
  color: var(--text-dim);
  font-size: var(--fs-md);
  text-align: center;
  white-space: nowrap;
}
.node-hp.damaged { color: #e05c5c; }
.node-hp.healed { color: #5cba7d; } /* .nt-heal's green */

.node-indicators {
  display: flex;
  gap: 3px;
  margin-top: 3px;
  min-height: 17px;
}

.node-ind {
  font-size: var(--fs-sm);
  font-weight: 700;
  cursor: default;
  line-height: 1;
}
.card-ind  { color: #9ecfff; }
.relic-ind { color: #c49fe8; }

/* ---- Node tooltip ---- */

.node-tooltip {
  display: none;
  position: absolute;
  top: calc(100% + 4px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 100;
  background: var(--panel-2);
  border: 1px solid var(--panel-border);
  border-radius: 6px;
  padding: 0.5rem 0.65rem;
  min-width: 160px;
  max-width: 220px;
  max-height: 88vh;
  overflow-y: auto;
  pointer-events: none;
  box-shadow: 0 6px 22px rgba(0,0,0,0.6), 0 0 0 1px rgba(224,196,104,0.08);
  white-space: nowrap;
}
.node-card:hover .node-tooltip,
.node-card:focus .node-tooltip { display: block; }

.nt-floor  { font-weight: 700; color: var(--gold); font-size: var(--fs-sm); margin-bottom: 2px; }
.nt-hp-gold { color: var(--text); font-size: var(--fs-sm); margin-bottom: 4px; }
.nt-enc    { color: var(--text); font-size: var(--fs-sm); font-weight: 600; margin-bottom: 2px; }
.nt-dmg     { color: #e05c5c; font-size: var(--fs-sm); }
.nt-avg-dmg { color: #e05c5c88; font-size: var(--fs-sm); }
.nt-heal   { color: #5cba7d; font-size: var(--fs-sm); }
.nt-turns       { color: var(--text-dim); font-size: var(--fs-sm); }
.nt-rest        { color: #5b9bd5; font-size: var(--fs-sm); }
.nt-section { color: var(--text-dim); font-size: var(--fs-sm); text-transform: uppercase; letter-spacing: 0.05em; margin-top: 5px; margin-bottom: 1px; }
.nt-reward-card  { color: #9ecfff; font-size: var(--fs-sm); }
.nt-reward-relic { color: #c49fe8; font-size: var(--fs-sm); }
.nt-skipped  { color: var(--text-dim); font-size: var(--fs-sm); }
.nt-removed  { color: #e05c5c; font-size: var(--fs-sm); }
.nt-bought-tag { color: #5cba7d; font-size: var(--fs-sm); font-style: italic; }

/* ---- Shared floating tooltip (charts + table cells) ---- */
/* Rendered as a real DOM element, positioned in chartTooltipHandler() /
   showTableTooltip() and clamped to the viewport there — see dashboard.js.
   Chart.js's own canvas-drawn tooltip only avoids overflowing the chart's
   plot area, not the browser window, and native `title` attributes render
   unstyled and slow — this replaces both with one consistent, instant,
   always-on-screen tooltip. max-width + wrapping (rather than nowrap) is
   needed for the occasional long single-line table tip that would
   otherwise force the box wider than the viewport itself, which the
   position clamp alone can't fix. */

.chart-tooltip {
  position: fixed;
  z-index: 1000;
  pointer-events: none;
  background: var(--panel-2);
  border: 1px solid var(--panel-border);
  border-radius: 6px;
  padding: 0.5rem 0.65rem;
  box-shadow: 0 6px 22px rgba(0,0,0,0.6), 0 0 0 1px rgba(224,196,104,0.08);
  font-size: var(--fs-sm);
  color: var(--text);
  max-width: 320px;
  opacity: 0;
}
.chart-tooltip-title { font-weight: 700; color: var(--gold); margin-bottom: 4px; }
.chart-tooltip-row { display: flex; align-items: flex-start; gap: 6px; }
.chart-tooltip-row + .chart-tooltip-row { margin-top: 3px; }
.chart-tooltip-swatch {
  width: 10px;
  height: 10px;
  margin-top: 3px;
  border-radius: 2px;
  border: 1px solid rgba(255,255,255,0.3);
  flex-shrink: 0;
}
.chart-tooltip-lines { line-height: 1.4; min-width: 0; }

/* Rich-content variant (card/relic tooltip markup instead of plain text
   lines) -- the inner .card-tooltip/.relic-tooltip box already brings its
   own background/border/padding, so strip this element's chrome to avoid
   a double frame around it. */
.chart-tooltip.chart-tooltip-rich {
  background: none;
  border: none;
  border-radius: 0;
  padding: 0;
  box-shadow: none;
  max-width: none;
}

/* ---- Run header stat chips ---- */

.run-summary-stat {
  display: inline-flex;
  align-items: baseline;
  gap: 0.3rem;
}

.run-summary-label { color: var(--text-dim); }
.run-summary-value { color: var(--text); font-weight: 600; }

.run-boon-icon {
  /* Sized against this row's own 14px divider height, not the 22px used for
     relic icons elsewhere -- at 22px these overpowered the header's compact
     text stats next to them. */
  width: 16px;
  height: 16px;
  object-fit: contain;
  vertical-align: middle;
  border-radius: 3px;
}
.run-boon-wrap {
  position: relative;
  display: inline-block;
}
.run-boon-wrap .relic-tooltip-wrap {
  /* Anchored to the right edge rather than centered -- these icons sit at
     the header's right edge, where a centered 180px tooltip would run off
     the viewport. */
  visibility: hidden;
  position: absolute;
  bottom: calc(100% + 6px);
  left: auto;
  right: 0;
  transform: none;
  z-index: 200;
}
.run-boon-wrap:hover .relic-tooltip-wrap,
.run-boon-wrap:focus-within .relic-tooltip-wrap {
  visibility: visible;
}

/* ---- Floor breakdown summary table ---- */

.detail-section-heading {
  font-size: var(--fs-sm);
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 0.5rem;
}

/* ---- Card art thumbnails (tooltip) ---- */

.nt-card-thumb {
  width: 100%;
  max-width: 140px;
  height: auto;
  display: block;
  border-radius: 4px;
  margin-top: 3px;
  border: 1px solid var(--hairline);
}

/* ---- Card tiles (final deck) ---- */

.deck-group {
  margin-bottom: 12px;
}
.deck-group-label {
  font-size: var(--fs-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 6px;
}
.deck-group-count {
  color: var(--text-dim);
  font-weight: 400;
}
.deck-tile-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: flex-start;
}

.card-tile {
  position: relative;
  width: 96px;
  cursor: default;
  z-index: 1;
}
.card-tile:hover,
.card-tile:focus-within {
  z-index: 100;
}
.tile-art {
  width: 96px;
  height: 73px;
  object-fit: cover;
  object-position: center 20%;
  display: block;
  border-radius: 4px 4px 0 0;
  border: 2px solid var(--tile-color, #444);
  border-bottom: none;
  transform: translateZ(0);
  image-rendering: auto;
}
.tile-art-missing {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-deep);
  color: #6a6390;
  font-size: var(--fs-lg);
}
/* Column layout, not row: the name and its upgrade/count badges must not
   share one flex row, or the badges steal width from the name and force
   mid-word breaks even on short names (e.g. "Rupture" + "+1" + "x2") once
   the row gets tight. Each gets its own line instead. */
.tile-name {
  background: #1a1520;
  border-radius: 0 0 4px 4px;
  border-top: 2px solid var(--tile-color, #444);
  padding: 2px 4px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
/* 96px tile width (minus padding) comfortably fits "Metamorphosis" (81.6px
   at this font, the longest single word across card_data.json, measured via
   Playwright) with a margin. */
.tile-name-text {
  font-size: var(--fs-sm);
  color: #e8e0cc;
  text-align: center;
  line-height: 1.3;
  word-break: break-word;
  overflow-wrap: break-word;
  hyphens: auto;
  min-height: 2.6em;
  display: flex;
  align-items: center;
  justify-content: center;
}
.tile-badges {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 3px;
}
.tile-count {
  font-size: var(--fs-sm);
  color: #fffa;
}

/* ---- Rich card tooltip ---- */

.card-tooltip-wrap {
  visibility: hidden;
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 200;
  pointer-events: none;
}
/* :focus-within (not just :hover) so a keyboard-focused or tapped tile
   (tabindex added in card-face.js) shows its tooltip too -- plain :hover
   never fires on a touch tap. */
.card-tile:hover .card-tooltip-wrap,
.card-tile:focus-within .card-tooltip-wrap {
  visibility: visible;
}

.card-tooltip {
  width: 160px;
  max-width: min(92vw, 420px);
  max-height: 88vh;
  overflow-x: hidden;
  overflow-y: auto;
  background: #3d3020;
  border: 2px solid #c8882a;
  border-radius: 8px;
  outline: 3px solid #161616;
  box-shadow: 0 6px 24px #000e;
  font-size: var(--fs-sm);
  color: #fff;
}
.ct-art-wrap {
  position: relative;
}
.ct-art {
  width: 100%;
  display: block;
}
.ct-art-missing {
  height: 110px;
  background: var(--panel);
}
.ct-costs {
  position: absolute;
  top: 5px;
  left: 5px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  z-index: 2;
}
.ct-cost-energy {
  background: #c85a1a;
  color: #fff;
  font-size: var(--fs-sm);
  font-weight: 900;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid #fff8;
  box-shadow: 0 1px 4px #0008;
}
.ct-cost-stars {
  background: #2060c0;
  color: #fff;
  font-size: var(--fs-sm);
  font-weight: 700;
  padding: 1px 4px;
  border-radius: 4px;
  border: 1px solid #fff6;
  box-shadow: 0 1px 4px #0008;
  letter-spacing: 1px;
}
.ct-banner {
  padding: 3px 8px 4px;
  background: linear-gradient(180deg, #b8b8b8 0%, #787878 50%, #a0a0a0 100%);
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.ct-name {
  font-size: var(--fs-sm);
  font-weight: 700;
  color: #1a1a1a;
  text-shadow: 0 1px 0 #fff5;
  white-space: nowrap;
}
.ct-upgrade {
  color: #b06000;
  font-size: var(--fs-sm);
}
.ct-type-pill {
  background: #a0a0b8;
  border: 1px solid #bcbcd0;
  border-radius: 3px;
  padding: 1px 5px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: #1a1a1a;
  white-space: nowrap;
}
.ct-desc {
  padding: 6px 10px 10px;
  font-size: var(--fs-sm);
  color: #e8e0cc;
  line-height: 1.5;
  text-align: center;
  background: #3d3020;
}
.ct-desc b {
  color: #f0b030;
  font-weight: 700;
}
/* The enchantment a card carries: the game draws it as a tab on the card face,
   which the baked canonical face cannot show, so the site states it in words
   under the face (js/card-face.js's buildEnchantmentStrip). */
.ct-enchant {
  display: flex;
  align-items: flex-start;
  gap: 5px;
  padding: 6px 10px;
  border-top: 1px solid #6a5a3a;
  background: #33291c;
  font-size: var(--fs-xs);
  color: #e8e0cc;
  line-height: 1.45;
  text-align: left;
}
.ct-enchant-icon {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  image-rendering: auto;
}
.ct-enchant-rule b {
  color: #b8e088;
  font-weight: 700;
}
/* Hovering an enchanted deck tile explains the chip. The tile's own card face
   needs no tooltip, so this one holds the enchantment strip alone. */
.card-tooltip-wrap:has(> .ct-enchant) {
  width: 220px;
  border: 1px solid #6a5a3a;
  border-radius: 6px;
  overflow: hidden;
}
/* Inline "gain N Energy" glyph in a relic/potion/card description -- the
   actual in-game energy orb, colored per character pool (ui_icons/energy_
   <pool>.png, copies of the same chrome sprites baked onto a card's
   top-left corner -- Ironclad's is a red hexagon, Defect's a blue diamond,
   etc., not just a color swap). The specific pool's file is set as an
   inline background-image by substituteDescVars(); this class only sizes
   it to sit in a line of prose instead of a card's corner badge. */
.desc-energy-icon {
  display: inline-block;
  width: 0.9em;
  height: 0.9em;
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  vertical-align: -0.15em;
  margin: 0 1px;
}

/* ---- Final deck + relics ---- */

.deck-relic-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 0.35rem;
  margin-bottom: 0.5rem;
}

/* Relic tiles in the final deck: icon beside name, rarity and description, so
   a relic reads in place with no hover preview. */
.relic-tile {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 6px 8px 6px 6px;
  background: #1a1520;
  border: 1px solid #3a2a4a;
  border-left: 2px solid #6a4a9a;
  border-radius: 6px;
  min-width: 0;
}
.relic-tile-art {
  width: 44px;
  height: 44px;
  object-fit: contain;
  flex-shrink: 0;
}
.relic-tile-text {
  flex: 1;
  min-width: 0;
}
.relic-tile-name {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 6px;
  font-size: var(--fs-md);
  font-weight: bold;
  color: #e0d0f8;
  line-height: 1.3;
}
.relic-tile-desc {
  margin-top: 2px;
  font-size: var(--fs-sm);
  color: #bbb;
  line-height: 1.4;
}
.relic-tooltip-wrap {
  visibility: hidden;
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 200;
}

/* While scrolling, :hover can point at a stale element (Chrome doesn't
   re-evaluate hover until the mouse moves) — hide tooltips until then */
body.suppress-hover-tooltips .relic-tooltip-wrap,
body.suppress-hover-tooltips .card-tooltip-wrap,
body.suppress-hover-tooltips .node-tooltip {
  visibility: hidden !important;
  display: none !important;
}
.relic-tooltip {
  width: 180px;
  background: var(--bg-deep);
  border: 2px solid #4a3a6a;
  border-radius: 8px;
  outline: 3px solid #161616;
  padding: 0;
  overflow: hidden;
  box-shadow: 0 4px 16px rgba(0,0,0,0.6);
  pointer-events: none;
}
.rt-art {
  width: 100%;
  height: 72px;
  object-fit: contain;
  background: #120e20;
  padding: 6px;
}
.rt-header {
  padding: 4px 8px 2px;
  font-size: var(--fs-sm);
  font-weight: bold;
  color: #e0d0f8;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 4px;
}
.rt-rarity {
  font-size: var(--fs-xs);
  font-weight: normal;
}
.rt-desc {
  padding: 4px 8px 8px;
  font-size: var(--fs-sm);
  color: #bbb;
  line-height: 1.4;
}

/* ---- Card face: a real card composited from the baked game chrome ---- */
/* A card face is one baked <img> (tools/bake_finished_cards.py) — art and
   text both already flattened in, so there is no internal layout here. */
.cardface {
  display: block;
  user-select: none;
}

/* When the tooltip carries a real card face it needs no chrome of its own. */
.card-tooltip-face {
  width: auto;
  background: none;
  border: none;
  outline: none;
  padding: 0;
  box-shadow: none;
  filter: drop-shadow(0 6px 16px rgba(0,0,0,0.75));
}

/* Deck tiles that render a real card face need none of the portrait-tile
   chrome — the card supplies its own border, name and cost. */
.card-tile-face {
  width: auto;
  background: none;
  border: none;
}
.card-tile-face .tile-badges {
  position: absolute;
  /* A face image carries a 16px transparent margin (332px wide for a 300px card),
     so the badge has to clear it to land on the card's own corner: 16/332 = 4.8%
     of the width, 16/454 = 3.5% of the height, plus the 4px inset it had. */
  right: 6.5%;
  bottom: 4.8%;
  z-index: 8;
}
.card-tile-face .tile-count {
  background: rgba(0,0,0,0.78);
  border: 1px solid #6a6a80;
  border-radius: 4px;
  padding: 0 4px;
  font-size: var(--fs-sm);
  color: #fff;
}
/* The enchantment chip sits in the same badge row as the copy count. Rendered
   over the card face, so it needs its own backing to stay legible. */
.tile-enchant {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  background: rgba(0,0,0,0.78);
  border: 1px solid #7a9a5a;
  border-radius: 4px;
  padding: 0 4px;
  font-size: var(--fs-xs);
  color: #d8f0c0;
  white-space: nowrap;
}
.tile-enchant-icon {
  width: 12px;
  height: 12px;
}
/* The portrait-tile fallback draws a name bar instead of a face; the chip has
   no dark face to sit on there, so it keeps a readable size but drops the
   border weight. */
.card-tile:not(.card-tile-face) .tile-enchant {
  background: rgba(0,0,0,0.5);
  font-size: var(--fs-xs);
}

/* ---- Node tooltip: real art beside each reward ---- */
.nt-item {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
.nt-item-icon {
  width: 26px;
  height: 26px;
  object-fit: contain;
  flex: 0 0 auto;
}
/* Reward cards render a small card face. Skipped/removed/for-sale ones are
   dimmed so a floor's actual gains stay the thing you read first. */

/* Cards lay out side by side, --nt-cols per row, then onto further rows.
   fitNodeTooltip in run-detail.js picks the count and the card width from
   the room the window has. The column count lives on the row itself (not a
   width cap on the tooltip), so the tooltip hugs its cards: no leftover strip
   beside a full row, and a lone card gets a one-card-wide tooltip. The
   fallbacks only show if the script hasn't sized it. */
.node-tooltip { --nt-cols: 3; --nt-card-w: 150px; }
/* Laid out, unseen, while fitNodeTooltip measures -- even while scrolling
   suppresses hover tooltips (mouseover fires before the mousemove that lifts
   it). */
body .node-tooltip.nt-measuring { display: block !important; visibility: hidden !important; }
.nt-cardrow { display: grid; grid-template-columns: repeat(var(--nt-cols), max-content); gap: 4px; }
.node-tooltip:has(.nt-cardrow) {
  /* max-content, not shrink-to-fit: anchored under a 100px node the tooltip
     would otherwise sit at its 160px min-width. 92vw is a backstop. */
  /* A panel this size cannot be both anchored to a 100px node and on screen:
     centred on the viewport it always fits, at any zoom or window size. Plain
     text tooltips keep their anchored position -- only card-bearing ones,
     which are the tall ones, move. */
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: max-content;
  max-width: 92vw;
  max-height: 88vh;
  white-space: normal;
}
.nt-cardface { margin: 0; }
.nt-cardface-dim { opacity: 0.55; }

/* Visually hidden: screen-reader-only text that takes no layout space. Used to
   label the win/loss sides of colored value pairs so the meaning isn't
   conveyed by green-vs-red color alone. */
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ---- Accessibility ---- */

/* Visible focus for keyboard users. The browser-default focus ring measured as
   effectively invisible (rgb(16,16,16)) on this dark theme, and .seeds-input
   strips its outline entirely, so give keyboard focus a clear gold ring.
   :focus-visible keeps it from appearing for plain mouse clicks. */
:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}
.seeds-input:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 0;
}

/* Skip link: off-screen until keyboard focus lands on it, then pinned top-left
   so the first Tab reaches "Skip to content" before the page tabs/filters. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 1000;
}
.skip-link:focus-visible {
  left: 0.5rem;
  top: 0.5rem;
  padding: 0.5rem 0.9rem;
  background: var(--gold);
  color: #13132a;
  font-weight: 700;
  border-radius: 6px;
}

/* Honour reduced-motion: collapse transient transitions/animations (filter
   hover shifts, the Save-button pop) for users who request it. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* =========================================================================
   Mobile layout (phones, ~360-430px wide, or rotated to landscape).
   Desktop (>700px wide and >500px tall) is untouched.
   Kept at the END of the file, not next to the rules it overrides: several
   of its selectors (#detail-layout, .pivot-wrap, ...) are plain IDs/classes
   that tie in specificity with an unconditional desktop rule of the same
   selector declared later in this file, and a tied selector is resolved by
   source order, not which @media block "feels" more specific -- so a mobile
   override placed earlier in the file can silently lose to a desktop rule
   below it even while its own max-width condition is satisfied. Being last
   in the file guarantees it wins every such tie.
   The second condition catches phones turned sideways: they're ~850px wide
   (past the width cutoff) but only ~400px tall, and without it the desktop
   side-by-side grids come back the moment the phone is rotated.
   ========================================================================= */
@media (max-width: 700px), (orientation: landscape) and (max-height: 500px) {
  /* The desktop 2rem body gutter and 1.25rem chart-box padding eat most of
     a phone screen before any content shows -- trim both (overflow-x:hidden
     for the tooltip layout-box quirk is already set unconditionally on
     body, above). */
  body { padding: 14px; }
  .chart-box { padding: 0.85rem; }
  .grid-1, .grid-2, .grid-4 { gap: 0.9rem; margin-bottom: 1.5rem; }

  /* Page tabs: the four share one row, each an equal share of it. */
  .page-tabs { gap: 0.4rem; margin-bottom: 1rem; }
  .page-tab { flex: 1 1 0; min-width: 0; padding: 0.4rem 0.2rem; font-size: 0.82rem; text-align: center; }

  /* Filter bar: a .filter-group sizes to its widest child (the character
     selector, the ascension checkboxes are each 400px+) and a non-wrapping
     flex row won't shrink that below its content, so every group is wider
     than the screen regardless of how the bar itself wraps. Make each group
     take the full row and let ITS OWN content wrap, and force the two worst
     offenders onto their own line so their buttons wrap under the label
     instead of squeezing onto it. */
  .filter-bar { padding: 0.6rem 0.75rem; gap: 0.5rem; }
  .filter-bar .filter-group {
    width: 100%;
    flex-wrap: wrap;
  }
  #shared-char-selector, #shared-asc-checkboxes {
    flex-basis: 100%;
  }

  /* Grids that stay at desktop column counts squeeze their contents to a
     sliver (4-up charts at ~60px wide) instead of reflowing. Tracks use
     minmax(0, 1fr), not bare 1fr -- bare 1fr is minmax(auto, 1fr), so a
     track holding wide content (a .card's .value/.sub text, a chart canvas)
     refuses to shrink below that content's width and blows the grid out
     past the viewport instead of wrapping it. */
  .grid-2 { grid-template-columns: minmax(0, 1fr); }
  .grid-4, .grid-4.grid-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* One column, not two -- each of these cards packs a 3-4-wide row of
     label/value stat blocks (Best Win / Games Played / Total Wins / Final
     Boss Deaths) that's already tight at full card width; at half width
     the row has no room left to shrink into and silently spills past the
     card's edge instead. flex-wrap is a second safety net for that same
     row, in case a narrower phone still can't fit all of it. */
  #personal-bests-cards { grid-template-columns: minmax(0, 1fr); }
  .card > div { flex-wrap: wrap; }

  /* Summary stat cards (Time Played, Runs, etc.): each one is short
     enough that a single-column stack (from .cards' 220px auto-fit minimum)
     leaves half the card empty. Two narrower columns use that space instead. */
  .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #summary-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* Run Detail: the 230px run list + timeline side-by-side has no room.
     Stack them, and cap the run list's height (it's independently
     scrollable already) so it doesn't push the timeline below the fold. */
  #detail-layout { grid-template-columns: minmax(0, 1fr); }
  #detail-run-list { max-height: 240px; }

}

/* Narrow screens only, not a phone turned sideways: landscape has room for
   the full tables. */
@media (max-width: 700px) {
  /* Run header: date, seed and Copy link share one row under the run's
     name line, instead of the seed and the button each wrapping alone. */
  .detail-run-header-bar { gap: 0.3rem 0.6rem; }
  .rh-date, .rh-seed { font-size: 0.72rem; white-space: nowrap; }
  .rh-seed-label { display: none; }
  .run-copy-link { font-size: 0.7rem; padding: 0.12rem 0.4rem; white-space: nowrap; }

  /* Tables fit the screen instead of scrolling sideways. */

  /* Win % and Final Boss Win %: tighter cells, headers may wrap.
     (Show granular adds a column per ascension and still scrolls.) */
  #pivot-table th, #final-boss-win-table th { padding: 0.4rem 0.2rem; font-size: 0.62rem; letter-spacing: 0; white-space: normal; }
  #pivot-table td.cell, #final-boss-win-table td.cell { min-width: 0; padding: 0.3rem 0.15rem; }
  #pivot-table td.char-name, #final-boss-win-table td.char-name { padding: 0 0.3rem 0 0; font-size: 0.74rem; }
  #pivot-table td.char-name .dot, #final-boss-win-table td.char-name .dot { margin-right: 5px; }
  #pivot-table td.cell .pct, #final-boss-win-table td.cell .pct { font-size: 0.85rem; }
  #pivot-table td.cell .meta, #final-boss-win-table td.cell .meta { font-size: 0.66rem; }

  /* Card Stats: Pool, Type and Rarity are dropped (the filters above cover
     them); the numbers stay. The table sets its widths inline, hence
     !important. */
  #cards-table-main { width: 100% !important; }
  #cards-table-main th:nth-child(n+2):nth-child(-n+4),
  #cards-table-main td:nth-child(n+2):nth-child(-n+4) { display: none; }
  #cards-table-main th { white-space: normal !important; padding: 0.3rem 0.15rem !important; font-size: 0.6rem !important; letter-spacing: 0 !important; vertical-align: bottom; }
  #cards-table-main th:first-child { width: auto !important; }
  #cards-table-main th:nth-child(5) { width: 46px !important; }
  #cards-table-main th:nth-child(6) { width: 50px !important; }
  #cards-table-main th:nth-child(7) { width: 50px !important; }
  #cards-table-main th:nth-child(8) { width: 52px !important; }
  #cards-table-main td { padding: 0.18rem 0.15rem !important; font-size: 0.83rem !important; }
  .cards-thumb { width: 22px; height: 22px; }
  .cards-thumb-wrap { margin-right: 6px; }
  .cards-hi { font-size: 0.88rem; }
  #cards-table-main td:first-child { white-space: normal !important; }

  /* Seed Data: four tight columns; what a search matched goes on its own
     line under the row instead of in a fifth column. */
  /* No sideways scroll here (the grid fits), so the headings can stick to the page. */
  .seeds-list { overflow: visible; }
  #seeds-table, #seeds-table thead, #seeds-table tbody { display: block; }
  #seeds-table tr { display: block; }
  #seeds-table #seeds-thead-row, #seeds-table tr.seed-row { display: grid; grid-template-columns: 7.4rem minmax(0, 1fr) 2.4rem 4.9rem; align-items: center; }
  #seeds-table tr.seed-row > td, #seeds-table tr.seed-row > td * { font-size: 0.72rem !important; }
  #seeds-table .seed-expand-arrow { margin-right: 0.2rem !important; }
  #seeds-table th, #seeds-table tr.seed-row > td { padding: 0.4rem 0.25rem !important; }
  #seeds-table th { font-size: 0.62rem; letter-spacing: 0; }
  #seeds-table th:last-child { display: none; }
  #seeds-table tr.seed-row > td:last-child { grid-column: 1 / -1; padding-top: 0 !important; }
  #seeds-table tr.seed-row > td:last-child:empty { display: none; }
  #seeds-table tr:not(.seed-row) > td { display: block; }
  /* The opened run's deck: two cards a row, as on Run History. */
  #seeds-table .seed-detail-panel { padding-left: 0; padding-right: 0; }
  #seeds-table .seed-detail-cards .deck-tile-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #seeds-table .seed-detail-cards .cardface { width: 100% !important; }
}
