:root {
  --bg: #14161a; --panel: #1b1e24; --line: #2c313a;
  --fg: #e6e8ec; --dim: #9aa3b2; --accent: #7fb2ff;
  --win: #67d98b; --loss: #e06c75; --aband: #c8a45c;
}
@media (prefers-color-scheme: light) {
  :root {
    --bg: #fbfbfc; --panel: #fff; --line: #dfe3ea;
    --fg: #1c2027; --dim: #5d6675; --accent: #2f6fd0;
    --win: #1f8b4c; --loss: #c0392b; --aband: #96702a;
  }
}
* { box-sizing: border-box; }
body {
  margin: 0; padding: 1.5rem 1rem 4rem; background: var(--bg); color: var(--fg);
  font: 15px/1.5 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
}
main { max-width: 1100px; margin: 0 auto; }
h1 { font-size: 1.6rem; margin: 0 0 .25rem; }
h2 {
  font-size: .8rem; text-transform: uppercase; letter-spacing: .09em;
  color: var(--dim); margin: 2.25rem 0 .6rem; font-weight: 600;
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
.sub { color: var(--dim); margin: 0 0 .5rem; }
.tablewrap { overflow-x: auto; border: 1px solid var(--line); border-radius: 6px; }
table { border-collapse: collapse; width: 100%; background: var(--panel); }
th, td { padding: .4rem .6rem; text-align: left; white-space: nowrap; }
th {
  position: sticky; top: 0; background: var(--panel); z-index: 1;
  border-bottom: 1px solid var(--line); font-size: .72rem;
  text-transform: uppercase; letter-spacing: .06em; color: var(--dim);
}
tbody tr:nth-child(even) { background: rgba(127, 178, 255, .04); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
td.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .86rem; }
.win { color: var(--win); } .loss { color: var(--loss); } .aband { color: var(--aband); }
.stats { display: flex; flex-wrap: wrap; gap: 1.75rem; margin: .75rem 0 0; }
.stats div { min-width: 6rem; }
.stats .k { font-size: .7rem; text-transform: uppercase; letter-spacing: .07em; color: var(--dim); }
.stats .v { font-size: 1.25rem; font-variant-numeric: tabular-nums; }
.matrix td.zero { color: var(--dim); opacity: .45; }
footer { margin-top: 3rem; color: var(--dim); font-size: .8rem; }

/* Floor-by-floor: a colour-coded left edge plus a glyph, so the shape of a
   run (elite density, rest cadence, where the bosses fell) reads at a glance
   without parsing the type column word by word. The colour is carried on a
   border rather than the row background so it survives the zebra striping. */
td.ptype { white-space: nowrap; }
td.ptype .ico { display: inline-block; width: 1.35em; margin-right: .3rem; }
tbody tr[class^="pt-"] td:first-child { border-left: 3px solid transparent; }
tr.pt-monster   td:first-child { border-left-color: #7fb2ff; }
tr.pt-elite     td:first-child { border-left-color: #ff9d5c; }
tr.pt-boss      td:first-child { border-left-color: #ff6b6b; }
tr.pt-rest-site td:first-child { border-left-color: #7ddb9a; }
tr.pt-shop      td:first-child { border-left-color: #ffd479; }
tr.pt-treasure  td:first-child { border-left-color: #e0c060; }
tr.pt-unknown   td:first-child { border-left-color: #b48ce0; }
tr.pt-ancient   td:first-child { border-left-color: #8fdcd0; }
tr.pt-other     td:first-child { border-left-color: var(--line); }

/* Chips: badges, relics, and the deck are all "a pile of named things", so
   they share one dense wrapped grid instead of three long two-column tables.
   A 28-card deck collapses to ~15 distinct cards with a multiplier. */
ul.chips {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: .3rem;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}
ul.chips .chip {
  display: flex; align-items: baseline; gap: .4rem;
  padding: .3rem .55rem; background: var(--panel);
  border: 1px solid var(--line); border-radius: 5px;
}
ul.chips .cname { flex: 1; }
ul.chips .mult { font-variant-numeric: tabular-nums; font-weight: 600; }
ul.chips .added {
  color: var(--dim); font-size: .78rem; font-variant-numeric: tabular-nums;
}
.chip.rar-bronze { border-left: 3px solid #c08457; }
.chip.rar-silver { border-left: 3px solid #b6c0cc; }
.chip.rar-gold   { border-left: 3px solid #e3c04b; }

/* Offered-at-this-floor, merged into the floor table. Taken reads solid,
   skipped reads struck through and dim, so a row shows the decision, not just
   the options. This column is the one place the table may wrap. */
td.offers { white-space: normal; max-width: 26rem; }
.offer {
  display: inline-block; margin: 1px 3px 1px 0; padding: 0 .35rem;
  border: 1px solid var(--line); border-radius: 4px; font-size: .8rem;
}
.offer.took { color: var(--fg); border-color: var(--accent); }
.offer.skipped { color: var(--dim); text-decoration: line-through; opacity: .7; }

/* Hover tooltips carrying the game's own rules text. Pure CSS on a data
   attribute: no script, and the text stays in the markup where a reader (or a
   screen reader) can reach it. Positioned above the element and pinned inside
   the viewport width so a long description near the right edge still reads. */
.tip { position: relative; cursor: help; }
.tip::after {
  content: attr(data-tip);
  position: absolute; left: 0; bottom: calc(100% + 6px); z-index: 5;
  width: max-content; max-width: min(26rem, 80vw);
  padding: .4rem .55rem; border: 1px solid var(--line); border-radius: 5px;
  background: var(--bg); color: var(--fg);
  font-size: .82rem; line-height: 1.35; white-space: normal;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .45);
  opacity: 0; visibility: hidden; transition: opacity .09s ease .25s;
}
.tip:hover::after, .tip:focus-visible::after { opacity: 1; visibility: visible; }
/* Rows near the top of a table would clip a tooltip drawn above them. */
tbody tr:first-child .tip::after { bottom: auto; top: calc(100% + 6px); }

/* Records read as label / value / context rather than name / count / floor. */
ul.records .mult { font-size: 1.05rem; }

/* The floor marker sat flush against the name, so "Bound Phylactery" and "f1"
   read as one word — and copied out of the page as "Bound Phylacteryf1", since
   flex gaps are layout, not text. A real separator character fixes both. */
ul.chips .added::before { content: "· "; opacity: .55; }
ul.records .added::before { content: none; }

/* Sortable headers. Only the affordance and the direction marker live here;
   the behaviour is assets/sort.js, and a table still reads fine without it. */
th.sortable-th { cursor: pointer; user-select: none; }
th.sortable-th:hover { color: var(--fg); }
th.sortable-th::after { content: " ⇅"; opacity: .35; }
th.sort-asc::after { content: " ↑"; opacity: .9; }
th.sort-desc::after { content: " ↓"; opacity: .9; }

/* Win rate by character: server-rendered bars, no chart library. A grid keeps
   the four columns aligned across rows, which is what makes it readable as a
   chart rather than as four loose spans. */
ul.charbars {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: .35rem;
}
ul.charbars li {
  display: grid; align-items: center; gap: .6rem;
  grid-template-columns: 9rem 1fr 3.6rem 4.5rem;
}
ul.charbars .bar {
  height: .85rem; background: var(--panel);
  border: 1px solid var(--line); border-radius: 3px; overflow: hidden;
}
ul.charbars .fill {
  display: block; height: 100%;
  background: linear-gradient(90deg, #4f7fd0, #7fb2ff);
}
ul.charbars .fill.empty { background: none; }
ul.charbars .cv { text-align: right; font-variant-numeric: tabular-nums; }
ul.charbars .cn {
  text-align: right; color: var(--dim); font-size: .8rem;
  font-variant-numeric: tabular-nums;
}
@media (max-width: 30rem) {
  ul.charbars li { grid-template-columns: 7rem 1fr 3.2rem; }
  ul.charbars .cn { display: none; }
}

/* Character filter. Buttons rather than a <select> so the whole set is visible
   at once — with five characters, a dropdown hides the options for no gain. */
.filterbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: .35rem;
  margin: 1.5rem 0 .25rem;
}
.filterbar .fl {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--dim); margin-right: .35rem;
}
.filterbar button {
  font: inherit; font-size: .85rem; cursor: pointer;
  padding: .2rem .6rem; border-radius: 999px;
  border: 1px solid var(--line); background: var(--panel); color: var(--dim);
}
.filterbar button:hover { color: var(--fg); }
.filterbar button.on {
  color: var(--bg); background: var(--accent); border-color: var(--accent);
}

/* Matrix rollups: totals sit in the last column and the foot, separated by a
   rule so they read as a summary rather than as another ascension. */
.matrix td.roll, .matrix th.roll { border-left: 1px solid var(--line); font-weight: 600; }
.matrix tfoot td { border-top: 1px solid var(--line); font-weight: 600; }
.matrix tfoot td.roll { color: var(--fg); }
.matrix td.grand { color: var(--accent); }
