/* SkyCompass shared stylesheet.
 *
 * Self-hosted on purpose: no fonts, scripts, analytics or images are fetched
 * from anywhere else. The site therefore sets no cookies and cannot leak a
 * visitor to a third party — which matters for an audience that skews young.
 *
 * This file is the only stylesheet. The production CSP is `style-src 'self'`
 * with no 'unsafe-inline', so inline <style> blocks and style="" attributes
 * will NOT render in production. Keep all styling here.
 */

/* Theming: /assets/theme.js sets data-mode (light|dark) on <html>, persisted
 * in the visitor's own browser via localStorage — never sent to the server,
 * so the site's no-cookies/no-tracking position holds.
 *
 * The palette is Skyward Blue, deliberately the only scheme. The bare :root
 * is its dark mode: the site default, and what a visitor with JavaScript
 * disabled gets. Mode is an explicit user choice, so there is deliberately
 * no prefers-color-scheme dependence.
 */

:root { /* Skyward Blue — dark (site default) */
  color-scheme: dark;
  --bg: #0c1118;
  --panel: #131b25;
  --text: #e7edf3;
  --muted: #93a1b0;
  --line: #22303f;
  --accent: #6db1ec;
  --accent-soft: #142434;
  --warn: #e8b84a;
  --warn-soft: #2a2210;
  /* Chart series (ask = blue, bid = gold): validated per mode with the
     dataviz palette checker against this mode's --bg. Don't eyeball edits —
     re-run the validator. */
  --chart-ask: #3e8ed2;
  --chart-bid: #b1861f;
  /* Chart furniture. WCAG ratios sit at parity across modes, but thin light
     marks wash out on a bright surface far more than the ratio suggests, so
     the light values below run visibly darker (measured 2026-08-11):
     gridlines 1.29:1 here vs 1.48:1 light; disabled ink ~2.2:1 both. */
  --chart-grid: #22303f;        /* = --line here; light mode splits them */
  --disabled: #46545f;          /* dimmer than --muted, but readable */
  --chip-sample-dim: .4;        /* unselected series-chip line sample */
  --mayor-band-alpha: .055;
  --tf-fill: var(--accent);     /* timeframe-slider selected range */
  /* Minecraft lore palette for the stat-page item interfaces (hover
     spec 2026-08-23). Dark mode carries the game's own colours; light
     mode swaps in darker shades so the runs stay readable on the
     white panel (mock-validated; re-check with the dataviz checker if
     edited). */
  --mc-gold: #ffaa00; --mc-gray: #aaaaaa; --mc-dgray: #6d6d6d;
  --mc-blue: #6b6bff; --mc-green: #55cc55; --mc-aqua: #4fd8d8;
  --mc-pink: #ff55ff; --mc-red: #ff5555; --mc-yellow: #e0e055;
  --mc-white: #ffffff; --mc-purple: #c04ad6;
}
html[data-mode="light"] { /* Skyward Blue — light */
  color-scheme: light;
  --bg: #e8edf3;
  --panel: #ffffff;
  --text: #131820;
  --muted: #57626f;
  --line: #d3dbe4;              /* 1.40:1 on panel — 1px borders vanish on a
                                   bright surface any lighter than this */
  --accent: #2065ae;
  --accent-soft: #e3eefa;
  --warn: #8a5a00;
  --warn-soft: #fdf3df;
  --chart-ask: #2065ae;
  --chart-bid: #96660a;
  --chart-grid: #ccd5df;
  --disabled: #a0acba;
  --chip-sample-dim: .55;
  --mayor-band-alpha: .08;
  --tf-fill: #5b8cc4;           /* full --accent reads as a heavy black-blue
                                   bar across a light page; ~3:1 still says
                                   "selected range" without shouting */
  --mc-gold: #9a6b00; --mc-gray: #6b7480; --mc-dgray: #8a94a0;
  --mc-blue: #3347c9; --mc-green: #1f8a3a; --mc-aqua: #0f7f8f;
  --mc-pink: #b0309a; --mc-red: #c0392b; --mc-yellow: #8a7a00;
  --mc-white: #131820; --mc-purple: #7a1fa0;
}

* { box-sizing: border-box; }

/* The hidden attribute must always win: any author display rule (flex,
 * grid…) on the same element silently overrides the UA's [hidden] rule —
 * exactly how an "empty" filter row once rendered its controls anyway. */
[hidden] { display: none !important; }

/* Keyboard users' bypass for the sticky topbar (WCAG 2.4.1): visually
 * hidden until focused, then pinned over the bar. First element in <body>
 * on every page. Colors are the inverse pair, contrast-verified both modes. */
.skip-link {
  position: fixed;
  top: -100px;
  left: 0;
  z-index: 100;
  background: var(--accent);
  color: var(--bg);
  font-weight: 600;
  text-decoration: none;
  padding: .6rem 1.1rem;
  border-radius: 0 0 10px 0;
}
.skip-link:focus { top: 0; }

body {
  margin: 0;
  padding: 2rem 1.25rem 3rem;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.65 system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-text-size-adjust: 100%;
}
.wrap { max-width: 41rem; margin: 0 auto; }
/* Data-heavy pages (item charts) get the same width as the topbar. */
.wrap-wide { max-width: 60rem; }

/* --- top navbar ----------------------------------------------------------
 * Full-width bar: wordmark left, search centre, hamburger menu right.
 * No JavaScript anywhere (the CSP forbids it): the menu is a native
 * <details> element, and the search input sits outside any <form> so Enter
 * does nothing — there is no search backend yet, and form-action is 'none'.
 */

body.has-topbar { padding: 0; }
.has-topbar .content { padding: 2rem 1.25rem 3rem; }

.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
}
.topbar-inner {
  max-width: 60rem;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .6rem 1.25rem;
  position: relative;
}
.topbar .wordmark { flex: none; }

/* Search is centered on the SCREEN, not in the leftover flex space (the
 * wordmark and menu differ in width, so flex-centering sits off-center).
 * The width backs off before it can reach the side elements. */
.topbar-search {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: min(32rem, calc(100% - 24rem));
  display: flex;
  justify-content: center;
  min-width: 0;
}
@media (max-width: 44rem) {
  /* Narrow screens: back to in-flow, between wordmark and menu. */
  .topbar-search { position: static; transform: none; width: auto; flex: 1; }
}
.search-results {
  position: absolute;
  top: calc(100% + .4rem);
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: 32rem;
  z-index: 30;
  margin: 0;
  padding: .3rem;
  list-style: none;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .12);
  max-height: 19rem;
  overflow-y: auto;
}
.search-result {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin: 0;
  padding: .45rem .65rem;
  border-radius: 6px;
  font-size: .88rem;
  cursor: pointer;
}
.search-result .result-name { flex: 1; min-width: 0; }
.result-icon {
  flex: none;
  width: 20px;
  height: 20px;
  image-rendering: pixelated;
}
.search-result .result-key {
  font-size: .68rem;
  color: var(--muted);
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Which chart a result opens (search spans both catalogs). */
.search-result .result-tag {
  flex: none;
  font-size: .62rem;
  font-weight: 650;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: .08rem .45rem;
}
.search-result:hover, .search-result.active {
  background: var(--accent-soft);
  color: var(--accent);
}
.search-empty {
  margin: 0;
  padding: .45rem .65rem;
  font-size: .85rem;
  color: var(--muted);
}
.topbar-search input {
  width: 100%;
  max-width: 32rem;
  min-width: 0;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 100px;
  padding: .45rem 1rem;
  font: inherit;
  font-size: .95rem;
}
.topbar-search input::placeholder { color: var(--muted); }
.topbar-search input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}

.menu { position: relative; flex: none; }
.menu summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  padding: .55rem;
  border: 1px solid transparent;
  border-radius: 8px;
}
.menu summary::-webkit-details-marker { display: none; }
.menu summary:hover, .menu[open] summary {
  background: var(--accent-soft);
  border-color: var(--line);
}
.burger {
  display: inline-flex;
  flex-direction: column;
  gap: 4px;
}
.burger span {
  display: block;
  width: 18px;
  height: 2px;
  background: var(--text);
  border-radius: 2px;
}
.menu-panel {
  position: absolute;
  right: 0;
  top: calc(100% + .5rem);
  min-width: 11.5rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .4rem;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .12);
}
.menu-panel a {
  display: block;
  padding: .45rem .8rem;
  border-radius: 6px;
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
}
.menu-panel a:hover { background: var(--accent-soft); color: var(--accent); }
.menu-panel a[aria-current="page"] { color: var(--accent); font-weight: 600; }

/* --- wordmark ------------------------------------------------------------ */

.wordmark {
  font-size: 1.3rem;
  font-weight: 650;
  letter-spacing: -.015em;
  color: var(--text);
  text-decoration: none;
}
.wordmark span { color: var(--accent); }
.wordmark .mark {
  width: 1.2em;
  height: 1.2em;
  color: var(--accent);
  vertical-align: -.22em;
  margin-right: .4rem;
}

/* --- common elements ----------------------------------------------------- */

.badge {
  display: inline-block;
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--accent);
  background: var(--accent-soft);
  border: 1px solid var(--line);
  border-radius: 100px;
  padding: .25rem .7rem;
  margin-bottom: 1rem;
}
h1 {
  font-size: clamp(1.6rem, 5vw, 2.3rem);
  line-height: 1.2;
  letter-spacing: -.02em;
  margin: 0 0 1rem;
}
.lede { font-size: 1.06rem; color: var(--muted); margin: 0 0 2rem; }

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 1.4rem 1.5rem;
  margin-bottom: 1.25rem;
}
.card h2 {
  font-size: .78rem; font-weight: 650; text-transform: uppercase;
  letter-spacing: .07em; color: var(--muted); margin: 0 0 .9rem;
}
.card p { margin: 0 0 .8rem; }
.card p:last-child { margin-bottom: 0; }

ul { margin: 0 0 1rem; padding-left: 1.15rem; }
.card ul { margin-bottom: 0; }
li { margin-bottom: .55rem; }
li:last-child { margin-bottom: 0; }
li strong { font-weight: 600; }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }

/* --- long-form pages (about, terms, privacy, legal) ---------------------- */

.prose h2 {
  font-size: 1.15rem;
  letter-spacing: -.01em;
  margin: 2rem 0 .6rem;
}
.prose h2:first-child { margin-top: 0; }
.prose p { margin: 0 0 .9rem; }
.prose .updated { font-size: .85rem; color: var(--muted); margin-bottom: 2rem; }

/* Draft watermark for legal documents that are not yet in force. */
.draft-banner {
  background: var(--warn-soft);
  border: 1px solid var(--warn);
  border-radius: 10px;
  color: var(--warn);
  font-weight: 600;
  padding: .8rem 1.1rem;
  margin: 0 0 1.75rem;
}
.draft-banner p { margin: 0; }

/* Decisions the owner still has to make before a draft can be finalised.
 * Visually loud on purpose: these must never read as finished text. */
.todo-owner {
  background: var(--warn-soft);
  border-left: 3px solid var(--warn);
  color: var(--warn);
  display: block;
  font-weight: 600;
  padding: .5rem .8rem;
  margin: .6rem 0 .9rem;
  border-radius: 0 8px 8px 0;
}

/* Standing caveat inside a page's own copy — the interim dev-key notice on
 * the Stat Breakdown page is the first. Amber like .draft-banner so the
 * site has one visual language for "read this before you trust what's
 * below", but the body text stays --text: this is several sentences a
 * visitor actually has to read, and a whole paragraph set in --warn is
 * tiring at that length. The lead-in carries the colour instead. */
.notice {
  background: var(--warn-soft);
  border: 1px solid var(--warn);
  border-radius: 10px;
  color: var(--text);
  font-size: .95rem;
  padding: .8rem 1.05rem;
  margin: 0 0 1.7rem;
}
.notice p { margin: 0; }
.notice p + p { margin-top: .6rem; }
.notice strong { color: var(--warn); }

/* --- item page: stats, range toggle, chart -------------------------------- */

.item-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  background: var(--panel);  /* a card like everything below it */
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 1rem 1.25rem;
  margin-bottom: 1.5rem;
}
.item-head h1 { margin-bottom: .25rem; }

/* Item art (official Hypixel SkyBlock pack, see assets/icons/LICENSE.txt).
 * Pixel art scales with hard edges, never smoothing. */
.item-icon {
  flex: none;
  width: 72px;
  height: 72px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
}
.item-icon img {
  width: 52px;
  height: 52px;
  image-rendering: pixelated;
}

/* Monogram tile: the no-art fallback, sized by context. */
.icon-tile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--accent-soft);
  color: var(--accent);
  border-radius: 5px;
  font-size: .58rem;
  font-weight: 700;
  letter-spacing: .02em;
}
.icon-tile-lg {
  width: 52px;
  height: 52px;
  border-radius: 9px;
  font-size: 1.15rem;
}
.item-key-line {
  font-size: .8rem;
  color: var(--muted);
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  margin: 0;
}
/* The one-line indexable page description (SEO), under the item title. */
.page-tagline { margin: .3rem 0 0; font-size: .8rem; color: var(--muted); }
.item-wiki-line { margin: .35rem 0 0; font-size: .78rem; }
.item-wiki-line a { color: var(--accent); text-decoration: none; }
.item-wiki-line a:hover { text-decoration: underline; }

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: .8rem;
  margin-bottom: 1.5rem;
}
.stat {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .7rem .9rem;
}
.stat .stat-label {
  display: block;
  font-size: .68rem;
  font-weight: 650;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: .2rem;
}
.stat .stat-value {
  font-size: 1.15rem;
  font-weight: 650;
  letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
}

/* Series toggles: the chart legend and the show/hide control are the same
 * element. Color encodes the side only (blue buy / gold sell — a validated
 * CVD-safe pair); the dash pattern in each chip's line sample encodes the
 * measure, so no series is identified by color alone.
 *
 * Layout mirrors the data: every measure is a buy/sell pair, so each
 * family is a card holding a two-column grid — buy side left, sell side
 * right, one measure per row. */
.series-toggles {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: .8rem;
  margin-bottom: 1rem;
}
.series-group {
  flex: 1 1 16rem;
  background: var(--panel);  /* a card like its neighbours (stats, Sale
                                filters) — bare on --bg it read unfinished */
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .55rem .65rem .65rem;
}
.series-group-label {
  display: block;
  font-size: .68rem;
  font-weight: 650;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 .15rem .5rem;
}
.series-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .3rem .4rem;
}
.series-chip {
  position: relative;
  display: flex;
  align-items: center;
  gap: .45rem;
  font: inherit;
  font-size: .76rem;
  text-align: left;
  padding: .28rem .6rem;
  background: var(--panel);  /* also serves the mayor toggle, which sits
                                directly on --bg rather than in a group */
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 8px;
  cursor: pointer;
}
.series-chip .chip-line {
  width: 1.7em;
  height: 6px;
  flex: none;
  opacity: var(--chip-sample-dim);
}
.series-chip.side-ask .chip-line { color: var(--chart-ask); }
.series-chip.side-bid .chip-line { color: var(--chart-bid); }
.series-chip:hover { color: var(--text); border-color: var(--muted); }
.series-chip[aria-pressed="true"] {
  background: var(--accent-soft);
  color: var(--text);
  border-color: var(--muted);
  font-weight: 600;
}
.series-chip[aria-pressed="true"] .chip-line { opacity: 1; }

/* Plain-language explanation on hover or keyboard focus, from data-tip —
 * shared by series chips, overlay toggles, and perk chips. (Series chips
 * add a hidden span with the same text for screen readers — generated
 * content is not reliably exposed to them.) */
[data-tip] { position: relative; }
[data-tip]::after {
  content: attr(data-tip);
  position: absolute;
  left: 50%;
  bottom: calc(100% + .45rem);
  transform: translateX(-50%);
  width: max-content;
  max-width: 16rem;
  background: var(--panel);
  color: var(--text);
  font-size: .74rem;
  font-weight: 400;
  line-height: 1.45;
  text-align: left;
  white-space: normal;
  padding: .45rem .6rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .18);
  opacity: 0;
  visibility: hidden;
  transition: opacity .12s ease .2s, visibility 0s linear .32s;
  pointer-events: none;
  z-index: 30;
}
[data-tip]:hover::after,
[data-tip]:focus-visible::after {
  opacity: 1;
  visibility: visible;
  transition-delay: .2s, .2s;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* Coarse timeframe presets: evenly spread, directly above the chart. */
.preset-row {
  display: flex;
  background: var(--panel);  /* the interval-label cell has no background of
                                its own; without this the page bg shows
                                through it as a hole in the row */
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
  margin-bottom: .8rem;
}
.preset-row button {
  flex: 1;
  font: inherit;
  font-size: .82rem;
  padding: .38rem .5rem;
  background: var(--panel);
  color: var(--muted);
  border: 0;
  cursor: pointer;
  text-align: center;
}
.preset-row button + button { border-left: 1px solid var(--line); }
.preset-row button:hover { color: var(--accent); }
.preset-row button[aria-pressed="true"] {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}
/* A fixed interval that would exceed the point budget for the selected
 * window (or outsize it) is disabled until the window changes. */
.preset-row button[disabled] {
  color: var(--disabled);
  cursor: default;
}
.preset-row button[disabled]:hover { color: var(--disabled); }

/* Aggregation-interval row: same segmented look, prefixed with a label.
 * The label is a span, so the first button gets no border from the
 * `button + button` rule — give it the same separator explicitly. */
.interval-row .interval-label + button { border-left: 1px solid var(--line); }
.interval-row button { font-size: .78rem; padding: .3rem .4rem; }
.interval-row .interval-label {
  flex: 0 1 auto;
  align-self: center;
  font-size: .68rem;
  font-weight: 650;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 0 .8rem;
}
/* Auxiliary panels: volumes and order counts on their own y-scales, as
 * small multiples below the price chart — never a second axis on it. */
.aux-panel { margin-bottom: 1rem; }
.aux-title {
  font-size: .8rem;
  font-weight: 650;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 .4rem .2rem;
}
.aux-title .aux-unit {
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  margin-left: .35rem;
}
.chart-wrap-aux { margin-bottom: 0; }

/* Overlay toggles (mayor terms) sit apart from the series chips: they are
 * annotations, not data series. The perks of a selected mayor/minister
 * (clicked on the chart) render beside the toggle. */
.overlay-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .8rem;
  margin-bottom: .5rem;
}
.mayor-perks {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .35rem;
  font-size: .78rem;
}
.mayor-perks .perk-owner { font-weight: 650; margin-right: .25rem; }
.mayor-perks .perk-owner:not(:first-child) { margin-left: .6rem; }
/* Perk chips are BUTTONS so keyboard users can focus them and get the
 * description tooltip (data-tip shows on :focus-visible too); they toggle
 * nothing — focusability exists purely to expose the description. */
.perk-chip {
  display: inline-flex;
  align-items: center;
  padding: .18rem .55rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--muted);
  font: inherit;
  font-size: inherit;
  cursor: help;
}
.perk-chip:hover { color: var(--text); border-color: var(--muted); }

/* Terms are separated by the alternating band tint alone — no divider
 * lines (removed by request; they turned dense views into stripes). */
.chart-mayor-band { fill: var(--accent); opacity: var(--mayor-band-alpha); }
.chart-mayor-label { fill: var(--muted); font-size: 11px; font-weight: 650; }
.chart-mayor-minister { fill: var(--muted); font-size: 9.5px; }
/* Both name lines are one selectable group with a shared invisible hit
 * rectangle; hover and active color the whole block together. */
.chart-mayor-group { cursor: pointer; }
.chart-mayor-hit { fill: none; pointer-events: all; }
.chart-mayor-group:hover text,
.chart-mayor-group.active text { fill: var(--accent); }
.chart-mayor-group:focus-visible { outline: 2px solid var(--accent); }
.chart-tooltip .tt-mayor { color: var(--muted); }

.chart-wrap {
  position: relative;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: .8rem .6rem .4rem;
  margin-bottom: 1rem;
}
.chart-wrap svg { display: block; width: 100%; height: auto; }
/* The data svg and the hover-crosshair overlay svg stack in one box and
 * share a viewBox, so they scale identically; keeping the crosshair in
 * its own svg means mousemove repaints one line, not the series raster. */
.chart-stack { position: relative; }
.chart-wrap .chart-overlay {
  position: absolute;
  inset: 0;
  height: 100%;
  pointer-events: none;
  will-change: transform;  /* own layer: crosshair moves repaint only it */
}
.chart-grid line { stroke: var(--chart-grid); stroke-width: 1; }
.chart-axis text {
  fill: var(--muted);
  font-size: 11px;
  font-family: system-ui, sans-serif;
}
.chart-series-ask { stroke: var(--chart-ask); }
.chart-series-bid { stroke: var(--chart-bid); }
.chart-series {
  fill: none;
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}
/* Dashed strokes draw every dash with its own end caps: round caps on
 * thousands of 2px dashes along a jagged percentile/extreme line is what
 * made hovering those series lag. Dashes get cheap butt caps; solid
 * lines keep their round ones. */
.chart-series[stroke-dasharray] { stroke-linecap: butt; }
.chart-dot-ask { fill: var(--chart-ask); }
.chart-dot-bid { fill: var(--chart-bid); }
.chart-dot { stroke: var(--panel); stroke-width: 2; }
.chart-endlabel-ask { fill: var(--chart-ask); }
.chart-endlabel-bid { fill: var(--chart-bid); }
.chart-endlabel { font-size: 11px; font-weight: 650; }
/* SkyCofl pre-collection segment: same hues as our series so ask/bid stay
 * recognisable, but visibly not ours — thinner and faded, ending at the
 * cutover marker where our own collection takes over. */
.chart-series-cofl {
  stroke-width: 1.5;
  opacity: .55;
}
.chart-cutover {
  stroke: var(--muted);
  stroke-width: 1;
  stroke-dasharray: 5 4;
  opacity: .8;
}
.chart-cutover-label {
  fill: var(--muted);
  font-size: 10px;
  font-weight: 650;
}
.cofl-attribution {
  text-align: right;
  font-size: .74rem;
  color: var(--muted);
  margin: -.4rem .2rem 1rem;
}
.cofl-attribution a { color: var(--accent); text-decoration: none; }
.cofl-attribution a:hover { text-decoration: underline; }

.chart-crosshair {
  stroke: var(--muted);
  stroke-width: 1;
  stroke-dasharray: 3 3;
}
.chart-tooltip {
  position: absolute;
  /* Anchored at the origin and MOVED via transform: with will-change the
   * tooltip gets its own compositor layer, so dragging it across a dense
   * chart never re-rasterizes the pixels beneath — the last per-frame
   * hover cost on very busy items (God Potion at 1-min intervals). */
  left: 0;
  top: 0;
  will-change: transform;
  pointer-events: none;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .14);
  padding: .45rem .65rem;
  font-size: .78rem;
  line-height: 1.5;
  white-space: nowrap;
  z-index: 10;
}
.chart-tooltip .tt-time { color: var(--muted); }
.chart-tooltip .tt-val { font-variant-numeric: tabular-nums; font-weight: 600; }
.chart-tooltip .tt-dot {
  display: inline-block;
  width: .6em;
  height: .6em;
  border-radius: 50%;
  margin-right: .35rem;
}
.tt-dot-ask { background: var(--chart-ask); }
.tt-dot-bid { background: var(--chart-bid); }
.chart-msg {
  padding: 2.5rem 1rem;
  text-align: center;
  color: var(--muted);
}

/* --- sold-auction page: attribute filters and event marks ----------------- */

/* Filter bar: only values observed in the item's recorded sales are
 * offered (auction.js builds it from /api/auction/filters). */
.filters {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .6rem .8rem;
  margin-bottom: 1rem;
}
.filters-row {
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  gap: .5rem .6rem;
}
/* Labeled filter groups (Sale, Item, Gemstones…): fieldset/legend for the
 * semantics, a quiet inset box for the looks. Groups wrap as units, so
 * related selects can never end up on opposite ends of a wrapped row. */
.filters-group {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .5rem .9rem;
  margin: 0;
  padding: .55rem .7rem .5rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  min-inline-size: 0;
}
.filters-group-title {
  font-size: .64rem;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 0 .3rem;
}
/* The enchantment picker is its own group visually, same chrome. */
.filters-ench-row {
  margin-top: .5rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: .55rem .7rem .5rem;
}
.filter-field {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
}
.filters-label {
  font-size: .68rem;
  font-weight: 650;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--muted);
}
.filters select {
  font: inherit;
  font-size: .82rem;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: .28rem .45rem;
  max-width: 12rem;
}
.filters select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* --- dropdown lists (native <select>) ------------------------------------- */

/* The closed control has always been ours; the OPEN list was the browser's,
 * and Chromium on Windows drew it as a white popup with black text hanging
 * off a dark page (owner 2026-08-21). Two layers, because neither is enough
 * on its own:
 *
 *   1. `option` colours. This is the whole of what a browser painting a
 *      NATIVE popup will honour, and it is the floor everywhere — the list
 *      is at least the site's surface and ink. (Chromium needs it stated:
 *      an author background-color on the <select> takes the popup off the
 *      `color-scheme` path, and it then falls back to white.)
 *   2. `appearance: base-select` (Chromium 135+), where the picker stops
 *      being an OS widget and becomes real DOM in the top layer. There the
 *      list can simply BE the site's existing dropdown — the same surface,
 *      border, radius, shadow, row padding and accent-soft selection as
 *      .search-results above, which is the one popup language the site
 *      already had.
 *
 * A browser without layer 2 keeps its native popup wearing layer 1's
 * colours, so this degrades instead of breaking. Rules are deliberately
 * unscoped: every <select> the site grows should inherit this. */
select {
  /* The surface the control is painted on. Named as a variable because the
     arrow's fade lane below has to match it exactly; a select on a different
     surface sets this alongside its background and everything follows. */
  --select-bg: var(--bg);
}
select option,
select optgroup {
  background-color: var(--panel);
  color: var(--text);
}

@supports (appearance: base-select) {
  /* Must be opted into on BOTH halves — the control and its picker — or
     the browser keeps the native widget for the half left out. */
  select,
  select::picker(select) { appearance: base-select; }

  /* base-select re-renders the control as a flex button whose content is
     the selected option plus ::picker-icon. Everything the closed control
     already looked like (.filters select) still applies; this only places
     the label and the arrow within it. */
  select {
    display: inline-flex;
    align-items: center;
    position: relative;
    padding-right: 1.75rem;   /* the arrow's own lane, reserved */
    /* These controls are flex items of .filter-field, and `overflow: hidden`
       drops their automatic minimum size to zero — so on a cramped row they
       would shrink until even "Any" was cut in half. A floor wide enough for
       the short labels the filters actually use; longer ones stop at the
       12rem cap above and fade out under the arrow. */
    min-width: 4.75rem;
    /* The button renders the selected option's TEXT into an internal
       wrapper we cannot select, so the one-line rule has to arrive by
       inheritance (white-space is inherited; the option rule below only
       reaches the rows in the list). Without it the 59-character Ability
       Scrolls value wrapped to three lines and tripled the control's
       height, where the native control had clipped it. */
    white-space: nowrap;
    overflow: hidden;
  }
  select::picker-icon {
    position: absolute;
    inset-block: 0;
    right: 0;
    display: flex;
    align-items: center;
    padding: 0 .5rem 0 .75rem;
    /* Out of flow and opaque on purpose: in normal flow an over-long label
       (Ability Scrolls' three-scroll value) pushes the arrow straight out
       of the clipped box, and the control loses the only thing that says
       it opens. Its own lane fades the label out behind it instead. */
    background: linear-gradient(to right, transparent, var(--select-bg) .7rem);
    color: var(--muted);
    transition: transform .15s ease;
  }
  select:open { border-color: var(--accent); }
  select:open::picker-icon {
    color: var(--accent);
    transform: rotate(180deg);
  }

  /* The panel: .search-results' chrome, so the two dropdowns on the site
     are visibly the same object. */
  select::picker(select) {
    margin-block-start: .4rem;
    padding: .3rem;
    background: var(--panel);
    color: var(--text);
    border: 1px solid var(--line);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, .12);
    /* Same cap as .search-results: the enchantment picker is 40 options
       long, and leaving the height to the UA's viewport fitting means the
       list looks different depending on where on the page it opens. The
       width cap is for the other extreme — Ability Scrolls' longest value
       is "Implosion Scroll + Shadow Warp Scroll + Wither Shield Scroll",
       about 23rem, so 30rem holds every real label without letting one
       outlier stretch a list across the page. */
    max-height: 19rem;
    max-width: min(30rem, 92vw);
    overflow-y: auto;
  }
  /* The rows in the list. (Only the list: the closed button renders the
     selected label into an internal wrapper these rules do not reach —
     hence the inherited white-space above.) One line with an ellipsis
     rather than wrapping, so a long value cannot make one row three rows
     tall; `display: block` and not flex, because text-overflow does
     nothing on a flex container and these rows are plain text anyway. */
  select option {
    display: block;
    min-width: 0;
    padding: .38rem .6rem;
    border-radius: 6px;
    font-size: .82rem;
    background: transparent;
    color: var(--text);
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* One selection language across the site: accent-soft fill, accent ink —
     the same as .search-result:hover, .preset-row [aria-pressed=true] and
     .profile-chip[aria-pressed=true]. */
  select option:hover,
  select option:focus {
    background: var(--accent-soft);
    color: var(--accent);
  }
  select option:checked {
    background: var(--accent-soft);
    color: var(--accent);
    font-weight: 650;
  }
  /* The UA's tick column indents every label to reserve room for one
     checkmark; the accent fill already says which row is chosen. */
  select option::checkmark { display: none; }
}
/* Pet level bounds: two small numeric fields reading "min–max". */
.filter-level {
  font: inherit;
  font-size: .82rem;
  width: 4.2rem;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: .28rem .45rem;
}
.filter-level:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.filter-level::placeholder { color: var(--muted); }
.filters-add {
  font: inherit;
  font-size: .8rem;
  padding: .28rem .7rem;
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid var(--line);
  border-radius: 8px;
  cursor: pointer;
}
.filters-add:hover { border-color: var(--muted); }
/* The base-item preset toggle. */
.filters-clean {
  position: relative;
  font: inherit;
  font-size: .8rem;
  font-weight: 600;
  padding: .28rem .8rem;
  background: var(--panel);
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 8px;
  cursor: pointer;
}
.filters-clean:hover { color: var(--accent); }
.filters-clean[aria-pressed="true"] {
  background: var(--accent-soft);
  color: var(--accent);
  border-color: var(--muted);
}
/* BIN filter: the same segmented look as the appearance toggle. */
.bin-toggle {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
}
.bin-toggle button {
  font: inherit;
  font-size: .8rem;
  padding: .26rem .65rem;
  background: var(--panel);
  color: var(--muted);
  border: 0;
  cursor: pointer;
}
.bin-toggle button + button { border-left: 1px solid var(--line); }
.bin-toggle button:hover { color: var(--accent); }
.bin-toggle button[aria-pressed="true"] {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}
/* --- items directory (items.html) ----------------------------------------- */

.dir-filter-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .6rem;
  margin: 1rem 0;
}
.dir-filter {
  font: inherit;
  font-size: .9rem;
  width: min(22rem, 100%);
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: .45rem .7rem;
}
.dir-filter:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.dir-filter-count { font-size: .8rem; color: var(--muted); }
/* One card per category (owner 2026-08-21), the same panel chrome the item
   page's header block uses — a 2,000-name column list needs a surface under
   it or the headings read as floating over the page background. */
.dir-section {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 1rem 1.25rem 1.1rem;
  margin-bottom: 1.25rem;
}
.dir-section h2 {
  font-size: 1rem;
  margin: 0 0 .5rem;
}
.dir-section h2 .dir-count {
  font-size: .75rem;
  font-weight: 400;
  color: var(--muted);
  margin-left: .4rem;
}
.dir-list {
  list-style: none;
  margin: 0;
  padding: 0;
  columns: 14rem auto;
  column-gap: 1.4rem;
  font-size: .85rem;
}
.dir-list li {
  break-inside: avoid;
  padding: .1rem 0;
}
.dir-list a { color: var(--text); text-decoration: none; }
.dir-list a:hover { color: var(--accent); text-decoration: underline; }

/* --- current order book (bazaar item pages) ------------------------------- */

.book {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .6rem .8rem .8rem;
  margin-bottom: 1rem;
}
.book-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.book-asof { font-size: .78rem; color: var(--muted); }
.book-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}
@media (max-width: 760px) {
  .book-grid { grid-template-columns: 1fr; }
}
/* A grid item's automatic minimum size is its CONTENT's min-content width,
   so the nowrap price table pushed the track — and with it the whole page —
   wider than the viewport on a phone, and .book-scroll's overflow-x never
   got a chance to fire. min-width:0 is what lets the scroll container do
   its job (found on a 390px screen, 2026-08-21). */
.book-panel { min-width: 0; }
.book-title {
  margin: .2rem 0 .4rem;
  font-size: .9rem;
}
.book-scroll {
  overflow-x: auto;
  max-height: 24rem;
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: 8px;
}
.book-table {
  width: 100%;
  border-collapse: collapse;
  font-size: .82rem;
}
.book-table th {
  position: sticky;
  top: 0;
  background: var(--panel);
  text-align: left;
  font-size: .68rem;
  font-weight: 650;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
  padding: .4rem .6rem;
  border-bottom: 1px solid var(--line);
}
.book-table td {
  padding: .32rem .6rem;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.book-table tr:last-child td { border-bottom: 0; }
/* Depth bar behind the price cell, scaled to the side's largest level.
 * Color-blind safety: the two sides are already separated by panel and
 * title, so the hue is redundant decoration, not the only signal. */
.book-price { position: relative; }
.book-bar {
  position: absolute;
  left: 0;
  top: 15%;
  height: 70%;
  border-radius: 2px;
  opacity: .28;
}
.book-sell .book-bar { background: #c0564f; }
.book-buy .book-bar { background: #4f9e63; }
.book-price-text { position: relative; }
.book-empty { color: var(--muted); text-align: center; }
/* Phones: four columns of long coin figures do not fit at .82rem, and a
   sideways scroll inside a vertical scroll inside the page is a miserable
   thing to operate. Tightened type and padding fit the common cases
   outright; anything longer still scrolls, now inside the panel. */
@media (max-width: 560px) {
  .book { padding: .6rem .55rem .7rem; }
  .book-table { font-size: .72rem; }
  .book-table th { padding: .35rem .3rem; letter-spacing: .01em; }
  .book-table td { padding: .3rem .3rem; }
  .book-scroll { max-height: 18rem; }
}

/* --- recently sold list + sale-details dialog ----------------------------- */

.recent-panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .6rem .8rem .8rem;
  margin-bottom: 1rem;
}
.recent-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: .4rem;
}
.recent-row {
  font: inherit;
  font-size: .82rem;
  display: flex;
  align-items: center;
  gap: .5rem;
  width: 100%;
  padding: .35rem .55rem;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 8px;
  cursor: pointer;
  text-align: left;
}
.recent-row:hover { border-color: var(--muted); }
.recent-row:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.recent-icon {
  width: 24px;
  height: 24px;
  flex: none;
  image-rendering: pixelated;
}
.recent-icon-empty {
  display: inline-block;
  border: 1px dashed var(--line);
  border-radius: 4px;
}
.recent-price { font-weight: 600; }
.recent-kind {
  font-size: .68rem;
  font-weight: 650;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: .05rem .35rem;
  flex: none;
}
.recent-ago {
  margin-left: auto;
  color: var(--muted);
  white-space: nowrap;
}
.recent-empty {
  color: var(--muted);
  padding: .3rem .2rem;
}

.sale-dialog {
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .9rem 1.1rem;
  max-width: min(30rem, 90vw);
  max-height: 80vh;
}
.sale-dialog::backdrop { background: rgba(0, 0, 0, .55); }
.sale-dialog-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: .5rem;
}
.sale-dialog-title { margin: 0; font-size: 1rem; }
.sale-dialog-close {
  font: inherit;
  font-size: .9rem;
  background: none;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: .15rem .5rem;
  cursor: pointer;
}
.sale-dialog-close:hover { color: var(--accent); }
.sale-dialog-summary { margin: 0 0 .5rem; font-weight: 600; }
.sale-dialog-mods {
  margin: 0;
  padding-left: 1.1rem;
}
.sale-dialog-mods li { margin: .15rem 0; }
.sale-dialog-none { margin: 0; color: var(--muted); }

/* Active enchantment filters, each removable. */
.ench-chips {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .35rem;
}
.ench-chip {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  font-size: .78rem;
  padding: .18rem .3rem .18rem .6rem;
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid var(--line);
  border-radius: 999px;
}
.ench-remove {
  font: inherit;
  font-size: .85rem;
  line-height: 1;
  padding: 0 .3rem;
  background: transparent;
  color: inherit;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
}
.ench-remove:hover { color: var(--text); }

/* Individual sales. Shape carries the BIN/bid distinction (filled vs
 * hollow), never color alone; the panel-colored ring keeps overlapping
 * dots separable per the mark spec. */
.chart-sale-dot {
  fill: var(--chart-ask);
  stroke: var(--panel);
  stroke-width: 1;
  opacity: .75;
}
.chart-sale-dot-auc {
  fill: var(--panel);
  stroke: var(--chart-ask);
  stroke-width: 1.4;
  opacity: .9;
}
/* Robust-zoom clip note: how many values sit beyond the fitted axis. */
.chart-clip-note {
  fill: var(--muted);
  font-size: 10px;
  font-weight: 650;
}
/* Isolated bucket markers: a one-point line segment is invisible. */
.chart-point-ask { fill: var(--chart-ask); }
.chart-point-bid { fill: var(--chart-bid); }
/* An inert chip: the server withheld individual sales because the window
 * holds too many. Dashed border + dimmed swatch, NOT element opacity —
 * the hover tip is a pseudo-element of the chip, so fading the chip would
 * fade the very text that explains why it is inert. */
.series-chip.chip-inert {
  border-style: dashed;
  cursor: default;
}
.series-chip.chip-inert:hover { color: var(--muted); border-color: var(--line); }
.series-chip.chip-inert .chip-line { opacity: .2; }

/* Timeframe slider: two handles over the active preset's window. Sits
 * between the preset row and the interval row, above the charts. */
.timeframe { margin: .2rem .3rem .9rem; }
.tf-readout {
  text-align: center;
  font-size: .85rem;
  font-variant-numeric: tabular-nums;
  margin-bottom: .7rem;
}
.tf-readout .tf-arrow { color: var(--muted); padding: 0 .5rem; }
.tf-readout .tf-label {
  color: var(--muted);
  font-size: .72rem;
  font-weight: 650;
  letter-spacing: .07em;
  text-transform: uppercase;
  margin-right: .6rem;
}
.tf-slider {
  position: relative;
  height: 28px;
  cursor: pointer;
  touch-action: none;
}
.tf-track {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 4px;
  transform: translateY(-50%);
  background: var(--line);
  border-radius: 2px;
}
.tf-fill {
  position: absolute;
  top: 50%;
  height: 4px;
  transform: translateY(-50%);
  background: var(--tf-fill);
  border-radius: 2px;
}
.tf-handle {
  position: absolute;
  top: 50%;
  width: 16px;
  height: 16px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--panel);
  border: 2px solid var(--accent);
  padding: 0;
  cursor: grab;
}
.tf-handle:active { cursor: grabbing; }
.tf-handle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.tf-ticks {
  position: relative;
  height: 1.4rem;
  margin-top: .2rem;
}
.tf-tick {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
  padding-top: 6px;
  font-size: .68rem;
  color: var(--muted);
  white-space: nowrap;
}
.tf-tick::before {
  content: "";
  position: absolute;
  top: -3px;
  left: 50%;
  width: 1px;
  height: 6px;
  background: var(--line);
}
.tf-bounds {
  display: flex;
  justify-content: space-between;
  font-size: .72rem;
  color: var(--muted);
  margin-top: .3rem;
  font-variant-numeric: tabular-nums;
}

/* --- appearance settings (mode toggle + scheme picker) --------------------
 * Lives in the hamburger menu on the homepage and in the footer elsewhere.
 * Controls are inert without theme.js; they are progressive enhancement. */

.appearance {
  display: flex;
  align-items: center;
  gap: .6rem;
  flex-wrap: wrap;
}
.appearance-label {
  font-size: .72rem;
  font-weight: 650;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--muted);
}
.mode-toggle {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
}
.mode-toggle button {
  font: inherit;
  font-size: .82rem;
  padding: .3rem .7rem;
  background: var(--panel);
  color: var(--muted);
  border: 0;
  cursor: pointer;
}
.mode-toggle button + button { border-left: 1px solid var(--line); }
.mode-toggle button[aria-pressed="true"] {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}
.menu-settings {
  border-top: 1px solid var(--line);
  margin-top: .4rem;
  padding: .65rem .8rem .45rem;
}
.menu-settings .appearance {
  flex-direction: column;
  align-items: stretch;
  gap: .5rem;
}
.menu-settings .mode-toggle button { flex: 1; }

/* --- footer -------------------------------------------------------------- */

footer {
  margin-top: 2.5rem; padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  font-size: .85rem; color: var(--muted);
}
footer p { margin: 0 0 .7rem; }
footer p:last-child { margin-bottom: 0; }
.disclaimer { font-weight: 600; color: var(--text); }
.footer-nav { margin-bottom: 1rem; }
.footer-nav a { color: var(--muted); }
.footer-nav a:hover { color: var(--accent); }
.footer-nav .sep { padding: 0 .35rem; color: var(--line); }


/* --- player stats page ---------------------------------------------------- */

.lookup-row {
  display: flex; gap: .6rem; margin-bottom: 1rem; max-width: 26rem;
}
.lookup-row input {
  flex: 1; min-width: 0;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--line); border-radius: 8px;
  padding: .55rem .8rem; font: inherit;
}
.lookup-row input:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}
.lookup-row button {
  background: var(--accent-soft); color: var(--accent);
  border: 1px solid var(--accent); border-radius: 8px;
  padding: .55rem 1rem; font: inherit; font-weight: 650; cursor: pointer;
}
.lookup-row button:disabled { opacity: .55; cursor: default; }
.lookup-status { min-height: 1.4em; color: var(--muted); margin: 0 0 1.2rem; }

.player-head {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: .6rem 1.2rem; margin-bottom: 1.1rem;
}
.player-name { margin: 0; font-size: 1.25rem; }
.profile-chips { display: flex; flex-wrap: wrap; gap: .45rem; }
.profile-chip {
  background: var(--panel); color: var(--muted);
  border: 1px solid var(--line); border-radius: 999px;
  padding: .25rem .8rem; font: inherit; font-size: .82rem; cursor: pointer;
}
.profile-chip[aria-pressed="true"] {
  color: var(--accent); border-color: var(--accent);
  background: var(--accent-soft); font-weight: 650;
}

.table-scroll { overflow-x: auto; }
.player-table {
  border-collapse: collapse; width: 100%; font-size: .9rem;
}
.player-table th {
  text-align: left; font-size: .68rem; font-weight: 650;
  text-transform: uppercase; letter-spacing: .07em; color: var(--muted);
  padding: .3rem .6rem .45rem; border-bottom: 1px solid var(--line);
}
.player-table td {
  padding: .38rem .6rem; border-bottom: 1px solid var(--line);
}
.player-table tr:last-child td { border-bottom: 0; }
.player-table th.num, .player-table td.num {
  text-align: right; font-variant-numeric: tabular-nums;
}
.table-note { font-size: .82rem; color: var(--muted); margin: .8rem 0 0; }
/* Footnotes under the stat sources: extra air so they read as notes
   about the card, not another row of it. The p qualifier matches
   ".card p"'s specificity, which otherwise zeroes margin-top. */
p.note-gap { margin-top: 1.6rem; }

/* Skill switcher on the Stat Breakdown page: the segmented .preset-row
   look, spanning the full content column so it lines up with the cards
   under it (owner 2026-08-21). Hidden while only one skill is shipped
   (player.js). */
.skill-tabs {
  margin: .2rem 0 1.3rem;
}
.skill-tabs button {
  font-size: .88rem;
  padding: .45rem 1.1rem;
}

/* Trophy grids: uncaught tiers sit dim so the filled cells carry the
   story; fixed equal tier columns so the fish and frog cards line up
   with each other (owner 2026-08-15). */
.player-table .trophy-zero { color: var(--disabled); }
#trophy-table th:not(:first-child),
#frog-table th:not(:first-child) { width: 12%; text-align: center; }
#trophy-table td.num, #frog-table td.num { text-align: center; }


.pending-list { font-size: .85rem; color: var(--muted); margin: 0 0 .8rem; }

/* Inside the full-width HOTM card: the tree centered and dominant,
 * the allocation table below it. */
.tree-row { margin-top: .9rem; }
.tree-row .hotm-grid { margin: 0 auto 1.25rem; }
.tree-side { max-width: 48rem; margin: 0 auto; }
/* The tree gets its own frame inside the card (owner request). */
.hotm-grid {
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 1rem;
  background: var(--bg);
}
.tree-side { flex: 1 1 22rem; min-width: 0; }

/* SkyCrypt-style HOTM grid: 9 columns, tier 10 on top. */
.hotm-grid {
  display: grid;
  grid-template-columns: repeat(9, minmax(2.8rem, 4.4rem));
  grid-auto-rows: minmax(2.8rem, 4.4rem);
  gap: .4rem;
  justify-content: center;
  margin: .9rem 0 1.1rem;
  max-width: 46rem;
}
/* The foraging tree is 7 columns × 8 tiers. */
.hotf-grid {
  grid-template-columns: repeat(7, minmax(2.8rem, 4.4rem));
}
/* HOTF ability states (owner icon spec 2026-08-17): greyscaled
   sapling when locked; red-tinted cell when unlocked but not the
   enabled ability. Tints are theme-agnostic overlays. */
.hotm-icon.icon-grey img { filter: grayscale(1) brightness(.75); }
.hotm-cell.cell-red {
  background: rgba(190, 60, 60, .28);
  border-color: rgba(190, 60, 60, .6);
}
.hotm-cell {
  display: flex; align-items: center; justify-content: center;
  border-radius: 6px;
  /* Lighter than the frame behind it so dark icons (coal) stay legible;
     color-mix keeps it theme-relative with a plain fallback. */
  background: var(--panel);
  background: color-mix(in srgb, var(--panel) 88%, #9fb0c0 12%);
  border: 1px solid var(--line);
  padding: .3rem;
  cursor: help;
}
/* Icon wrapper: the hover zoom lives here, so it composes with the
 * 3D cube rotation and never moves the cell itself. */
.hotm-icon {
  width: 80%; height: 80%;
  display: flex; align-items: center; justify-content: center;
  transition: transform .09s ease-out;
}
.hotm-cell:hover .hotm-icon,
.hotm-cell:focus-visible .hotm-icon { transform: scale(1.35); }
.hotm-icon img {
  width: 100%; height: 100%; object-fit: contain;
  image-rendering: pixelated;
}
/* Isometric block canvases (drawn by player.js). */
.mc-block-canvas {
  width: 92%; height: 92%;
  image-rendering: pixelated;
}
.hotm-cell.locked { opacity: .75; border-style: dashed; }
.hotm-cell:focus-visible { outline: 2px solid var(--accent); }

/* Grid tooltip (built by player.js). */
.hotm-tip {
  display: none; position: fixed; z-index: 60;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: .55rem .75rem;
  max-width: 19rem;
  font-size: .82rem; line-height: 1.4;
  pointer-events: none;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .35);
}
.hotm-tip .t-name { font-weight: 700; }
.hotm-tip .t-level { color: var(--muted); font-size: .74rem; }
.hotm-tip .t-desc { margin-top: .3rem; }

/* Skin model beside the stat tiles. */
.player-top {
  display: flex; gap: 1.25rem; align-items: stretch;
  margin-bottom: 1.5rem;
}
/* 3 columns x 4 rows beside the model; powders share the last row. */
.player-top .stats {
  flex: 1; margin-bottom: 0;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-auto-rows: 1fr;
}
/* Fishing's four milestone tiles: a 2×2 square beside the model
   (owner 2026-08-15). Must sit after the 3-column rule; the 44rem
   auto-fit override below still wins on phones. */
.player-top .stats-2x2 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
/* Left column: the model with the ability card under it. */
.player-left { display: flex; flex-direction: column; gap: .8rem; }
.player-left .stat { text-align: center; }
/* Values centered both ways in the tile, slightly larger type. */
.player-top .stat {
  text-align: center;
  display: flex; flex-direction: column;
}
.player-top .stat .stat-value {
  flex: 1;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.5rem;
}
/* Golden mastery styling for maxed milestones. */
.stat.stat-max {
  border-color: var(--warn);
  background: var(--warn-soft);
}
.stat.stat-max .stat-value { color: var(--warn); }
.stat.stat-max .stat-label { color: var(--warn); opacity: .85; }
.skin-box {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  padding: .4rem;
}
/* Narrow screens: the model is decoration — drop it, stack the ability
   card above the milestone tiles, and let the tiles reflow fluidly (the
   fixed 3-columns-beside-the-model layout garbles at phone width). */
@media (max-width: 44rem) {
  .skin-box { display: none; }
  .player-top { flex-direction: column; }
  .player-top .stats {
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  }
}

/* Homepage on wide screens: hero text stays a readable measure. */
main > h1 { max-width: 46rem; }
main > .lede { max-width: 60rem; }

/* Crystal Hollows chip row. */
.crystal-chips {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: .45rem;
  max-width: 48rem;
  margin: 0 auto;
}
.crystal-chips .crystal-chip { text-align: center; }
@media (max-width: 44rem) {
  .crystal-chips { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.crystal-chip {
  border-radius: 999px;
  padding: .25rem .8rem;
  font-size: .82rem;
  border: 1px solid var(--line);
  cursor: default;
}
.crystal-chip.is-found {
  color: var(--accent); border-color: var(--accent);
  background: var(--accent-soft);
}
.crystal-chip.is-missing { color: var(--muted); opacity: .8; }
/* Farming's crop-upgrade chips reuse the crystal grid; the small
   heading separates them from the garden tiles above. */
.chips-head {
  font-size: .72rem; font-weight: 650; letter-spacing: .07em;
  text-transform: uppercase; color: var(--muted);
  margin: 1.1rem 0 .55rem;
}
.crop-chips { grid-template-columns: repeat(5, minmax(0, 1fr)); }
@media (max-width: 44rem) {
  .crop-chips { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* Garden chip cells: name + a miniature level bar (cap 20). */
.chip-cell {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .4rem .6rem .5rem;
  text-align: center;
}
.chip-cell .chip-name { font-size: .82rem; margin-bottom: .35rem; }
.chip-cell.is-missing .chip-name { color: var(--muted); opacity: .8; }
.chip-bar {
  height: 4px; border-radius: 999px; background: var(--line);
  overflow: hidden;
}
.chip-bar-fill { height: 100%; background: var(--accent); }
.chip-cell.is-max { border-color: var(--warn); }
.chip-cell.is-max .chip-name { color: var(--warn); }
.chip-cell.is-max .chip-bar-fill { background: var(--warn); }
.hotm-tip .t-gap { height: .45rem; }

/* Stat-row tooltip: the HOTM tip shell, widened for the yours-vs-max
   columns. Rows are focusable, so give keyboard users a visible ring. */
.stat-tip { max-width: 34rem; }
/* Plain-text notes reuse the shell but not its width: 34rem of one
   sentence reads as a banner, so they take the HOTM tip's measure. */
.stat-tip.stat-tip-text { max-width: 19rem; }
.stat-tip-cols { display: flex; gap: 1.1rem; }
.stat-tip-col { min-width: 12rem; flex: 1; }
.stat-tip .t-col-title {
  font-size: .64rem; font-weight: 650; letter-spacing: .07em;
  text-transform: uppercase; color: var(--muted);
}
.stat-tip .t-part {
  display: flex; justify-content: space-between; gap: 1rem;
  color: var(--muted); font-size: .78rem;
}
.stat-tip .t-part-val {
  font-variant-numeric: tabular-nums; color: var(--text);
}
.stat-tip .t-total {
  border-top: 1px solid var(--line); margin-top: .25rem;
  padding-top: .2rem; font-weight: 650; color: var(--text);
}
/* Enumerated step ladders in a tooltip (accessory lines, set tiers,
   anything with five rungs or fewer). The rung you are standing on is
   called out; the ones behind you recede. */
.stat-tip .t-steps { margin-top: .35rem; }
.stat-tip .t-part.is-past { opacity: .55; }
.stat-tip .t-part.is-here { color: var(--accent); font-weight: 650; }
.stat-tip .t-part.is-here .t-part-val { color: var(--accent); }
.stat-tip .t-note {
  margin-top: .4rem; font-size: .72rem; color: var(--muted);
  border-top: 1px solid var(--line); padding-top: .3rem;
}
/* Item interfaces inside the hover (spec 2026-08-23): the game-style
   box for a gear row's Yours/Max sides. Lore colours come from the
   --mc-* tokens; runs arrive from the server as [text, colour] pairs
   and are set with textContent only. */
.stat-tip-cols.has-iface { gap: .9rem; }
.tti {
  background: var(--bg); border: 1px solid var(--line);
  border-radius: 8px; padding: .5rem .65rem; margin-top: .25rem;
  font-size: .8rem; line-height: 1.45; min-width: 15rem;
}
.tti-head { display: flex; align-items: center; gap: .5rem; margin-bottom: .3rem; }
.tti-icon { image-rendering: pixelated; flex: none; }
.tti-name { font-weight: 700; font-size: .88rem; }
.tti-line { min-height: 1.2em; }
.tti-gap { height: .45rem; }
.tti-rarity { font-weight: 800; letter-spacing: .04em; margin-top: .4rem; }
.tti-foot { margin-top: .35rem; }
.stat-tip-col.is-maxed .tti { border-color: var(--warn); }
/* Accessory lines as a strip of rung interfaces (8C), and the
   climbed-past icon ladder (9F). */
/* The 18C card header: the thing's picture beside its name. */
.card-head { display: flex; align-items: center; gap: .55rem; margin-bottom: .2rem; }
.card-head img { image-rendering: pixelated; flex: none; }
.t-sub { color: var(--muted); font-size: .72rem; }
.tti-strip { display: flex; gap: .5rem; flex-wrap: wrap; align-items: stretch; }
.tti-cell { display: flex; flex-direction: column; }
.tti-cell.is-dim .tti { opacity: .55; }
.tti-tag {
  font-size: .6rem; font-weight: 650; letter-spacing: .07em;
  text-transform: uppercase; color: var(--muted); min-height: .9rem;
}
.tti-tag.is-yours { color: var(--accent); }
.tti.tti-sm { min-width: 10rem; max-width: 14rem; font-size: .76rem; }
/* 22B: several modifiers in one container. */
.tti.tti-multi { display: flex; flex-direction: column; gap: .55rem; }
.tti.tti-inner {
  border: 0; border-top: 1px solid var(--line); border-radius: 0;
  box-shadow: none; padding: .45rem 0 0; margin-top: 0; min-width: 0;
}
.tti.tti-multi .tti-inner:first-child { border-top: 0; padding-top: 0; }
.tti-ladder {
  display: flex; gap: .4rem; align-items: center; flex-wrap: wrap;
  margin-top: .45rem;
}
.tti-rung {
  display: flex; flex-direction: column; align-items: center; gap: .1rem;
  font-size: .68rem; color: var(--muted); min-width: 4.2rem;
  text-align: center;
}
.tti-rung .rung-val { font-variant-numeric: tabular-nums; color: var(--text); }
.tti-rung.is-here { color: var(--accent); }
.tti-rung.is-here .rung-val, .tti-rung.is-here .rung-name {
  color: var(--accent); font-weight: 650;
}
.rung-arrow { color: var(--muted); }
.stat-tip-col.is-maxed .t-total, .stat-tip-col.is-maxed .t-total .t-part-val { color: var(--warn); }
/* Small screens (owner report 2026-08-24): the desktop layout is two
   15rem-minimum interfaces side by side in a 34rem tip — wider than
   any phone, so the Max column clipped off-screen. Here the tip caps
   to the viewport, the sides stack, the boxes give up their minimum
   widths, and a tall stacked tip scrolls internally — pointer events
   come back on so touch can scroll it (tips open on tap-focus there,
   and a tap on the tip blurs the row, which dismisses it). */
@media (max-width: 44rem) {
  .hotm-tip, .stat-tip, .stat-tip.stat-tip-text {
    max-width: calc(100vw - 16px);
  }
  .stat-tip-cols, .stat-tip-cols.has-iface {
    flex-direction: column; gap: .45rem;
  }
  .stat-tip-col { min-width: 0; }
  .tti { min-width: 0; padding: .4rem .55rem; }
  .tti.tti-sm { min-width: 8.5rem; }
  .stat-tip { font-size: .78rem; }
}
/* Touch only: a mouse entering an interactive tip would fire the
   row's mouseleave and flicker, so hover-capable devices keep
   pointer-events off and this stays gated on (hover: none). The
   height cap deliberately leaves a band of page visible around the
   tip (owner 2026-08-24: a full-height tip left nowhere obvious to
   tap it away) — taps outside the row dismiss it in player.js. */
@media (max-width: 44rem) and (hover: none) {
  .stat-tip {
    max-height: 72vh;
    max-height: 72dvh;
    overflow-y: auto;
    pointer-events: auto;
  }
}
.c-gold { color: var(--mc-gold); } .c-gray { color: var(--mc-gray); }
.c-dgray { color: var(--mc-dgray); } .c-blue { color: var(--mc-blue); }
.c-green { color: var(--mc-green); } .c-aqua { color: var(--mc-aqua); }
.c-pink { color: var(--mc-pink); } .c-red { color: var(--mc-red); }
.c-yellow { color: var(--mc-yellow); } .c-white { color: var(--mc-white); }
.c-purple { color: var(--mc-purple); }
.srow:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* --- tabbed stat card ----------------------------------------------------- */

/* Option B (owner-picked 2026-08-14): the stat selector is labelled
   category columns of slim meter rows — half the height of the old tile
   grid, and progress reads at a glance from the meters. Same row
   language as the source lists in the panel below. */
.stat-tabs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: .9rem 1.8rem;
  margin-bottom: 1.1rem;
}
.stat-cat { min-width: 0; }
/* Rows layout (farming — owner 2026-08-16): category sections stack
   full-width, and each section's meters wrap into columns, so a
   3-stat section no longer pins a whole column of empty space. */
.stat-tabs.is-rows { grid-template-columns: 1fr; gap: 1.1rem; }
.stat-tabs.is-rows .stat-cat {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
  gap: 0 1.8rem;
}
.stat-tabs.is-rows .stat-cat-head { grid-column: 1 / -1; }
.stat-cat-head {
  font-size: .66rem; font-weight: 650; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted);
  margin: 0 0 .3rem;
}
.stat-row {
  display: block; width: 100%;
  background: none; border: 1px solid transparent; border-radius: 6px;
  padding: .3rem .5rem .38rem;
  font: inherit; color: var(--muted);
  cursor: pointer; text-align: left;
}
.stat-row:hover { background: var(--accent-soft); }
.stat-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.stat-row-top {
  display: flex; justify-content: space-between; gap: .8rem;
  font-size: .82rem; margin-bottom: .24rem;
}
.stat-row-name {
  color: var(--text);
  min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap;
}
.stat-row-nums {
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.stat-row[aria-selected="true"] {
  background: var(--accent-soft);
  border-color: var(--accent);
}
.stat-row[aria-selected="true"] .stat-row-name,
.stat-row[aria-selected="true"] .stat-row-nums { color: var(--accent); }
.stat-row.is-max .stat-row-nums { color: var(--warn); }
.stat-row.is-max .smeter-fill { background: var(--warn); }

/* Hero bar: pill-rounded, accent blue; gold mastery when maxed. */
.stat-bar {
  position: relative;
  height: 2rem;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 999px;
  overflow: hidden;
  margin: .4rem 0 1.2rem;
}
.stat-bar-fill {
  position: absolute; inset: 0 auto 0 0;
  background: var(--accent);
  border-radius: 999px;
}
.stat-bar.is-max .stat-bar-fill { background: var(--warn); }
.stat-bar-text {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-variant-numeric: tabular-nums;
  color: #fff; text-shadow: 0 1px 2px rgba(0, 0, 0, .55);
}

/* Grouped slim meters (Option A). */
/* Section headings carry the card's structure, so they are allowed to
   look like headings (owner 2026-08-21): full-strength ink, heavier and
   a size up from the rows they introduce. */
.sgroup-head {
  font-size: .92rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--text);
  margin: 1.5rem 0 .45rem;
}
.srow { padding: .3rem 0; }
.srow-top {
  display: flex; justify-content: space-between; gap: 1rem;
  font-size: .88rem;
}
.srow-name {
  min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap;
}
.srow-val {
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* One half of an alternative row's "x / y" that the tab total does NOT
   take from this row — fishing shows both rod types, and only the
   better one counts on each side. Dimmed rather than hidden: it is
   still this rod's own honest figure. */
.srow-val .uncounted { opacity: .42; }
.smeter {
  height: 4px; background: var(--line); border-radius: 2px;
  margin-top: .3rem; overflow: hidden;
}
.smeter-fill {
  height: 100%; background: var(--accent); border-radius: 2px;
}
.srow.is-max .srow-val { color: var(--warn); }
.srow.is-max .smeter-fill { background: var(--warn); }
.srow.is-missing .srow-name,
.srow.is-missing .srow-val { color: var(--muted); }

/* Small pill action button (the True Specific toggle). */
.excl-btn {
  font: inherit; font-size: .74rem; color: var(--accent);
  background: none; border: 1px solid var(--line); border-radius: 999px;
  padding: .15rem .7rem; cursor: pointer;
}
.excl-btn:hover:not(:disabled) { background: var(--accent-soft); }
.excl-btn:disabled { color: var(--disabled); cursor: default; }
.excl-btn:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.excl-btn[aria-pressed="true"] {
  background: var(--accent-soft); border-color: var(--accent);
}
/* Card title row with an action beside it (True Specific toggle). */
.card-head {
  display: flex; align-items: center; gap: .8rem;
  margin: 0 0 .9rem;
}
.card-head h2 { margin: 0; }

/* Temporary-buff rows: displayed, never counted. */
/* "Not counted" opens with a rule so the excluded shelf reads as
   separate from the counted sources above it. */
.sgroup-head.nc-sep {
  border-top: 1px solid var(--line);
  padding-top: 1.1rem; margin-top: 1.3rem;
}
/* Subsection labels inside "Not counted" — quieter than .sgroup-head
   so the section reads as one group with three shelves. */
.ssub-head {
  font-size: .84rem; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text); opacity: .85;
  margin: 1.1rem 0 .25rem;
}
/* Third level inside "Not counted": the same categories the counted list
   uses, nested under Owned / Trackable / Untrackable. Quieter than
   .ssub-head so the shelf still reads as the outer grouping. */
.ssub-cat {
  font-size: .74rem; font-weight: 650; letter-spacing: .07em;
  text-transform: uppercase; color: var(--accent); opacity: .95;
  margin: .75rem 0 .15rem;
}
.trow {
  display: flex; justify-content: space-between; gap: 1rem;
  padding: .28rem 0; font-size: .86rem;
  color: var(--muted);
}
.trow.is-active { color: var(--text); }
.trow.is-active .srow-val { color: var(--accent); font-weight: 650; }

/* --- Pet XP Profit (web/pet-xp-profit.html, 2026-08-24) ---------------------
 * The settings card is a stack of rows separated by rules (owner): each
 * row is a label plus wrapped controls. Toggles reuse the segmented
 * .preset-row look as inline groups (.cfg-seg) — no sliders. Each boost
 * lives in its own cell with its multiplier printed directly beneath the
 * input. Inputs behind an off toggle stay visible but disabled and
 * emptied, so the row keeps its shape. */
.cfg-card { padding-top: .25rem; padding-bottom: .25rem; }
.cfg-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .8rem;
  padding: .8rem 0; border-top: 1px solid var(--line);
}
.cfg-row:first-child { border-top: 0; }
.cfg-row.is-top { align-items: flex-start; }
.cfg-label {
  flex: 0 0 5.6rem; font-size: .68rem; font-weight: 650;
  text-transform: uppercase; letter-spacing: .07em; color: var(--muted);
  padding-top: .5rem; align-self: flex-start;
}
.cfg-sub { font-size: .8rem; color: var(--muted); }
.cfg-seg {
  display: inline-flex; background: var(--panel);
  border: 1px solid var(--line); border-radius: 8px; overflow: hidden;
}
.cfg-seg button {
  font: inherit; font-size: .82rem; padding: .38rem .7rem;
  background: var(--panel); color: var(--muted); border: 0; cursor: pointer;
  white-space: nowrap;
}
.cfg-seg button + button { border-left: 1px solid var(--line); }
.cfg-seg button:hover { color: var(--accent); }
.cfg-seg button[aria-pressed="true"] {
  background: var(--accent-soft); color: var(--accent); font-weight: 600;
}
.cfg-seg button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* A standalone toggle button styled like a seg, WITHOUT the seg's
 * overflow:hidden wrapper — that clips the data-tip bubble (caught on
 * the Inferno page's Include Setup Costs, 2026-09-02). */
.cfg-toggle {
  font: inherit; font-size: .82rem; padding: .38rem .7rem;
  background: var(--panel); color: var(--muted);
  border: 1px solid var(--line); border-radius: 8px; cursor: pointer;
  white-space: nowrap;
}
.cfg-toggle:hover { color: var(--accent); }
.cfg-toggle[aria-pressed="true"] {
  background: var(--accent-soft); color: var(--accent); font-weight: 600;
  border-color: var(--accent);
}
.cfg-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.cfg-input, .cfg-select {
  font: inherit; font-size: .84rem; background: var(--panel); color: var(--text);
  border: 1px solid var(--line); border-radius: 8px; padding: .38rem .6rem;
}
.cfg-input { font-variant-numeric: tabular-nums; width: 7.5rem; }
.cfg-input.is-narrow { width: 4.6rem; }
.cfg-input.cfg-name { width: 12rem; font-variant-numeric: normal; }
.cfg-input:disabled, .cfg-select:disabled {
  color: var(--disabled); background: var(--bg); cursor: default;
}
.cfg-input:focus-visible, .cfg-select:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}
.cfg-btn {
  background: var(--accent-soft); color: var(--accent);
  border: 1px solid var(--accent); border-radius: 8px;
  padding: .4rem .9rem; font: inherit; font-size: .84rem; font-weight: 650; cursor: pointer;
}
.cfg-btn:disabled { opacity: .55; cursor: default; }
.cfg-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.cfg-status { flex-basis: 100%; min-height: 1.2em; font-size: .82rem; color: var(--muted); margin: 0; }
.boost-cell {
  display: inline-flex; flex-direction: column; gap: .35rem;
  padding-right: .8rem; border-right: 1px dashed var(--line);
}
.boost-cell:last-child { border-right: 0; padding-right: 0; }
.boost-label {
  font-size: .66rem; font-weight: 650; text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted);
}
.boost-input { display: flex; gap: .35rem; align-items: center; flex-wrap: wrap; }
.boost-factor {
  font-family: ui-monospace, Consolas, "Cascadia Mono", monospace;
  font-size: .8rem; font-weight: 600; color: var(--accent);
}
.boost-factor.is-dim { color: var(--muted); font-weight: 400; }
.boost-cell.is-total .boost-factor { font-size: .88rem; }
.auto-tag {
  display: inline-block; font-size: .6rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; padding: .05em .4em; border-radius: 4px;
  background: var(--accent-soft); color: var(--accent); margin-left: .35rem;
  vertical-align: middle;
}
.cfg-seg button[aria-pressed="true"] .auto-tag { background: var(--panel); }

/* The ranking table: headers stack on two lines to keep the table narrow
 * (owner); the sorted column carries aria-sort, drawn as an arrow. */
.petxp-table th { white-space: normal; line-height: 1.2; vertical-align: bottom; }
.petxp-table th button {
  font: inherit; color: inherit; background: none; border: 0; padding: 0;
  cursor: pointer; text-transform: inherit; letter-spacing: inherit;
  text-align: inherit; font-weight: inherit;
}
.petxp-table th button:hover { color: var(--accent); }
.petxp-table th button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.petxp-table th[aria-sort="descending"] button::after { content: " ▼"; color: var(--accent); }
.petxp-table th[aria-sort="ascending"] button::after { content: " ▲"; color: var(--accent); }
.petxp-table td { white-space: nowrap; }
/* Low-volume rows are dulled by COLOUR, not opacity: opacity on the cell
 * would also fade the hover tooltip drawn inside it (owner: tooltips on
 * low-volume links must read at full strength). The badge keeps its own
 * colour; only the icon fades. */
.petxp-table tr.is-lowvol td,
.petxp-table tr.is-lowvol td .pet-name,
.petxp-table tr.is-lowvol td .t-pos,
.petxp-table tr.is-lowvol td .t-neg { color: var(--disabled); }
.petxp-table tr.is-lowvol .pet-icon { opacity: .55; }
.badge-lowvol, .badge-hatch {
  display: inline-block; font-size: .6rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; padding: .05em .4em; border-radius: 4px;
  background: var(--warn-soft); color: var(--warn); margin-left: .35rem;
  vertical-align: middle;
}
/* The dragons' "no item until 100" note (owner 2026-08-29): the same
 * mark in the accent, with the explanation as the site's tooltip. */
.badge-hatch { background: var(--accent-soft); color: var(--accent); cursor: help; white-space: nowrap; }
.petxp-table .pet-icon {
  width: 20px; height: 20px; image-rendering: pixelated;
  vertical-align: middle; margin-right: .4rem;
}
/* Price links take the cell's colour; the pet name keeps its rarity
 * class (.c-gold …, defined once for the whole site). A blanket
 * `.petxp-table a { color: inherit }` outranked those single-class
 * colours and left every name in the row colour (owner, 2026-08-25). */
.petxp-table a { text-decoration: underline; text-underline-offset: 2px; }
.petxp-table td.num a { color: inherit; }
.petxp-table a.pet-name { font-weight: 600; }
.petxp-table a.pet-name.c-common { color: var(--text); }
.petxp-table a:hover { color: var(--accent); }
.petxp-table .t-pos { color: var(--mc-green); font-weight: 600; }
.petxp-table .t-neg { color: var(--mc-red); font-weight: 600; }
/* Tooltips on a table cell: left-aligned above the cell (the site
 * default is centred above). The table sits in a scroll box, which clips
 * anything drawn outside it, so petxp.js marks the first rows tip-below
 * and their tooltips open downwards instead of into the sticky header. */
.petxp-table [data-tip]::after { left: 0; transform: none; }
.petxp-table tr.tip-below [data-tip]::after {
  bottom: auto; top: calc(100% + .35rem);
}

/* The page runs wider than the chart pages so more of the table shows
 * (owner): full width minus a margin, capped well above .wrap-wide. */
.wrap-petxp { max-width: min(96rem, 100% - 2rem); }
/* About twenty rows tall, then the rows scroll under a header that
 * stays put (owner). The header's rule is a shadow: a border on a
 * sticky cell scrolls away with the first row in most engines. */
.petxp-scroll { max-height: 46rem; overflow: auto; }
.petxp-scroll thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--panel); border-bottom: 0;
  box-shadow: 0 1px 0 var(--line);
}
/* On the wide page the lede wrapped at 60rem while the notice and cards
 * below ran full width, which read as a ragged gap (owner screenshot):
 * let it span the page like everything under it. */
.wrap-petxp main > .lede { max-width: none; }

/* Phones: each settings row becomes label-above-controls, segmented
 * groups turn into wrapping chips (a one-line segment cannot wrap
 * cleanly), and the boost cells stack full-width with a rule between
 * them instead of beside them. The table keeps its own scroll box. */
@media (max-width: 720px) {
  .cfg-row { gap: .45rem .55rem; padding: .7rem 0; }
  .cfg-label { flex-basis: 100%; padding-top: 0; }
  .cfg-seg { flex-wrap: wrap; gap: .35rem; border: 0; border-radius: 0;
             background: none; overflow: visible; }
  .cfg-seg button { border: 1px solid var(--line); border-radius: 8px; }
  .cfg-seg button + button { border-left: 1px solid var(--line); }
  .cfg-seg button[aria-pressed="true"] { border-color: var(--accent); }
  .cfg-input.cfg-name { flex: 1 1 10rem; width: auto; }
  .boost-cell {
    flex: 1 1 100%; padding-right: 0; border-right: 0;
    padding-bottom: .55rem; border-bottom: 1px dashed var(--line);
  }
  .boost-cell:last-child { border-bottom: 0; padding-bottom: 0; }
  .boost-input .cfg-select { max-width: 100%; }
}

/* --- Minion Profits (web/minion-profits.html, 2026-08-27) -------------------
 * The pet page's settings rows and table, plus: press buttons inside
 * .cfg-seg, the storage bar, badges in the Notes column, the ƒ button and
 * the row-maths panel it opens beneath its row (labelled terms, "|" as
 * the only separator — owner). */
.wrap-minions { max-width: min(100rem, 100% - 2rem); }
/* Layout N1 (owner 2026-08-27): every setting is a .boost-cell — label
 * above, the item's name alone in the control, its effect beneath in
 * the accent monospace — so nothing truncates and rows never wrap a
 * lone button. Wide selects share one width. */
.wrap-minions .cfg-select.mp-wide { width: 15rem; }
/* The customisable-select button reserves a 1.75rem arrow lane that its
 * intrinsic width does not include, so an unsized select clips its last
 * two characters (owner screenshots, 2026-08-27). Every select on this
 * page is sized to its longest option plus the lane. */
#mp-sell { width: 13.5rem; }
#mp-show { width: 11.5rem; }
#mp-tier { width: 9.5rem; }
#mp-beacon { width: 6.5rem; }
#mp-item { width: 6.5rem; }
#mp-crest-rarity { width: 8.5rem; }
#mp-crest-kills { width: 10rem; }
#mp-battle { width: 10.5rem; }
#mp-members { width: 6.5rem; }
#mp-chest, #mp-hopper { width: 11.5rem; }   /* room for the Permanent group on the same line (owner) */
#mp-fuel { width: 13rem; }                  /* "Enchanted Lava Bucket" is the longest (owner: slightly narrower) */
.wrap-minions .boost-factor { max-width: 15rem; white-space: normal; line-height: 1.35; }
.wrap-minions .boost-cell { gap: .3rem; }
.wrap-minions .cfg-row.is-top .cfg-status { flex-basis: 100%; }
/* The cells of a field row live in their own wrapping box beside the
 * row label, so when the screen is too narrow the second line starts
 * under the first line's cells, not under the label (owner 2026-08-27). */
.wrap-minions .mp-fields {
  flex: 1 1 0; min-width: 0; display: flex; flex-wrap: wrap;
  gap: .5rem .8rem; align-items: flex-start;
}
.wrap-minions #mp-unique { display: inline-flex; gap: .35rem; align-items: center; }
.wrap-minions #mp-status { max-width: 34rem; }
.wrap-minions main > .lede { max-width: none; }
.minions-scroll { max-height: 48rem; overflow: auto; }
.minions-scroll thead th {
  position: sticky; top: 0; z-index: 1; background: var(--panel);
  box-shadow: 0 1px 0 var(--line);
}
.minions-table th small {
  display: block; font-size: .62rem; letter-spacing: .04em; text-transform: none;
  color: var(--accent); font-weight: 600; margin-top: .15rem;
}
.minions-table th[data-sort] button { white-space: nowrap; }
.minions-table td.mp-notes { text-align: center; width: 2.6rem; }
.mp-info {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.25rem; height: 1.25rem; border-radius: 50%; padding: 0; cursor: pointer;
  font: inherit; font-size: .72rem; font-weight: 700; font-style: italic; line-height: 1;
  font-family: Georgia, "Times New Roman", serif;
  background: var(--accent-soft); color: var(--accent); border: 1px solid var(--accent);
}
.mp-info.is-warn { background: var(--warn-soft); color: var(--warn); border-color: var(--warn); }
.mp-info:hover, .mp-info:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.mp-tip .t-line { padding: .12rem 0; }
.mp-tip .t-line + .t-line { border-top: 1px dashed var(--line); }
.mp-tip .t-line.is-warn { color: var(--warn); }
.minions-table tr.is-loss td.num { color: var(--muted); }
.mp-datarow { border-top: 0; padding: .35rem 0; }
/* Pet per skill picker (owner 2026-08-27): name in its rarity colour
 * (the site's .c-gold … classes), "from→to" right-aligned, | coins per
 * XP — the same four-column line on the button and on every option. */
.mp-petpick { position: relative; width: 15.5rem; }
.pp-btn, .pp-list li {
  display: grid; grid-template-columns: 1fr auto auto auto; gap: 0 .4rem; align-items: baseline;
  width: 100%; text-align: left; font: inherit; font-size: .84rem;
}
.pp-btn {
  grid-template-columns: 1fr auto auto auto auto;
  background: var(--panel); color: var(--text); border: 1px solid var(--line); border-radius: 8px;
  padding: .38rem .6rem; cursor: pointer;
}
.pp-btn:disabled { color: var(--disabled); cursor: default; }
.pp-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.pp-btn[aria-expanded="true"] { border-color: var(--accent); }
.pp-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pp-name.c-common { color: var(--text); }
.pp-lv { font-family: ui-monospace, Consolas, "Cascadia Mono", monospace; font-variant-numeric: tabular-nums; text-align: right; color: var(--text); }
.pp-sep { color: var(--muted); }
.pp-cpx { font-family: ui-monospace, Consolas, "Cascadia Mono", monospace; font-variant-numeric: tabular-nums; text-align: right; color: var(--accent); font-weight: 600; min-width: 2.6rem; }
.pp-caret { color: var(--muted); padding-left: .2rem; }
.pp-list {
  position: absolute; left: 0; right: 0; top: calc(100% + .25rem); z-index: 40; margin: 0; padding: .25rem 0; list-style: none;
  background: var(--panel); border: 1px solid var(--accent); border-radius: 8px; box-shadow: 0 8px 24px rgba(0, 0, 0, .28);
}
.pp-list li { padding: .35rem .6rem; cursor: pointer; }
.pp-list li:hover, .pp-list li:focus { background: var(--accent-soft); outline: none; }
.pp-list li.is-selected { background: var(--accent-soft); }
.mp-name { font-weight: 600; }
.mp-bar {
  display: inline-block; width: 4.2rem; height: 6px; border-radius: 3px;
  background: var(--line); overflow: hidden; vertical-align: middle; margin-right: .4rem;
}
.mp-bar i { display: block; height: 100%; background: var(--accent); }
.mp-bar.is-full i { background: var(--warn); }
.mp-badge {
  display: inline-block; font-size: .62rem; font-weight: 700; letter-spacing: .04em;
  padding: .1em .45em; border-radius: 4px; margin: .1rem .3rem .1rem 0;
  background: var(--accent-soft); color: var(--accent); white-space: nowrap;
}
.mp-badge.is-warn { background: var(--warn-soft); color: var(--warn); }
.mp-fbtn {
  font: inherit; font-family: ui-monospace, Consolas, "Cascadia Mono", monospace;
  font-size: .8rem; width: 1.7rem; height: 1.5rem; padding: 0; cursor: pointer;
  background: var(--panel); color: var(--muted); border: 1px solid var(--line); border-radius: 6px;
}
.mp-fbtn:hover { color: var(--accent); border-color: var(--accent); }
.mp-fbtn[aria-expanded="true"] { background: var(--accent-soft); color: var(--accent); border-color: var(--accent); }
.mp-fbtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.minions-table tr.mp-detail td {
  white-space: normal; background: var(--bg); padding: .8rem .9rem .9rem 2.4rem;
  border-bottom: 2px solid var(--accent);
}
/* The ƒ panel: ledgers — operator left, value right, ruled result rows
 * (owner, F1) — and the Items table. */
/* L2 (owner 2026-08-27): a fixed-width left stack (Speed, Fuel, Cost)
 * and a right stack (Items table, then the result ledgers side by side).
 * Each stack is content-sized, so nothing stretches to match a neighbour. */
.mp-panel { display: grid; grid-template-columns: minmax(19rem, 23rem) 1fr; gap: .7rem; align-items: start; }
.mp-left, .mp-right { display: grid; gap: .7rem; align-content: start; min-width: 0; }
.mp-results { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .7rem; align-items: start; }
.mp-results.has-pet { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.mp-fuelcell { line-height: 1.25; }
.mp-fueltop { white-space: nowrap; }
.mp-fuelbot { display: block; font-size: .7rem; color: var(--muted); font-family: inherit; white-space: nowrap; }
.mp-lrow.hl .v { color: var(--warn); font-weight: 650; }
.mp-book {
  background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
  padding: .6rem .75rem .7rem; display: grid; gap: .1rem; align-content: start; min-width: 0;
}
.mp-book h4 {
  font-size: .66rem; font-weight: 650; text-transform: uppercase; letter-spacing: .07em;
  color: var(--muted); margin: 0 0 .3rem;
}
.mp-lrow {
  display: grid; grid-template-columns: 1.2rem 1fr auto; gap: .5rem; align-items: baseline;
  font-size: .82rem; padding: .1rem 0;
}
.mp-lrow .o { color: var(--muted); font-family: ui-monospace, Consolas, "Cascadia Mono", monospace; }
.mp-lrow .l { color: var(--muted); min-width: 0; overflow-wrap: anywhere; }
.mp-lrow .l b { color: var(--text); font-weight: 600; }
.mp-lrow .v {
  font-family: ui-monospace, Consolas, "Cascadia Mono", monospace; font-variant-numeric: tabular-nums;
  text-align: right; white-space: nowrap;
}
.mp-lrow.res { border-top: 1px solid var(--line); margin-top: .25rem; padding-top: .35rem; }
.mp-lrow.res .v, .mp-lrow.res .l b { color: var(--accent); font-weight: 650; }
.mp-lrow.off .v, .mp-lrow.off .l, .mp-lrow.off .l b { color: var(--muted); text-decoration: line-through; }
.mp-lrow .side {
  display: inline-block; font-size: .58rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  padding: 0 .35em; border-radius: 3px; background: var(--panel2); color: var(--muted); margin-left: .3rem;
  text-decoration: none; vertical-align: middle;
}
.mp-items { overflow-x: auto; }
.mp-itab { width: 100%; border-collapse: collapse; font-size: .8rem; }
.mp-itab th {
  font-size: .64rem; font-weight: 650; letter-spacing: .06em; text-transform: uppercase; color: var(--muted);
  text-align: right; padding: .3rem .5rem; border-bottom: 1px solid var(--line); white-space: nowrap;
}
.mp-itab th:first-child { text-align: left; }
.mp-itab td {
  padding: .3rem .5rem; border-bottom: 1px solid var(--line); text-align: right; white-space: nowrap;
  font-family: ui-monospace, Consolas, "Cascadia Mono", monospace; font-variant-numeric: tabular-nums;
}
.mp-itab td:first-child { text-align: left; font-family: inherit; color: var(--muted); white-space: normal; }
.mp-itab td:first-child b { color: var(--text); font-weight: 600; }
.mp-itab tr.res td { color: var(--accent); font-weight: 650; }
.mp-itab tr:last-child td { border-bottom: 0; }
.mp-itab td.dim { color: var(--muted); }
.mp-itab td .r {
  display: inline-block; font-size: .6rem; font-weight: 700; letter-spacing: .03em; padding: 0 .35em;
  border-radius: 3px; background: var(--warn-soft); color: var(--warn); margin-left: .3rem; font-family: inherit;
}
.mp-itab td .to { display: block; font-size: .62rem; color: var(--muted); font-family: inherit; font-weight: 400; white-space: normal; }
.mp-ifoot { margin: .4rem 0 0; font-size: .78rem; color: var(--muted); }
@media (max-width: 1100px) { .mp-results.has-pet { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 860px) {
  .mp-panel, .mp-results, .mp-results.has-pet { grid-template-columns: 1fr; }
}

/* --- Calculators hub (web/calculators.html, 2026-08-29) ---------------------
 * Layout P1 of the mockups: one card per calculator, the row holding as
 * many as fit the content width (auto-fit), each card a mark, a name,
 * a sentence, what you give / get, and an Open button. */
.calc-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); gap: .9rem; margin-bottom: 1.2rem; }
.calc-card { display: grid; gap: .6rem; align-content: start; }
.calc-head { display: flex; align-items: center; gap: .7rem; }
.calc-head h2 { margin: 0; font-size: 1.05rem; line-height: 1.25; }
.calc-head h2 a { color: var(--text); text-decoration: none; }
.calc-head h2 a:hover { color: var(--accent); text-decoration: underline; }
.calc-glyph {
  width: 2.6rem; height: 2.6rem; border-radius: .6rem; flex: none;
  background: var(--accent-soft); color: var(--accent);
  display: flex; align-items: center; justify-content: center;
}
.calc-glyph svg { width: 1.45rem; height: 1.45rem; }
.calc-desc { margin: 0; color: var(--muted); font-size: .92rem; }
.calc-io { margin: 0; font-size: .82rem; color: var(--muted); }
.calc-io b { color: var(--text); font-weight: 600; }
.calc-io .sep { margin: 0 .25rem; }
.calc-foot { display: flex; align-items: center; justify-content: space-between; gap: .6rem; margin-top: .2rem; }
.calc-pill {
  display: inline-block; font-size: .72rem; padding: .1rem .55rem; border-radius: 999px;
  border: 1px solid var(--line); color: var(--muted); white-space: nowrap;
}
.calc-pill.is-new { color: var(--accent); border-color: var(--accent); }
.calc-open { text-decoration: none; }

/* --- Minion Slots (web/minion-slots.html, 2026-08-29) -----------------------
 * The profit page's field cells and ledgers, plus: a tile row for the
 * slot readout, the target slider whose unreachable stretch is dimmed
 * (--reach, set by minionslots.js — owner Q19 A), and the three plain
 * tables (crafts, shopping list, not counted). */
.ms-inline { display: contents; }
.ms-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: .6rem; flex: 1; }
.ms-tile { border: 1px solid var(--line); border-radius: 8px; padding: .5rem .7rem; display: grid; gap: .1rem; }
.ms-tile-l { font-size: .68rem; font-weight: 650; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.ms-tile-v { font-size: 1.45rem; font-weight: 700; letter-spacing: -.01em; font-variant-numeric: tabular-nums; line-height: 1.15; }
.ms-tile-s { font-size: .8rem; color: var(--muted); }
/* Gold when maxed (owner 2026-08-29): the "maxed" colour the Stat
 * Breakdown chips use. */
.ms-tile.is-max { border-color: var(--warn); }
.ms-tile.is-max .ms-tile-l, .ms-tile.is-max .ms-tile-v { color: var(--warn); }
.ms-big { font-size: 1.02rem; font-weight: 650; font-variant-numeric: tabular-nums; }
.ms-rangecell { min-width: 24rem; }
.ms-shopcell { min-width: 20rem; }
.ms-shopcell .ms-range { min-width: 8rem; }
/* The Community Shop slider (owner 2026-08-29): always 0–5; the stretch
 * below the tiers already bought (--floor, set by minionslots.js) is
 * drawn dead, since the knob cannot go there; at 5/5 the whole control
 * turns gold and locks. */
.ms-shopcell .ms-range { --floor: 0%; }
.ms-shopcell .ms-range::-webkit-slider-runnable-track {
  background: linear-gradient(to right, var(--disabled) var(--floor), var(--accent) var(--floor));
}
.ms-shopcell .ms-range::-moz-range-track {
  background: linear-gradient(to right, var(--disabled) var(--floor), var(--accent) var(--floor));
}
.ms-range.is-max:disabled { opacity: 1; cursor: default; }
.ms-range.is-max::-webkit-slider-runnable-track { background: var(--warn); }
.ms-range.is-max::-moz-range-track { background: var(--warn); }
.ms-range.is-max::-webkit-slider-thumb { background: var(--warn); box-shadow: 0 0 0 1px var(--warn); }
.ms-range.is-max::-moz-range-thumb { background: var(--warn); box-shadow: 0 0 0 1px var(--warn); }
.ms-shopcell .ms-range.is-max + .ms-range-end, .ms-shopcell .ms-range.is-max ~ .ms-range-end { color: var(--warn); font-weight: 700; }
.wrap-minions .ms-rangecell .boost-factor { max-width: none; white-space: nowrap; }
.ms-rangebox { display: flex; align-items: center; gap: .5rem; width: 100%; }
.ms-range-end { font-size: .78rem; color: var(--muted); font-variant-numeric: tabular-nums; min-width: 1.4rem; text-align: center; }
.ms-range {
  --reach: 100%;
  flex: 1; min-width: 12rem; height: 1.4rem; margin: 0; cursor: pointer;
  -webkit-appearance: none; appearance: none; background: transparent;
}
.ms-range:disabled { cursor: default; opacity: .5; }
.ms-range::-webkit-slider-runnable-track {
  height: 4px; border-radius: 2px;
  background: linear-gradient(to right, var(--accent) var(--reach), var(--line) var(--reach));
}
.ms-range::-moz-range-track {
  height: 4px; border-radius: 2px;
  background: linear-gradient(to right, var(--accent) var(--reach), var(--line) var(--reach));
}
.ms-range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: 16px; height: 16px; margin-top: -6px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--panel); box-shadow: 0 0 0 1px var(--accent);
}
.ms-range::-moz-range-thumb {
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--panel); box-shadow: 0 0 0 1px var(--accent);
}
.ms-range:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 4px; }
.ms-check { display: inline-flex; align-items: center; gap: .4rem; color: var(--text); margin-right: .6rem; }
.ms-check input { accent-color: var(--accent); }
.ms-h2 { margin: 0 0 .6rem; font-size: 1.05rem; }
.ms-h2 small { font-weight: 400; margin-left: .4rem; }
.ms-cardhead { display: flex; align-items: center; justify-content: space-between; gap: .8rem; flex-wrap: wrap; margin-bottom: .6rem; }
.ms-cardhead .ms-h2 { margin: 0; }
.ms-table td { white-space: normal; }
.ms-table td.ms-craft { white-space: nowrap; font-weight: 600; }
.ms-table td.ms-trade { color: var(--muted); font-size: .84rem; white-space: nowrap; }
/* A1: the materials fold — icon chips under the row. */
.ms-chev {
  font: inherit; font-size: .8rem; width: 1.7rem; height: 1.5rem; padding: 0; cursor: pointer;
  background: var(--panel); color: var(--muted); border: 1px solid var(--line); border-radius: 6px;
}
.ms-chev:hover, .ms-chev[aria-expanded="true"] { color: var(--accent); border-color: var(--accent); }
.ms-chev:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.ms-table tr.ms-fold td { background: var(--bg); padding: .5rem .9rem .6rem 4.6rem; white-space: normal; }
.ms-chips { display: flex; flex-wrap: wrap; gap: .35rem; }
.ms-chip {
  display: inline-flex; align-items: center; gap: .3rem; padding: .15rem .55rem .15rem .3rem;
  border: 1px solid var(--line); border-radius: 999px; background: var(--panel); font-size: .8rem;
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.ms-chip b { font-weight: 650; }
.ms-chip.is-cur { border-color: var(--warn); color: var(--warn); background: var(--warn-soft); padding-left: .55rem; }
.ms-chip.is-coin { padding-left: .55rem; }
.ms-chip.is-note { color: var(--muted); padding-left: .55rem; border-style: dashed; }
.ms-chip-note { color: var(--muted); font-size: .74rem; margin-left: .15rem; }
.ms-ic { width: 20px; height: 20px; image-rendering: pixelated; flex: none; }
/* B4: the shopping list as a chip ledger. */
.ms-ledger { gap: .4rem; }
.ms-ledger .ms-chip { background: var(--bg); }
/* C3: Not Unlocked cards with the gap to close. */
.ms-ncards { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: .6rem; }
.ms-ncard { border: 1px solid var(--line); border-radius: 8px; padding: .55rem .75rem .65rem; background: var(--bg); display: grid; gap: .3rem; }
.ms-ncard.is-included { border-color: var(--accent); }
.ms-ncard.is-unpriced { opacity: .75; }
.ms-ncard-top { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.ms-ncard-why { color: var(--muted); font-size: .8rem; line-height: 1.35; }
.ms-mini { height: 5px; background: var(--line); border-radius: 3px; overflow: hidden; }
.ms-mini i { display: block; height: 100%; background: var(--accent); }
.ms-sw { position: relative; display: inline-block; width: 2rem; height: 1.15rem; flex: none; cursor: pointer; }
.ms-sw input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.ms-sw-knob { position: absolute; inset: 0; border-radius: 999px; background: var(--line); transition: background .12s; }
.ms-sw-knob::after { content: ""; position: absolute; top: .12rem; left: .12rem; width: .9rem; height: .9rem; border-radius: 50%; background: var(--panel); transition: left .12s; }
.ms-sw input:checked + .ms-sw-knob { background: var(--accent); }
.ms-sw input:checked + .ms-sw-knob::after { left: .98rem; }
.ms-sw input:focus-visible + .ms-sw-knob { outline: 2px solid var(--accent); outline-offset: 2px; }
.ms-tick { accent-color: var(--accent); }
.ms-panel { display: grid; grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr)); gap: .7rem; align-items: start; }
.ms-table tr.mp-detail td { white-space: normal; background: var(--bg); padding: .8rem .9rem .9rem 2.4rem; border-bottom: 2px solid var(--accent); }
@media (max-width: 720px) {
  .ms-rangecell { min-width: 0; width: 100%; }
}

/* ---- Inferno Minion Calculator (web/inferno-minion.html, 2026-08-29) ----
 * Layout A (owner): the Minion Profits controls, then a result card of
 * tiles and two ledgers (.mp-book / .mp-lrow reused), then the upgrade
 * card. Every ƒ opens a panel of ledgers in place. */
.wrap-inferno .cfg-select.im-wide { width: 17rem; }
.wrap-inferno .cfg-select.im-mid { width: 13rem; }
#im-tier, #im-up-from, #im-up-to { width: 6.5rem; }
#im-beacon, #im-flipper { width: 6.5rem; }
#im-hab-side { width: 8.5rem; }
.wrap-inferno .boost-input .mp-fbtn { margin-left: .35rem; }
.im-static { font-family: ui-monospace, Consolas, "Cascadia Mono", monospace; font-variant-numeric: tabular-nums; font-size: .9rem; }
.im-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr)); gap: .6rem; margin: .2rem 0 .9rem; }
.im-tile {
  display: grid; gap: .1rem; align-content: start; background: var(--bg); border: 1px solid var(--line);
  border-radius: 8px; padding: .55rem .75rem; min-width: 0;
}
.im-tl { font-size: .66rem; font-weight: 650; text-transform: uppercase; letter-spacing: .07em; color: var(--muted); }
.im-tv {
  font-family: ui-monospace, Consolas, "Cascadia Mono", monospace; font-variant-numeric: tabular-nums;
  font-size: 1.25rem; font-weight: 650; white-space: nowrap;
}
.im-tv.is-gold { color: var(--mc-gold); }
.im-tv.is-loss { color: var(--mc-red); }
/* The Chest tile's "fills after 11 h 56 min" is longer than the tile: the
 * warning state wraps instead of running out of the box (owner
 * screenshot, 2026-08-29). */
.im-tv.is-warn { color: var(--warn); font-size: .95rem; white-space: normal; line-height: 1.25; overflow-wrap: anywhere; }
.im-ts { font-size: .74rem; color: var(--muted); line-height: 1.3; }
.im-ts .mp-fbtn { vertical-align: middle; }
.im-panel { display: grid; grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr)); gap: .7rem; margin: .4rem 0 .9rem; }
.im-panel .mp-book.is-best { border-color: var(--accent); }
.im-ledgers { margin-bottom: .6rem; }
.im-ledgers .mp-lrow.im-fold .o { padding: 0; }
.im-tri {
  background: none; border: 0; padding: 0; margin: 0; color: var(--accent); cursor: pointer;
  font: inherit; font-size: .8rem; line-height: 1;
}
.im-tri:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-radius: 3px; }
.im-sub { display: grid; gap: .05rem; margin: 0 0 .25rem 1.7rem; padding-left: .5rem; border-left: 1px dashed var(--line); }
.im-sub .mp-lrow { font-size: .76rem; }
.im-sub .mp-lrow.res { margin-top: .1rem; padding-top: .2rem; }
.mp-lrow .side.is-forced { background: var(--warn-soft); color: var(--warn); }
.mp-lrow .side.is-thin { background: var(--warn-soft); color: var(--warn); cursor: help; }
.mp-lrow.is-loss .v { color: var(--mc-red); }
.im-foot { margin: .4rem 0 0; font-size: .78rem; color: var(--muted); }
.im-chips { display: flex; flex-wrap: wrap; gap: .4rem; margin: .5rem 0 .2rem; }
.im-chip {
  display: inline-flex; gap: .4rem; align-items: baseline; border: 1px solid var(--line); border-radius: 6px;
  padding: .2rem .55rem; font-size: .8rem; background: var(--bg);
}
.im-chip .num { font-family: ui-monospace, Consolas, "Cascadia Mono", monospace; font-variant-numeric: tabular-nums; color: var(--mc-gold); }
.im-chip.is-dim { color: var(--muted); }
.im-chip.is-setup { border-style: dashed; }
.im-tiles-up { margin-top: .6rem; }
.wrap-inferno #im-status[hidden] { display: none; }
@media (max-width: 760px) { .im-ledgers { grid-template-columns: 1fr; } }
/* The Molten Powder line ("cheapest of 338.0k | 293.2k | 318.7k") stays
 * on one row (owner screenshot, 2026-08-29): this cell's effect text is
 * exempt from the 15 rem effect-line cap. */
.wrap-inferno #im-e-up-molten { max-width: none; white-space: nowrap; }
/* The Molten Powder chip folds open to its material list (owner
 * 2026-08-29): a button in the chip's clothes. */
.im-chip.is-fold { cursor: pointer; font-family: inherit; font-size: .8rem; font-weight: inherit; line-height: inherit; color: inherit; margin: 0; }
.im-chip.is-fold:hover { border-color: var(--accent); }
.im-chip.is-fold:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.im-chip .tri { color: var(--accent); font-size: .75rem; margin-right: .1rem; }

/* --- Attribute Tracker (2026-08-30, docs/attributes-spec.md) ------------- */
/* Controls */
/* Control rows separated the way the other tool pages' cfg-rows are:
   a hairline divider and real padding, not a margin (owner redlines
   2026-08-30 — two margin bumps still read as "no space"). */
.at-ctl { display: flex; flex-wrap: wrap; gap: .8rem 1.2rem; align-items: center; padding: 1rem 0; border-top: 1px solid var(--line); }
.cfg-card .at-ctl:first-child { border-top: 0; padding-top: .55rem; }
/* A row that continues the group above: no divider (owner 2026-08-30). */
.at-ctl.at-ctl-cont { border-top: 0; padding-top: 0; }
/* The two dropdowns were clipping their labels ("Cost to m…"). */
#at-sort { min-width: 10.5rem; }
#at-family { min-width: 11.5rem; }
/* One filter per row (owner 2026-08-30, replacing the vertical rules):
   the leading labels line up as a column. "Category" is the widest. */
.at-ctl > .at-lab:first-child { flex: 0 0 5.2rem; }
.at-lab { font-size: .75rem; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
.at-note { font-size: .82rem; color: var(--muted); margin: 0; padding: .9rem 0 .3rem; border-top: 1px solid var(--line); }
.at-ctl .at-note { border-top: 0; padding: 0; }
.at-seg { display: inline-flex; border: 1px solid var(--line); border-radius: 6px; overflow: hidden; }
.at-seg button { border: 0; background: var(--panel); color: var(--text); padding: .3rem .7rem; font: inherit; font-size: .88rem; cursor: pointer; }
.at-seg button.is-on { background: var(--accent); color: #fff; font-weight: 600; }
.at-dirbtn { min-width: 2.2rem; }
.at-q { min-width: 11rem; }
.at-chips { display: inline-flex; flex-wrap: wrap; gap: .45rem; }
.at-chip { border: 1px solid var(--line); background: var(--panel); color: var(--text); border-radius: 999px; padding: .18rem .6rem; font: inherit; font-size: .84rem; cursor: pointer; }
.at-chip.is-on { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.at-chip.rar-common { color: var(--mc-white); border-color: var(--mc-white); }
.at-chip.rar-uncommon { color: var(--mc-green); border-color: var(--mc-green); }
.at-chip.rar-rare { color: var(--mc-blue); border-color: var(--mc-blue); }
.at-chip.rar-epic { color: var(--mc-purple); border-color: var(--mc-purple); }
.at-chip.rar-legendary { color: var(--mc-gold); border-color: var(--mc-gold); }
.at-chip[class*="rar-"]:not(.is-on) { opacity: .8; }
.at-chip.rar-common.is-on, .at-chip.rar-uncommon.is-on, .at-chip.rar-rare.is-on,
.at-chip.rar-epic.is-on, .at-chip.rar-legendary.is-on { background: var(--accent-soft); opacity: 1; }
/* Summary tiles */
.at-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr)); gap: .7rem; margin-top: .9rem; }
.at-tile-s { background: var(--bg); border: 1px solid var(--line); border-radius: 8px; padding: .55rem .7rem; display: grid; gap: .1rem; }
.at-tl { font-size: .72rem; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
.at-tv { font-size: 1.3rem; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1.2; }
.at-ts { font-size: .76rem; color: var(--muted); font-variant-numeric: tabular-nums; }
/* The grid of attribute tiles */
.at-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(215px, 1fr)); gap: .7rem; margin: .8rem 0 1.2rem; }
.at-tile { position: relative; text-align: left; font: inherit; color: var(--text); background: var(--panel); border: 1px solid var(--line); border-left: 4px solid var(--line); border-radius: 8px; padding: .55rem .65rem .55rem .75rem; display: grid; grid-template-columns: 38px 1fr; gap: .15rem .6rem; cursor: pointer; }
.at-tile:hover { border-color: var(--accent); border-left-width: 4px; }
.at-tile:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.at-tile.r-common { border-left-color: var(--mc-white); }
.at-tile.r-uncommon { border-left-color: var(--mc-green); }
.at-tile.r-rare { border-left-color: var(--mc-blue); }
.at-tile.r-epic { border-left-color: var(--mc-purple); }
.at-tile.r-legendary { border-left-color: var(--mc-gold); }
.at-tile.is-maxed { background: linear-gradient(90deg, var(--accent-soft), var(--panel) 60%); }
.at-tile.is-locked { opacity: .75; }
.at-tile img, .at-noicon { width: 36px; height: 36px; image-rendering: pixelated; grid-row: 1 / 4; align-self: start; margin-top: .1rem; }
.at-nm { font-weight: 700; line-height: 1.2; padding-right: 3rem; font-size: .92rem; }
.at-tile.r-common .at-nm { color: var(--mc-white); }
.at-tile.r-uncommon .at-nm { color: var(--mc-green); }
.at-tile.r-rare .at-nm { color: var(--mc-blue); }
.at-tile.r-epic .at-nm { color: var(--mc-purple); }
.at-tile.r-legendary .at-nm { color: var(--mc-gold); }
.at-lv { display: flex; align-items: center; gap: .45rem; font-size: .8rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.at-lv b { color: var(--text); min-width: 1.2em; }
.at-bar { flex: 1; height: 5px; background: var(--line); border-radius: 3px; overflow: hidden; }
.at-bar i { display: block; height: 100%; background: var(--accent); }
.at-tile.is-maxed .at-bar i { background: var(--mc-green); }
.at-cost { font-size: .8rem; color: var(--muted); font-variant-numeric: tabular-nums; display: flex; justify-content: space-between; gap: .5rem; }
.at-cost b { color: var(--text); font-weight: 600; }
.at-badge { position: absolute; top: .45rem; right: .5rem; font-size: .66rem; padding: .06rem .38rem; border-radius: 3px; border: 1px solid var(--line); color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
.at-badge.is-max { border-color: var(--mc-green); color: var(--mc-green); }
.at-badge.is-req { border-color: var(--warn); color: var(--warn); }
/* The hover card / tap dialog (Minecraft-lore styling on --mc tokens) */
.at-tip { position: fixed; z-index: 60; max-width: 420px; pointer-events: none; }
.at-card { background: var(--panel); border: 2px solid var(--line); border-radius: 6px; padding: .65rem .85rem; font-family: ui-monospace, "Cascadia Mono", Consolas, monospace; font-size: .78rem; line-height: 1.5; box-shadow: 0 8px 24px rgba(0, 0, 0, .35); }
/* Card border in the attribute's rarity colour (owner redline 2026-08-30). */
.at-card.r-common { border-color: var(--mc-white); }
.at-card.r-uncommon { border-color: var(--mc-green); }
.at-card.r-rare { border-color: var(--mc-blue); }
.at-card.r-epic { border-color: var(--mc-purple); }
.at-card.r-legendary { border-color: var(--mc-gold); }
.at-card hr { border: 0; border-top: 1px solid var(--line); margin: .4rem 0; }
.at-card-t { font-weight: 700; font-size: .92rem; }
.at-card .c-common { color: var(--mc-white); }
.at-card .c-uncommon { color: var(--mc-green); }
.at-card .c-rare { color: var(--mc-blue); }
.at-card .c-epic { color: var(--mc-purple); }
.at-card .c-legendary { color: var(--mc-gold); }
.at-card-eff { color: var(--mc-gray); }
.at-card-dim { color: var(--mc-dgray); }
.at-card-warn { color: var(--mc-red); }
.at-card-row { color: var(--mc-gray); }
.at-card-lab { color: var(--mc-dgray); }
.at-card-rar { font-weight: 800; letter-spacing: .05em; margin-top: .45rem; }
.at-dialog { border: 0; border-radius: 8px; padding: .8rem; background: var(--panel); color: var(--text); max-width: min(30rem, calc(100vw - 2rem)); }
.at-dialog::backdrop { background: rgba(0, 0, 0, .45); }
.at-dialog .at-card { box-shadow: none; }
.at-dialog .cfg-btn { margin-top: .6rem; }
@media (max-width: 34rem) {
  .at-grid { grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); }
  .at-nm { padding-right: 0; }
  .at-badge { position: static; justify-self: start; }
}

/* --- Cheapest upgrades (Stat Breakdown, 2026-08-31 plan) ----------------
   Q10: Option A below the source rows — two ranked lists per stat tab,
   badges beside the action text so the number columns stay aligned. */
.upg-list-head {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  margin: 10px 0 2px;
}
.upg-h-coin { color: var(--mc-gold); }
.upg-h-grind { color: var(--mc-green); }
.upg-row {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 4px 10px; padding: 6px 2px; border-top: 1px solid var(--line);
  font-size: 13px;
}
.upg-row:first-of-type { border-top: 0; }
.upg-rank {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: 11px; color: var(--muted); min-width: 14px;
}
.upg-act { flex: 1 1 220px; }
.upg-icon {
  width: 16px; height: 16px; vertical-align: -3px; margin-right: 6px;
  image-rendering: pixelated;
}
.upg-badge {
  display: inline-block; margin-left: 8px; padding: 2px 8px;
  border-radius: 999px; border: 1px solid var(--warn);
  background: var(--warn-soft); color: var(--warn);
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: 10.5px; letter-spacing: .03em; white-space: nowrap;
}
.upg-cost, .upg-gain, .upg-pp {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* A grind step's NOTE rides the .upg-pp slot but is prose, not a
   number: it wraps on its own full-width line so it can never run
   past the card (owner screenshot 2026-09-02). */
.upg-pp-note {
  white-space: normal; overflow-wrap: break-word;
  flex: 1 1 100%; min-width: 0;
}
.upg-cost { color: var(--mc-gold); }
.upg-gain { color: var(--mc-green); }
.upg-pp { font-size: 11px; color: var(--muted); }
.upg-more {
  background: none; border: 0; padding: 4px 2px; cursor: pointer;
  color: var(--accent); font: inherit; font-size: 12.5px;
}
.upg-more:hover { text-decoration: underline; }
.upg-note { margin-top: 6px; }

/* 2026-08-31 redlines: the upgrades card is its own container with an
   Include-not-counted toggle; situational steps carry a quiet tag. */
.upg-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--muted); font-size: 12.5px; cursor: pointer;
  user-select: none;
}
.upg-toggle input { accent-color: var(--accent); }
.upg-sit {
  display: inline-block; margin-left: 8px; padding: 2px 8px;
  border-radius: 999px; border: 1px solid var(--line);
  color: var(--muted);
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: 10.5px; letter-spacing: .03em; white-space: nowrap;
}
