/**
 * Trading Post (/market/) — FOUNDATION styles for the Browse (read-only)
 * view. Reuses public/web/site.css tokens (--gold, --ink, --panel, the
 * `.framed` nine-slice chrome, `.btn`/`.btn-secondary`) so the page already
 * reads as part of the HeroBrowser site. A designer + web-design-critic pass
 * does the visual polish later — this targets correctness, accessibility,
 * and token consistency, not final chrome.
 */

/* Defensive: an element toggled via the `hidden` DOM property must actually
 * disappear even when a later, equal-or-higher-specificity author rule sets
 * `display` on it (e.g. `.market-signin-needed{display:flex}`) — author
 * rules always beat the UA stylesheet's `[hidden]{display:none}` regardless
 * of specificity, so several `hidden`-toggled panels below silently stayed
 * visible until this was added. */
[hidden] {
  display: none !important;
}

/* Vault backdrop (atmosphere pass): a fixed, heavily dimmed treasure-room
 * interior behind the whole page so empty tabs still feel like standing in a
 * Trading Post. Kept at ~13% over --bg — dark enough that panel/body text
 * contrast is untouched; if the image is missing the layer is invisible. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  background: url('/web/art/market/vault-backdrop.png') center / cover no-repeat;
  opacity: 0.13;
  pointer-events: none;
}

.market-page {
  position: relative;
  max-width: 1120px;
  margin: 0 auto;
  padding: 40px 20px 80px;
}

/* Ambient depth layer (C1): a faint gold vignette behind the title/account
 * area so the page doesn't sit on flat --bg. Alpha stays low (~8-10%) and the
 * layer fades to nothing by the browse grid, so body text contrast is never
 * touched. */
.market-page::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 460px;
  z-index: -1;
  background: radial-gradient(ellipse 62% 60% at 50% 0%, rgba(244, 197, 66, 0.1) 0%, rgba(244, 197, 66, 0.04) 45%, transparent 75%);
  pointer-events: none;
}

.market-title {
  text-align: center;
  margin: 0 0 32px;
  /* Framed like every other surface on the page (design re-review: the page
   * should OPEN in the same chrome language, not a bare title block). */
  padding: 26px 22px 22px;
}

.market-title h1 {
  margin: 0 0 10px;
  color: var(--gold);
  font-size: clamp(1.8rem, 4vw, 2.6rem);
}

.market-sub {
  margin: 0 auto;
  max-width: 640px;
  color: var(--ink-dim);
}

/* Market-health ticker (fix 5) — a subtle framed strip under the sub-copy,
 * populated by market.ts once the Browse fetch resolves. Uses `hidden` (not
 * :empty) since market.ts explicitly toggles it for the empty/error case. */
.market-ticker {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  margin: 16px auto 0;
  padding: 6px 16px;
  border: 1px solid rgba(184, 146, 58, 0.3);
  border-radius: 999px;
  background: rgba(184, 146, 58, 0.08);
  color: var(--ink-dim);
  font-size: 0.82rem;
}

.market-ticker-segment {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.market-ticker-sep {
  opacity: 0.5;
}

/* Visually-hidden but screen-reader-visible heading (labels the browse
 * region without duplicating the visible page <h1>). */
.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;
}

/* No-JS fallback (mirrors landing.css's html:not(.js) guard): the market has
 * no server-rendered listings, so JS-off shows a note instead of an empty
 * shell, and the JS-driven regions stay out of the accessibility tree. */
.market-jsonly-note {
  display: none;
  text-align: center;
  color: var(--ink-dim);
  padding: 24px;
}

html:not(.js) .market-jsonly-note {
  display: block;
}

html:not(.js) #market-browse,
html:not(.js) #market-detail {
  display: none;
}

/* ── purchase return banner (Stripe Checkout success/cancel) ────────────── */

.purchase-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 20px;
  padding: 14px 18px;
  border-radius: 6px;
  border: 1px solid rgba(184, 146, 58, 0.35);
  background: rgba(184, 146, 58, 0.08);
  color: var(--ink);
}

.purchase-banner.is-success {
  border-color: var(--good);
  background: rgba(90, 200, 130, 0.1);
}

.purchase-banner.is-cancel {
  border-color: rgba(184, 146, 58, 0.35);
  background: rgba(0, 0, 0, 0.2);
  color: var(--ink-dim);
}

.purchase-banner-text {
  flex: 1 1 auto;
}

.purchase-banner-close {
  flex: 0 0 auto;
  background: none;
  border: none;
  color: inherit;
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
  padding: 2px 6px;
  opacity: 0.7;
}

.purchase-banner-close:hover {
  opacity: 1;
}

/* ── account bar ──────────────────────────────────────────────────────── */

.market-account {
  padding: 18px 20px;
  margin-bottom: 20px;
}

.account-signed-out {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
}

.account-hint {
  margin: 0;
  color: var(--ink-dim);
}

.account-signed-in {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}

.account-name {
  color: var(--gold);
  font-weight: 700;
}

.account-balance {
  display: inline-flex;
  align-items: center;
}

.account-signin-panel {
  margin-top: 16px;
  max-width: 360px;
}

.auth-mode-toggle {
  display: flex;
  gap: 8px;
  margin-bottom: 14px;
}

.auth-mode-btn {
  flex: 1 1 0;
  padding: 8px 10px;
  border: 1px solid rgba(184, 146, 58, 0.35);
  background: transparent;
  color: var(--ink-dim);
  font: inherit;
  font-size: 0.85rem;
  cursor: pointer;
  border-radius: 4px;
}

.auth-mode-btn.is-active {
  color: var(--gold);
  border-color: var(--gold);
  background: rgba(184, 146, 58, 0.1);
}

.auth-field {
  display: block;
  margin-bottom: 12px;
  font-size: 0.85rem;
  color: var(--ink-dim);
}

.auth-field span {
  display: block;
  margin-bottom: 4px;
}

.auth-field em {
  font-style: normal;
  /* --ink-dim (not --ink-faint) clears WCAG AA on this dark well — see the
   * identical fix on .site-footer in site.css. */
  color: var(--ink-dim);
}

.auth-field input,
.auth-field select {
  width: 100%;
  box-sizing: border-box;
  padding: 8px 10px;
  border: 1px solid rgba(184, 146, 58, 0.35);
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.25);
  color: var(--ink);
  font: inherit;
}

.auth-status {
  margin: 10px 0 0;
  font-size: 0.85rem;
  color: var(--ink-dim);
}

.auth-status:empty {
  display: none;
}

.auth-google {
  margin-top: 16px;
}

.auth-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 12px;
  color: var(--ink-faint);
  font-size: 0.8rem;
}

.auth-divider::before,
.auth-divider::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: rgba(184, 146, 58, 0.25);
}

/* ── tabs ─────────────────────────────────────────────────────────────── */

.market-tabs {
  display: flex;
  gap: 8px;
  margin-bottom: 20px;
  border-bottom: 1px solid rgba(184, 146, 58, 0.25);
}

.market-tab {
  padding: 10px 16px;
  border: none;
  background: transparent;
  color: var(--ink-dim);
  font: inherit;
  font-size: 0.95rem;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  /* Single-line labels: the container horizontally scrolls (with a fade cue)
   * on mobile — wrapping to two lines defeats that strip. */
  white-space: nowrap;
  flex-shrink: 0;
}

.market-tab:hover {
  color: var(--ink);
}

.market-tab.is-active {
  color: var(--gold);
  border-bottom-color: var(--gold);
}

/* Active-tab flourish (C3): same gold filigree diamond the site nav's
 * a.active uses (site.css .site-nav .nav-links a.active), so the tabs read
 * as the same chrome language as the header. */
.market-tab.is-active::before,
.market-tab.is-active::after {
  content: '\2726'; /* ✦ */
  color: var(--filigree);
  font-size: 0.62em;
  vertical-align: middle;
  opacity: 0.85;
}

.market-tab.is-active::before {
  margin-right: 8px;
}

.market-tab.is-active::after {
  margin-left: 8px;
}

/* ── Browse hero strip (atmosphere pass): key art atop the default view so
 * the first thing a visitor sees isn't bare text. Its own art (merchant
 * counter, higgsfield 2026-07-16) — deliberately NOT the gacha banner, so the
 * two tabs don't repeat one image. The 62% crop centers the wares band; a
 * bottom scrim fades the strip into the page. ───────────────────────────── */

.market-browse-hero {
  height: 210px;
  margin-bottom: 18px;
  border-radius: 4px;
  image-rendering: pixelated;
  background:
    linear-gradient(to bottom, rgba(8, 8, 12, 0.15) 0%, rgba(8, 8, 12, 0) 30%, rgba(8, 8, 12, 0.55) 78%, rgba(8, 8, 12, 0.92) 100%),
    url('/web/art/market/browse-hero.png') center 62% / cover no-repeat,
    linear-gradient(to bottom, var(--metal-light), var(--metal));
  box-shadow: 0 0 22px rgba(0, 0, 0, 0.5), inset 0 0 0 1px rgba(244, 197, 66, 0.14);
}

@media (max-width: 600px) {
  .market-browse-hero {
    height: 130px;
  }
}

/* ── sign-in CTA rows (all signed-out tabs) ──────────────────────────────── */

.market-signin-needed {
  color: var(--ink-dim);
  padding: 24px 0;
}

/* One primary sign-in CTA lives in the account bar; each tab's signed-out
 * line uses this link-styled button instead of repeating a full button. */
.signin-inline-link {
  padding: 0;
  border: none;
  background: transparent;
  color: var(--gold);
  font: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.signin-inline-link:hover {
  color: var(--ink);
}

/* ── Sell tab ─────────────────────────────────────────────────────────── */

.market-sell-body {
  max-width: 640px;
}

#sell-form {
  padding: 20px;
}

.sell-band {
  margin: -6px 0 14px;
  font-size: 0.8rem;
  /* --ink-dim (not --ink-faint) clears WCAG AA — see .auth-field em above. */
  color: var(--ink-dim);
}

/* ── Sell tab: visual item picker (replaces the old text-only <select> —
 * players recognize gear by icon, not name) ─────────────────────────────── */

.sell-picker-field {
  margin-bottom: 16px;
}

.sell-picker {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 10px;
}

.sell-picker-empty {
  /* Span the full grid (fix 2) — without this the empty-state message gets
   * crushed into the picker's first ~110px auto-fill column. */
  grid-column: 1 / -1;
  margin: 0;
  padding: 16px 4px;
  color: var(--ink-dim);
  font-size: 0.85rem;
}

.sell-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 10px 8px 8px;
  text-align: center;
  font: inherit;
  color: var(--ink);
  cursor: pointer;
  appearance: none;
  transition: filter 0.15s ease, transform 0.15s ease, outline-color 0.15s ease;
}

.sell-tile:hover {
  filter: brightness(1.08);
  transform: translateY(-2px);
}

.sell-tile:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

/* Selected state (S3): gold border/highlight, mirrors keyboard focus so the
 * two read as the same kind of "this one" affordance. */
.sell-tile.is-selected {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
  filter: brightness(1.12);
}

.sell-tile-icon {
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
}

.sell-tile-name {
  font-size: 0.78rem;
  line-height: 1.2;
  /* Long item names wrap onto a second line rather than overflowing the tile. */
  overflow-wrap: break-word;
}

.sell-tile-count {
  font-size: 0.72rem;
  color: var(--ink-dim);
}

.sell-tile.is-selected .sell-tile-count {
  color: var(--gold);
}

/* ── Sell tab: quantity stepper (N listings created in one submit — the
 * order book itself stays qty-1 server-side, this is purely a client-side
 * "create N listings" convenience) ───────────────────────────────────────── */

.sell-qty-field {
  margin-bottom: 4px;
}

.sell-qty-stepper {
  display: flex;
  align-items: center;
  gap: 8px;
}

.sell-qty-btn {
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(184, 146, 58, 0.35);
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.25);
  color: var(--ink);
  font: inherit;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  appearance: none;
}

.sell-qty-btn:hover:not(:disabled) {
  filter: brightness(1.15);
}

.sell-qty-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

#sell-qty {
  width: 64px;
  flex-shrink: 0;
  text-align: center;
  box-sizing: border-box;
  padding: 8px 6px;
  border: 1px solid rgba(184, 146, 58, 0.35);
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.25);
  color: var(--ink);
  font: inherit;
}

#sell-qty:disabled,
.sell-qty-btn:disabled {
  background: rgba(0, 0, 0, 0.15);
}

.sell-qty-hint {
  margin: 6px 0 0;
  font-size: 0.8rem;
  color: var(--ink-dim);
}

.sell-qty-hint:empty {
  display: none;
}

/* ── Sell tab: live total preview ─────────────────────────────────────── */

.sell-total {
  display: flex;
  align-items: center;
  gap: 4px;
  margin: -6px 0 14px;
  font-size: 0.85rem;
  color: var(--ink-dim);
}

.sell-total:empty {
  display: none;
}

.sell-total .diamond-icon {
  vertical-align: -2px;
}

/* ── My Listings tab ──────────────────────────────────────────────────── */

.mine-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.mine-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 4px;
  border-bottom: 1px solid rgba(184, 146, 58, 0.16);
  flex-wrap: wrap;
}

.mine-row:last-child {
  border-bottom: none;
}

.mine-name {
  flex: 1 1 160px;
  color: var(--ink);
}

.mine-price {
  color: var(--gold);
  font-weight: 700;
}

.mine-status-badge {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-faint);
  padding: 2px 8px;
  border: 1px solid rgba(184, 146, 58, 0.3);
  border-radius: 999px;
}

.mine-row.is-sold .mine-status-badge {
  color: var(--good);
  border-color: var(--good);
}

.mine-row.is-cancelled .mine-status-badge,
.mine-row.is-expired .mine-status-badge {
  color: var(--ink-faint);
}

/* Anti-snipe publicize delay: active but not yet in Browse. Amber to read as
   "in progress, not failed". */
.mine-row.is-pending .mine-status-badge {
  color: var(--gold);
  border-color: var(--gold);
}

.mine-expiry {
  font-size: 0.8rem;
  color: var(--ink-dim);
  flex: 1 1 auto;
}

.mine-cancel-btn {
  padding: 6px 14px;
  font-size: 0.85rem;
}

/* ── Buy Diamonds tab ─────────────────────────────────────────────────── */

.market-buy-body {
  max-width: 960px;
}

.buy-launching-note {
  margin: 0 0 20px;
  padding: 12px 16px;
  color: var(--gold);
  font-size: 0.9rem;
  text-align: center;
}

.buy-pack-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 16px;
}

.buy-pack-card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 22px 16px 18px;
  text-align: center;
}

/* Per-tier treasure illustration (pouch -> vault escalation). 100px = a clean
 * 4x downscale of the 400px sources (120px was a blurry non-integer 3.33x). */
.buy-pack-art {
  width: 100px;
  height: 100px;
  border-radius: 6px;
  image-rendering: pixelated;
  box-shadow: 0 0 14px rgba(0, 0, 0, 0.45);
}

.buy-pack-card.is-best-value {
  outline: 1px solid var(--gold);
  box-shadow: 0 0 12px rgba(244, 197, 66, 0.25);
}

.buy-pack-best {
  position: absolute;
  top: -10px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--gold);
  color: #1a1005;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 3px 10px;
  border-radius: 999px;
  white-space: nowrap;
}

.buy-pack-amount {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 1.3rem;
  font-weight: 700;
  color: var(--ink);
}

.buy-pack-amount .diamond-icon {
  width: 22px;
  height: 22px;
}

.buy-pack-bonus {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--good);
  border: 1px solid var(--good);
  border-radius: 999px;
  padding: 2px 10px;
}

.buy-pack-price {
  margin: 4px 0 6px;
  font-size: 1.05rem;
  color: var(--ink-dim);
}

.buy-pack-btn {
  width: 100%;
}

.buy-pack-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

@media (max-width: 600px) {
  .buy-pack-grid {
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 12px;
  }
}

/* ── Mailbox tab ──────────────────────────────────────────────────────── */

/* "You have mail" count badge next to the tab label. */
.mailbox-badge {
  display: inline-block;
  min-width: 16px;
  margin-left: 6px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--gold);
  color: #1a1005;
  font-size: 0.7rem;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  vertical-align: middle;
}

.market-mailbox-body {
  max-width: 560px;
}

.mailbox-hint {
  margin: 0 0 16px;
  color: var(--ink-dim);
  font-size: 0.85rem;
}

.mailbox-list {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
}

.mailbox-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 4px;
  border-bottom: 1px solid rgba(184, 146, 58, 0.16);
}

.mailbox-row:last-child {
  border-bottom: none;
}

.mailbox-row .mailbox-icon {
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
}

.mailbox-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.mailbox-name {
  color: var(--ink);
  font-weight: 700;
}

.mailbox-reason {
  font-size: 0.8rem;
  /* --ink-dim (not --ink-faint) clears WCAG AA — see .auth-field em above. */
  color: var(--ink-dim);
}

.mailbox-claim-btn {
  width: 100%;
  max-width: 260px;
}

/* ── toolbar ──────────────────────────────────────────────────────────── */

.market-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 20px;
}

.market-status {
  margin: 0;
  color: var(--ink-dim);
}

.market-status:empty {
  display: none;
}

/* ── browse filters (B4) — compact pill chips, echoes .market-ticker's pill
 * look and .auth-mode-btn's active-state treatment; rarity chips tint via
 * the SAME --rarity-* tokens as .market-card/.gacha-odds-table so a filter
 * chip and the cards it filters read as the same color language. ────────── */

.market-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 16px;
  margin-bottom: 16px;
}

.filter-group {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.filter-group-rarity.is-disabled {
  opacity: 0.45;
}

.filter-chip {
  padding: 5px 13px;
  border: 1px solid rgba(184, 146, 58, 0.3);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.2);
  color: var(--ink-dim);
  font: inherit;
  font-size: 0.78rem;
  line-height: 1.3;
  cursor: pointer;
  transition: filter 0.15s ease, background-color 0.15s ease;
}

.filter-chip:hover:not(:disabled) {
  filter: brightness(1.15);
}

.filter-chip:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

.filter-chip:disabled {
  cursor: not-allowed;
}

.filter-chip.is-active {
  color: var(--gold);
  border-color: var(--gold);
  background: rgba(184, 146, 58, 0.14);
  font-weight: 700;
}

/* Rarity chips: border/text tinted to the rarity at rest (so the ladder is
 * scannable even before selecting anything), a colored glow when active —
 * same rgba glow values already used for these rarities elsewhere on this
 * page (.market-detail-rarity / .gacha-directbuy-card). */
.filter-chip-rarity[data-rarity='common'] {
  color: var(--rarity-common);
  border-color: var(--rarity-common);
}
.filter-chip-rarity[data-rarity='uncommon'] {
  color: var(--rarity-uncommon);
  border-color: var(--rarity-uncommon);
}
.filter-chip-rarity[data-rarity='rare'] {
  color: var(--rarity-rare);
  border-color: var(--rarity-rare);
}
.filter-chip-rarity[data-rarity='epic'] {
  color: var(--rarity-epic);
  border-color: var(--rarity-epic);
}
.filter-chip-rarity[data-rarity='legendary'] {
  color: var(--rarity-legendary);
  border-color: var(--rarity-legendary);
}
.filter-chip-rarity[data-rarity='mythic'] {
  /* Text uses the AA-safe tint (fix 1); border stays the saturated token. */
  color: var(--rarity-mythic-text);
  border-color: var(--rarity-mythic);
}
.filter-chip-rarity[data-rarity='cursed'] {
  color: var(--rarity-cursed-text);
  border-color: var(--rarity-cursed);
}
.filter-chip-rarity[data-rarity='divine'] {
  color: var(--rarity-divine);
  border-color: var(--rarity-divine);
}

.filter-chip-rarity.is-active {
  font-weight: 700;
}
.filter-chip-rarity.is-active[data-rarity='common'] {
  background: rgba(184, 192, 200, 0.18);
}
.filter-chip-rarity.is-active[data-rarity='uncommon'] {
  background: rgba(91, 214, 107, 0.18);
}
.filter-chip-rarity.is-active[data-rarity='rare'] {
  background: rgba(74, 163, 255, 0.18);
}
.filter-chip-rarity.is-active[data-rarity='epic'] {
  background: rgba(192, 97, 255, 0.18);
}
.filter-chip-rarity.is-active[data-rarity='legendary'] {
  background: rgba(255, 176, 32, 0.18);
  box-shadow: 0 0 8px rgba(255, 176, 32, 0.3);
}
.filter-chip-rarity.is-active[data-rarity='mythic'] {
  background: rgba(255, 45, 85, 0.18);
  box-shadow: 0 0 8px rgba(255, 45, 85, 0.35);
}
.filter-chip-rarity.is-active[data-rarity='cursed'] {
  background: rgba(214, 23, 74, 0.18);
  box-shadow: 0 0 8px rgba(214, 23, 74, 0.35);
}
.filter-chip-rarity.is-active[data-rarity='divine'] {
  background: rgba(255, 244, 214, 0.18);
  box-shadow: 0 0 10px rgba(255, 244, 214, 0.4);
}

.filter-search-field {
  display: inline-flex;
  margin-left: auto;
}

.filter-search-field input {
  width: 200px;
  max-width: 100%;
  box-sizing: border-box;
  padding: 6px 12px;
  border: 1px solid rgba(184, 146, 58, 0.3);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.25);
  color: var(--ink);
  font: inherit;
  font-size: 0.85rem;
}

.filter-search-field input:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

.filter-search-field input::placeholder {
  color: var(--ink-faint);
}

/* Filters-caused empty state — distinct from "the market has zero listings"
 * (that stays plain .market-status text, unchanged). Framed like every other
 * inline notice on this page (.buy-launching-note, .gacha-locked-notice). */
.market-empty {
  margin: 0 0 20px;
  padding: 14px 18px;
  text-align: center;
  color: var(--ink-dim);
}

.market-empty-clear {
  background: none;
  border: none;
  padding: 0;
  margin-left: 2px;
  color: var(--accent);
  font: inherit;
  font-size: inherit;
  text-decoration: underline;
  cursor: pointer;
}

.market-empty-clear:hover {
  color: var(--gold);
}

/* ── browse grid ──────────────────────────────────────────────────────── */

.market-group-heading {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 28px 0 12px;
  color: var(--gold);
  font-size: 1.1rem;
}

.market-group-heading:first-child {
  margin-top: 0;
}

/* Trailing filigree line (C4) so the heading reads as chrome, not bare text
 * floating over the grid — matches the .auth-divider line treatment above. */
.market-group-heading::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: linear-gradient(to right, rgba(184, 146, 58, 0.55), transparent);
}

.market-grid-group {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 16px;
}

.market-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  padding: 16px;
  text-align: left;
  font: inherit;
  color: var(--ink);
  cursor: pointer;
  appearance: none;
  transition: filter 0.15s ease, transform 0.15s ease;
}

/* Rarity tint (B2): a colored edge so gear cards read at a glance, same
 * tokens as the game's rarity system (src/ui/theme.ts rarityColorNum ->
 * --rarity-* here). Material lots use the neutral common tone (see B2 note
 * in market.ts).
 *
 * NOTE: a literal `border-left` doesn't render here — `.market-card` carries
 * `.framed`, whose `border-image` (the nine-slice ui_frame.png) paints over
 * all four edges and masks any `border-*-color` underneath (verified: with a
 * plain `border-left` the rule was present in the DOM but invisible on
 * screen). A small inset bar on its own layer achieves the same "colored
 * edge" read without fighting the frame art. */
/* `.sell-tile` (Sell tab's visual item picker) shares this rarity-edge idiom
 * with `.market-card` — same tokens, same "inset bar" technique (the .framed
 * border-image masks a literal border-*-color, see note above), just a
 * tighter inset since the tile itself is smaller/denser. */
.market-card[data-rarity]::before,
.sell-tile[data-rarity]::before {
  content: '';
  position: absolute;
  top: 8px;
  bottom: 8px;
  left: 3px;
  width: 4px;
  border-radius: 2px;
  z-index: 1;
}

.market-card[data-rarity='common']::before,
.sell-tile[data-rarity='common']::before {
  background: var(--rarity-common);
}

.market-card[data-rarity='uncommon']::before,
.sell-tile[data-rarity='uncommon']::before {
  background: var(--rarity-uncommon);
}

.market-card[data-rarity='rare']::before,
.sell-tile[data-rarity='rare']::before {
  background: var(--rarity-rare);
}

.market-card[data-rarity='epic']::before,
.sell-tile[data-rarity='epic']::before {
  background: var(--rarity-epic);
}

.market-card[data-rarity='legendary']::before,
.sell-tile[data-rarity='legendary']::before {
  background: var(--rarity-legendary);
  box-shadow: 0 0 6px var(--rarity-legendary);
}

/* Apex rarities (tradeable since the apex-monetization pass) — same tokens
 * as the gacha odds table / reveal rows below. */
.market-card[data-rarity='mythic']::before,
.sell-tile[data-rarity='mythic']::before {
  background: var(--rarity-mythic);
  box-shadow: 0 0 6px var(--rarity-mythic);
}

.market-card[data-rarity='cursed']::before,
.sell-tile[data-rarity='cursed']::before {
  background: var(--rarity-cursed);
  box-shadow: 0 0 6px var(--rarity-cursed);
}

.market-card[data-rarity='divine']::before,
.sell-tile[data-rarity='divine']::before {
  background: var(--rarity-divine);
  box-shadow: 0 0 6px var(--rarity-divine);
}

.market-card-icon {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
}

.market-card:hover {
  filter: brightness(1.08);
  transform: translateY(-2px);
}

.market-card:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
}

.market-card-name {
  margin: 0;
  font-size: 1rem;
  color: var(--ink);
}

.market-card-kind {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-dim);
}

.market-card-price {
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--gold);
}

.market-card-supply,
.market-card-band {
  margin: 0;
  font-size: 0.8rem;
  color: var(--ink-dim);
}

.market-card-band {
  /* --ink-dim (not --ink-faint) clears WCAG AA — see .auth-field em above. */
  color: var(--ink-dim);
}

/* ── price tag (shared by card + order-book row) ─────────────────────── */

.price-tag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

.diamond-icon {
  /* 16x16, an integer downscale of the 32px source (A2) — 14px forced a
   * non-integer scale factor that aliased the pixel art. */
  width: 16px;
  height: 16px;
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
  flex-shrink: 0;
}

/* ── detail / order book ──────────────────────────────────────────────── */

.market-detail {
  padding: 24px;
  margin-top: 8px;
}

.market-detail-back {
  background: none;
  border: none;
  padding: 0 0 16px;
  color: var(--accent);
  font: inherit;
  font-size: 0.9rem;
  cursor: pointer;
}

.market-detail-back:hover {
  text-decoration: underline;
}

.market-detail-head {
  display: flex;
  align-items: flex-start;
  gap: 14px;
}

/* Commodity icon (fix 2) — same 56px pixelated treatment idiom as
 * .market-card-icon (44px) / .mailbox-icon (28px), just larger for the
 * detail view's more spacious header. Hides itself on 404 (see market.ts). */
.market-detail-icon {
  width: 56px;
  height: 56px;
  flex-shrink: 0;
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
}

.market-detail-heading-text {
  min-width: 0;
}

.market-detail-head h2 {
  margin: 0 0 4px;
  color: var(--gold);
  font-size: 1.3rem;
}

/* Rarity chip (fix 2) — same [data-rarity] + --rarity-* token idiom as
 * .market-card / .gacha-reveal-row. No data-rarity attribute = neutral
 * "Material" chip (material lots have no rarity of their own). */
.market-detail-rarity {
  display: inline-block;
  margin: 0 0 6px;
  padding: 2px 10px;
  border: 1px solid rgba(184, 146, 58, 0.3);
  border-radius: 999px;
  color: var(--ink-dim);
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.market-detail-rarity[data-rarity='common'] {
  color: var(--rarity-common);
  border-color: var(--rarity-common);
}
.market-detail-rarity[data-rarity='uncommon'] {
  color: var(--rarity-uncommon);
  border-color: var(--rarity-uncommon);
}
.market-detail-rarity[data-rarity='rare'] {
  color: var(--rarity-rare);
  border-color: var(--rarity-rare);
}
.market-detail-rarity[data-rarity='epic'] {
  color: var(--rarity-epic);
  border-color: var(--rarity-epic);
}
.market-detail-rarity[data-rarity='legendary'] {
  color: var(--rarity-legendary);
  border-color: var(--rarity-legendary);
  box-shadow: 0 0 6px rgba(255, 176, 32, 0.25);
}
.market-detail-rarity[data-rarity='mythic'] {
  /* Text uses the AA-safe tint (fix 1); border/glow stay saturated. */
  color: var(--rarity-mythic-text);
  border-color: var(--rarity-mythic);
  box-shadow: 0 0 6px rgba(255, 45, 85, 0.3);
}
.market-detail-rarity[data-rarity='cursed'] {
  color: var(--rarity-cursed-text);
  border-color: var(--rarity-cursed);
  box-shadow: 0 0 6px rgba(214, 23, 74, 0.3);
}
.market-detail-rarity[data-rarity='divine'] {
  color: var(--rarity-divine);
  border-color: var(--rarity-divine);
  box-shadow: 0 0 8px rgba(255, 244, 214, 0.4);
}

.market-detail-band {
  margin: 0 0 16px;
  color: var(--ink-dim);
  font-size: 0.9rem;
}

/* Price-position bar (fix 6) — one dot per active listing along the price
 * band; the lowest (buyable) listing's dot is tinted --good. */
.market-price-bar {
  margin: 0 0 18px;
}

.market-price-bar-track {
  position: relative;
  height: 6px;
  border-radius: 999px;
  background: linear-gradient(to right, rgba(184, 146, 58, 0.2), rgba(244, 197, 66, 0.4));
}

.market-price-bar-dot {
  position: absolute;
  top: 50%;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--bg);
  transform: translate(-50%, -50%);
}

.market-price-bar-dot.is-buyable {
  background: var(--good);
}

.market-price-bar-dot.is-mine {
  outline: 1px solid var(--gold);
  outline-offset: 1px;
}

/* ×N label when several listings share one price (one dot, counted). */
.market-price-bar-count {
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translate(-50%, -3px);
  font-size: 0.62rem;
  line-height: 1;
  color: var(--ink-dim);
  white-space: nowrap;
}

.market-detail-status {
  margin: 0 0 12px;
  color: var(--ink-dim);
}

.market-detail-status:empty {
  display: none;
}

.market-listing-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.market-listing-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 4px;
  border-bottom: 1px solid rgba(184, 146, 58, 0.16);
}

.market-listing-row:last-child {
  border-bottom: none;
}

.market-listing-price {
  min-width: 64px;
  color: var(--ink);
  font-weight: 700;
}

.market-listing-note {
  flex: 1 1 auto;
  font-size: 0.85rem;
  color: var(--ink-dim);
}

.market-listing-row.is-buyable .market-listing-note {
  color: var(--good);
}

.market-listing-row.is-mine {
  background: rgba(106, 208, 255, 0.07);
}

.market-buy-btn {
  flex: 0 0 auto;
  padding: 6px 14px;
  font-size: 0.85rem;
}

.market-buy-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

@media (max-width: 600px) {
  .market-page {
    /* Tighten the empty space above the account bar (C5) — the desktop
     * 40px top padding plus the 32px title margin below left an outsized gap
     * on narrow screens. */
    padding: 16px 14px 60px;
  }

  .market-page::before {
    height: 340px;
  }

  .market-title {
    margin-bottom: 20px;
  }

  .market-grid-group {
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 12px;
  }

  .market-card {
    padding: 12px;
  }

  .sell-picker {
    grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
    gap: 8px;
  }

  .sell-tile {
    padding: 8px 4px 6px;
  }

  .sell-tile-icon {
    width: 30px;
    height: 30px;
  }

  .sell-qty-btn,
  #sell-qty {
    height: 40px;
  }

  .sell-qty-btn {
    width: 40px;
  }

  .market-toolbar {
    flex-direction: column;
    align-items: stretch;
  }

  .market-filters {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
  }

  .filter-search-field {
    margin-left: 0;
    width: 100%;
  }

  .filter-search-field input {
    width: 100%;
  }

  .account-signed-out,
  .account-signed-in {
    flex-direction: column;
    align-items: stretch;
    text-align: center;
  }

  .account-signin-panel {
    max-width: none;
  }

  .market-tabs {
    overflow-x: auto;
    /* Right-edge fade (S3): hints more tabs sit off-screen without an
     * explicit scrollbar. -webkit- prefix required for iOS/Android Safari. */
    -webkit-mask-image: linear-gradient(to right, black 88%, transparent);
    mask-image: linear-gradient(to right, black 88%, transparent);
  }

  .mine-row {
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
  }

  .mailbox-claim-btn {
    max-width: none;
  }
}

/* ── Gacha tab ─────────────────────────────────────────────────────────── */

.market-gacha-body {
  max-width: 720px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.gacha-locked-notice {
  margin: 0;
  padding: 14px 18px;
  color: var(--gold);
  font-size: 0.9rem;
  text-align: center;
}

/* The banner card is deliberately the flashiest surface on the page — a
 * gold/legendary gradient glow instead of the flat .framed metal panel used
 * everywhere else, so the premium pull sits above the rest of the tab even
 * while its buttons are disabled (locked state). */
.gacha-banner {
  position: relative;
  /* Hero art (higgsfield, 2026-07-16): the game's own weapons bursting from
   * the summoning altar. A bottom scrim keeps the name/buttons readable; the
   * art's lower-left was generated deliberately calm for overlay. */
  padding: 190px 22px 22px;
  text-align: center;
  background:
    linear-gradient(to bottom, rgba(10, 10, 14, 0) 22%, rgba(10, 10, 14, 0.62) 55%, rgba(8, 8, 12, 0.94) 82%, rgba(8, 8, 12, 0.97) 100%),
    url('/web/art/market/gacha-banner.png') center 22% / cover no-repeat,
    linear-gradient(to bottom, var(--metal-light), var(--metal));
  box-shadow: 0 0 28px rgba(244, 197, 66, 0.18), inset 0 0 0 1px rgba(244, 197, 66, 0.12);
}

@media (max-width: 600px) {
  .gacha-banner {
    /* Mobile legibility (MUST-fix): the desktop 190px/22%-anchored crop puts
     * the art's bright center right behind "Gear Gacha" at 390px width. Taller
     * top padding pushes the text band down past the brightest pixels, a
     * stronger/earlier scrim (0.62 stop moved 55%→38%) darkens what's left
     * behind it, and `center 35%` re-anchors the crop so the calmer lower
     * portion of the art sits under the text instead of the busy center. */
    padding-top: 155px;
    background:
      linear-gradient(to bottom, rgba(10, 10, 14, 0) 14%, rgba(10, 10, 14, 0.72) 38%, rgba(8, 8, 12, 0.95) 68%, rgba(8, 8, 12, 0.97) 100%),
      url('/web/art/market/gacha-banner.png') center 35% / cover no-repeat,
      linear-gradient(to bottom, var(--metal-light), var(--metal));
  }
}

.gacha-banner-name {
  margin: 0 0 6px;
  color: var(--gold);
  font-size: 1.4rem;
  text-shadow: 0 0 12px rgba(244, 197, 66, 0.35);
}

.gacha-banner-tagline {
  margin: 0 0 18px;
  color: var(--ink-dim);
  font-size: 0.85rem;
}

.gacha-pull-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
}

.gacha-pull-btn {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  min-width: 150px;
  padding: 14px 20px;
}

.gacha-pull-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  filter: grayscale(0.4);
}

.gacha-pull-label {
  font-size: 1rem;
}

.gacha-pull-price {
  font-size: 0.85rem;
  font-weight: 400;
  opacity: 0.85;
}

.gacha-discount-note {
  position: absolute;
  top: -10px;
  right: -8px;
  background: var(--good);
  color: #072b0e;
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 3px 8px;
  border-radius: 999px;
  white-space: nowrap;
}

.gacha-odds h3,
.gacha-directbuy h3 {
  margin: 0 0 14px;
  color: var(--gold);
  font-size: 1.05rem;
}

.gacha-odds-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}

.gacha-odds-table th {
  text-align: left;
  padding: 6px 8px;
  color: var(--ink-dim);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-bottom: 1px solid rgba(184, 146, 58, 0.3);
}

.gacha-odds-table td {
  padding: 7px 8px;
  border-bottom: 1px solid rgba(184, 146, 58, 0.12);
  color: var(--ink);
}

.gacha-odds-table tr:last-child td {
  border-bottom: none;
}

.gacha-odds-pct {
  text-align: right;
  font-weight: 700;
  color: var(--gold);
}

/* Rarity-tinted rarity name cell (same rarity ladder as the rest of the site). */
.gacha-odds-table tr[data-rarity='common'] .gacha-odds-rarity {
  color: var(--rarity-common);
}
.gacha-odds-table tr[data-rarity='uncommon'] .gacha-odds-rarity {
  color: var(--rarity-uncommon);
}
.gacha-odds-table tr[data-rarity='rare'] .gacha-odds-rarity {
  color: var(--rarity-rare);
}
.gacha-odds-table tr[data-rarity='epic'] .gacha-odds-rarity {
  color: var(--rarity-epic);
}
.gacha-odds-table tr[data-rarity='legendary'] .gacha-odds-rarity {
  color: var(--rarity-legendary);
}
.gacha-odds-table tr[data-rarity='mythic'] .gacha-odds-rarity {
  /* AA-safe text tint (fix 1) — table sits on the framed panel background. */
  color: var(--rarity-mythic-text);
}
.gacha-odds-table tr[data-rarity='cursed'] .gacha-odds-rarity {
  color: var(--rarity-cursed-text);
}
.gacha-odds-table tr[data-rarity='divine'] .gacha-odds-rarity {
  color: var(--rarity-divine);
  text-shadow: 0 0 6px rgba(255, 244, 214, 0.5);
}

.gacha-pity-list {
  list-style: none;
  margin: 14px 0 0;
  padding: 12px 14px;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 6px;
  color: var(--ink-dim);
  font-size: 0.82rem;
}

.gacha-pity-list li {
  padding: 3px 0;
}

.gacha-directbuy-lead {
  margin: 0 0 14px;
  color: var(--ink-dim);
  font-size: 0.85rem;
}

.gacha-directbuy-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 16px;
}

.gacha-directbuy-card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 20px 14px 16px;
  text-align: center;
}

.gacha-directbuy-card[data-rarity='mythic'] {
  box-shadow: 0 0 14px rgba(255, 45, 85, 0.18);
}
.gacha-directbuy-card[data-rarity='cursed'] {
  box-shadow: 0 0 14px rgba(214, 23, 74, 0.18);
}
.gacha-directbuy-card[data-rarity='divine'] {
  box-shadow: 0 0 14px rgba(255, 244, 214, 0.22);
}

.gacha-directbuy-name {
  margin: 0;
  font-size: 1rem;
}

.gacha-directbuy-card[data-rarity='mythic'] .gacha-directbuy-name {
  /* AA-safe text tint (fix 1) — heading sits on the framed card background. */
  color: var(--rarity-mythic-text);
}
.gacha-directbuy-card[data-rarity='cursed'] .gacha-directbuy-name {
  color: var(--rarity-cursed-text);
}
.gacha-directbuy-card[data-rarity='divine'] .gacha-directbuy-name {
  color: var(--rarity-divine);
}

.gacha-directbuy-note {
  margin: 0;
  font-size: 0.78rem;
  color: var(--ink-dim);
}

.gacha-directbuy-price {
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--gold);
  margin: 2px 0 4px;
}

.gacha-directbuy-btn {
  width: 100%;
}

.gacha-directbuy-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ── pull reveal ──────────────────────────────────────────────────────── */

.gacha-reveal {
  padding: 20px;
}

.gacha-reveal h3 {
  margin: 0 0 12px;
  color: var(--gold);
  font-size: 1.05rem;
}

.gacha-reveal-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 10px;
}

.gacha-reveal-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.2);
  border: 1px solid rgba(184, 146, 58, 0.16);
}

.gacha-reveal-row[data-rarity='common'] {
  border-color: var(--rarity-common);
}
.gacha-reveal-row[data-rarity='uncommon'] {
  border-color: var(--rarity-uncommon);
}
.gacha-reveal-row[data-rarity='rare'] {
  border-color: var(--rarity-rare);
}
.gacha-reveal-row[data-rarity='epic'] {
  border-color: var(--rarity-epic);
}
.gacha-reveal-row[data-rarity='legendary'] {
  border-color: var(--rarity-legendary);
  box-shadow: 0 0 8px rgba(255, 176, 32, 0.25);
}
.gacha-reveal-row[data-rarity='mythic'] {
  border-color: var(--rarity-mythic);
  box-shadow: 0 0 8px rgba(255, 45, 85, 0.3);
}
.gacha-reveal-row[data-rarity='cursed'] {
  border-color: var(--rarity-cursed);
  box-shadow: 0 0 8px rgba(214, 23, 74, 0.3);
}
.gacha-reveal-row[data-rarity='divine'] {
  border-color: var(--rarity-divine);
  box-shadow: 0 0 10px rgba(255, 244, 214, 0.4);
}

.gacha-reveal-icon {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  image-rendering: pixelated;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
}

.gacha-reveal-info {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.gacha-reveal-name {
  color: var(--ink);
  font-size: 0.85rem;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.gacha-reveal-rarity {
  font-size: 0.72rem;
  color: var(--ink-dim);
  text-transform: capitalize;
}

.gacha-pity-tag {
  margin-left: auto;
  flex-shrink: 0;
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--gold);
  border: 1px solid var(--gold);
  border-radius: 999px;
  padding: 2px 7px;
}

.gacha-status-link {
  background: none;
  border: none;
  padding: 0;
  color: var(--accent);
  font: inherit;
  font-size: inherit;
  text-decoration: underline;
  cursor: pointer;
}

.gacha-status-link:hover {
  color: var(--gold);
}

@media (max-width: 600px) {
  .gacha-pull-row {
    flex-direction: column;
    align-items: stretch;
  }

  .gacha-pull-btn {
    min-width: 0;
  }

  .gacha-directbuy-grid {
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 12px;
  }

  .gacha-reveal-list {
    grid-template-columns: 1fr;
  }
}

/* ── motion (fix 4): the page's two purposeful moments — new Browse cards
 * fading in and gacha pull results revealing. Both are gated so
 * reduced-motion users get instant static rendering. ─────────────────────── */

@media (prefers-reduced-motion: no-preference) {
  @keyframes market-card-in {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }

  @keyframes gacha-reveal-in {
    from {
      opacity: 0;
      transform: scale(0.92);
    }
    to {
      opacity: 1;
      transform: scale(1);
    }
  }

  .market-card {
    animation: market-card-in 150ms ease-out both;
  }

  .gacha-reveal-row {
    animation: gacha-reveal-in 220ms ease-out both;
  }
}

/* ── narrow phones (fix 8): tighten the tab strip so at least five of the
 * six tabs are visible on a 390px viewport without scrolling. The 600px
 * block's fade-mask scroll cue still covers whatever remains off-screen. ── */

@media (max-width: 400px) {
  .market-tabs {
    gap: 4px;
  }

  .market-tab {
    padding: 8px 7px;
    font-size: 0.76rem;
  }

  .market-tab.is-active::before {
    margin-right: 4px;
  }

  .market-tab.is-active::after {
    margin-left: 4px;
  }
}
