/* Public /market explorer (P4, ahg-macqj). Dedicated stylesheet — same
   convention as dashboard.css/pull.css: a per-page-family CSS file linked
   via asset_path, not an inline <style> block (view-conventions ratchet).
   Vault Industrial palette per DESIGN.md; amber reserved for the primary
   series / key CTA, everything else defers. */

/* Full-bleed shell to match the dashboard app shell and /collect: the page
   spans the viewport (capped at 2000px, the same ceiling as the global
   `.container` and collect's `.qa-app`) so the logo, nav, and content align
   top-left instead of sitting indented inside a narrow 1100px column. The
   32px horizontal padding matches `.container`'s so the logo lands at the
   same left offset as every other signed-in page. */
.mkt-page {
  max-width: 2000px;
  margin: 0 auto;
  padding: 24px 32px 64px;
}

/* Zero the global 32px body padding (application.html.erb sets it) so it does
   NOT stack with `.mkt-page`'s own 32px -- that double gutter pushed the logo
   and content to 64px from the edge, far more inset than the dashboard and
   /collect. Collect does the same reset (`body.qa-collect { padding: 0 }`);
   now `.mkt-page` is the sole gutter, landing content at 32px like the app
   shell. */
body.mkt-body {
  padding: 0;
}

/* The app shell's global `.container` (application.html.erb) wraps every
   page in a padded, rounded, bordered card -- right for the dashboard's
   dense tool chrome, wrong for a public explorer that should read as a page
   on the body's own dark gradient, not a widget floating inside one more
   box. Scoped to `body.mkt-body` (set via content_for :body_class on every
   market/*.html.erb) so nothing outside this page family is affected. */
body.mkt-body .container {
  max-width: none;
  background: transparent;
  border: none;
  box-shadow: none;
  border-radius: 0;
  padding: 0;
  min-height: 0;
}

.mkt-subtitle {
  font-family: 'Cabinet Grotesk', sans-serif;
  font-size: 20px;
  font-weight: 600;
  color: var(--text-primary);
  margin: 24px 0 12px;
}

.mkt-empty {
  font-size: 14px;
  color: var(--text-muted);
  padding: 12px 0;
}
/* Preorder notice on an unreleased set page -- a light amber-tinted status
   note (amber is the sanctioned accent), explaining why every product shows
   "—" and the index hasn't started. */
.mkt-preorder {
  font-size: 14px;
  color: var(--text-secondary);
  padding: 12px 14px;
  margin: 4px 0 0;
  background: rgba(245, 158, 11, 0.08);
  border: 1px solid rgba(245, 158, 11, 0.28);
  border-radius: var(--radius-md);
}

.mkt-delta-pos { color: #4ade80; }
.mkt-delta-neg { color: #f87171; }
.mkt-delta-flat { color: var(--text-muted); }

/* Fixed-scope drilldown stat strip (/market/:game, /market/:game/:set --
   ahg-85hzm). Server-rendered (Market::SeriesSummary is computed at request
   time, not client-fetched -- no reason to wait on JS for numbers the
   controller already has). A plain label/value row, not a boxed card grid:
   DESIGN.md's "tables are the hero, no widgets competing with data" applies
   here too -- these are headline numbers, not a dashboard tile, so no
   .mkt-card-style box is reintroduced for them. */
.mkt-page .stats {
  display: flex;
  flex-wrap: wrap;
  gap: 28px;
  margin: 20px 0;
  padding: 16px 0;
  border-top: 1px solid var(--border-subtle);
  border-bottom: 1px solid var(--border-subtle);
}
.mkt-page .stat { min-width: 96px; }
.mkt-page .stat-label {
  font-size: 14px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 4px;
}
.mkt-page .stat-value {
  font-family: 'Geist Mono', monospace;
  font-size: 22px;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
/* ahg-2npqv: "N of M priced" coverage caption under a stat value. */
.mkt-page .stat-sub {
  font-size: 14px;
  color: var(--text-muted);
  margin-top: 2px;
}
/* ahg-e8axv: logged-in seller's "Your position" panel (async), reuses .stats. */
.mkt-page .mkt-your-position { margin-top: 20px; }
.mkt-page .mkt-your-position .mkt-subtitle { margin-bottom: 8px; }

.mkt-table-wrap {
  overflow-x: auto;
  overflow-y: hidden;
}

.mkt-table {
  width: 100%;
  min-width: 560px;
  border-collapse: collapse;
}

.mkt-table th {
  /* 14px horizontal matches td so every header sits directly over its column;
     numeric headers right-align to meet their right-aligned numeric cells
     (they were left-aligned, floating left of the numbers). */
  padding-left: 14px;
  padding-right: 14px;
  text-align: left;
  font-size: 14px;
}
.mkt-table th.mkt-num { text-align: right; }

.mkt-table td {
  padding: 11px 14px;
  font-size: 14px;
  border-top: 1px solid var(--border-subtle);
}

.mkt-table td.mkt-num {
  font-family: 'Geist Mono', monospace;
  text-align: right;
}

.mkt-table a {
  color: var(--text-primary);
  text-decoration: none;
  border-bottom: 1px dotted var(--text-muted);
}

/* Sets table search (ahg-85hzm follow-up): plain text input, filters
   already-rendered rows client-side via data-set-name -- no round trip. */
.mkt-sets-search { margin-bottom: 10px; }
.mkt-sets-search-input {
  width: 100%;
  max-width: 320px;
  min-height: 44px;
  padding: 0 14px;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text-primary);
  font: inherit;
  font-size: 16px; /* iOS zoom floor */
}
.mkt-sets-search-input::placeholder { color: var(--text-muted); }

/* Set icon + name, one cell -- the icon is decorative (alt="") since the
   link text already names the set. Placeholder is a plain hairline-bordered
   swatch, not a Magic-only guessed URL: set_icon_url is null for every
   game besides Magic/Pokemon today (ahg-85hzm), so a missing icon is the
   COMMON case, not an edge case. */
.mkt-set-cell { display: flex; align-items: center; gap: 8px; }
.mkt-set-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  object-fit: contain;
}
.mkt-set-icon--placeholder {
  /* A filled tile, NOT a bordered empty square -- the old border + empty
     interior read as an unchecked checkbox and invited clicks that did
     nothing. This is a decorative "no set logo" placeholder (aria-hidden),
     so it must not look like a control. */
  border-radius: var(--radius-sm);
  background: linear-gradient(135deg, var(--s2), var(--s3));
}

.mkt-buy-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 16px;
  border-radius: 6px;
  background: var(--accent-amber, #f59e0b);
  color: #0c0a09;
  font-weight: 600;
  font-size: 14px;
  text-decoration: none;
}

/* /market/:game/:set card roster (ahg-i62pa) -- the forward door into each
   card's own /cards/:product_id page. Mobile-first list rows; the whole row
   is the tap target (min 44px). */
.mkt-roster { margin: 24px 0 8px; }
.mkt-roster-hd {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}
.mkt-roster-title {
  font-size: 18px;
  font-weight: 600;
  color: var(--text-primary);
  margin: 0;
}
.mkt-roster-note { font-size: 13px; color: var(--text-muted); }
.mkt-roster-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--border-subtle);
}
.mkt-roster-item { border-bottom: 1px solid var(--border-subtle); }
.mkt-roster-link {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  padding: 8px 4px;
  text-decoration: none;
  color: inherit;
}
.mkt-roster-link:hover { background: var(--bg-secondary); }
.mkt-roster-thumb {
  width: 32px;
  height: 44px;
  object-fit: cover;
  border-radius: 4px;
  flex-shrink: 0;
  background: var(--bg-secondary);
}
.mkt-roster-thumb--empty { border: 1px solid var(--border-subtle); }
.mkt-roster-info { flex: 1; min-width: 0; }
.mkt-roster-name {
  display: block;
  font-size: 14px;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mkt-roster-meta { display: block; font-size: 12px; color: var(--text-muted); }
/* Price sits in a fixed-width, right-aligned mono column right before the name,
   so the number reads next to the card it belongs to (not stranded at the row's
   far edge) and every price still lines up its decimal down the column. */
.mkt-roster-price {
  font-family: 'Geist Mono', monospace;
  font-variant-numeric: tabular-nums;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  flex-shrink: 0;
  width: 84px;
  text-align: right;
}
@media (max-width: 480px) {
  .mkt-roster-price { width: 72px; }
}

/* /market/:game/:set "Compare to" picker (ahg-85hzm follow-up) -- same
   search/dropdown/pick-row shape as /market/compare's rail (.rail-search,
   .mkt-compare-search-input, .mkt-compare-results, .pick/.pick-row are
   already unscoped or reused below), just a smaller inline block instead
   of a full rail column. */
.mkt-compare-picker { margin: 20px 0 16px; max-width: 420px; }
.mkt-compare-label {
  display: block;
  font-size: 14px;
  color: var(--text-secondary);
  margin-bottom: 6px;
}
.mkt-compare-picker .rail-search { position: relative; margin-bottom: 8px; }
/* Same 3-column shape as .mkt-page.mkt-compare .pick-row (name + remove,
   no rank column -- this is "what you're comparing to", not a ranked
   leaderboard) without requiring the whole page to carry a .mkt-compare
   class it doesn't otherwise need. */
.mkt-compare-picker .pick { border-top: 0; }
.mkt-compare-picker .pick-row {
  grid-template-columns: 16px 1fr auto;
  cursor: default;
}
.mkt-compare-picker a.pick-name {
  align-self: stretch;
  display: flex;
  align-items: center;
  min-height: 44px;
  color: var(--text-primary);
  text-decoration: none;
  cursor: pointer;
}
.mkt-compare-picker a.pick-name:hover { text-decoration: underline; }
.mkt-compare-picker .pick-remove {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  color: var(--text-muted);
  text-decoration: none;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
}
.mkt-compare-picker .pick-remove:hover { color: var(--text-primary); }

@media (max-width: 768px) {
  .mkt-page { padding: 20px 16px 48px; }
}

@media (max-width: 480px) {
  .mkt-page .stats { gap: 16px 20px; }
}

/* ---- P2 split-brain overview (ahg-3f3pl): .bar / .seg / .pick / .panel /
   .chart / .legend / .note / .split, lifted from the approved variant-c
   wireframe (~/.gstack/projects/tryhoard-hoard/designs/market-leaderboard-
   20260804/_shared.css + variant-c-splitbrain.html). Token names translated
   to this app's existing :root custom properties (app/views/layouts/
   application.html.erb) instead of redefining duplicate tokens under the
   wireframe's names -- --surface-1/2/3 == --bg-secondary/--s2/--s3,
   --hairline == --border-subtle, --accent == --accent-amber, --success/
   error/info == --accent-green/rose/blue: every one an exact hex/rgba
   match, confirmed against DESIGN.md before porting. ahg-85hzm moved
   /market/:game and /market/:game/:set onto this same .bar/.panel/.chart
   family (they used to run the P4 .mkt-card/.mkt-chart-wrap/.mkt-stats/
   .mkt-grid look with a fixed-viewBox chart) -- only the .mkt-empty/
   .mkt-subtitle/.mkt-table/.mkt-buy-btn/.mkt-compare-form rules above are
   still theirs, none of it a chart. Scoped under .mkt-page so nothing here
   leaks past the /market page family (market.css only loads there, via
   head_extra). */

/* Minimal cross-page header (ahg-lhae1, market/_header partial): logo + a
   way back to the dashboard for signed-in users who land on /market from
   the app. Logged-out visitors see only the logo -- shared/_logo is already
   auth-aware and routes to '/' for them, so it doubles as their way home.
   Sits above .bar so it never competes with the page's own toolbar. */
.mkt-page .mkt-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px 16px;
  margin-bottom: 24px;
}
.mkt-page .mkt-topbar-left {
  display: flex;
  align-items: center;
  gap: 16px;
}
/* Both the logo anchor (rendered by shared/_logo, no class of its own) and
   the back link are direct children -- one rule gives both a real 44px tap
   target without reaching into the shared partial. */
.mkt-page .mkt-topbar-left > a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.mkt-page .mkt-topbar-back {
  font-size: 14px;
  color: var(--text-secondary);
  text-decoration: none;
  border-bottom: 1px dotted var(--text-muted);
}
.mkt-page .mkt-topbar-back:hover { color: var(--text-primary); }

/* Header game switcher (ahg-ftqi4 follow-up) -- native <details> disclosure. */
.mkt-page .mkt-gameswitch { position: relative; }
.mkt-page .mkt-gameswitch-summary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 12px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  color: var(--text-primary);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
  user-select: none;
  white-space: nowrap;
}
.mkt-page .mkt-gameswitch-summary::-webkit-details-marker { display: none; }
.mkt-page .mkt-gameswitch-summary:hover { border-color: var(--accent-amber); }
.mkt-page .mkt-gameswitch-summary:focus-visible { outline: 2px solid var(--accent-amber); outline-offset: 1px; }
.mkt-page .mkt-gameswitch-caret { flex-shrink: 0; color: var(--text-muted); transition: transform 120ms ease; }
.mkt-page .mkt-gameswitch[open] .mkt-gameswitch-caret { transform: rotate(180deg); }
.mkt-page .mkt-gameswitch-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 60;
  min-width: 220px;
  padding: 6px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
}
/* Type-to-filter field (ahg-frktq): pinned above the list, which owns the
   scroll so the field stays put while the games scroll under it. 16px font
   keeps iOS from zooming on focus. */
.mkt-page .mkt-gameswitch-search {
  width: 100%;
  box-sizing: border-box;
  margin-bottom: 6px;
  padding: 8px 10px;
  font-size: 16px;
  font-family: 'Geist', sans-serif;
  color: var(--text-primary);
  background: var(--bg-primary);
  border: 1px solid var(--border-subtle);
  border-radius: 6px;
}
.mkt-page .mkt-gameswitch-search:focus { outline: none; border-color: var(--accent-amber); }
.mkt-page .mkt-gameswitch-list { max-height: 52vh; overflow-y: auto; }
.mkt-page .mkt-gameswitch-empty { padding: 9px 10px; font-size: 13px; color: var(--text-muted); }
.mkt-page .mkt-gameswitch-item {
  display: block;
  padding: 9px 10px;
  border-radius: 6px;
  font-size: 14px;
  color: var(--text-primary);
  text-decoration: none;
  white-space: nowrap;
}
.mkt-page .mkt-gameswitch-item:hover { background: var(--bg-glass, rgba(255,255,255,0.04)); }
.mkt-page .mkt-gameswitch-item.is-current { color: var(--accent-amber); font-weight: 700; }

/* Right-hand cluster (Condition guide / Compare sets / theme toggle):
   pushed to the far edge by the parent's justify-content: space-between --
   one visual cluster ("utility nav") distinct from the "way back" links on
   the left, instead of 5 items packed into one row. */
.mkt-page .mkt-topbar-nav {
  display: flex;
  align-items: center;
  gap: 20px;
}
.mkt-page .mkt-topbar-link {
  font-size: 14px;
  font-weight: 600;
  color: var(--accent-amber);
  text-decoration: none;
}
.mkt-page .mkt-topbar-link:hover { color: #fbbf24; }
.mkt-page .mkt-topbar-nav .theme-toggle { flex-shrink: 0; }

@media (max-width: 768px) {
  .mkt-page .mkt-topbar { margin-bottom: 14px; row-gap: 10px; }
}

.mkt-page .bar {
  display: flex;
  align-items: center;
  gap: 14px 24px;
  flex-wrap: wrap;
  min-height: 44px;
  padding-bottom: 14px;
  margin-bottom: 20px;
  border-bottom: 1px solid var(--border);
}
/* Set shortcut bar (ahg-ftqi4) -- ports the /collect set command bar
   (collect/index.html.erb .qa-selected-set-bar + .qa-set-neighbors) into the
   market page family so set-hopping looks the same in both contexts. Neighbor
   set icons, the current set, a "Change set" search picker, and a card-name
   filter over the roster. Filled by market_explorer.js#initSetNav. */
.mkt-page .mkt-setnav {
  display: flex;
  align-items: center;
  gap: 12px 16px;
  flex-wrap: wrap;
  margin: 0 0 20px;
}
.mkt-page .mkt-setnav-strip {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1 1 auto;
  min-width: 0;
  position: relative;
}
.mkt-page .mkt-setnav-neighbors {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}
.mkt-page .mkt-setnav-neighbors:empty { display: none; }
.mkt-page .mkt-setnav-neighbor {
  height: 30px;
  width: 30px;
  border-radius: 6px;
  border: 1.5px solid var(--border-subtle);
  background: transparent;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2px;
  flex-shrink: 0;
  transition: border-color 100ms, transform 80ms;
}
.mkt-page .mkt-setnav-neighbor:hover { border-color: var(--accent-amber); transform: scale(1.1); }
.mkt-page .mkt-setnav-neighbor:focus-visible { outline: 2px solid var(--accent-amber); outline-offset: 1px; }
.mkt-page .mkt-setnav-neighbor img { width: 20px; height: 20px; object-fit: contain; }
.mkt-page .mkt-setnav-initials {
  font-family: 'Geist Mono', monospace;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text-secondary);
  line-height: 1;
}
[data-theme="dark"] .mkt-page .mkt-setnav-neighbor img:not(.mkt-setnav--card) { filter: invert(0.7); }
.mkt-page .mkt-setnav-logo { height: 30px; max-width: 160px; object-fit: contain; flex-shrink: 0; }
.mkt-page .mkt-setnav-icon { width: 30px; height: 30px; object-fit: contain; flex-shrink: 0; }
[data-theme="dark"] .mkt-page .mkt-setnav-icon { filter: invert(1); }
.mkt-page .mkt-setnav-icon--placeholder {
  border-radius: 6px;
  background: var(--surface-2, var(--bg-secondary));
  border: 1px solid var(--border-subtle);
  filter: none;
}
.mkt-page .mkt-setnav-name {
  font-family: 'Cabinet Grotesk', sans-serif;
  font-size: 16px;
  font-weight: 700;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.mkt-page .mkt-setnav-change {
  padding: 5px 12px;
  border: 1px solid var(--border-subtle);
  border-radius: 6px;
  background: transparent;
  color: var(--text-muted);
  font-size: 13px;
  font-family: 'Geist', sans-serif;
  cursor: pointer;
  flex-shrink: 0;
  min-height: 32px;
  transition: border-color 100ms, color 100ms;
}
.mkt-page .mkt-setnav-change:hover { border-color: var(--accent-amber); color: var(--text-primary); }
/* Change-set picker: an absolutely-positioned popover under the strip, same
   fetch-once/filter-client-side autocomplete as .mkt-compare-picker. */
.mkt-page .mkt-setnav-picker {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 40;
  width: min(340px, 90vw);
  background: var(--bg-secondary);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: 8px;
}
.mkt-page .mkt-setnav-picker-input {
  width: 100%;
  box-sizing: border-box;
  background: var(--bg-primary);
  border: 1px solid var(--border-subtle);
  border-radius: 6px;
  color: var(--text-primary);
  font-family: 'Geist', sans-serif;
  font-size: 14px;
  padding: 8px 10px;
  min-height: 40px;
}
.mkt-page .mkt-setnav-results {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
  max-height: 260px;
  overflow-y: auto;
}
.mkt-page .mkt-setnav-result {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  border: 0;
  color: var(--text-primary);
  font-family: 'Geist', sans-serif;
  font-size: 14px;
  padding: 9px 8px;
  border-radius: 6px;
  cursor: pointer;
}
.mkt-page .mkt-setnav-result:hover { background: var(--bg-glass, rgba(255,255,255,0.04)); color: var(--accent-amber); }
.mkt-page .mkt-setnav-noresults { color: var(--text-muted); font-size: 13px; padding: 9px 8px; }
.mkt-page .mkt-setnav-filter {
  flex: 0 1 300px;
  min-width: 180px;
  background: var(--bg-primary);
  border: 1px solid var(--border-subtle);
  border-radius: 6px;
  color: var(--text-primary);
  font-family: 'Geist', sans-serif;
  font-size: 16px;
  padding: 8px 12px;
  min-height: 40px;
}
.mkt-page .mkt-setnav-filter:focus { outline: none; border-color: var(--accent-amber); }
@media (max-width: 768px) {
  .mkt-page .mkt-setnav { gap: 10px; margin-bottom: 14px; }
  .mkt-page .mkt-setnav-filter { flex-basis: 100%; min-height: 44px; }
  /* Hard 44px touch targets on the interactive controls (mobile minimum). */
  .mkt-page .mkt-setnav-change { min-height: 44px; padding: 5px 14px; }
  .mkt-page .mkt-setnav-neighbor { height: 38px; width: 38px; }
  .mkt-page .mkt-setnav-picker-input { min-height: 44px; }
}
@media (max-width: 560px) {
  /* Neighbour icons are a desktop quick-hop nicety; on a phone six of them plus
     the set name and "Change set" overflow the row. Hide them and let "Change
     set" carry set switching (the picker lists every set in the game). */
  .mkt-page .mkt-setnav-neighbors { display: none; }
}

.mkt-page .bar-title {
  font-family: 'Cabinet Grotesk', sans-serif;
  font-weight: 700;
  font-size: 21px;
  line-height: 1.1;
  color: var(--text-primary);
  margin: 0;
  letter-spacing: -0.01em;
  /* No nowrap here (ahg-85hzm): overview/compare's short "Market" / "Market
     / Compare" titles never wrapped anyway, but the game/set drilldown
     breadcrumb ("Market / <game> / <set>") can run long -- a set name alone
     can exceed a 375px viewport, and nowrap would force horizontal overflow
     on the whole page instead of just wrapping the heading. */
  overflow-wrap: break-word;
}
/* Breadcrumb drill-up links ("Market / Pokemon / <set>" -- Market and
   Pokemon are real links, the final segment is the page you're on and
   stays plain). Without this they inherited .bar-title's bold heading
   color with no hover cue, so a clickable segment looked identical to the
   inert one. Same dotted-underline/muted-to-primary treatment as
   .mkt-topbar-back and .bar-link, so every "step up a level" affordance in
   this page family reads the same way. */
.mkt-page .bar-up {
  color: var(--text-secondary);
  text-decoration: none;
  border-bottom: 1px dotted var(--text-muted);
}
.mkt-page .bar-up:hover { color: var(--text-primary); border-bottom-color: var(--text-secondary); }
.mkt-page .bar-asof {
  order: 9;
  margin-left: auto;
  font-size: 14px;
  color: var(--text-muted);
  white-space: nowrap;
  font-family: 'Geist Mono', monospace;
}
.mkt-page .bar-break { display: none; }

/* Discoverability link from the overview to /market/compare (ahg-eqatd) --
   same minimal underline treatment as .mkt-breadcrumb a, but sized as a
   real 44px tap target for mobile (project rule: no sub-44px targets). */
.mkt-page .bar-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: 14px;
  color: var(--text-secondary);
  text-decoration: none;
  border-bottom: 1px dotted var(--text-muted);
}
.mkt-page .bar-link:hover { color: var(--text-primary); }

/* segmented controls -- shared by the toolbar's track switch (server-round-
   trip links) and the chart panel's range switch (buttons, static in P2). */
.mkt-page .seg {
  display: inline-flex;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 3px;
  gap: 2px;
}
.mkt-page .seg a,
.mkt-page .seg button {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--text-secondary);
  font: inherit;
  font-size: 14px;
  padding: 0 16px;
  min-height: 44px; /* DESIGN.md tap-target floor, not 38 */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-decoration: none;
  transition: background 100ms ease-in-out, color 100ms ease-in-out;
}
.mkt-page .seg a:hover,
.mkt-page .seg button:hover { background: var(--s2); }
.mkt-page .seg a[aria-pressed='true'],
.mkt-page .seg button[aria-pressed='true'] {
  background: var(--accent-amber);
  color: #1c1310;
  font-weight: 600;
}
/* Range control (30d/90d/1y): an amber-TINT active state -- a deliberate brand
   touch on the chart panel (DESIGN.md: segmented controls carry amber), kept
   quieter than the primary track control's full amber fill so amber stays
   rationed. Zero amber on the panel was the design-review deviation. */
.mkt-page .seg--quiet a[aria-pressed='true'],
.mkt-page .seg--quiet button[aria-pressed='true'] {
  background: var(--amber-tint, rgba(245, 158, 11, 0.14));
  color: var(--accent-amber);
  font-weight: 600;
}
.mkt-page .bar .seg { padding: 2px; }
.mkt-page .bar .seg a,
.mkt-page .bar .seg button { min-height: 40px; padding: 0 14px; }

/* master-detail split: leaderboard rail + chart panel */
.mkt-page .split {
  display: grid;
  grid-template-columns: 380px 1fr;
  gap: 24px;
  align-items: start;
  margin-bottom: 24px;
}

/* left rail: leaderboard doubles as the chart series picker (toggle wiring
   is Phase 3 -- P2 renders the correct static aria-pressed/swatch state). */
/* Frame the rail as a card matching the chart .panel, so the leaderboard and
   the chart read as one matched pair instead of two unrelated components
   (design review: rail had no container, just floating hairlines). */
.mkt-page .pick {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.mkt-page .pick-row {
  display: grid;
  /* minmax(0,1fr) on the name lets it shrink so the value/delta column always
     keeps its width -- a plain 1fr has a min-content floor that pushed a long
     "$398,995.34" past the framed rail's clipped edge on a narrow column. */
  grid-template-columns: 44px 22px minmax(0, 1fr) auto;
  align-items: center;
  column-gap: 10px;
  width: 100%;
  min-height: 52px;
  padding: 8px 10px;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--border-subtle);
  color: inherit;
  font: inherit;
  text-align: left;
  transition: background 100ms ease-in-out;
}
.mkt-page .pick-row:hover { background: var(--bg-secondary); }
.mkt-page .pick-row[aria-pressed='true'] { background: var(--s2); }
.mkt-page .pick-row--empty { color: var(--text-muted); }

/* Chart on/off toggle -- the checkbox-style control (the swatch reads as a
   checked/unchecked box). 44px hit target per DESIGN.md; the 12px swatch
   stays centered inside it. */
.mkt-page .pick-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  min-height: 44px;
  padding: 0;
  background: transparent;
  border: 0;
  cursor: pointer;
  color: inherit;
}
.mkt-page .pick-toggle:disabled { cursor: default; }
.mkt-page .pick-toggle:disabled .swatch { opacity: 0.5; }

/* Drill-in name link: goes to the game's set list (/market/:game). The
   trailing chevron is a persistent "opens a page" affordance (not hover-only)
   -- mirrors the icon-presence-signals-navigation rule in DESIGN.md. */
/* The name is the drill-in tap target -- stretch it to the full row height so
   the hit area clears the 44px minimum (the row is ~52px; a baseline inline
   <a> was only ~24px tall, failing the mobile tap-target rule). */
.mkt-page a.pick-name {
  display: flex;
  align-items: center;
  align-self: stretch;
  min-width: 0; /* allow the name column to shrink so the value never clips */
  min-height: 44px;
  text-decoration: none;
  cursor: pointer;
}
.mkt-page a.pick-name::after {
  content: "\203A"; /* › -- single right angle quote */
  margin-left: 5px;
  color: var(--text-muted);
  font-weight: 400;
}
.mkt-page a.pick-name:hover { text-decoration: underline; }
.mkt-page .pick-row--empty a.pick-name { color: var(--text-muted); }
/* Keyboard focus lands on the two real controls (toggle + drill-in name), not
   the row -- give each its own amber focus ring (was outline:none territory). */
.mkt-page .pick-toggle:focus-visible,
.mkt-page a.pick-name:focus-visible {
  outline: 2px solid var(--accent-amber);
  outline-offset: -2px;
  border-radius: var(--radius-sm);
}
.mkt-page .swatch {
  width: 12px;
  height: 12px;
  border-radius: 3px;
  border: 1.5px solid var(--text-muted);
  background: transparent;
}
/* Categorical series palette -- the dataviz reference order, validated for
   adjacent-pair CVD + normal-vision separation on BOTH --bg-secondary
   surfaces (#1c1917 dark / #f5f5f4 light) in both modes. Dark steps are the
   default (dark is the app default); [data-theme="light"] swaps in the light
   steps. Kept as custom properties so the chart lines (.mkt-s0..7 -> stroke
   currentColor), legend dots, crosshair dots, and rail swatches all resolve
   ONE source and theme-swap together. App chrome (range tabs, buttons) stays
   amber; only the data series wear these hues. The light-mode <3:1 contrast
   WARN on some steps is relieved by the always-present legend labels +
   crosshair tooltip -- identity is never color-alone. */
.mkt-page {
  --series-0: #3987e5; --series-1: #d95926; --series-2: #199e70; --series-3: #c98500;
  --series-4: #d55181; --series-5: #008300; --series-6: #9085e9; --series-7: #e66767;
}
[data-theme="light"] .mkt-page {
  --series-0: #2a78d6; --series-1: #eb6834; --series-2: #1baf7a; --series-3: #eda100;
  --series-4: #e87ba4; --series-5: #008300; --series-6: #4a3aa7; --series-7: #e34948;
}
.mkt-page .mkt-s0 { color: var(--series-0); }
.mkt-page .mkt-s1 { color: var(--series-1); }
.mkt-page .mkt-s2 { color: var(--series-2); }
.mkt-page .mkt-s3 { color: var(--series-3); }
.mkt-page .mkt-s4 { color: var(--series-4); }
.mkt-page .mkt-s5 { color: var(--series-5); }
.mkt-page .mkt-s6 { color: var(--series-6); }
.mkt-page .mkt-s7 { color: var(--series-7); }
.mkt-page .swatch--0 { background: var(--series-0); border-color: transparent; }
.mkt-page .swatch--1 { background: var(--series-1); border-color: transparent; }
.mkt-page .swatch--2 { background: var(--series-2); border-color: transparent; }
.mkt-page .swatch--3 { background: var(--series-3); border-color: transparent; }
.mkt-page .swatch--4 { background: var(--series-4); border-color: transparent; }
.mkt-page .swatch--5 { background: var(--series-5); border-color: transparent; }
.mkt-page .swatch--6 { background: var(--series-6); border-color: transparent; }
.mkt-page .swatch--7 { background: var(--series-7); border-color: transparent; }
.mkt-page .pick-rank,
.mkt-page .pick-val,
.mkt-page .pick-d30 {
  font-family: 'Geist Mono', monospace;
  font-variant-numeric: tabular-nums; /* DESIGN.md: numeric cells align */
}
.mkt-page .pick-rank { color: var(--text-muted); font-size: 14px; }
.mkt-page .pick-name { color: var(--text-primary); font-size: 15px; }
/* min-height reserves room for the 2-line case (value + 30d change) so an
   insufficient-data row's single "Not enough market data" line is
   vertically centered to match instead of coming out shorter than every
   row around it (ahg-nbi70). */
.mkt-page .pick-right {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 44px;
  text-align: right;
}
.mkt-page .pick-val,
.mkt-page .pick-d30 { display: block; font-size: 14px; }
.mkt-page .pick-empty { font-size: 14px; color: var(--text-muted); }
/* ahg-nbi70: reverted ahg-2npqv's "N% of products priced" from visible
   .pick-cov text back to hover-only (the row's title= attribute) -- an
   unexplained percentage only some rows had read as clutter, not a useful
   caveat, and was the root cause of the jagged rail this bead's min-height
   fix above addresses more directly. .pick-cov itself is gone; the game/set
   drill-down's "Tracked products... of M priced" caption (_tracked_products
   _stat.html.erb) is a separate, more contextual disclosure and is untouched. */

/* right: the chart is the point */
.mkt-page .panel {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 20px;
  position: relative; /* offset anchor for the absolutely-positioned .chart-tip */
}
.mkt-page .panel-hd { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
.mkt-page .panel-title { color: var(--text-primary); font-size: 17px; font-weight: 500; margin: 0; }
.mkt-page .panel-note { color: var(--text-muted); font-size: 14px; font-weight: 400; margin-left: 8px; }
.mkt-page .panel-sub { color: var(--text-muted); font-size: 14px; margin: 4px 0 0; }

/* Drilldown headline (/market/:game, /market/:game/:set): eyebrow + the ONE
   number that matters (index level) + its change pill, promoted into the
   card header -- amber is rationed to the active range tab below, never
   spent on the eyebrow label too. */
.mkt-page .panel-headline { min-width: 0; }
.mkt-page .panel-eyebrow {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.mkt-page .panel-value-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.mkt-page .panel-value {
  font-family: 'Geist Mono', monospace;
  font-size: 34px;
  font-weight: 700;
  line-height: 1;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.mkt-page .panel-pill {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border-radius: var(--radius-lg);
  border: 1px solid transparent;
  font-family: 'Geist Mono', monospace;
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.mkt-page .panel-pill.mkt-delta-pos { background: var(--green-tint); border-color: rgba(74, 222, 128, 0.28); color: var(--accent-green); }
.mkt-page .panel-pill.mkt-delta-neg { background: var(--rose-tint); border-color: rgba(248, 113, 113, 0.28); color: var(--accent-rose); }
.mkt-page .panel-pill.mkt-delta-flat { background: var(--s2); border-color: var(--border-subtle); color: var(--text-muted); }

/* Secondary metrics: one hairline-divided strip inside the card, never a
   wrapping grid of equal-weight boxes (no card chrome per item). */
.mkt-page .panel-stats {
  display: flex;
  flex-wrap: wrap;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--border-subtle);
}
.mkt-page .panel-stat {
  flex: 1 1 0;
  min-width: 110px;
  padding: 0 18px;
  border-left: 1px solid var(--border-subtle);
}
.mkt-page .panel-stat:first-child { padding-left: 0; border-left: 0; }
.mkt-page .panel-stat-label {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  margin-bottom: 4px;
}
.mkt-page .panel-stat-value {
  font-family: 'Geist Mono', monospace;
  font-size: 17px;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.mkt-page .panel-stat-sub { font-size: 12px; color: var(--text-muted); margin-top: 2px; }

/* Explanatory prose is a footnote, not a subtitle wedged between the title
   and the chart -- lives OUTSIDE the card, muted and small. */
.mkt-page .panel-footnote {
  margin: 12px 0 0;
  font-size: 13px;
  color: var(--text-muted);
  max-width: 78ch;
}
.mkt-page svg.chart { width: 100%; height: 300px; margin-top: 12px; display: block; }
.mkt-page svg.chart .grid-line { stroke: var(--border-subtle); stroke-width: 1; }
/* The 100 = flat index reference -- stronger than the faint gridlines so
   "above = rising, below = falling" reads without reading the axis. */
.mkt-page svg.chart .grid-baseline { stroke: var(--text-muted); stroke-width: 1; stroke-opacity: 0.55; }
/* 14px floor applies to axis labels too -- the uppercase-label exception in
   DESIGN.md covers letterspaced caps, not chart scales (GATE FIX). */
.mkt-page svg.chart .axis-lbl {
  fill: var(--text-muted);
  font-family: 'Geist Mono', monospace;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}
/* The 100 axis label rides the emphasized baseline -- lift it out of the faint
   muted tier so the break-even reference is legible. */
.mkt-page svg.chart .axis-lbl--base { fill: var(--text-secondary); }
.mkt-page .legend { display: flex; gap: 20px; flex-wrap: wrap; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border-subtle); }
.mkt-page .legend-item { display: flex; align-items: center; gap: 8px; font-size: 14px; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.mkt-page .legend-dot { width: 10px; height: 10px; border-radius: 2px; background: currentColor; }

/* Crosshair layer (market_explorer.js bindChartInteraction): a vertical rule
   + a focus dot per series, both hidden until the pointer enters the chart.
   The dot inherits its series color via .mkt-sN (color -> currentColor); a
   surface-colored ring lifts it off an overlapping line (dataviz marks-and-
   anatomy: 2px surface ring on overlapping marks). */
.mkt-page svg.chart .chart-cursor-line { stroke: var(--text-muted); stroke-width: 1; stroke-dasharray: 3 3; pointer-events: none; }
.mkt-page svg.chart .chart-cursor-dot { stroke: var(--bg-secondary); stroke-width: 2; pointer-events: none; }

/* Crosshair tooltip: absolutely positioned within .panel (position:relative),
   follows the nearest date column, lists every series present there. */
.mkt-page .chart-tip {
  position: absolute;
  z-index: 5;
  min-width: 132px;
  max-width: 240px;
  padding: 8px 10px;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.28);
  pointer-events: none;
  font-size: 14px; /* DESIGN.md 14px floor -- hierarchy via color, not size */
}
.mkt-page .chart-tip[hidden] { display: none; }
.mkt-page .chart-tip-date { color: var(--text-muted); margin-bottom: 6px; font-variant-numeric: tabular-nums; }
.mkt-page .chart-tip-row { display: flex; align-items: center; gap: 8px; line-height: 1.7; }
.mkt-page .chart-tip-dot { width: 9px; height: 9px; border-radius: 2px; flex: none; background: currentColor; }
.mkt-page .chart-tip-name { color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mkt-page .chart-tip-val { color: var(--text-primary); margin-left: auto; }

/* Visually-hidden but readable by screen readers -- same pattern as
   dashboard.css.erb's .sr-only (that stylesheet isn't loaded on /market). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Client empty-state (findings 4 & 6, ahg-iyofn): the `hidden` attribute
   already yields display:none via the UA stylesheet, but svg.chart's own
   `display: block` rule below has equal specificity on the element itself
   -- the attribute selector here wins deterministically instead of relying
   on source order. */
.mkt-page svg.chart[hidden] { display: none; }
.mkt-page .panel-empty { margin: 12px 0 0; }

/* Fetch-failure banner (finding 2): aria-pressed/URL already flipped
   optimistically on tap, so a failed request needs a visible, retryable
   contradiction-breaker rather than staying silent. */
/* Same specificity trap as svg.chart[hidden] above: this `display: flex`
   is author-origin and would otherwise beat the UA `[hidden]{display:none}`,
   leaving the banner permanently visible. Explicit override keeps it hidden
   until showFetchError() clears the attribute (QA finding, ahg-iyofn). */
.mkt-page .panel-error[hidden] { display: none; }
.mkt-page .panel-error {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 12px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--s2);
  border: 1px solid var(--border-subtle);
  font-size: 14px;
  color: var(--text-secondary);
}
.mkt-page .panel-error-retry {
  appearance: none;
  border: 1px solid var(--border-subtle);
  background: transparent;
  color: var(--text-primary);
  font: inherit;
  font-weight: 600;
  padding: 0 14px;
  min-height: 44px;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.mkt-page .panel-error-retry:hover { background: var(--s3); }

/* CARRIED FROM P2 REVIEW (ahg-pnypl notes): legend numbers render in
   <span class="num"> but nothing set the mono face -- they fell back to
   body Geist instead of Geist Mono, a typographic drift from the approved
   wireframe. */
.mkt-page .num { font-family: "Geist Mono", ui-monospace, monospace; font-variant-numeric: tabular-nums; }

/* P3 (ahg-pnypl): a toggle/range change refetches before redrawing -- the
   PRIOR chart line stays on screen (never blanks) while the request is in
   flight; this just dims it slightly so the update doesn't look inert. */
.mkt-page svg.chart { transition: opacity 150ms ease-in-out; }
.mkt-page .panel--loading svg.chart { opacity: 0.55; }

/* Cap-at-3 nudge: clicking a 4th rail row while 3 are already charted must
   never fire the request that 422s (API MAX_SCOPES=3) -- this is the "brief
   visual nudge" that tells the tap something happened without changing
   selection or state. */
@keyframes mkt-pick-nudge {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-4px); }
  75% { transform: translateX(4px); }
}
.mkt-page .pick-row--nudge { animation: mkt-pick-nudge 220ms ease-in-out; }
@media (prefers-reduced-motion: reduce) {
  .mkt-page .pick-row--nudge { animation: none; }
}

.mkt-page .note {
  margin-top: 24px;
  font-size: 14px;
  color: var(--text-muted);
  border-top: 1px solid var(--border-subtle);
  padding-top: 16px;
  max-width: 78ch;
}
.mkt-page .note b { color: var(--text-secondary); font-weight: 500; }

/* Minimal public-explorer footer (ahg-o9isl) -- attribution + copyright, no
   marketing columns. Mirrors the layout footer-bottom region; link treatment
   matches .mkt-topbar-back (dotted, muted, 44px tap target). */
.mkt-page .mkt-footer {
  margin-top: 40px;
  padding-top: 16px;
  border-top: 1px solid var(--border-subtle);
}
.mkt-page .mkt-footer-attrib {
  margin: 0 0 12px;
  font-size: 14px;
  color: var(--text-muted);
  max-width: 78ch;
}
.mkt-page .mkt-footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 20px;
  font-size: 14px;
  color: var(--text-muted);
}
.mkt-page .mkt-footer-links {
  display: flex;
  gap: 20px;
  margin-left: auto;
}
.mkt-page .mkt-footer-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: 14px;
  color: var(--text-secondary);
  text-decoration: none;
  border-bottom: 1px dotted var(--text-muted);
}
.mkt-page .mkt-footer-link:hover { color: var(--text-primary); }

@media (max-width: 768px) {
  .mkt-page .mkt-footer-links { margin-left: 0; }
}

@media (max-width: 960px) {
  .mkt-page .split { grid-template-columns: 1fr; }
  .mkt-page svg.chart { height: 240px; }
}

@media (max-width: 768px) {
  .mkt-page .bar { gap: 8px 10px; min-height: 0; padding-bottom: 10px; margin-bottom: 12px; }
  .mkt-page .bar-title { font-size: 19px; flex: 1 1 auto; width: auto; }
  .mkt-page .bar-asof { order: 0; margin-left: auto; }
  .mkt-page .bar-break { display: block; flex-basis: 100%; height: 0; margin: 0; }
  .mkt-page .bar .seg { flex: 1; }
  .mkt-page .bar .seg a,
  .mkt-page .bar .seg button { min-height: 44px; padding: 0 10px; flex: 1 1 0; min-width: 0; }

  /* Tapping a rail row must show its effect. With the chart below a
     nine-row list it lands off-screen and the tap reads as broken -- pin
     the chart to the top and let the rail scroll under it (ahg-q0r0r
     MOBILE, non-negotiable). No gap under the pinned panel: a transparent
     gap lets rows scroll through it and reads as a rendering glitch. */
  .mkt-page .split { display: flex; flex-direction: column; gap: 0; }
  .mkt-page .split > .panel { order: 1; position: sticky; top: 0; z-index: 2; }
  .mkt-page .split > div:not(.panel) { order: 2; }
  .mkt-page .panel {
    padding: 12px 14px;
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    border-top: 0;
    margin: 0 -16px; /* full-bleed against .mkt-page's 16px mobile padding */
    background: var(--bg-secondary);
  }
  .mkt-page .panel-title { font-size: 18px; }
  .mkt-page .panel-note,
  .mkt-page .panel-sub { display: none; }
  .mkt-page svg.chart { height: 170px; margin-top: 10px; }
  .mkt-page .legend { margin-top: 10px; padding-top: 10px; gap: 6px 16px; }
  .mkt-page .pick-row { min-height: 56px; }

  /* On the 170px phone chart a floating tooltip blankets the whole plot it
     annotates. Dock it below the chart as a compact wrapping strip instead
     (the JS-set absolute left/top are ignored under position:static). */
  .mkt-page .chart-tip {
    position: static;
    min-width: 0;
    max-width: none;
    margin: 10px 0 0;
    padding: 10px 0 0;
    background: transparent;
    border: 0;
    border-top: 1px solid var(--border-subtle);
    border-radius: 0;
    box-shadow: none;
  }
  .mkt-page .chart-tip-date { display: inline-block; margin: 0 12px 6px 0; }
  .mkt-page .chart-tip-row { display: inline-flex; width: auto; margin: 0 14px 6px 0; }
  .mkt-page .chart-tip-val { margin-left: 6px; }

  /* The range control belongs to the chart, not the page -- the base
     mobile rule above gives every .seg width:100%, which would make it
     claim its own row. Scope it back to content width. */
  .mkt-page .panel-hd { flex-wrap: nowrap; align-items: center; gap: 10px; }
  .mkt-page .panel-hd .panel-title { min-width: 0; }
  .mkt-page .panel-hd .seg { width: auto; flex: none; }
  .mkt-page .panel-hd .seg button { min-height: 44px; padding: 0 10px; flex: none; }

  /* Drilldown headline shrinks to fit next to the range tabs on one row. */
  .mkt-page .panel-headline { min-width: 0; }
  .mkt-page .panel-eyebrow { font-size: 11px; margin-bottom: 4px; }
  .mkt-page .panel-value { font-size: 24px; }
  .mkt-page .panel-pill { font-size: 12px; padding: 2px 8px; }
  .mkt-page .panel-stats { margin-top: 12px; padding-top: 10px; }
}

@media (max-width: 560px) {
  /* Below ~3 items per row a hairline-divided single strip wraps into a
     ragged half-row -- a clean 2-column grid (vertical divider down the
     middle, horizontal hairlines between rows) reads better than that. */
  .mkt-page .panel-stats { flex-wrap: wrap; }
  .mkt-page .panel-stat {
    flex: 1 1 50%;
    min-width: 0;
    border-left: 0;
    padding: 10px 0 0;
    margin-top: 10px;
    border-top: 1px solid var(--border-subtle);
  }
  .mkt-page .panel-stat:nth-child(-n+2) { margin-top: 0; padding-top: 0; border-top: 0; }
  .mkt-page .panel-stat:nth-child(odd) { padding-right: 12px; }
  .mkt-page .panel-stat:nth-child(even) { padding-left: 12px; border-left: 1px solid var(--border-subtle); }
}

/* ---- /market/compare (ahg-eqatd) -- reuses every .bar/.seg/.split/.pick/
   .pick-row/.swatch/.panel/svg.chart/.legend/.panel-empty/.panel-error rule
   above VERBATIM. Only new here: the game selector + search + results
   dropdown (the autocomplete), and dropping the leaderboard-only rank
   column from .pick-row. */

/* No .pick-rank on this surface -- the rail here is "what you picked", not a
   ranked leaderboard, so the column disappears rather than going blank. */
.mkt-page.mkt-compare .pick-row { grid-template-columns: 16px 1fr auto; cursor: default; }
/* The name is a drill-in link filling its cell so the whole set label is a
   44px tap target into the set's own page. */
.mkt-page.mkt-compare a.pick-name {
  align-self: stretch;
  display: flex;
  align-items: center;
  min-height: 44px;
  color: var(--text-primary);
  text-decoration: none;
  cursor: pointer;
}
.mkt-page.mkt-compare a.pick-name:hover { text-decoration: underline; }
/* Real <button>, not a decorative span -- reset its chrome and give it a
   44px square hit area for the remove action. */
.mkt-page.mkt-compare .pick-remove {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  background: transparent;
  border: 0;
  color: var(--text-muted);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
}
.mkt-page.mkt-compare .pick-remove:hover { color: var(--text-primary); }

.mkt-compare-toolbar { margin-bottom: 10px; }
.mkt-compare-game-select {
  width: 100%;
  min-height: 44px;
  padding: 0 12px;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text-primary);
  font: inherit;
  font-size: 16px; /* iOS zoom floor -- applies to selects too */
}

.mkt-compare .rail-search { position: relative; margin-bottom: 12px; }
.mkt-compare-search-input {
  width: 100%;
  min-height: 48px;
  padding: 0 14px;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text-primary);
  font: inherit;
  font-size: 16px; /* iOS zoom floor */
}
.mkt-compare-search-input::placeholder { color: var(--text-muted); }
.mkt-compare-search-input:focus-visible { outline: 2px solid var(--accent-amber); outline-offset: -1px; }

.mkt-compare-results {
  position: absolute;
  z-index: 4;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  margin: 0;
  padding: 4px;
  list-style: none;
  background: var(--s2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  max-height: 320px;
  overflow-y: auto;
}
.mkt-compare-result {
  display: block;
  width: 100%;
  min-height: 44px;
  padding: 0 12px;
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font: inherit;
  font-size: 15px;
  text-align: left;
  cursor: pointer;
}
.mkt-compare-result:hover { background: var(--s3); }
.mkt-compare-noresults {
  padding: 10px 12px;
  color: var(--text-muted);
  font-size: 14px;
}

@media (max-width: 768px) {
  .mkt-page.mkt-compare .pick-row { min-height: 52px; }
}

/* Hoard attribution line (ahg-99x5k, shared/_hoard_attribution partial) --
   small factual "priced and tracked with Hoard" strip on public /cards and
   /market pages. 14px meets the DESIGN.md text-size floor exactly; the
   dotted-underline / arrow-suffix split follows DESIGN.md's Links
   convention (internal action = dotted underline, external destination =
   trailing arrow, both text-primary, no separate color register). */
.hoard-attribution {
  font-size: 14px;
  color: var(--text-muted);
  line-height: 1.5;
  margin: 20px 0;
}
.hoard-attribution a {
  color: var(--text-primary);
  text-decoration: none;
  border-bottom: 1px dotted var(--text-muted);
}
.hoard-attribution a:hover { border-bottom-color: var(--text-secondary); }
.hoard-attribution a.hoard-attribution-external {
  border-bottom: none;
}
.hoard-attribution a.hoard-attribution-external::after {
  content: " \2197";
}

/* One-sentence factual summary on the market index/game/set pages -- the
   exact same string embedded in that page's JSON-LD `description`, so the
   visible copy and the structured data can never drift apart. */
.mkt-summary {
  font-size: 15px;
  color: var(--text-secondary);
  line-height: 1.5;
  margin: 8px 0 20px;
}
