/* Snapshot Showdown — companion site
   Palette lifted from the game: deep navy/starfield ground, #EDC772 gold trim.
   No build step, no dependencies — this is deployable to GitHub Pages as-is. */

:root {
  --gold: #edc772;
  --gold-dim: #b9975a;
  --bg: #0b0d1a;
  --panel: #141830;
  --panel-2: #1b2040;
  --line: #2a3160;
  --text: #e8eaf2;
  --muted: #9aa0c0;
  --common: #b6bccd;
  --rare: #3d86ff;
  --epic: #a855f7;
  --legendary: #ffb300;
  --win: #6ee7a0;
  --loss: #ff7366;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  padding: 0 1rem 4rem;
  background:
    radial-gradient(1200px 600px at 50% -10%, #1d2450 0%, transparent 60%),
    var(--bg);
  color: var(--text);
  font: 16px/1.6 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

a { color: var(--gold); }

/* ── header ── */
.site-header { text-align: center; padding: 2.25rem 0 2rem; }

/* The game's title art, on every page, linking home.
   It's a rectangular plate of dark nebula rather than a cut-out wordmark, so
   it gets the same border-radius and 1px line as .panel below — framed
   deliberately, which reads better than a hard-edged image floating on the
   page gradient. */
.brand {
  display: inline-block;
  line-height: 0;
  margin-bottom: 1rem;
  border-radius: 14px;
  overflow: hidden;
  border: 1px solid var(--line);
  box-shadow: 0 0 34px rgba(237, 199, 114, .10);
  transition: border-color .15s, box-shadow .15s;
}
.brand:hover { border-color: var(--gold-dim); box-shadow: 0 0 34px rgba(237, 199, 114, .2); }
.brand img { display: block; width: min(430px, 78vw); height: auto; }

.wordmark {
  margin: 0;
  font-size: clamp(2rem, 7vw, 3.4rem);
  letter-spacing: .04em;
  color: var(--gold);
  text-shadow: 0 0 26px rgba(237, 199, 114, .28);
}

/* The page title sits UNDER the logo now, so it stops being the biggest thing
   on screen — two competing gold headlines at full size just fight. */
.brand + .wordmark { font-size: clamp(1.5rem, 4.5vw, 2.2rem); }

.tagline { margin: .4rem 0 0; color: var(--muted); }

main { max-width: 900px; margin: 0 auto; }

/* ── panels ── */
.panel {
  background: linear-gradient(180deg, var(--panel) 0%, var(--panel-2) 100%);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 1.5rem;
  margin-bottom: 1.5rem;
}

.panel h2 { margin: 0 0 .5rem; font-size: 1.15rem; color: var(--gold); }
.panel h2.mt { margin-top: 1.75rem; }
.hint { margin: 0 0 1rem; color: var(--muted); font-size: .95rem; }

textarea {
  width: 100%;
  background: #0d1024;
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .8rem;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: .85rem;
  resize: vertical;
}

textarea:focus { outline: 2px solid var(--gold-dim); border-color: transparent; }

.row { display: flex; gap: .75rem; flex-wrap: wrap; margin-top: .9rem; }

.btn-primary, .btn-ghost {
  font: inherit;
  font-weight: 600;
  padding: .7rem 1.4rem;
  border-radius: 10px;
  cursor: pointer;
  border: 1px solid var(--gold-dim);
  text-decoration: none;
  display: inline-block;
}

.btn-primary { background: var(--gold); color: #1a1408; }
.btn-primary:hover { filter: brightness(1.08); }
.btn-ghost { background: transparent; color: var(--gold); }
.btn-ghost:hover { background: rgba(237, 199, 114, .1); }

/* ── card page vote ── */
.vote-panel { text-align: center; }
.vote-box #vote-btn { font-size: 1rem; }
.vote-box .hint { margin: .6rem 0 0; }

/* ── list / grid toggle on Your cards ── */
.view-toggle { display: flex; gap: 0; margin-left: auto; margin-right: .8rem; }
.view-btn {
  font: inherit;
  font-size: .8rem;
  padding: .3rem .8rem;
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--line);
  cursor: pointer;
}
.view-btn:first-child { border-radius: 8px 0 0 8px; }
.view-btn:last-child  { border-radius: 0 8px 8px 0; border-left: 0; }
.view-btn[aria-pressed="true"] {
  background: rgba(237, 199, 114, .1);
  border-color: var(--gold-dim);
  color: var(--gold);
}

/* Grid view: the same card markup, restacked. The art goes on top at full
   width instead of being an 84px thumbnail on the left, which is the whole
   point — you're looking at the pictures, not reading the stats. */
#cards-list.grid-view {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 14px;
}
#cards-list.grid-view .owned-card {
  flex-direction: column;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #0d1024;
}
#cards-list.grid-view .owned-art {
  width: 100%;
  flex: 0 0 auto;
}
#cards-list.grid-view .owned-main { width: 100%; }
/* The action buttons wrap to three or four lines in a narrow column and
   drown the card. Still all there, just tighter. */
#cards-list.grid-view .owned-actions { gap: .3rem; }
#cards-list.grid-view .owned-stats { font-size: .78rem; gap: .6rem; }

/* ── album search ── */
.search-row { gap: .6rem; flex-wrap: wrap; margin-bottom: 1rem; }
.search-row input[type="search"] {
  flex: 1 1 180px;
  min-width: 0;              /* or flex items refuse to shrink below content */
  background: #0d1024;
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .55rem .8rem;
  font: inherit;
}
.search-row input[type="search"]:focus { outline: 1px solid var(--gold-dim); }

/* ── "Get the app" (injected by js/getapp.js) ── */
.app-bar { padding-top: 12px; }

/* Solid gold rather than the outlined .btn-ghost treatment: this is the one
   thing on the site that should pull the eye, and it competes with a big
   piece of title art directly below it. Pill-shaped so it doesn't read as
   just another form button. */
.get-app {
  display: inline-block;
  font-weight: 600;
  font-size: .85rem;
  padding: .45rem 1rem;
  border-radius: 999px;
  background: var(--gold);
  color: #1a1408;          /* overrides the global gold `a` colour */
  border: 1px solid var(--gold-dim);
  text-decoration: none;
  white-space: nowrap;
}
.get-app:hover { filter: brightness(1.08); }

.error { color: var(--loss); margin: .9rem 0 0; }

/* ── the card ── */
.card-wrap { display: flex; justify-content: center; margin-bottom: 1.5rem; }

.card {
  width: 300px;
  background: linear-gradient(180deg, #1a2048, #0f1330);
  border: 3px solid var(--gold-dim);
  border-radius: 16px;
  padding: .9rem;
  box-shadow: 0 14px 40px rgba(0, 0, 0, .55);
  position: relative;
}

.card.rarity-Rare      { border-color: var(--rare); }
.card.rarity-Epic      { border-color: var(--epic); }
.card.rarity-Legendary { border-color: var(--legendary); box-shadow: 0 0 34px rgba(255, 179, 0, .35); }

.card.shiny::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: 13px;
  pointer-events: none;
  background: linear-gradient(115deg, transparent 35%, rgba(255, 245, 200, .28) 50%, transparent 65%);
}

.card-top { display: flex; justify-content: space-between; font-weight: 700; color: var(--gold); }

.card-art {
  height: 180px;
  margin: .6rem 0;
  border-radius: 10px;
  border: 1px dashed var(--line);
  background: repeating-linear-gradient(45deg, #10142e, #10142e 10px, #131737 10px, #131737 20px);
  display: grid;
  place-items: center;
}

.art-note { color: var(--muted); font-size: .75rem; text-align: center; padding: 0 1rem; }

.card-name {
  margin: .2rem 0 .6rem;
  text-align: center;
  color: var(--gold);
  font-size: 1.15rem;
}

.card-stats { display: flex; justify-content: space-around; text-align: center; }
.card-stats .stat b { display: block; font-size: 1.25rem; }
.card-stats .stat i { font-style: normal; font-size: .7rem; color: var(--muted); }
.stat.atk b { color: #ff9d7a; }
.stat.hp  b { color: var(--win); }
.stat.def b { color: #7ab6ff; }

.card-tags { display: flex; gap: .4rem; flex-wrap: wrap; justify-content: center; margin-top: .8rem; }

.tag {
  font-size: .7rem;
  padding: .16rem .6rem;
  border-radius: 99px;
  border: 1px solid var(--line);
  color: var(--muted);
}

.tag.rarity-Common    { color: var(--common);    border-color: var(--common); }
.tag.rarity-Rare      { color: var(--rare);      border-color: var(--rare); }
.tag.rarity-Epic      { color: var(--epic);      border-color: var(--epic); }
.tag.rarity-Legendary { color: var(--legendary); border-color: var(--legendary); }
.tag.shiny { color: #fff0b8; border-color: #fff0b8; }
.tag.elite { color: var(--gold); border-color: var(--gold); }
.tag.grave { color: var(--loss); border-color: var(--loss); }

/* ── battle record ── */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: .75rem;
  margin: 0;
}

.stat-grid div {
  background: #0d1024;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .7rem .85rem;
}

.stat-grid dt { color: var(--muted); font-size: .75rem; text-transform: uppercase; letter-spacing: .05em; }
.stat-grid dd { margin: .15rem 0 0; font-size: 1.35rem; font-weight: 700; }
.stat-grid dd.good { color: var(--win); }
.stat-grid dd.bad  { color: var(--loss); }

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

.ability-list li {
  background: #0d1024;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .6rem .85rem;
  margin-bottom: .5rem;
}

.ability-list .slot { color: var(--muted); font-size: .72rem; text-transform: uppercase; }
.ability-list .nm { color: var(--gold); font-weight: 600; }

.meta { color: var(--muted); font-size: .8rem; margin-top: 1.25rem; }

.cta { text-align: center; }

footer { text-align: center; color: var(--muted); margin-top: 3rem; font-size: .85rem; }
footer .small { font-size: .78rem; opacity: .75; }

/* ── upload page ── */
input[type="email"] {
  width: 100%;
  max-width: 380px;
  background: #0d1024;
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .7rem .85rem;
  font: inherit;
}

input[type="email"]:focus { outline: 2px solid var(--gold-dim); border-color: transparent; }

.owned-card {
  background: #0d1024;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .7rem .9rem;
  margin-bottom: .6rem;
}

.owned-head { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.owned-head .nm { color: var(--gold); font-weight: 600; }

.owned-stats {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  color: var(--muted);
  font-size: .85rem;
  margin-top: .3rem;
}

code {
  background: #0d1024;
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: .1rem .35rem;
  font-size: .85em;
}

.hint.warn {
  border-left: 3px solid var(--gold);
  background: rgba(237, 199, 114, .07);
  padding: .6rem .85rem;
  border-radius: 0 8px 8px 0;
}

.or {
  text-align: center;
  color: var(--muted);
  font-size: .85rem;
  margin: .9rem 0 0;
  max-width: 380px;
}

.btn-danger {
  font: inherit;
  font-weight: 600;
  padding: .7rem 1.4rem;
  border-radius: 10px;
  cursor: pointer;
  background: transparent;
  color: var(--loss);
  border: 1px solid var(--loss);
}

.btn-danger:hover { background: rgba(255, 115, 102, .12); }
.small-note { font-size: .82rem; opacity: .8; }

/* ── nav ── */
.site-nav {
  display: flex;
  gap: .4rem;
  justify-content: center;
  flex-wrap: wrap;
  max-width: 900px;
  margin: 0 auto 1.5rem;
}

.site-nav a {
  padding: .45rem 1rem;
  border-radius: 99px;
  border: 1px solid var(--line);
  text-decoration: none;
  font-size: .9rem;
  color: var(--muted);
}

.site-nav a:hover { border-color: var(--gold-dim); color: var(--gold); }
.site-nav a.here { border-color: var(--gold); color: var(--gold); background: rgba(237,199,114,.08); }

/* ── tabs ── */
.tabs { display: flex; gap: .5rem; justify-content: center; margin-bottom: 1.25rem; }

.tab {
  font: inherit;
  font-weight: 600;
  padding: .6rem 1.4rem;
  border-radius: 10px;
  cursor: pointer;
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--line);
}

.tab.active { color: var(--gold); border-color: var(--gold); background: rgba(237,199,114,.08); }

/* ── chips ── */
.chips { display: flex; gap: .5rem; flex-wrap: wrap; }

.chip {
  font: inherit;
  font-size: .88rem;
  padding: .4rem .9rem;
  border-radius: 99px;
  cursor: pointer;
  background: #0d1024;
  color: var(--muted);
  border: 1px solid var(--line);
}

.chip:hover { color: var(--text); }
.chip.active { color: #1a1408; background: var(--gold); border-color: var(--gold); font-weight: 600; }

/* ── board rows ── */
.board-row {
  display: flex;
  align-items: center;
  gap: .9rem;
  background: #0d1024;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .65rem .9rem;
  margin-bottom: .5rem;
}

.board-row .pos {
  min-width: 2.2rem;
  text-align: center;
  font-weight: 700;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.board-row:nth-child(1) .pos { color: var(--legendary); }
.board-row:nth-child(2) .pos { color: #cfd6e4; }
.board-row:nth-child(3) .pos { color: #d08b52; }

.board-row .who { flex: 1; min-width: 0; }
.board-row .line1 { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.board-row .line1 .nm { color: var(--gold); font-weight: 600; }
.board-row .line2 { color: var(--muted); font-size: .8rem; margin-top: .15rem; }
.board-row .score { font-size: 1.05rem; font-variant-numeric: tabular-nums; }

.vote {
  font: inherit;
  cursor: pointer;
  background: transparent;
  border: 1px solid var(--line);
  color: var(--muted);
  border-radius: 99px;
  padding: .35rem .8rem;
  font-variant-numeric: tabular-nums;
}

.vote:hover { border-color: var(--loss); color: var(--loss); }
.vote.voted { border-color: var(--loss); color: var(--loss); background: rgba(255,115,102,.1); }
.vote.refused { border-color: var(--loss); background: rgba(255,115,102,.25); }

/* ── category entry controls on the collection page ── */
.entry-row { margin-top: .6rem; padding-top: .6rem; border-top: 1px solid var(--line); }

.entry-label {
  display: block;
  color: var(--muted);
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  margin-bottom: .4rem;
}

.entry-chip { font-size: .8rem; padding: .3rem .7rem; }
.entry-chip[disabled] { opacity: .35; cursor: not-allowed; }

/* ── album + permalink extras ── */
input[type="text"] {
  width: 100%;
  max-width: 480px;
  background: #0d1024;
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .7rem .85rem;
  font: inherit;
  margin-bottom: .6rem;
}

input[type="text"]:focus { outline: 2px solid var(--gold-dim); border-color: transparent; }

a.link-row { text-decoration: none; color: inherit; }
a.link-row:hover { border-color: var(--gold-dim); }

.owned-head a.nm { text-decoration: none; }
.owned-head a.nm:hover { text-decoration: underline; }

.link-danger {
  background: none;
  border: none;
  color: var(--loss);
  cursor: pointer;
  font: inherit;
  font-size: .85rem;
  padding: 0;
  text-decoration: underline;
}

select {
  background: #0d1024;
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .65rem .8rem;
  font: inherit;
  max-width: 320px;
}

/* ── card photos ── */
.thumb {
  width: 34px;
  height: 34px;
  object-fit: cover;
  border-radius: 6px;
  border: 1px solid var(--line);
}

input[type="file"] {
  font: inherit;
  font-size: .82rem;
  color: var(--muted);
  max-width: 260px;
}

input[type="file"]::file-selector-button {
  font: inherit;
  font-size: .82rem;
  background: transparent;
  color: var(--gold);
  border: 1px solid var(--gold-dim);
  border-radius: 8px;
  padding: .35rem .8rem;
  margin-right: .6rem;
  cursor: pointer;
}

.card-art.has-photo { border-style: solid; padding: 0; overflow: hidden; }
.card-art.has-photo img { width: 100%; height: 100%; object-fit: cover; }

/* ── photo preview staging (upload page) ── */
.photo-stage {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  margin-top: 10px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: rgba(0, 0, 0, .18);
}
.photo-stage .preview {
  width: 96px;
  height: 134px;
  object-fit: cover;
  border-radius: 8px;
  flex: 0 0 auto;
}
.photo-stage .preview-side { flex: 1 1 auto; min-width: 0; }
.photo-stage .warn {
  color: #f0b429;
  font-size: .85rem;
  margin: 0 0 6px;
}
.photo-stage .hint { margin: 0 0 8px; word-break: break-all; }
.photo-stage .row { display: flex; gap: 10px; align-items: center; }
.photo-stage .good { color: #6fcf7f; font-size: .85rem; margin: 0 0 6px; }
.photo-stage .checking { opacity: .7; font-style: italic; }
.photo-stage .confirm-photo.risky {
  background: #7a3b1d;
  border-color: #b3591f;
}

/* ── exported card image (permalink page) ──
   Replaces the synthetic card when the player has uploaded the real thing.
   Same footprint as .card so the page layout doesn't jump. */
.card-shot {
  margin: 0;
  max-width: 320px;
  width: 100%;
}
.card-shot img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 12px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .45);
}
.card-shot figcaption {
  margin-top: 8px;
  text-align: center;
  font-size: .8rem;
  opacity: .6;
}
.card-shot.shiny img {
  box-shadow: 0 6px 28px rgba(240, 200, 90, .35), 0 6px 24px rgba(0, 0, 0, .45);
}

/* ── fixes 2026-08-12 ──
   The `hidden` attribute only works because the UA stylesheet says
   `display: none` — ANY author `display:` rule beats it, so a styled panel
   with hidden set still renders (this bit .photo-stage, which showed as an
   empty bordered box). Global rule so the trap can't be stepped on again. */
[hidden] { display: none !important; }

/* Card images are portrait, so a square 34px thumb cropped them to an
   unreadable nub. Card-shaped and big enough to actually recognise. */
.thumb {
  width: 46px;
  height: 64px;
  object-fit: cover;
  border-radius: 6px;
  border: 1px solid var(--line);
  flex: 0 0 auto;
}
.owned-head .thumb {
  width: 60px;
  height: 84px;
}

/* The collection row needs a way through to the card's own page — that's
   where the image is shown full size. */
.owned-head {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.owned-head .nm { font-weight: 600; }
.view-card-link {
  margin-left: auto;
  font-size: .85rem;
  white-space: nowrap;
}
.thumb-link { display: inline-flex; line-height: 0; }
.thumb-link:hover .thumb { border-color: var(--accent, #edc772); }

/* ── board tiles (2026-08-12) ──
   Boards are judged on how cards LOOK, so the image is the tile, not a
   thumbnail beside a name. Replaces the old .board-row list. */
.board {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 18px;
}
.board-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  background: rgba(255, 255, 255, .03);
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
}
.board-tile.shiny { border-color: rgba(240, 200, 90, .5); }

.tile-rank {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 2;
  min-width: 26px;
  height: 26px;
  padding: 0 7px;
  border-radius: 13px;
  background: rgba(0, 0, 0, .72);
  color: #edc772;
  font-weight: 700;
  font-size: .85rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.tile-art {
  display: block;
  aspect-ratio: 3 / 4;
  background: rgba(0, 0, 0, .25);
}
.tile-art img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
.tile-noart {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 12px;
  opacity: .45;
  font-size: .85rem;
}

.tile-body { padding: 10px 12px 12px; display: flex; flex-direction: column; gap: 6px; }
.tile-name { font-weight: 600; text-decoration: none; }
.tile-tags { display: flex; flex-wrap: wrap; gap: 5px; }
.tile-meta { font-size: .8rem; opacity: .65; }
.tile-score { margin-top: 4px; display: flex; align-items: center; gap: 8px; }
.tile-score i { font-style: normal; opacity: .6; font-size: .8rem; }

.tile-abilities {
  list-style: none;
  margin: 4px 0 0;
  padding: 0;
  font-size: .82rem;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.tile-abilities li {
  padding: 3px 7px;
  border-radius: 5px;
  background: rgba(255, 255, 255, .05);
}
.tile-abilities .slot {
  display: inline-block;
  margin-right: 6px;
  font-size: .7rem;
  opacity: .55;
  text-transform: uppercase;
}

/* ── account bar (2026-08-12) ──
   Was a full panel mid-page; it's status, not content. */
.account-bar {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 8px 16px;
  font-size: .85rem;
  background: rgba(0, 0, 0, .25);
  border-bottom: 1px solid var(--line);
}
.account-who { opacity: .8; margin-right: auto; }
.link-quiet {
  background: none;
  border: 0;
  color: inherit;
  opacity: .7;
  cursor: pointer;
  font-size: inherit;
  padding: 0;
  text-decoration: underline;
}
.link-quiet:hover { opacity: 1; }

/* ── collection rows ──
   Image-led, actions only — no file input buried in the row. */
.owned-card {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  padding: 14px 0;
  border-bottom: 1px solid var(--line);
}
.owned-card:last-child { border-bottom: 0; }

.owned-art {
  flex: 0 0 auto;
  width: 84px;
  aspect-ratio: 3 / 4;
  border-radius: 8px;
  border: 1px solid var(--line);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, .25);
}
.owned-art img { width: 100%; height: 100%; object-fit: contain; }
.owned-noart { font-size: .72rem; opacity: .45; text-align: center; padding: 6px; }

.owned-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.owned-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.owned-head .nm { font-weight: 600; text-decoration: none; }
.owned-actions { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.btn-ghost.small { padding: 5px 12px; font-size: .82rem; }

.panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}
.sort-control { font-size: .85rem; opacity: .8; display: flex; align-items: center; gap: 8px; }
.sort-control select {
  background: rgba(0, 0, 0, .3);
  color: inherit;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 5px 8px;
}

/* Add-a-card panel when it's been aimed at a specific card. */
#upload-panel.targeted { border-color: rgba(237, 199, 114, .55); }
.version-note {
  border-left: 3px solid #edc772;
  padding-left: 10px;
}
#image-step { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line); }
#image-step h3 { margin: 0 0 6px; font-size: 1rem; }

/* ── shared card detail popup (2026-08-12) ── */
body.modal-open { overflow: hidden; }

.card-modal { position: fixed; inset: 0; z-index: 200; }
.card-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, .72);
  backdrop-filter: blur(2px);
}
.card-modal-panel {
  position: relative;
  margin: 4vh auto;
  max-width: 720px;
  width: calc(100% - 32px);
  max-height: 92vh;
  overflow-y: auto;
  background: #161a2c;
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 22px;
  box-shadow: 0 18px 60px rgba(0, 0, 0, .6);
}
.card-modal-close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 34px;
  height: 34px;
  border-radius: 17px;
  border: 1px solid var(--line);
  background: rgba(0, 0, 0, .35);
  color: inherit;
  cursor: pointer;
  font-size: .9rem;
}
.card-modal-close:hover { background: rgba(255, 255, 255, .08); }

.cm-top { display: flex; gap: 20px; flex-wrap: wrap; margin-bottom: 8px; }
.cm-art {
  flex: 0 0 auto;
  width: 190px;
  aspect-ratio: 3 / 4;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: rgba(0, 0, 0, .28);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.cm-art img { width: 100%; height: 100%; object-fit: contain; }
.cm-noart { font-size: .8rem; opacity: .45; text-align: center; padding: 10px; }

.cm-headline { flex: 1 1 240px; min-width: 0; }
.cm-headline h2 { margin: 0 0 2px; }
.cm-owner { margin: 0 0 8px; font-size: .85rem; opacity: .6; }
.cm-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }

.cm-core { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 12px; }
.cm-core span { display: flex; flex-direction: column; line-height: 1.15; }
.cm-core b { font-size: 1.15rem; }
.cm-core i { font-style: normal; font-size: .68rem; opacity: .55; letter-spacing: .04em; }

.cm-abilities { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.cm-abilities li {
  font-size: .85rem;
  padding: 4px 8px;
  border-radius: 5px;
  background: rgba(255, 255, 255, .05);
}
.cm-abilities .slot {
  display: inline-block;
  min-width: 62px;
  font-size: .68rem;
  opacity: .5;
  text-transform: uppercase;
}

.card-modal-panel h3 { margin: 18px 0 8px; font-size: .95rem; opacity: .8; }
.cm-actions {
  display: flex;
  gap: 14px;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

@media (max-width: 520px) {
  .cm-art { width: 100%; max-width: 240px; margin: 0 auto; }
  .card-modal-panel { margin: 0; border-radius: 0; max-height: 100vh; min-height: 100vh; }
}

/* ── consent + reporting (2026-08-12) ── */
.terms-list { margin: 12px 0 18px; padding-left: 20px; display: flex; flex-direction: column; gap: 8px; }
.terms-list li { font-size: .9rem; line-height: 1.45; }

.consent-check {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin-bottom: 16px;
  font-size: .9rem;
  cursor: pointer;
}
.consent-check input { margin-top: 3px; flex: 0 0 auto; }

.cm-report h4 { margin: 0 0 4px; }
.cm-report select,
.cm-report textarea {
  width: 100%;
  margin: 8px 0;
  background: rgba(0, 0, 0, .3);
  color: inherit;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 8px;
  font: inherit;
}
.btn-danger.small { padding: 6px 14px; font-size: .85rem; }
.good { color: #6fcf7f; }

/* ── album binder (2026-08-12) ──
   Eight fixed slots, empty ones visible, so an album reads as a page you're
   filling rather than a short list. */
.binder {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
}
@media (max-width: 720px) { .binder { grid-template-columns: repeat(2, 1fr); } }

.binder-slot {
  position: relative;
  border-radius: 10px;
  border: 1px solid var(--line);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.binder-slot.empty {
  border-style: dashed;
  opacity: .4;
  aspect-ratio: 3 / 4;
  align-items: center;
  justify-content: center;
}
.binder-slot.shiny { border-color: rgba(240, 200, 90, .55); }

.slot-no {
  position: absolute;
  top: 6px;
  left: 6px;
  z-index: 2;
  font-size: .7rem;
  opacity: .5;
  background: rgba(0, 0, 0, .5);
  border-radius: 9px;
  padding: 1px 7px;
}
.binder-slot.empty .slot-no { position: static; background: none; font-size: 1.1rem; }
.slot-hint { font-size: .75rem; }

.slot-art {
  display: block;
  aspect-ratio: 3 / 4;
  background: rgba(0, 0, 0, .25);
}
.slot-art img { width: 100%; height: 100%; object-fit: contain; display: block; }
.slot-noart {
  display: flex; height: 100%; align-items: center; justify-content: center;
  text-align: center; padding: 10px; font-size: .78rem; opacity: .5;
}

.slot-foot {
  display: flex;
  justify-content: space-between;
  gap: 6px;
  padding: 7px 9px;
  font-size: .78rem;
}
.slot-foot .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.slot-foot .hearts { opacity: .65; flex: 0 0 auto; }

.slot-remove {
  position: absolute;
  top: 6px;
  right: 6px;
  z-index: 2;
  /* 28px so it clears the ~24px minimum comfortable tap target. */
  width: 28px;
  height: 28px;
  border-radius: 14px;
  border: 1px solid rgba(255, 128, 128, .5);
  background: rgba(0, 0, 0, .72);
  color: #ff8080;
  cursor: pointer;
  font-size: .78rem;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  /* ALWAYS visible, not hover-only. Hover does not exist on a
     phone, so this button was simply unreachable there — and on
     desktop it was only findable by accident. It is only rendered
     for the album owner in the first place, so there is nothing to
     hide it from. */
  opacity: 1;
  transition: opacity .15s;
}

/* Inline album picker, anchored to its button. */
.owned-actions { position: relative; }
.album-pop {
  position: absolute;
  z-index: 40;
  top: calc(100% + 6px);
  left: 0;
  min-width: 230px;
  max-width: 300px;
  padding: 12px;
  background: #161a2c;
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 10px 34px rgba(0, 0, 0, .5);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.album-pop .pop-title { margin: 0; font-size: .85rem; }
.pop-list { display: flex; flex-direction: column; gap: 4px; max-height: 210px; overflow-y: auto; }
.pop-album {
  text-align: left;
  padding: 7px 10px;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, .04);
  color: inherit;
  cursor: pointer;
  font: inherit;
  font-size: .85rem;
}
.pop-album:hover:not(:disabled) { background: rgba(255, 255, 255, .1); }

/* ── swipe voting (2026-08-12) ── */
.swipe-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}
.swipe-stage {
  position: relative;
  max-width: 340px;
  margin: 0 auto;
  min-height: 460px;
}
.swipe-card {
  position: relative;
  background: #161a2c;
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 10px 34px rgba(0, 0, 0, .45);
  cursor: grab;
  user-select: none;
  touch-action: pan-y;
  transition: transform .22s ease, opacity .22s ease;
}
.swipe-card.dragging { transition: none; cursor: grabbing; }
.swipe-card.shiny { border-color: rgba(240, 200, 90, .55); }

.swipe-card.fly-right { transform: translateX(130%) rotate(18deg); opacity: 0; }
.swipe-card.fly-left  { transform: translateX(-130%) rotate(-18deg); opacity: 0; }

.swipe-art { aspect-ratio: 3 / 4; background: rgba(0, 0, 0, .3); }
.swipe-art img { width: 100%; height: 100%; object-fit: contain; display: block; }
.swipe-noart {
  display: flex; height: 100%; align-items: center; justify-content: center;
  padding: 16px; text-align: center; opacity: .5;
}

.swipe-info { padding: 12px 14px 16px; }
.swipe-info h3 { margin: 0 0 2px; }
.swipe-info .hint { margin: 0 0 8px; }
.swipe-abilities {
  list-style: none; margin: 0 0 10px; padding: 0;
  display: flex; flex-wrap: wrap; gap: 5px;
}
.swipe-abilities li {
  font-size: .76rem; padding: 3px 8px; border-radius: 5px;
  background: rgba(255, 255, 255, .06);
}

/* Verdict stamps that fade in as you drag past the threshold. */
.swipe-verdict {
  position: absolute;
  top: 18px;
  z-index: 3;
  padding: 5px 12px;
  border: 3px solid;
  border-radius: 8px;
  font-weight: 800;
  font-size: 1.05rem;
  letter-spacing: .06em;
  opacity: 0;
  transition: opacity .12s;
  pointer-events: none;
}
.swipe-verdict.up   { left: 16px;  color: #6fcf7f; border-color: #6fcf7f; transform: rotate(-14deg); }
.swipe-verdict.down { right: 16px; color: #9aa3b8; border-color: #9aa3b8; transform: rotate(14deg); }
.swipe-card.will-up   .swipe-verdict.up   { opacity: 1; }
.swipe-card.will-down .swipe-verdict.down { opacity: 1; }

.swipe-controls {
  display: flex;
  justify-content: center;
  gap: 18px;
  margin: 20px 0 10px;
}
.swipe-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  width: 74px;
  padding: 10px 0;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, .04);
  color: inherit;
  cursor: pointer;
  font: inherit;
}
.swipe-btn:disabled { opacity: .35; cursor: default; }
.swipe-btn .ico { font-size: 1.3rem; line-height: 1; }
.swipe-btn .lbl { font-size: .72rem; opacity: .7; }
.swipe-btn.vote:not(:disabled):hover   { border-color: #6fcf7f; color: #6fcf7f; }
.swipe-btn.skip:not(:disabled):hover   { border-color: #9aa3b8; }
.swipe-btn.report:not(:disabled):hover { border-color: #ff8080; color: #ff8080; }

.swipe-hint { text-align: center; }
.swipe-done { text-align: center; padding: 60px 20px; }
.swipe-done h3 { margin: 0 0 8px; }

/* ── moderation (2026-08-12) ── */
.tag.pending  { background: rgba(240, 180, 40, .18); color: #f0b429; }
.tag.rejected { background: rgba(255, 90, 90, .16); color: #ff8080; }

.mod-item {
  display: flex;
  gap: 18px;
  align-items: flex-start;
  transition: opacity .25s, transform .25s;
}
.mod-item.mod-done { opacity: 0; transform: translateX(28px); }

.mod-art {
  flex: 0 0 auto;
  width: 150px;
  aspect-ratio: 3 / 4;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: rgba(0, 0, 0, .3);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.mod-art img { width: 100%; height: 100%; object-fit: contain; }
.mod-noart { font-size: .78rem; opacity: .45; text-align: center; padding: 10px; }

.mod-body { flex: 1 1 auto; min-width: 0; }
.mod-body h3 { margin: 0 0 4px; }
.mod-note {
  width: 100%;
  margin: 8px 0;
  background: rgba(0, 0, 0, .3);
  color: inherit;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 8px;
  font: inherit;
  font-size: .85rem;
}
.btn-primary.small { padding: 6px 14px; font-size: .85rem; }
.bad { color: #ff8080; }

@media (max-width: 560px) {
  .mod-item { flex-direction: column; }
  .mod-art { width: 100%; max-width: 200px; }
}

.kofi-link { white-space: nowrap; }

.pending-note { font-size: .85rem; color: #f0b429; }
.pending-note.bad { color: #ff8080; }


/* ── leaderboard layout (2026-08-12) ──
   Podium for the top three, compact collection-style rows below. The old
   tile grid buried the ranking, which is the point of a leaderboard. */
.board { display: block; }
.board-limit { margin: 10px 0 0; font-size: .85rem; opacity: .75; }
.board-limit select {
  background: rgba(0, 0, 0, .3);
  color: inherit;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 4px 8px;
  margin-left: 6px;
}

/* podium */
.podium {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  align-items: end;
  margin-bottom: 26px;
}
.podium-slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 14px 10px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: rgba(255, 255, 255, .03);
  position: relative;
}
/* First place sits taller and centre — that's what makes it read as a podium. */
.podium-slot.place-1 { padding-top: 26px; border-color: rgba(240, 200, 90, .6); }
.podium-slot.place-2 { border-color: rgba(190, 195, 210, .45); }
.podium-slot.place-3 { border-color: rgba(190, 130, 80, .45); }

.podium-rank {
  position: absolute;
  top: -14px;
  width: 30px;
  height: 30px;
  border-radius: 15px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  background: #161a2c;
  border: 1px solid var(--line);
}
.podium-slot.place-1 .podium-rank { color: #f0c85a; border-color: #f0c85a; }
.podium-slot.place-2 .podium-rank { color: #c8ccd8; border-color: #c8ccd8; }
.podium-slot.place-3 .podium-rank { color: #cd8a4e; border-color: #cd8a4e; }

.podium-art {
  display: block;
  width: 100%;
  max-width: 110px;
  aspect-ratio: 3 / 4;
  border-radius: 8px;
  overflow: hidden;
  background: rgba(0, 0, 0, .25);
}
.podium-slot.place-1 .podium-art { max-width: 132px; }
.podium-art img { width: 100%; height: 100%; object-fit: contain; display: block; }

.podium-name { display: block; margin-top: 8px; font-weight: 600; text-decoration: none; }
.podium-meta { font-size: .74rem; opacity: .6; }
.podium-score { margin-top: 6px; }
.podium-score i { font-style: normal; opacity: .6; font-size: .74rem; display: block; }

/* rows */
.board-list { display: flex; flex-direction: column; }
.board-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.board-row:last-child { border-bottom: 0; }
.board-row.shiny .row-art { border-color: rgba(240, 200, 90, .5); }

.row-rank {
  flex: 0 0 auto;
  min-width: 34px;
  text-align: right;
  font-weight: 700;
  opacity: .55;
  font-variant-numeric: tabular-nums;
}
.row-art {
  flex: 0 0 auto;
  width: 44px;
  aspect-ratio: 3 / 4;
  border-radius: 6px;
  border: 1px solid var(--line);
  overflow: hidden;
  background: rgba(0, 0, 0, .25);
  display: flex;
  align-items: center;
  justify-content: center;
}
.row-art img { width: 100%; height: 100%; object-fit: contain; }
.row-noart { font-size: .7rem; opacity: .4; }

.row-main { flex: 1 1 auto; min-width: 0; }
.row-head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.row-name { font-weight: 600; text-decoration: none; }
.row-meta { font-size: .78rem; opacity: .6; }
.row-score { flex: 0 0 auto; text-align: right; }
.row-score i { font-style: normal; opacity: .55; font-size: .74rem; display: block; }

@media (max-width: 520px) {
  .podium { gap: 8px; }
  .podium-meta { display: none; }
  .row-rank { min-width: 26px; }
}

/* Mismatch: the only way forward is to pick the right file, so the primary
   button re-opens the picker. There is deliberately no override. */
.photo-stage .row { flex-wrap: wrap; }

/* Categories keep the tile grid; stat boards are a ranked list. */
.board-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 18px;
}

/* ── album list rows (2026-08-12) ──
   Own class, NOT .owned-card. That one became a flex row expecting
   .owned-art / .owned-main children when the collection was restyled, and an
   album has neither — the list rendered squashed. */
.album-row {
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
}
.album-row:last-child { border-bottom: 0; }
.album-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.album-head .nm { font-weight: 600; text-decoration: none; }
.album-desc { font-size: .85rem; opacity: .7; margin-top: 3px; }
.album-meta {
  display: flex;
  gap: 14px;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 6px;
  font-size: .8rem;
  opacity: .7;
}


.ink-pop {
  position: fixed;
  left: 50%;
  top: 22%;
  transform: translateX(-50%);
  z-index: 300;
  padding: 10px 20px;
  border-radius: 22px;
  background: rgba(0, 0, 0, .82);
  border: 1px solid #edc772;
  color: #edc772;
  font-weight: 700;
  pointer-events: none;
  animation: inkpop 1.6s ease forwards;
}
@keyframes inkpop {
  0%   { opacity: 0; transform: translate(-50%, 10px); }
  15%  { opacity: 1; transform: translate(-50%, 0); }
  75%  { opacity: 1; }
  100% { opacity: 0; transform: translate(-50%, -14px); }
}

/* ── higher/lower voting (2026-08-12) ── */
.guess-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 12px 14px;
  border-top: 1px solid var(--line);
  font-size: .85rem;
  text-align: center;
}
.guess-bar .threshold {
  font-size: 1.5rem;
  color: #edc772;
  line-height: 1;
}

.timer-track { height: 4px; background: rgba(255, 255, 255, .07); }
.timer-fill {
  height: 100%;
  width: 100%;
  background: #edc772;
  transition: width .1s linear;
}

.swipe-card.correct   { box-shadow: 0 0 0 2px #6fcf7f, 0 10px 34px rgba(0,0,0,.45); }
.swipe-card.incorrect { box-shadow: 0 0 0 2px #ff8080, 0 10px 34px rgba(0,0,0,.45); }

.guess-result {
  margin-top: 12px;
  padding: 12px 14px;
  border-radius: 10px;
  background: rgba(0, 0, 0, .4);
  border: 1px solid var(--line);
  font-size: .85rem;
  text-align: center;
  line-height: 1.6;
}
.frag-win { color: #edc772; font-weight: 700; }

.swipe-btn.higher:not(:disabled):hover { border-color: #6fcf7f; color: #6fcf7f; }
.swipe-btn.lower:not(:disabled):hover  { border-color: #7aa7ff; color: #7aa7ff; }

.vote-earnings .streak {
  color: #6fcf7f;
  font-weight: 600;
}
#get-more { display: block; margin: 0 auto 12px; }

/* ── shiny / elite shimmer (2026-08-12) ──
   The exported PNG is now the CLEAN card — the game hides its animated
   overlays before capturing, because a screenshot froze them into a flat
   gold smear. The effect is re-created HERE from the card's is_shiny /
   is_elite flags, where it can actually animate.

   Wrapper-based: a pseudo-element over the image, so it works on any
   surface that already puts a .shiny class on the container. */
/* overflow:hidden is REQUIRED, not cosmetic — the shimmer layer is 250% of
   the card and rotated, so without clipping it spills across the page. */
.card-shot.shiny,
.board-tile.shiny .tile-art,
.podium-slot.shiny .podium-art,
.binder-slot.shiny .slot-art,
.swipe-card.shiny .swipe-art,
.cm-art.shiny,
.card-shot.elite,
.board-tile.elite .tile-art,
.cm-art.elite,
.row-art {
  position: relative;
  overflow: hidden;
}

/* ── the moving sheen ──
   Wider spacing than before: a 320px period rather than 140, so one band
   crosses at a time instead of several stacking up. Travel is still exactly
   one period, which is what keeps the loop seamless. */
.card-shot.shiny::after,
.board-tile.shiny .tile-art::after,
.podium-slot.shiny .podium-art::after,
.binder-slot.shiny .slot-art::after,
.swipe-card.shiny .swipe-art::after,
.cm-art.shiny::after {
  content: "";
  position: absolute;
  pointer-events: none;
  /* Margins in PIXELS, not percent. The travel is an absolute 320px, so a
     percentage margin only covers it on a wide card — at 250%/-75% a 284px
     card had just 213px of spare overlay on the right, and the element's own
     edge slid into view as a hard diagonal line partway across. 500px of
     slack each side beats the 320px travel at any card size. */
  top: -500px;
  left: -500px;
  width: calc(100% + 1000px);
  height: calc(100% + 1000px);
  background: repeating-linear-gradient(
    90deg,
    transparent 0,
    rgba(255, 255, 255, .07) 22px,
    rgba(120, 220, 255, .18) 36px,
    rgba(255, 240, 180, .28) 44px,
    rgba(255, 140, 220, .18) 52px,
    rgba(255, 255, 255, .07) 66px,
    transparent 92px,
    transparent 320px
  );
  mix-blend-mode: screen;
  animation: shinySweep 2s linear infinite;
}

@keyframes shinySweep {
  from { transform: rotate(24deg) translateX(0); }
  to   { transform: rotate(24deg) translateX(-320px); }
}

/* ── the sparkles ──
   Matches the game's ShinySparkles: twinkling points scattered over the card,
   NOT drifting with the sheen. So they live on ::before with no transform,
   and only their opacity animates.

   Two layers at different tile sizes and different durations, because a
   single layer means every point twinkles in lockstep, which reads as the
   whole card flashing rather than as sparkle. */
.card-shot.shiny::before,
.board-tile.shiny .tile-art::before,
.podium-slot.shiny .podium-art::before,
.binder-slot.shiny .slot-art::before,
.swipe-card.shiny .swipe-art::before,
.cm-art.shiny::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  border-radius: inherit;
  /* Each sparkle is its own radial-gradient layer, positioned in PERCENT so
     they scatter correctly whatever size the card is rendered at — a 44px
     board thumbnail and a 320px permalink both get the same arrangement.

     (The usual box-shadow-dot trick needs a tiny element to clone; this
     element is card-sized, so shadows would duplicate the whole card.) */
  background-image:
    radial-gradient(circle, rgba(255,255,255,.95), rgba(255,245,200,.45) 40%, transparent 70%),
    radial-gradient(circle, rgba(255,255,255,.90), rgba(190,230,255,.45) 40%, transparent 70%),
    radial-gradient(circle, rgba(255,255,255,.85), rgba(255,235,180,.40) 40%, transparent 70%),
    radial-gradient(circle, rgba(255,255,255,.95), rgba(255,255,255,.40) 40%, transparent 70%),
    radial-gradient(circle, rgba(255,255,255,.80), rgba(210,240,255,.40) 40%, transparent 70%),
    radial-gradient(circle, rgba(255,255,255,.90), rgba(255,240,190,.40) 40%, transparent 70%),
    radial-gradient(circle, rgba(255,255,255,.85), rgba(255,255,255,.35) 40%, transparent 70%),
    radial-gradient(circle, rgba(255,255,255,.95), rgba(200,235,255,.40) 40%, transparent 70%),
    radial-gradient(circle, rgba(255,255,255,.75), rgba(255,240,200,.35) 40%, transparent 70%);
  background-size: 7px 7px, 5px 5px, 9px 9px, 6px 6px, 7px 7px, 5px 5px, 8px 8px, 6px 6px, 9px 9px;
  background-position:
    14% 21%, 73% 11%, 38% 47%, 88% 38%, 26% 68%,
    59% 79%, 8% 52%, 47% 16%, 81% 66%;
  background-repeat: no-repeat;
  animation: sparkleTwinkle 2.3s ease-in-out infinite;
}

@keyframes sparkleTwinkle {
  0%,
  100% { opacity: .25; }
  30%  { opacity: 1; }
  55%  { opacity: .4; }
  80%  { opacity: .85; }
}

/* ── elite ──
   A rim glow on the PARENT rather than another overlay. A card can be both
   shiny and elite, and there are only two pseudo-elements — the sheen and the
   sparkles need both, so elite can't have one. It reads better as a rim
   anyway: elite is a status, not a surface finish. */
.card-shot.elite,
.board-tile.elite .tile-art,
.podium-slot.elite .podium-art,
.binder-slot.elite .slot-art,
.swipe-card.elite .swipe-art,
.cm-art.elite {
  animation: eliteRim 3.4s ease-in-out infinite;
}

@keyframes eliteRim {
  0%,
  100% { box-shadow: inset 0 0 0 2px rgba(237, 199, 114, .55), 0 0 14px rgba(237, 199, 114, .25); }
  50%  { box-shadow: inset 0 0 0 2px rgba(255, 232, 170, .95), 0 0 26px rgba(255, 210, 120, .55); }
}

/* Anyone who's asked the OS to stop moving things gets it static. */
@media (prefers-reduced-motion: reduce) {
  .card-shot.shiny::after,
  .board-tile.shiny .tile-art::after,
  .podium-slot.shiny .podium-art::after,
  .binder-slot.shiny .slot-art::after,
  .swipe-card.shiny .swipe-art::after,
  .cm-art.shiny::after,
  .card-shot.shiny::before,
  .board-tile.shiny .tile-art::before,
  .podium-slot.shiny .podium-art::before,
  .binder-slot.shiny .slot-art::before,
  .swipe-card.shiny .swipe-art::before,
  .cm-art.shiny::before,
  .card-shot.elite,
  .board-tile.elite .tile-art,
  .podium-slot.elite .podium-art,
  .binder-slot.elite .slot-art,
  .swipe-card.elite .swipe-art,
  .cm-art.elite { animation: none; }
}

.slot-remove:hover {
  background: rgba(120, 20, 20, .9);
  border-color: #ff8080;
}

/* ── ink fragment meter (2026-08-12) ──
   Fifteen pips you can watch fill, rather than a "4 / 15" to read. */
.vote-earnings {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  margin-bottom: 14px;
}

.frag-track {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 14px;
  border-radius: 20px;
  background: rgba(0, 0, 0, .3);
  border: 1px solid var(--line);
}
.frag-label {
  font-size: .7rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
}
.frag-count {
  font-size: .78rem;
  color: var(--gold);
  font-variant-numeric: tabular-nums;
}

.pips { display: flex; gap: 3px; }
.pip {
  width: 9px;
  height: 9px;
  border-radius: 2px;
  transform: rotate(45deg);          /* diamonds, echoing the Ink icon */
  background: rgba(255, 255, 255, .10);
  border: 1px solid rgba(255, 255, 255, .12);
  transition: background .25s, box-shadow .25s;
}
.pip.on {
  background: var(--gold);
  border-color: #ffe9b0;
  box-shadow: 0 0 6px rgba(237, 199, 114, .6);
}
/* The one just earned gets a single pop, so a fragment landing is visible
   even when the +N popup is off-screen on a small display. */
.pip.just { animation: pipPop .45s ease-out; }
@keyframes pipPop {
  0%   { transform: rotate(45deg) scale(1); }
  45%  { transform: rotate(45deg) scale(1.9); box-shadow: 0 0 14px rgba(255, 235, 170, .95); }
  100% { transform: rotate(45deg) scale(1); }
}

.vote-meta {
  display: flex;
  gap: 14px;
  align-items: baseline;
  font-size: .8rem;
}
.streak { color: #6fcf7f; font-weight: 600; }
.ink-next { opacity: .55; }

@media (prefers-reduced-motion: reduce) {
  .pip.just { animation: none; }
}

/* ── Ink badge (2026-08-12) ──
   Persistent balance in the corner, distinct from the fragment meter: the
   meter shows progress toward the NEXT Ink, this shows what's banked. */
.ink-badge {
  position: fixed;
  top: 12px;
  right: 12px;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 7px 14px;
  border-radius: 20px;
  background: rgba(10, 12, 26, .92);
  border: 1px solid var(--gold-dim);
  box-shadow: 0 4px 18px rgba(0, 0, 0, .5);
  font-size: .85rem;
}
.ink-gem {
  color: var(--gold);
  font-size: .95rem;
  line-height: 1;
  text-shadow: 0 0 8px rgba(237, 199, 114, .7);
}
.ink-amount { color: var(--gold); font-weight: 700; font-variant-numeric: tabular-nums; }
.ink-word { color: var(--muted); font-size: .75rem; }

@media (max-width: 520px) {
  .ink-badge { top: 8px; right: 8px; padding: 5px 11px; font-size: .78rem; }
}

/* ── ink claim codes (2026-08-12) ── */
.ink-code {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: clamp(1.1rem, 4vw, 1.6rem);
  letter-spacing: .12em;
  text-align: center;
  color: var(--gold);
  background: #0d1024;
  border: 1px solid var(--gold-dim);
  border-radius: 10px;
  padding: 14px 10px;
  margin: 10px 0;
  user-select: all;          /* one tap selects the whole code */
  word-break: break-all;
}

#past-codes { margin-top: 18px; }
#past-codes summary { cursor: pointer; font-size: .85rem; color: var(--muted); }

.code-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 7px 0;
  border-bottom: 1px solid var(--line);
  font-size: .82rem;
}
.code-row:last-child { border-bottom: 0; }
.code-row code { font-size: .8rem; }
.code-row .code-state { margin-left: auto; opacity: .6; }
.code-row.used { opacity: .45; }
.code-row.used code { text-decoration: line-through; }
