:root {
  --bg-0: #05070f;
  /* Colour at the very top of the page — also the iOS status-bar tint. */
  --bg-top: #0f1738;
  /* Breathing room above the first element of every view. The board and trade
     screens hide .site-header, so without this their titles sit flush against
     the iOS status bar (and the window edge on desktop). */
  --top-gap: clamp(0.85rem, 2.5vw, 1.5rem);
  --bg-1: #070a1c;
  --bg-2: #0c1030;
  --panel: #0d1338;
  --panel-2: #0c1230;
  --line: #82beff33;
  --line-strong: #82beff66;
  --ink: #eaf2ff;
  --ink-dim: #9fb2d8;
  --ink-faint: #6f83ad;
  --cyan: #1ab4ff;
  --cyan-soft: #7fe7ff;
  --gold: #ffc31f;
  --gold-deep: #f5a300;
  --radius: 16px;
  --shadow: 0 10px 40px #00060fbf;
  /* spritelocker-style display face: heavy condensed italic */
  --font-display: "Barlow Condensed", "Inter", system-ui, sans-serif;
}

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

* {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  /* Paint the canvas with the page's TOP colour, not near-black: on iOS this
     area sits under the status bar / notch, and #05070f read as a black bar
     against the blue app. Matches the first stop of the body gradient. */
  background: var(--bg-top);
}

body {
  margin: 0;
  min-height: 100vh;
  font-family: "Inter", system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
  color: var(--ink);
  background:
    linear-gradient(#7fa8ff08 1px, transparent 1px),
    linear-gradient(90deg, #7fa8ff08 1px, transparent 1px),
    radial-gradient(120% 90% at 50% -10%, #1b2c6b 0%, transparent 55%),
    radial-gradient(90% 70% at 100% 10%, #3c1b7a66 0%, transparent 55%),
    linear-gradient(180deg, #0b1030 0%, var(--bg-0) 100%);
  background-size: 42px 42px, 42px 42px, auto, auto, auto;
  background-attachment: fixed;
  padding: 0 clamp(0.75rem, 3vw, 2rem) 4rem;
  /* With viewport-fit=cover the page extends under the notch — keep content
     clear of the status bar and home indicator. */
  padding-top: calc(env(safe-area-inset-top) + var(--top-gap));
  padding-bottom: calc(4rem + env(safe-area-inset-bottom));
}

.bg-glow {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(40% 30% at 15% 20%, #1ab4ff1a, transparent 70%),
    radial-gradient(40% 30% at 85% 30%, #ffc31f14, transparent 70%);
}

/* ---------- Header ---------- */
.site-header {
  text-align: center;
  padding: clamp(1.75rem, 5vw, 3rem) 0 1rem;
}

.site-title {
  margin: 0;
  font-family: "Titan One", "Inter", sans-serif;
  font-weight: 400;
  font-size: clamp(2.2rem, 8vw, 4rem);
  letter-spacing: 0.01em;
  line-height: 1;
  text-transform: uppercase;
  background: linear-gradient(92deg, #1ab4ff 0%, #7fe7ff 45%, #ffc31f 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-stroke: 1.5px #0a1030;
  filter: drop-shadow(0 3px 0 #0009) drop-shadow(0 0 22px #1ab4ff4d);
  transform: skew(-4deg);
}

.site-sub {
  margin: 0.85rem auto 0;
  max-width: 40rem;
  color: var(--ink-dim);
  font-size: clamp(0.85rem, 2.4vw, 1rem);
}

/* ---------- Profile bar ---------- */
.profile-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin: 0.5rem auto 1.25rem;
  max-width: 60rem;
}

.profile-label {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--ink-faint);
  margin-right: 0.25rem;
}

.profile-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.profile-chip {
  appearance: none;
  cursor: pointer;
  border: 1px solid var(--line-strong);
  background: linear-gradient(180deg, #14224e 0%, #0c1533 100%);
  color: var(--ink);
  font: inherit;
  font-weight: 700;
  font-size: 0.95rem;
  padding: 0.45rem 1rem;
  border-radius: 999px;
  transition: transform 0.08s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}

.profile-chip:hover {
  transform: translateY(-1px);
  border-color: var(--cyan);
}

.profile-chip.is-active {
  border-color: var(--cyan-soft);
  background: linear-gradient(180deg, #1ab4ff 0%, #0f7fd6 100%);
  color: #041022;
  box-shadow: 0 0 18px #1ab4ff80, inset 0 -6px 12px #0a4c8a66;
}

/* ---------- Buttons ---------- */
.btn {
  appearance: none;
  cursor: pointer;
  font: inherit;
  font-weight: 700;
  border-radius: 999px;
  padding: 0.45rem 1rem;
  border: 1px solid var(--line-strong);
  background: #101a3f;
  color: var(--ink);
  transition: transform 0.08s ease, filter 0.15s ease, background 0.15s ease;
}
.btn:hover {
  transform: translateY(-1px);
  filter: brightness(1.08);
}
.btn:active {
  transform: translateY(0);
}

.btn-add {
  border-color: #ffe08a99;
  background: linear-gradient(180deg, #ffe680, #ffc31f 55%, #f5a300);
  color: #3a2a00;
}

.btn-ghost {
  background: transparent;
  color: var(--ink-dim);
}

.btn-reset {
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 0.82rem;
  border-color: #ff6b6b66;
  background: #2a1030;
  color: #ff9c9c;
}
.btn-reset:hover {
  background: #3a1030;
  color: #ffbcbc;
}

/* ---------- View banner ---------- */
.view-banner {
  max-width: 60rem;
  margin: -0.5rem auto 1rem;
  text-align: center;
  padding: 0.55rem 1rem;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: #0c1533cc;
  color: var(--ink-dim);
  font-size: 0.9rem;
}
.view-banner {
  display: block;
  width: calc(100% - 2rem);
  min-height: 44px;
  font: inherit;
  font-size: 0.9rem;
  cursor: pointer;
}
.view-banner.is-editing {
  border-color: #ca3e1a;
  background: #f9e5dd;
  color: #9c3218;
}
.view-banner b {
  color: var(--cyan-soft);
}
.view-banner.is-editing b {
  color: inherit;
}
/* In the bottom bar it sits above the tabs, so it shows on every page. */
.pocket-bottom .view-banner {
  width: 100%;
  max-width: none;
  margin: 0;
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  background: #19222e;
  color: #fff;
  font-size: 13px;
}
.pocket-bottom .view-banner b {
  color: inherit;
}
.pocket-bottom .view-banner.is-editing {
  background: #ca3e1a;
  color: #fff;
}

/* ---------- Stats ---------- */
.stats {
  max-width: 60rem;
  margin: 0 auto 1.25rem;
  display: grid;
  gap: 1rem;
  padding: 1.15rem 1.25rem;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: linear-gradient(180deg, #0c1533e6, #0a1130e6);
  box-shadow: var(--shadow);
}

.progress-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 0.5rem;
}
.progress-count {
  font-weight: 800;
}
.progress-pct {
  font-weight: 800;
  font-size: 1.35rem;
  color: var(--gold);
}

.rarity-breakdown {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}
.rarity-chip {
  --c: #888;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.28rem 0.6rem;
  border-radius: 9px;
  border: 1px solid color-mix(in srgb, var(--c) 45%, transparent);
  background: color-mix(in srgb, var(--c) 10%, #0a1130);
  font-size: 0.78rem;
  font-weight: 700;
}

/* Bottom stat strip: mastered / lost / rarity progress, below the grid. */
.stat-strip {
  max-width: 60rem;
  margin: 1rem auto 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1.1rem;
  padding: 0.7rem 1rem;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: linear-gradient(180deg, #0c1533e6, #0a1130e6);
}
.rarity-chip .dot {
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 50%;
  background: var(--c);
  box-shadow: 0 0 10px var(--c);
}
.rarity-chip .rc-name {
  color: color-mix(in srgb, var(--c) 60%, #fff);
}
.rarity-chip .rc-count {
  color: var(--ink-dim);
  font-variant-numeric: tabular-nums;
}

/* ---------- Controls: one toolbar card ---------- */
.controls {
  max-width: 60rem;
  margin: 0 auto 0.85rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  align-items: center;
  padding: 0.55rem 0.6rem;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: linear-gradient(180deg, #0c1533e6, #0a1130e6);
  box-shadow: var(--shadow);
}
.filter-group {
  display: inline-flex;
  padding: 0.24rem;
  gap: 0.2rem;
  border-radius: 12px;
  background: #060b1f99;
}
.filter-btn {
  appearance: none;
  cursor: pointer;
  border: 0;
  background: transparent;
  color: var(--ink-dim);
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 0.35rem 0.95rem;
  border-radius: 9px;
  transition: background 0.15s ease, color 0.15s ease;
}
.filter-btn.is-active {
  background: linear-gradient(180deg, #4fc4ff, #0f7fd6);
  color: #04182c;
  box-shadow: 0 0 12px #1ab4ff66;
}
.filter-btn.seg-icon {
  padding: 0.35rem 0.75rem;
  font-style: normal;
  font-size: 1rem;
  display: inline-grid;
  place-items: center;
}
.filter-btn.seg-icon svg { display: block; }
/* The crown and the ghost are a different kind of filter from the three word
   ones, so a hairline separates them rather than leaving two bare glyphs
   floating at the end of the row. */
.filter-btn.seg-icon { position: relative; }
.filter-btn[data-filter="mastered"] { margin-left: 0.35rem; }
.filter-btn[data-filter="mastered"]::before {
  content: "";
  position: absolute;
  left: -0.28rem;
  top: 22%;
  bottom: 22%;
  width: 1px;
  background: var(--line);
}
/* Idle tint ties each toggle to its key colour — a plain grey glyph read as
   decoration rather than a control. */
.filter-btn[data-filter="mastered"] { color: #c9a24e; }
.filter-btn[data-filter="lost"] { color: #c97b7b; }
/* Active states match the legend: gold crown, red ghost. Cyan for both made
   the row look like it had three "all" buttons. */
.filter-btn[data-filter="mastered"].is-active {
  background: linear-gradient(180deg, #ffd873, #f5a300);
  color: #2a1a00;
  box-shadow: 0 0 12px #ffc31f66;
}
.filter-btn[data-filter="lost"].is-active {
  background: linear-gradient(180deg, #ff9d9d, #d63a3a);
  color: #2a0808;
  box-shadow: 0 0 12px #ff4d4d55;
}
.controls-right {
  display: flex;
  align-items: center;
  margin-left: auto;
}
/* Save indicator: quiet fixed pill in the corner, out of the layout. */
.save-state {
  position: fixed;
  right: 0.9rem;
  bottom: 0.9rem;
  z-index: 40;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--ink-faint);
  padding: 0.3rem 0.7rem;
  border-radius: 999px;
  pointer-events: none;
}
.save-state.saving, .save-state.saved, .save-state.error {
  background: #0b1330f2;
  border: 1px solid var(--line-strong);
  box-shadow: 0 6px 20px #000a;
}
.save-state.saved {
  color: #6fe7b0;
}
.save-state.saving {
  color: var(--cyan-soft);
}
.save-state.error {
  color: #ff9c9c;
}

/* ---------- Grid ---------- */
.grid {
  max-width: 60rem;
  margin: 0 auto;
  display: grid;
  /* minmax(0,1fr) so a row card can never stretch the track past the viewport
     (its nowrap header + tile strip would otherwise set the track width) */
  grid-template-columns: minmax(0, 1fr);
  gap: 0.85rem;
}
.sprite-row, .row-head, .row-body { min-width: 0; }
.row-head .sprite-name { flex: 0 1 auto; }

/* Row card: dark panel, rarity read from its tint, its dot and its tag — the
   card edge stays quiet so a screenful of rows doesn't read as a stack of tabs. */
.sprite-row {
  --rarity: #888;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding: 0.75rem 0.85rem 0.5rem;
  border-radius: var(--radius);
  border: 1px solid color-mix(in srgb, var(--rarity) 30%, var(--line));
  background: linear-gradient(100deg, color-mix(in srgb, var(--rarity) 10%, #0b1130) 0%, #0a1028 60%);
  box-shadow: var(--shadow);
}

/* Header line: dot · NAME · (i) · rarity tag · count on the right. */
.row-head {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  min-width: 0;
}
.row-dot {
  flex: 0 0 auto;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background: color-mix(in srgb, var(--rarity) 80%, #fff);
  box-shadow: 0 0 10px var(--rarity);
}
.row-count {
  margin-left: auto;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: 0.03em;
  color: var(--ink-dim);
  font-variant-numeric: tabular-nums;
}
.row-count .mini-count { color: var(--ink); }

.row-body {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.row-body .portrait {
  flex: 0 0 auto;
  width: 3.6rem;
  height: 3.6rem;
  object-fit: contain;
  border-radius: 12px;
  background: radial-gradient(120% 100% at 50% 115%, color-mix(in srgb, var(--rarity) 35%, #0a1130) 0, #0a1130 72%);
  border: 1px solid color-mix(in srgb, var(--rarity) 55%, transparent);
  padding: 0.2rem;
  box-shadow: 0 0 12px color-mix(in srgb, var(--rarity) 45%, transparent);
}
.sprite-name {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 800;
  font-size: 1.35rem;
  line-height: 1.05;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rarity-tag {
  align-self: flex-start;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-style: italic;
  font-weight: 800;
  font-size: 0.72rem;
  color: #0b1226;
  padding: 0.12rem 0.6rem;
  border-radius: 0.25rem;
  border: 1px solid #ffffff99;
  transform: skew(-11deg);
  background: linear-gradient(180deg, color-mix(in srgb, var(--rarity) 72%, #fff) 0, var(--rarity) 60%, color-mix(in srgb, var(--rarity) 65%, #000) 100%);
}
.rarity-tag span {
  display: inline-block;
  transform: skew(11deg);
}
.sprite-mini {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  color: var(--ink-faint);
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
}

/* One horizontal row of variant tiles that scrolls sideways (no wrapping). */
.variant-cells {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-wrap: nowrap;
  gap: 0.55rem;
  overflow-x: auto;
  overflow-y: hidden;
  /* generous top/side padding so the check/crown badges (at -10px) and the
     skewed tile corners (which lean ~5px past the button box) aren't clipped
     by the scroll container */
  padding: 0.85rem 0.75rem 0.55rem;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent;
}
.variant-cells::-webkit-scrollbar { height: 7px; }
.variant-cells::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 999px; }
.variant-cells::-webkit-scrollbar-track { background: transparent; }
.variant-cells .cell { flex: 0 0 auto; }

/* Tile buttons: the tile itself is a skewed parallelogram (spritelocker
   style); the inner wrapper counter-skews so the art stays upright. */
.cell {
  --rarity: #888;
  position: relative;
  cursor: pointer;
  width: clamp(4.1rem, 15vw, 5.4rem);
  border: 0;
  background: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  user-select: none;
}
.cell .tile {
  display: block;
  width: 100%;
  border-radius: 10px;
  border: 1px solid var(--line-strong);
  background: linear-gradient(180deg, #0f1740, #0a1130);
  padding: 0.3rem;
  transform: skewX(-6deg);
  transition: transform 0.1s ease, box-shadow 0.18s ease, border-color 0.18s ease, background 0.18s ease;
}
.cell .tile-inner {
  position: relative;
  display: block;
  transform: skewX(6deg);
}
.cell:hover .tile {
  transform: skewX(-6deg) translateY(-2px);
  border-color: var(--rarity);
}
.cell:focus-visible { outline: none; }
.cell:focus-visible .tile {
  outline: 2px solid var(--cyan-soft);
  outline-offset: 2px;
}
.cell img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: contain;
  image-rendering: auto;
  filter: grayscale(0.8) brightness(0.45) opacity(0.6);
  transition: filter 0.18s ease;
  pointer-events: none;
}
/* padlock over unowned tiles */
.cell .tile-lock {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: #cdd8f0cc;
  filter: drop-shadow(0 1px 3px #000c);
  opacity: 1;
  transition: opacity 0.15s ease;
  pointer-events: none;
}
.cell.is-owned .tile-lock,
.cell.is-lost .tile-lock { opacity: 0; }

/* variant-coloured labels under every tile */
.cell .cell-label {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  font-size: 0.82rem;
  letter-spacing: 0.06em;
  color: #cfd8ec;
  text-transform: uppercase;
}
.cell.variant-gold .cell-label { color: #f5b733; }
.cell.variant-candy .cell-label { color: #f04db0; }
.cell.variant-galaxy .cell-label { color: #8a5dff; }
.cell.variant-holofoil .cell-label { color: #2ce0b8; }

/* Owned: bright card tinted to match the variant, spritelocker-style. */
.cell.is-owned .tile {
  border-color: #ffffffd9;
  background: linear-gradient(155deg, #ffffff 0%, #dbe4f5 55%, #97a8cc 100%);
  box-shadow: 0 0 14px color-mix(in srgb, var(--rarity) 70%, transparent), 0 4px 14px #0008;
}
.cell.variant-gold.is-owned .tile {
  border-color: #ffe9ad;
  background: linear-gradient(155deg, #ffe9a8 0%, #ffc31f 55%, #d98a0a 100%);
  box-shadow: 0 0 14px #f5b73399, 0 4px 14px #0008;
}
.cell.variant-candy.is-owned .tile {
  border-color: #ffc2e4;
  background: linear-gradient(155deg, #ff9ed6 0%, #f04db0 55%, #b51f6c 100%);
  box-shadow: 0 0 14px #f04db099, 0 4px 14px #0008;
}
.cell.variant-galaxy.is-owned .tile {
  border-color: #cdb6ff;
  background: linear-gradient(155deg, #b394ff 0%, #8a5dff 55%, #46219e 100%);
  box-shadow: 0 0 14px #8a5dff99, 0 4px 14px #0008;
}
.cell.variant-gem.is-owned .tile {
  border-color: #eef3ff;
  background: linear-gradient(155deg, #eef3ff 0%, #c4d2ff 55%, #8a9bd6 100%);
  box-shadow: 0 0 14px #c4d2ff99, 0 4px 14px #0008;
}
.cell.variant-holofoil.is-owned .tile {
  border-color: #a9f8e5;
  background: linear-gradient(155deg, #7df5dd 0%, #2ce0b8 55%, #129e7f 100%);
  box-shadow: 0 0 14px #2ce0b899, 0 4px 14px #0008;
}
.cell.variant-cube.is-owned .tile {
  border-color: #d4ffb0;
  background: linear-gradient(155deg, #bcff8e 0%, #86ef4a 55%, #3f9e1a 100%);
  box-shadow: 0 0 14px #86ef4a99, 0 4px 14px #0008;
}
.cell.variant-quack.is-owned .tile {
  border-color: #ffd4ae;
  background: linear-gradient(155deg, #ffba7e 0%, #ff8a3c 55%, #c4520a 100%);
  box-shadow: 0 0 14px #ff8a3c99, 0 4px 14px #0008;
}
.cell.is-owned img {
  filter: none;
}
.cell .badge {
  position: absolute;
  top: -10px;
  right: -10px;
  width: 1.35rem;
  height: 1.35rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 0.8rem;
  font-weight: 900;
  border: 1.5px solid #0c1030e6;
  box-shadow: 0 1px 5px #0008;
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 0.15s ease, transform 0.15s cubic-bezier(0.34, 1.56, 0.64, 1);
  pointer-events: none;
}
.cell .check {
  color: #04140a;
  background: linear-gradient(180deg, #7df5b0, #22c07a);
}
.cell .crown {
  color: #3a2a00;
  background: linear-gradient(180deg, #ffe08a, #f5a300);
}
/* owned but not mastered -> green check */
.cell.is-owned:not(.is-mastered) .check {
  opacity: 1;
  transform: scale(1);
}
/* mastered -> gold crown (and no check) */
.cell.is-mastered .crown {
  opacity: 1;
  transform: scale(1);
}
/* Mastered keeps the variant-coloured card — just a gold border + crown,
   like spritelocker. */
.cell.is-mastered .tile {
  border-color: #ffcf4d !important;
  box-shadow: 0 0 18px #ffc31f88, 0 4px 14px #0008 !important;
}
.cell.is-mastered img {
  filter: none;
}

/* locked nudge feedback */
@keyframes nudge {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-4px); }
  75% { transform: translateX(4px); }
}
.cell.nudge {
  animation: nudge 0.28s ease;
}
.grid.readonly .cell.nudge {
  border-color: #ff8f8f88;
}

/* read-only view mode */
.grid.readonly .cell {
  cursor: default;
}
.grid.readonly .cell:hover .tile {
  transform: skewX(-6deg);
}

.sprite-row.hidden,
.cell.hidden {
  display: none;
}

/* ---------- Footer ---------- */
.site-footer {
  max-width: 60rem;
  margin: 2.5rem auto 0;
  text-align: center;
  color: var(--ink-faint);
  font-size: 0.78rem;
}

/* ---------- Dialog ---------- */
.dialog {
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: linear-gradient(180deg, #0e1740, #0a1028);
  color: var(--ink);
  padding: 0;
  max-width: 24rem;
  width: calc(100% - 2rem);
  box-shadow: var(--shadow);
}
.dialog::backdrop {
  background: #02040bcc;
  backdrop-filter: blur(3px);
}
.dialog-form {
  padding: 1.4rem;
  display: grid;
  gap: 0.7rem;
}
.dialog-form h2 {
  margin: 0;
  font-size: 1.2rem;
}
.dialog-hint {
  margin: 0;
  color: var(--ink-dim);
  font-size: 0.85rem;
}
.dialog-input {
  width: 100%;
  font: inherit;
  padding: 0.6rem 0.8rem;
  border-radius: 10px;
  border: 1px solid var(--line-strong);
  background: #060b1f;
  color: var(--ink);
}
.dialog-input:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: 0 0 0 3px #1ab4ff33;
}
.dialog-error {
  margin: 0;
  color: #ff9c9c;
  font-size: 0.82rem;
}
.dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
  margin-top: 0.3rem;
}

/* ---------- Small screens ---------- */
@media (max-width: 640px) {
  .sprite-row { padding: 0.6rem 0.55rem 0.4rem; }
  .row-body .portrait { width: 3.1rem; height: 3.1rem; }
  .sprite-name { font-size: 1.2rem; }
  .row-count { font-size: 0.95rem; }
  .variant-cells {
    flex: 1 1 0;
    min-width: 0;
    padding-left: 0.55rem;
    padding-right: 0.55rem;
  }
}

/* ==================== Screens / views ==================== */
[hidden] { display: none !important; }

/* On the board the title lives inside the topbar card — hide the big header
   entirely so the top of the page is one clean block. */
.site-header.compact { display: none; }

.screen-card {
  max-width: 26rem;
  margin: 1rem auto 0;
  padding: 1.75rem 1.5rem;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: linear-gradient(180deg, #0c1533e6, #0a1130e6);
  box-shadow: var(--shadow);
  text-align: center;
}
.screen-title { margin: 0 0 0.35rem; font-size: 1.5rem; }
.screen-hint { margin: 0 0 1.2rem; color: var(--ink-dim); font-size: 0.92rem; }
.screen-error { margin: 0.2rem 0 0.8rem; color: #ff9c9c; font-size: 0.85rem; font-weight: 600; }
.btn-block { width: 100%; padding: 0.7rem 1rem; font-size: 1rem; }

/* PIN */
.pin-form { display: grid; gap: 0.8rem; justify-items: center; }
.pin-input {
  width: 11rem;
  font: inherit;
  font-size: 2rem;
  font-weight: 800;
  text-align: center;
  letter-spacing: 0.7rem;
  text-indent: 0.7rem; /* balance the trailing letter-spacing */
  padding: 0.55rem 0.5rem;
  color: var(--ink);
  background: #060b1f;
  border: 1px solid var(--line-strong);
  border-radius: 12px;
}
.pin-input:focus { outline: none; border-color: var(--cyan); box-shadow: 0 0 0 3px #1ab4ff33; }

/* Picker */
.picker-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
  gap: 0.7rem;
  margin-bottom: 1rem;
}
.picker-empty { grid-column: 1 / -1; color: var(--ink-faint); font-size: 0.9rem; margin: 0.5rem 0; }
.picker-chip {
  appearance: none;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  padding: 1rem 0.6rem;
  border-radius: 14px;
  border: 1px solid var(--line-strong);
  background: linear-gradient(180deg, #14224e 0%, #0c1533 100%);
  color: var(--ink);
  font: inherit;
  transition: transform 0.08s ease, border-color 0.15s ease, box-shadow 0.15s ease;
  position: relative;
}
.picker-chip:hover { transform: translateY(-2px); border-color: var(--cyan); box-shadow: 0 0 16px #1ab4ff33; }
.picker-chip.is-mine { border-color: var(--cyan-soft); }
.picker-avatar {
  width: 4rem; height: 4rem; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 1.75rem; font-weight: 800; color: #041022;
  background: linear-gradient(180deg, #7fe7ff, #1ab4ff);
  box-shadow: 0 0 14px #1ab4ff66;
}
.picker-name { font-weight: 700; font-size: 0.98rem; word-break: break-word; }
.picker-tag {
  position: absolute; top: 0.5rem; right: 0.5rem;
  font-size: 0.6rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em;
  color: #041022; background: var(--cyan-soft);
  padding: 0.05rem 0.35rem; border-radius: 999px;
}

/* Board topbar: one header card — ring · title/tracking-as · actions. */
.board-topbar {
  max-width: 60rem;
  margin: 0 auto 1rem;
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.75rem 0.95rem;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: linear-gradient(180deg, #0c1533e6, #0a1130e6);
  box-shadow: var(--shadow);
}
.topbar-text {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
}
.topbar-title {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 800;
  font-size: 1.9rem;
  line-height: 1;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #eaf2ff;
  white-space: nowrap;
}
.board-sub {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  font-size: 0.98rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.board-sub b { color: var(--cyan-soft); }

/* square icon buttons, spritelocker style */
.btn-icon {
  appearance: none;
  cursor: pointer;
  width: 2.9rem;
  height: 2.9rem;
  flex: 0 0 auto;
  border-radius: 13px;
  border: 1px solid var(--line);
  background: #101a3f;
  color: var(--ink-dim);
  font-size: 1.05rem;
  display: grid;
  place-items: center;
  transition: transform 0.08s ease, border-color 0.15s ease, background 0.15s ease;
}
.btn-icon:hover { transform: translateY(-1px); border-color: var(--line-strong); }
.btn-icon.btn-lock { background: #101a3f; color: var(--cyan-soft); }
.btn-icon.btn-lock.is-locked {
  border-color: #ffb84d80;
  background: linear-gradient(180deg, #3a2a08, #241a06);
  color: #ffd98a;
}
.topbar-title em {
  font-style: italic;
  color: var(--cyan-soft);
}
.topbar-actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex: 0 0 auto;
}
.board-who {
  color: var(--ink-dim);
  font-size: 0.82rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.board-who b { color: var(--cyan-soft); font-weight: 800; }

.btn-lock {
  border-color: var(--line-strong);
  background: linear-gradient(180deg, #16305e, #0c1a3c);
  color: var(--cyan-soft);
  /* Keep .btn-icon's centring — this used to be an inline-flex row with a
     visible text label, and the leftover gap pushed the glyph off-centre. */
  display: grid;
  place-items: center;
}

/* One SVG per state, swapped by the .is-locked class rather than in JS. */
.btn-lock .lock-open { display: none; }
.btn-lock:not(.is-locked) .lock-closed { display: none; }
.btn-lock:not(.is-locked) .lock-open { display: block; }
.btn-lock.is-locked {
  border-color: #ffb84d99;
  background: linear-gradient(180deg, #3a2a08, #241a06);
  color: #ffd98a;
}

/* Reset lives at the very bottom of the board, away from everyday controls. */
.board-danger {
  max-width: 60rem;
  margin: 2rem auto 0;
  text-align: center;
}

.mastered-line {
  margin-top: 0.5rem;
  color: #ffd98a;
  font-size: 0.82rem;
  font-weight: 700;
}
.mastered-line .crown-mini { color: #f5b733; }

/* ==================== Info button / panel ==================== */
.sprite-id-head { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
.info-btn {
  appearance: none;
  cursor: pointer;
  width: 1.3rem; height: 1.3rem;
  flex: 0 0 auto;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: #0c1a3c;
  color: var(--cyan-soft);
  font-family: Georgia, "Times New Roman", serif;
  font-style: italic;
  font-weight: 700;
  font-size: 0.85rem;
  line-height: 1;
  display: grid; place-items: center;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.08s ease;
}
.info-btn:hover { border-color: var(--cyan); transform: translateY(-1px); }
.info-btn.is-open { background: var(--cyan); color: #041022; border-color: var(--cyan-soft); }

.info-panel {
  flex: 1 1 100%;
  width: 100%;
  margin-top: 0.1rem;
  padding: 0.75rem 0.9rem;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: #0a1130cc;
  font-size: 0.86rem;
  color: var(--ink-dim);
}
.info-panel .ability { margin: 0 0 0.5rem; color: var(--ink); }
.info-panel .find { margin: 0 0 0.5rem; color: var(--ink); }
.info-panel .find b { color: var(--gold); }
.info-panel .variant-bonuses { margin: 0; padding-left: 1.1rem; display: grid; gap: 0.25rem; }
.info-panel .variant-bonuses b { color: var(--cyan-soft); }

/* ==================== Tooltip ==================== */
.sprite-tip {
  position: fixed;
  z-index: 50;
  max-width: 15rem;
  padding: 0.55rem 0.7rem;
  border-radius: 10px;
  border: 1px solid var(--line-strong);
  background: #0b1330f2;
  box-shadow: 0 10px 30px #000a;
  color: var(--ink);
  font-size: 0.8rem;
  line-height: 1.35;
  pointer-events: none;
  display: grid;
  gap: 0.2rem;
}
.sprite-tip b { font-size: 0.85rem; }
.sprite-tip .tip-rarity { font-weight: 800; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.04em; }
.sprite-tip .tip-bonus { color: var(--ink-dim); }

/* ==================== Guide ==================== */
.guide {
  max-width: 60rem;
  margin: 2rem auto 0;
}
.guide-title {
  text-align: center;
  font-family: "Titan One", "Inter", sans-serif;
  font-weight: 400;
  text-transform: uppercase;
  font-size: 1.4rem;
  color: var(--cyan-soft);
  margin: 0 0 1rem;
}
.guide-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 0.9rem;
}
.guide-card {
  padding: 1.1rem 1.2rem;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: linear-gradient(180deg, #0c1533e6, #0a1130e6);
  box-shadow: var(--shadow);
}
.guide-card h3 {
  margin: 0 0 0.6rem;
  font-size: 1.02rem;
  color: var(--gold);
}
.guide-card ul { margin: 0; padding-left: 1.1rem; display: grid; gap: 0.4rem; }
.guide-card li { color: var(--ink-dim); font-size: 0.88rem; line-height: 1.4; }
.guide-card b { color: var(--ink); }

/* ==================== Touch / mobile ==================== */
.cell, .btn, .filter-btn, .picker-chip, .info-btn, .profile-chip, .lock-ico {
  -webkit-tap-highlight-color: transparent;
}
.cell { touch-action: manipulation; }

/* ---- Native-app feel (mainly for Add to Home Screen on iOS) ----
   Together these remove the four tells that give a web app away: the grey
   flash on tap, the double-tap zoom, the rubber-band bounce past the ends of
   the page, and the text-selection / "Save Image" callout on a long press. */
html, body {
  /* No pull-to-refresh and no bounce past the top/bottom of the scroller. */
  overscroll-behavior: none;
}
body {
  /* Kill double-tap-to-zoom app-wide, not just on cells. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  /* A long press should do nothing — no selection handles, no share sheet. */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}
/* ...except where the user genuinely needs to select or type. */
input, textarea, [contenteditable] {
  -webkit-touch-callout: default;
  -webkit-user-select: text;
  user-select: text;
  /* Anything under 16px makes iOS zoom the viewport on focus and never zoom
     back out. Every text field in the app must clear that bar. */
  font-size: max(16px, 1rem);
}
img {
  -webkit-touch-callout: none;
  -webkit-user-drag: none;
}

/* Make the lock control easy to reach on phones: pin the topbar. */
@media (max-width: 640px) {
  body { padding-left: 0.6rem; padding-right: 0.6rem; }
  .board-topbar {
    position: sticky;
    top: calc(env(safe-area-inset-top) + var(--top-gap));
    z-index: 20;
    margin: 0 auto 0.9rem;
    padding: 0.5rem 0.6rem;
    gap: 0.55rem;
    background: linear-gradient(180deg, #0c1533f7, #0a1130f2);
    backdrop-filter: blur(6px);
  }
  .topbar-title { font-size: 1.4rem; }
  .board-sub { font-size: 0.82rem; }
  .btn-icon { width: 2.6rem; height: 2.6rem; }
  .progress-ring { width: 3.3rem; height: 3.3rem; }
  #progress-ring-pct { font-size: 0.92rem; }

  .stats { padding: 0.9rem 0.9rem; }
  .progress-count, .progress-pct { font-size: 1.15rem; }

  .controls { gap: 0.5rem; }
  .filter-group { flex: 1 1 100%; justify-content: space-between; }
  .filter-btn { flex: 1 1 auto; padding: 0.5rem 0.4rem; text-align: center; }
  .filter-btn.seg-icon { flex: 0 0 auto; padding: 0.5rem 0.7rem; }
  .controls-right { flex: 1 1 100%; justify-content: space-between; }

  .variant-cells { gap: 0.45rem; }
  .cell { width: clamp(3.6rem, 20vw, 4.6rem); }

  .guide-grid { grid-template-columns: 1fr; }
  .screen-card { margin-top: 0.5rem; padding: 1.4rem 1.1rem; }
}

/* Very small phones */
@media (max-width: 380px) {
  .cell { width: clamp(3.3rem, 26vw, 4rem); }
  .cell .cell-label { font-size: 0.6rem; }
}

/* Larger tap targets where it matters, regardless of width */
.info-btn { min-width: 1.5rem; min-height: 1.5rem; }
@media (hover: none) {
  .cell:hover { transform: none; }         /* no sticky hover lift on touch */
  .info-btn { width: 1.6rem; height: 1.6rem; }
}

/* ==================== Lost state + long-press menu ==================== */
/* Prevent iOS's "save image / copy" callout and text selection so press-and-
   hold opens our state menu instead. */
.cell, .cell img, .portrait {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

.cell .lostmark {
  color: #fff;
  background: linear-gradient(180deg, #ff7a7a, #b3352f);
}
/* Lost tile: spritelocker-style dashed border + dimmed art, plus an ✕ badge. */
.cell.is-lost .tile {
  border-style: dashed;
  border-color: #ff9c9ccc;
  background: linear-gradient(180deg, #241016, #140b16);
  box-shadow: 0 0 10px #ff4d4d33;
}
.cell.is-lost img { filter: grayscale(0.7) brightness(0.7) opacity(0.4); }
.cell.is-lost .cell-label { color: #ffb3b3; }
.cell.is-lost .lostmark { opacity: 1; transform: scale(1); }
/* make sure only the relevant badge shows */
.cell:not(.is-lost) .lostmark { opacity: 0; transform: scale(0.4); }

/* lost line in stats */
.stat-lines { margin-top: 0.5rem; display: flex; flex-wrap: wrap; gap: 0.25rem 1rem; }
.mastered-line { margin-top: 0; }
.lost-line { color: #ff9c9c; font-size: 0.82rem; font-weight: 700; }
.lost-line .lost-mini { color: #ff6b6b; }

/* ---- state menu popover ---- */
.state-pop {
  position: fixed;
  z-index: 60;
  min-width: 9.5rem;
  padding: 0.4rem;
  border-radius: 12px;
  border: 1px solid var(--line-strong);
  background: #0c1533f5;
  box-shadow: 0 14px 40px #000b;
  display: grid;
  gap: 0.25rem;
}
.state-pop-title {
  font-size: 0.66rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-faint);
  padding: 0.15rem 0.5rem 0.25rem;
}
.state-pop button {
  appearance: none;
  cursor: pointer;
  text-align: left;
  border: 1px solid transparent;
  border-radius: 8px;
  padding: 0.55rem 0.7rem;
  font: inherit;
  font-weight: 700;
  font-size: 0.9rem;
  color: var(--ink);
  background: #101a3f;
  display: flex;
  justify-content: flex-start;
  align-items: center;
  gap: 0.5rem;
}
.state-pop button:hover { filter: brightness(1.12); }
.state-pop button.is-current { outline: 2px solid var(--cyan-soft); }
.state-pop .tick { color: var(--cyan-soft); font-size: 1.1rem; line-height: 1; margin-left: auto; }
/* Each state carries its own colour, as a swatch beside the label rather than
   a bar down the edge — same information, less shouting. */
.state-pop .opt-swatch {
  flex: none;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--swatch, #6f83ad);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--swatch, #6f83ad) 22%, transparent);
}
.state-pop .opt-owned { --swatch: #22c07a; }
.state-pop .opt-mastered { --swatch: #f5b733; }
.state-pop .opt-lost { --swatch: #ff6b6b; }
.state-pop .opt-missing { --swatch: #6f83ad; color: var(--ink-dim); }

/* hint that tiles have a hold action */
@media (hover: hover) {
  .cell { cursor: pointer; }
}

/* ==================== Sprite level ==================== */
/* corner level pips (top-left), spritelocker-style — one gold dot per level */
.cell-level {
  position: absolute;
  top: 0; left: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 0.22rem 0.34rem 0.26rem 0.3rem;
  border-top-left-radius: 11px;
  border-bottom-right-radius: 8px;
  background: linear-gradient(135deg, #0b1330 0 60%, #0b133000 100%);
  opacity: 0;
  transform: scale(0.6);
  transform-origin: top left;
  transition: opacity 0.15s ease, transform 0.15s ease;
  pointer-events: none;
}
.cell.has-level .cell-level { opacity: 1; transform: scale(1); }
.cell-level .pip {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: #ffd970;
  box-shadow: 0 0 4px #ffc31fcc;
}

/* level stepper inside the state popover */
.lvl-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  margin-top: 0.35rem;
  padding: 0.5rem 0.55rem 0.2rem;
  border-top: 1px solid var(--line);
}
.lvl-label {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
  font-weight: 700;
}
.lvl-stepper { display: inline-flex; align-items: center; gap: 0.5rem; }
.lvl-stepper.is-disabled { opacity: 0.5; }
.lvl-btn {
  appearance: none;
  cursor: pointer;
  width: 1.9rem; height: 1.9rem;
  border-radius: 8px;
  border: 1px solid var(--line-strong);
  background: #101a3f;
  color: var(--ink);
  font: inherit;
  font-weight: 800;
  font-size: 1.1rem;
  line-height: 1;
  display: grid; place-items: center;
}
.lvl-btn:hover:not(:disabled) { border-color: var(--cyan); }
.lvl-btn:disabled { opacity: 0.4; cursor: default; }
.lvl-val {
  min-width: 3.2rem;
  text-align: center;
  font-style: italic;
  font-weight: 800;
  font-size: 0.95rem;
  color: #ffd970;
  font-variant-numeric: tabular-nums;
}

/* Rapid taps on the stepper must never trigger double-tap zoom or text
   selection on phones. */
.state-pop, .state-pop * {
  touch-action: manipulation;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}

/* ==================== Topbar progress ring ==================== */
.progress-ring {
  --p: 0; /* percent 0..100 */
  flex: 0 0 auto;
  width: 3.9rem;
  height: 3.9rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background:
    radial-gradient(closest-side, #0a1130 70%, transparent 71% 100%),
    conic-gradient(#3fbcff calc(var(--p) * 1%), #131c42 0);
  box-shadow: 0 0 16px #1ab4ff2e, inset 0 0 0 1px #82beff1f;
}
#progress-ring-pct {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 800;
  font-size: 1.05rem;
  color: #eaf2ff;
  font-variant-numeric: tabular-nums;
}
#progress-ring-pct::after {
  content: "%";
  font-size: 0.72em;
  font-weight: 700;
  opacity: 0.75;
  margin-left: 0.04em;
}

/* ==================== Filter dropdowns ==================== */
.filter-selects { display: inline-flex; gap: 0.5rem; }
.filter-select {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  font: inherit;
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--ink);
  padding: 0.42rem 1.7rem 0.42rem 0.8rem;
  border-radius: 999px;
  border: 1px solid var(--line);
  background:
    url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%237fe7ff' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E")
      no-repeat right 0.7rem center,
    #0a1130;
}
.filter-select:hover { border-color: var(--line-strong); }
.filter-select:focus-visible { outline: 2px solid var(--cyan-soft); outline-offset: 1px; }

/* mastered % of owned */
.mastered-pct { color: var(--ink-faint); font-weight: 600; }

/* ==================== Reference table ==================== */
.ref-title { margin-top: 2rem; }
.ref-table-wrap {
  overflow-x: auto;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: linear-gradient(180deg, #0c1533e6, #0a1130e6);
  box-shadow: var(--shadow);
}
.ref-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.86rem;
  min-width: 34rem;
}
.ref-table th {
  text-align: left;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--ink-faint);
  padding: 0.7rem 0.9rem;
  border-bottom: 1px solid var(--line-strong);
}
.ref-table td {
  padding: 0.55rem 0.9rem;
  border-bottom: 1px solid var(--line);
  color: var(--ink-dim);
  line-height: 1.35;
  vertical-align: middle;
}
.ref-table tr:last-child td { border-bottom: 0; }
/* Keep this a real table-cell (no flex — it breaks row alignment); the
   portrait sits inline beside the name instead. */
.ref-table .ref-name {
  font-weight: 700;
  color: var(--ink);
  white-space: nowrap;
}
.ref-table .ref-name img {
  border-radius: 8px;
  vertical-align: middle;
  margin-right: 0.55rem;
}
.ref-table .ref-rarity { font-weight: 800; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; }
.ref-table .ref-find { color: var(--ink); }

@media (max-width: 640px) {
  .filter-selects {
    flex: 1 1 100%;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.5rem;
  }
  #filter-season { grid-column: 1 / -1; }
  .filter-select { width: 100%; min-width: 0; }
}

/* ==================== Key / legend bar ==================== */
.legend {
  max-width: 60rem;
  margin: 0 auto 1.25rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1.1rem;
  padding: 0.65rem 1rem;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: linear-gradient(180deg, #0c1533e6, #0a1130e6);
}
.legend-title {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 800;
  font-size: 1rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.legend .lg {
  font-style: normal;
  width: 1.15rem;
  height: 1.15rem;
  border-radius: 5px;
  display: grid;
  place-items: center;
  font-size: 0.68rem;
  font-weight: 900;
}
.legend .lg-owned { background: linear-gradient(155deg, #fff, #b9c6e0); color: #17903f; border: 1px solid #fff; }
.legend .lg-mastered { background: linear-gradient(180deg, #ffe08a, #f5a300); color: #3a2a00; border: 1px solid #ffe08a; }
.legend .lg-lost { background: #241016; color: #ff9c9c; border: 1px dashed #ff9c9ccc; }
.legend .lg-missing { background: linear-gradient(180deg, #0f1740, #0a1130); border: 1px solid var(--line-strong); }
.legend .lg-soon { background: #0a1e1c; border: 1px dashed #2ce0b8cc; }

/* ==================== Unreleased variants ==================== */
/* Preview tiles: dashed teal border + SOON chip (spritelocker-style). */
.cell.is-unreleased:not(.is-owned) .tile {
  border-style: dashed;
  border-color: #2ce0b8b3;
  background: linear-gradient(180deg, #0c1b22, #0a1130);
}
.cell.is-unreleased:not(.is-owned) .tile-lock { color: #7df5ddb3; }
.soon-chip {
  position: absolute;
  left: 50%;
  bottom: 2px;
  transform: translateX(-50%) skewX(-6deg);
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 800;
  font-size: 0.56rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #04231b;
  background: linear-gradient(180deg, #7df5dd, #2ce0b8);
  padding: 0.1rem 0.45rem 0.12rem;
  border-radius: 6px;
  pointer-events: none;
}

/* "Show unreleased" toggle */
.unreleased-toggle {
  max-width: 60rem;
  margin: 0 auto 0.85rem;
  display: flex;
  align-items: center;
  gap: 0.55rem;
  cursor: pointer;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  font-size: 0.98rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-dim);
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.unreleased-toggle input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.ut-track {
  width: 2.9rem;
  height: 1.6rem;
  flex: 0 0 auto;
  border-radius: 999px;
  background: #101a3f;
  border: 1px solid var(--line);
  position: relative;
  transition: background 0.18s ease, border-color 0.18s ease;
}
.ut-knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: calc(1.6rem - 6px);
  height: calc(1.6rem - 6px);
  border-radius: 50%;
  background: #cfd8ec;
  transition: transform 0.18s ease, background 0.18s ease;
}
.unreleased-toggle input:checked + .ut-track {
  background: linear-gradient(180deg, #1fbf95, #128a6c);
  border-color: #2ce0b8cc;
}
.unreleased-toggle input:checked + .ut-track .ut-knob {
  transform: translateX(1.3rem);
  background: #eafff9;
}
.unreleased-toggle input:focus-visible + .ut-track {
  outline: 2px solid var(--cyan-soft);
  outline-offset: 2px;
}

/* Display-face accents on the stats card */
.progress-count, .progress-pct {
  font-family: var(--font-display);
  font-style: italic;
  letter-spacing: 0.03em;
}

/* ===== Trade view ===== */
#view-trade .trade-head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 18px;
}
#view-trade .trade-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-style: italic;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--ink);
}
#view-trade .trade-sub { color: var(--ink-dim); font-size: 0.85rem; margin-top: 3px; }

.trade-cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
@media (max-width: 720px) {
  .trade-cols { grid-template-columns: 1fr; }
}

.trade-col {
  background: linear-gradient(180deg, var(--panel) 0%, var(--panel-2) 100%);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px;
}
.trade-col h3 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-style: italic;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: 1.15rem;
  color: var(--ink);
}
.trade-col .trade-col-sub {
  color: var(--ink-dim);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin: 2px 0 12px;
}
.trade-col .trade-col-count {
  color: var(--ink-faint);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-top: 12px;
}

/* Compact rarity-tinted mini-cards, wrapping so the whole trade reads at a glance. */
.trade-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  gap: 9px;
}
.trade-item {
  --rarity: #555;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 5px;
  padding: 9px 5px 7px;
  border-radius: 13px;
  border: 1px solid color-mix(in srgb, var(--rarity) 55%, var(--line));
  background: radial-gradient(120% 100% at 50% 0%, color-mix(in srgb, var(--rarity) 26%, var(--panel)) 0%, var(--panel-2) 78%);
}
.trade-item img {
  width: 54px;
  height: 54px;
  object-fit: contain;
  filter: drop-shadow(0 3px 6px #00000066);
}
.trade-item .ti-text { display: flex; flex-direction: column; line-height: 1.15; width: 100%; min-width: 0; }
.trade-item .ti-name {
  font-weight: 700;
  font-size: 0.78rem;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.trade-item .ti-variant {
  color: color-mix(in srgb, var(--rarity) 55%, var(--ink-dim));
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-weight: 600;
}
.trade-item .ti-want {
  position: absolute;
  top: 5px;
  right: 5px;
  font-size: 0.58rem;
  font-weight: 800;
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  padding: 3px 5px;
  border-radius: 999px;
  background: #ff3b3b;
  color: #fff;
  box-shadow: 0 1px 4px #00000066;
}
.trade-empty {
  grid-column: 1 / -1;
  color: var(--ink-dim);
  font-size: 0.85rem;
  padding: 6px 0;
}

/* --- Live trade choreography ------------------------------------------------
   The columns re-poll while the screen is open, so tiles come and go under the
   viewer's nose. An arrival announces itself (pop + shine sweep); a departure
   puffs out in a little cloud of smoke rather than blinking away. Tiles that
   stay put FLIP into their new grid slots so the list closes over the gap. */
.trade-item.is-sliding {
  transition: transform 380ms cubic-bezier(0.22, 0.7, 0.2, 1);
}

@keyframes trade-tada {
  0%   { opacity: 0; transform: scale(0.3) translateY(10px); }
  55%  { opacity: 1; transform: scale(1.12) translateY(0); }
  75%  { transform: scale(0.96); }
  100% { transform: scale(1); }
}
@keyframes trade-shine {
  from { transform: translateX(-140%) skewX(-18deg); }
  to   { transform: translateX(260%) skewX(-18deg); }
}
.trade-item.is-arriving {
  animation: trade-tada 520ms cubic-bezier(0.2, 0.9, 0.25, 1.2) both;
  overflow: hidden;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--rarity) 70%, transparent),
    0 6px 22px color-mix(in srgb, var(--rarity) 45%, transparent);
}
.trade-item.is-arriving::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 45%;
  background: linear-gradient(90deg, transparent, #ffffffaa, transparent);
  animation: trade-shine 620ms 150ms ease-out both;
  pointer-events: none;
}

@keyframes trade-poof {
  0%   { opacity: 1; transform: scale(1); filter: blur(0); }
  30%  { transform: scale(1.14); }
  100% { opacity: 0; transform: scale(0.55); filter: blur(6px); }
}
.trade-item.is-poofing {
  animation: trade-poof 430ms ease-in forwards;
  pointer-events: none;
}
/* The smoke: five blurred puffs drifting out from the tile's centre. */
.poof { position: absolute; inset: 0; pointer-events: none; }
.poof i {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px;
  border-radius: 50%;
  background: radial-gradient(circle at 40% 35%, #ffffffe6, #c9d2dd8c 55%, #c9d2dd00 72%);
  filter: blur(3px);
  opacity: 0;
  animation: trade-smoke 440ms ease-out forwards;
}
.poof i:nth-child(1) { --px: -26px; --py: -20px; animation-delay: 0ms; }
.poof i:nth-child(2) { --px:  24px; --py: -24px; animation-delay: 40ms; }
.poof i:nth-child(3) { --px: -18px; --py:  18px; animation-delay: 70ms; }
.poof i:nth-child(4) { --px:  22px; --py:  16px; animation-delay: 30ms; }
.poof i:nth-child(5) { --px:   0px; --py: -34px; animation-delay: 90ms; }
@keyframes trade-smoke {
  0%   { opacity: 0; transform: translate(0, 0) scale(0.3); }
  25%  { opacity: 0.95; }
  100% { opacity: 0; transform: translate(var(--px), var(--py)) scale(1.5); }
}

/* Whose PIN is being asked for — the picker chip's identity, carried over. */
.pin-who {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
  font-weight: 600;
}

/* Trade: pick who to compare against (only shown with 3+ profiles). */
.trade-chooser { padding: 0.5rem 0 1rem; }
.trade-head #trade-change { margin-left: auto; flex: none; }

/* Transient explanation for a tap that did nothing (locked / read-only). */
.hint-toast {
  position: fixed;
  left: 50%;
  bottom: calc(1.1rem + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  /* Above the "you" sheet — "Avatar saved" is raised from inside it. */
  z-index: 120;
  padding: 0.5rem 0.9rem;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: #0c1533f2;
  backdrop-filter: blur(6px);
  box-shadow: var(--shadow);
  color: var(--ink);
  font-size: 0.86rem;
  font-weight: 600;
  white-space: nowrap;
  pointer-events: none;
}
.hint-toast.is-out { animation: hint-fade 1.9s ease forwards; }
@keyframes hint-fade {
  0%   { opacity: 0; transform: translate(-50%, 6px); }
  12%  { opacity: 1; transform: translate(-50%, 0); }
  78%  { opacity: 1; transform: translate(-50%, 0); }
  100% { opacity: 0; transform: translate(-50%, 4px); }
}
@media (prefers-reduced-motion: reduce) {
  .hint-toast.is-out { animation: none; }
  /* The trade screen still updates live — it just fades instead of performing. */
  .trade-item.is-sliding { transition: none; }
  .trade-item.is-arriving { animation: trade-fade-in 220ms ease-out both; box-shadow: none; }
  .trade-item.is-arriving::after { display: none; }
  .trade-item.is-poofing { animation: trade-fade-out 220ms ease-in forwards; }
  .poof { display: none; }
}
@keyframes trade-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes trade-fade-out { from { opacity: 1; } to { opacity: 0; } }

/* ==================== 100% celebration ====================
   Fires on the tap that completes the collection and STAYS until dismissed:
   the board is dimmed and blurred behind a scrim so the banner reads cleanly
   over it, confetti keeps falling, and an X in the corner ends the party. */
.celebrate {
  position: fixed;
  inset: 0;
  z-index: 90;
  overflow: hidden;
}
.celebrate.is-out { animation: cb-leave 340ms ease forwards; }
@keyframes cb-leave { to { opacity: 0; } }

/* The scrim: kills the colour and text underneath so 100% has somewhere to sit. */
.celebrate::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 90% at 50% 45%, #060a1ce0, #03050ff2 70%);
  backdrop-filter: blur(9px) saturate(0.6) brightness(0.5);
  -webkit-backdrop-filter: blur(9px) saturate(0.6) brightness(0.5);
  animation: cb-scrim 420ms ease forwards;
}
@keyframes cb-scrim { from { opacity: 0; } to { opacity: 1; } }

/* The bloom: a gold flash washing out from the middle, once. */
.celebrate::after {
  content: "";
  position: absolute;
  inset: -20%;
  pointer-events: none;
  background: radial-gradient(closest-side, #ffd76b8c, #ff9a1f33 45%, transparent 72%);
  animation: cb-bloom 1600ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes cb-bloom {
  0%   { opacity: 0; transform: scale(0.35); }
  18%  { opacity: 1; }
  100% { opacity: 0; transform: scale(1.35); }
}

.confetti {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  pointer-events: none;
}

.celebrate-banner {
  position: absolute;
  z-index: 2;
  left: 50%;
  top: 46%;
  transform: translate(-50%, -50%);
  display: grid;
  justify-items: center;
  gap: 0.1em;
  text-align: center;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 800;
  line-height: 0.86;
  white-space: nowrap;
  pointer-events: none;
  animation: cb-punch 900ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
/* A soft dark plate right behind the words — the scrim handles the page, this
   handles any confetti that flies between the reader and the text. */
.celebrate-banner::before {
  content: "";
  position: absolute;
  inset: -30% -26%;
  z-index: -1;
  background: radial-gradient(closest-side, #05070fe6, #05070fa6 58%, transparent 80%);
}
.cb-pct {
  font-size: clamp(4.6rem, 26vw, 13rem);
  letter-spacing: -0.02em;
  background: linear-gradient(180deg, #fffdf2 6%, var(--gold) 46%, var(--gold-deep) 78%, #ff7a1f);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-stroke: 2px #ffffff33;
  filter: drop-shadow(0 6px 0 #0009) drop-shadow(0 0 34px #ffb42dbf);
  animation: cb-glow 2.8s 900ms ease-in-out infinite;
}
/* It breathes while it waits to be dismissed. */
@keyframes cb-glow {
  0%, 100% { filter: drop-shadow(0 6px 0 #0009) drop-shadow(0 0 26px #ffb42d99); transform: scale(1); }
  50%      { filter: drop-shadow(0 6px 0 #0009) drop-shadow(0 0 46px #ffc93de6); transform: scale(1.035); }
}
.cb-word {
  font-size: clamp(1.5rem, 8vw, 4rem);
  letter-spacing: 0.16em;
  color: var(--cyan-soft);
  text-shadow: 0 0 18px #1ab4ffcc, 0 3px 0 #05070f80;
}
.cb-sub {
  margin-top: 0.55em;
  font-family: "Inter", system-ui, sans-serif;
  font-style: normal;
  font-weight: 700;
  font-size: clamp(0.72rem, 2.6vw, 0.95rem);
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
/* Overshoot in, then hold — no fade-out, dismissal is the user's call. */
@keyframes cb-punch {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.2) rotate(-7deg); }
  55%  { opacity: 1; transform: translate(-50%, -50%) scale(1.16) rotate(1.5deg); }
  78%  { transform: translate(-50%, -50%) scale(0.96) rotate(-0.5deg); }
  100% { opacity: 1; transform: translate(-50%, -50%) scale(1) rotate(0deg); }
}

.celebrate-close {
  position: absolute;
  z-index: 3;
  top: max(0.9rem, env(safe-area-inset-top));
  right: max(0.9rem, env(safe-area-inset-right));
  width: 3rem;
  height: 3rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: #0b1030cc;
  color: var(--ink);
  cursor: pointer;
  animation: cb-close-in 400ms 700ms ease both;
}
.celebrate-close:hover { background: #16205a; border-color: var(--cyan); color: #fff; }
.celebrate-close:focus-visible { outline: 2px solid var(--cyan-soft); outline-offset: 3px; }
@keyframes cb-close-in { from { opacity: 0; transform: scale(0.7); } to { opacity: 1; transform: scale(1); } }

@media (prefers-reduced-motion: reduce) {
  /* Keep the moment, lose the motion: scrim and banner, nothing animating. */
  .celebrate::after { display: none; }
  .confetti { display: none; }
  .celebrate::before,
  .celebrate-banner,
  .celebrate-close { animation: none; }
  .cb-pct { animation: none; }
}

/* ---- Season note ---------------------------------------------------------
   Sits under the filter row and explains the season on screen: retired ones
   can no longer be found, and Season 4 is running on provisional data until
   the catalogue syncs. Hidden entirely when there is nothing to say. */
.season-note {
  max-width: 60rem;
  margin: -0.35rem auto 0.9rem;
  padding: 0.55rem 0.9rem;
  border-radius: 10px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--cyan-soft);
  background: #0c1533cc;
  color: var(--ink-dim);
  font-size: 0.85rem;
  line-height: 1.45;
  text-align: left;
}
.season-note b { color: var(--cyan-soft); }
.season-note code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.95em;
  padding: 0.05rem 0.3rem;
  border-radius: 5px;
  background: #ffffff14;
}

/* ---- Missing art ---------------------------------------------------------
   No site hosts Season 4 sprite images yet, so those requests 404. A broken
   image glyph looks like a bug; this reads as "not in yet" instead. The image
   keeps its box so the grid never reflows when real art arrives. */
img.art-missing {
  background:
    repeating-linear-gradient(45deg, #ffffff0a 0 6px, transparent 6px 12px),
    #0d1838;
  border-radius: 8px;
  box-shadow: inset 0 0 0 1px var(--line);
}
/* Blank out the browser's own broken-image icon / alt text. */
img.art-missing { color: transparent; font-size: 0; text-indent: -9999px; }

/* (the provisional badge was dropped once real art and rarities landed) */

/* ---------- Avatars: a collected sprite, or the initial letter ---------- */
/* The letter disc is a bright gradient; a sprite needs the opposite — a dark
   well so the art reads against it rather than washing out. */
.picker-avatar.has-sprite,
.name-avatar.has-sprite {
  background: radial-gradient(closest-side, #1ab4ff2e, transparent 72%);
  border: 0;
  border-radius: 0;
  box-shadow: none;
  padding: 0;
  overflow: visible;
}
.avatar-img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
  /* Nothing behind the art now, so the shadow is what lifts it off the card. */
  filter: drop-shadow(0 3px 6px #0009);
}

/* ---------- Board topbar: the name is now a chip you can tap ---------- */
.board-name-chip {
  appearance: none;
  cursor: pointer;
  font: inherit;
  flex: 0 0 auto;
  max-width: 60%;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  vertical-align: middle;
  padding: 0.1rem 0.5rem 0.1rem 0.15rem;
  border-radius: 999px;
  border: 1px solid transparent;
  background: #ffffff0a;
  color: inherit;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.board-name-chip:hover:not(:disabled) { border-color: var(--line-strong); background: #ffffff14; }
.board-name-chip:disabled { cursor: default; background: none; }
.board-name-chip b { color: var(--cyan-soft); overflow: hidden; text-overflow: ellipsis; }
/* The count is what gives way when the topbar runs out of room. */
.board-sub-count { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.name-avatar {
  width: 1.8rem; height: 1.8rem; border-radius: 50%;
  display: grid; place-items: center;
  flex: 0 0 auto;
  font-family: "Inter", system-ui, sans-serif;
  font-style: normal;
  font-size: 0.9rem; font-weight: 800; letter-spacing: 0;
  color: #041022;
  background: linear-gradient(180deg, #7fe7ff, #1ab4ff);
}

/* ---------- Locked bar ---------- */
/* The padlock button alone was too easy to walk past. While editing is off
   there is a full-width amber bar saying so, and the bar IS the unlock. */
.lock-bar {
  appearance: none;
  cursor: pointer;
  font: inherit;
  max-width: 60rem;
  width: 100%;
  margin: -0.35rem auto 1rem;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.6rem 0.8rem;
  border-radius: 12px;
  border: 1px solid #ffb84d99;
  background: linear-gradient(180deg, #3a2a08, #241a06);
  color: #ffd98a;
  text-align: left;
  transition: transform 0.08s ease, filter 0.15s ease;
}
.lock-bar:hover { filter: brightness(1.15); }
.lock-bar:active { transform: translateY(1px); }
.lock-bar-ico { display: grid; place-items: center; flex: 0 0 auto; }
.lock-bar-text { font-weight: 700; font-size: 0.92rem; }
.lock-bar-cta {
  margin-left: auto;
  flex: 0 0 auto;
  font-size: 0.78rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: #241a06;
  background: #ffd98a;
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
}
/* Tapping a tile while locked flashes the bar instead of raising a toast
   somewhere else on screen: one place to look, and it's the place to tap. */
.lock-bar.is-flash { animation: lock-flash 0.62s ease; }
@keyframes lock-flash {
  0%, 100% { transform: none; box-shadow: none; }
  15% { transform: scale(1.02); box-shadow: 0 0 0 3px #ffb84d55, 0 0 22px #ffb84d66; }
  40% { transform: none; box-shadow: 0 0 0 3px #ffb84d33; }
  60% { transform: scale(1.015); box-shadow: 0 0 0 3px #ffb84d55, 0 0 22px #ffb84d66; }
}
@media (prefers-reduced-motion: reduce) {
  .lock-bar.is-flash { animation: none; box-shadow: 0 0 0 3px #ffb84d66; }
}

/* ---------- "You" sheet: avatar + PIN ---------- */
.sheet {
  position: fixed;
  inset: 0;
  z-index: 95;
  display: grid;
  place-items: center;
  padding: 1rem;
}
.sheet-scrim {
  position: absolute;
  inset: 0;
  background: #03050fcc;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.sheet-card {
  position: relative;
  width: min(28rem, 100%);
  max-height: min(85vh, 44rem);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 1.1rem 1.2rem 1.4rem;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: linear-gradient(180deg, #0d1740f2, #0a1130f2);
  box-shadow: var(--shadow);
  animation: sheet-in 180ms ease;
}
@keyframes sheet-in { from { opacity: 0; transform: translateY(10px); } }
.sheet-head {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin-bottom: 1rem;
}
.sheet-title {
  margin: 0;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 800;
  font-size: 1.6rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sheet-head .btn-icon { margin-left: auto; width: 2.2rem; height: 2.2rem; border-radius: 10px; }
.sheet-section {
  margin: 1.4rem 0 0.3rem;
  font-size: 0.72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--ink-faint);
}
.sheet-section:first-of-type { margin-top: 0; }
.sheet .screen-hint { margin-bottom: 0.7rem; text-align: left; }
.screen-ok { margin: 0.2rem 0 0.8rem; color: #7ce0a8; font-size: 0.85rem; font-weight: 600; }

/* The grid of sprites you're allowed to wear — collected ones only. */
.avatar-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(3.6rem, 1fr));
  gap: 0.5rem;
}
.avatar-pick {
  appearance: none;
  cursor: pointer;
  aspect-ratio: 1;
  padding: 0.3rem;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: radial-gradient(75% 75% at 50% 35%, #16224e, #0a1130);
  transition: transform 0.08s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.avatar-pick:hover { transform: translateY(-2px); border-color: var(--cyan); }
.avatar-pick.is-current {
  border-color: var(--cyan-soft);
  box-shadow: 0 0 0 2px #7fe7ff55, 0 0 18px #1ab4ff55;
}
.avatar-pick img { width: 100%; height: 100%; object-fit: contain; display: block; }

.pin-change { display: grid; gap: 0.6rem; justify-items: center; }
.pin-change .pin-input { width: 100%; max-width: 12rem; font-size: 1.4rem; letter-spacing: 0.3em; }

/* "Use as avatar" on the long-press menu — the shortcut for the sheet. */
.pop-avatar {
  width: 100%;
  margin-top: 0.35rem;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  cursor: pointer;
  font: inherit;
  font-size: 0.85rem;
  font-weight: 700;
  padding: 0.45rem 0.6rem;
  border-radius: 9px;
  border: 1px solid var(--line);
  background: #131f4a;
  color: var(--ink);
}
.pop-avatar:hover { filter: brightness(1.15); }
.pop-avatar.is-current { border-color: var(--cyan-soft); color: var(--cyan-soft); }
.pop-avatar-star { color: var(--gold); }

/* ---------- Codes & Lobby Hacks Drawer ---------- */
.codes-sheet-card {
  width: min(30rem, 100%);
}
.codes-icon-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.3rem;
  height: 2.3rem;
  border-radius: 10px;
  background: linear-gradient(135deg, #00d2ff22, #00f0ff44);
  border: 1px solid #00f0ff88;
  color: #00f0ff;
  box-shadow: 0 0 12px #00f0ff44;
}

/* Banner above/below controls */
.codes-banner {
  max-width: 60rem;
  margin: 0 auto 0.85rem;
}
.codes-banner-btn {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 0.9rem;
  background: linear-gradient(90deg, #0d1a44dd, #122256dd);
  border: 1px solid #233b82;
  border-radius: var(--radius);
  color: var(--ink);
  cursor: pointer;
  font-size: 0.86rem;
  text-align: left;
  transition: all 160ms ease;
  box-shadow: 0 2px 8px #0004;
}
.codes-banner-btn:hover {
  background: linear-gradient(90deg, #13245c, #193074);
  border-color: #00f0ffaa;
  box-shadow: 0 0 16px #00d2ff33;
}

@keyframes banner-code-pulse {
  0%, 100% {
    border-color: rgba(0, 240, 255, 0.7);
    box-shadow: 0 0 16px rgba(0, 240, 255, 0.45), 0 2px 10px rgba(0, 0, 0, 0.5);
  }
  50% {
    border-color: #00f0ff;
    box-shadow: 0 0 32px rgba(0, 240, 255, 0.85), 0 0 12px rgba(0, 240, 255, 0.6);
  }
}

.codes-banner-btn.has-unused {
  border-color: #00f0ffaa;
  animation: banner-code-pulse 2.2s ease-in-out infinite;
  background: linear-gradient(90deg, #102154, #18337a);
}
.codes-banner-btn.has-unused .codes-badge-pulse {
  box-shadow: 0 0 14px #00f0ff;
}
.codes-banner-btn.has-unused .codes-banner-text {
  text-shadow: 0 0 10px rgba(0, 240, 255, 0.5);
}
.codes-badge-pulse {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  padding: 0.2rem 0.5rem;
  border-radius: 6px;
  background: #00f0ff22;
  color: #00f0ff;
  border: 1px solid #00f0ff88;
  text-shadow: 0 0 8px #00f0ff88;
}
.codes-banner-text {
  flex: 1;
  font-weight: 600;
  color: var(--ink);
}
.codes-banner-arrow {
  color: #00f0ff;
  font-weight: 800;
  font-size: 1.1rem;
}

/* Category filter tabs */
.codes-cat-filter {
  display: flex;
  gap: 0.35rem;
  margin-bottom: 0.9rem;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 0.2rem;
}
.codes-cat-btn {
  appearance: none;
  cursor: pointer;
  border: 1px solid var(--line);
  background: #090e24;
  color: var(--ink-dim);
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  font-size: 0.8rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 0.3rem 0.65rem;
  border-radius: 8px;
  white-space: nowrap;
  transition: all 140ms ease;
}
.codes-cat-btn:hover {
  background: #111a3d;
  color: var(--ink);
  border-color: #24386e;
}
.codes-cat-btn.is-active {
  background: linear-gradient(180deg, #4fc4ff, #0f7fd6);
  color: #04182c;
  border-color: #4fc4ff;
  box-shadow: 0 0 10px #1ab4ff55;
}

.code-icon-generic {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.code-icon-generic svg {
  display: block;
}

/* Codes list */
.codes-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.code-card {
  padding: 0.85rem 1rem;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: linear-gradient(135deg, #0d1536 0%, #090e24 100%);
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  transition: all 180ms ease;
}
.code-card:hover {
  border-color: #2b4588;
  box-shadow: 0 2px 12px #0006;
}
.code-card.is-used {
  background: #090c1a;
  border-color: #171f36;
  opacity: 0.45;
  filter: grayscale(0.85);
}
.code-card.is-used:hover {
  opacity: 0.8;
  filter: grayscale(0.2);
}
/* Expired: dimmer than used and permanently so — there is nothing to undo, so
   the hover lift that "used" gets would be a lie here. */
.code-card.is-expired {
  background: #0a0a12;
  border-color: #2a1a1a;
  opacity: 0.4;
  filter: grayscale(1);
}
.code-card.is-expired .code-val {
  color: var(--ink-faint);
  background: #050814;
  border-color: #2a1a1a;
  text-decoration: line-through;
  text-decoration-color: #a8434388;
}
.code-expired-tag {
  display: inline-flex;
  align-items: center;
  padding: 0.4rem 0.75rem;
  font-size: 0.8rem;
  font-weight: 700;
  border-radius: 8px;
  background: #2a1214;
  border: 1px solid #6b2230;
  color: #e08a8a;
  flex-shrink: 0;
  white-space: nowrap;
}

.code-card-target {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.code-thumb-wrap {
  --rarity: #555;
  width: 2.7rem;
  height: 2.7rem;
  border-radius: 10px;
  border: 1px solid color-mix(in srgb, var(--rarity) 60%, transparent);
  background: radial-gradient(circle at center, color-mix(in srgb, var(--rarity) 30%, transparent), #070c20);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  overflow: hidden;
  box-shadow: 0 0 10px color-mix(in srgb, var(--rarity) 35%, transparent);
}
.code-thumb {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.code-target-info {
  flex: 1;
  min-width: 0;
}
.code-target-name {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 800;
  font-size: 1.05rem;
  color: var(--ink);
  letter-spacing: 0.02em;
}
.code-target-sub {
  font-size: 0.78rem;
  color: var(--ink-faint);
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin-top: 0.1rem;
}
.code-rarity-tag {
  font-weight: 700;
  text-transform: uppercase;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
}

.btn-code-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.4rem 0.75rem;
  font-size: 0.8rem;
  font-weight: 700;
  border-radius: 8px;
  background: #141f44;
  color: var(--ink-dim);
  border: 1px solid #233468;
  cursor: pointer;
  transition: all 150ms ease;
  flex-shrink: 0;
}
.btn-code-toggle:hover {
  background: #1d2d5e;
  border-color: #00d2ff88;
  color: var(--ink);
}
.btn-code-toggle.is-used {
  background: #0e2b1b;
  border-color: #1f6b3e;
  color: #7ce0a8;
}
.btn-code-toggle.is-used:hover {
  background: #143824;
  border-color: #349c5e;
}

.code-val-row {
  display: flex;
  width: 100%;
}
.code-val {
  width: 100%;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: 1.25rem;
  font-weight: 800;
  letter-spacing: 0.09em;
  color: #00f0ff;
  background: #060b1e;
  padding: 0.55rem 0.85rem;
  border-radius: 8px;
  border: 1px solid #1c326e;
  text-align: center;
  box-sizing: border-box;
  user-select: all;
  -webkit-user-select: all;
}
.code-card.is-used .code-val {
  color: var(--ink-faint);
  background: #050814;
  border-color: #151d32;
}

/* The bottom bar grows by the banner's height; keep the last row clear of it. */
body:has(.pocket-bottom .view-banner:not([hidden])) .app-shell {
  padding-bottom: 200px;
}
