/* Shared skin for the landing and the platform.
   Static files only: nginx serves this directory as-is, so there is no build
   step, no bundler and nothing here that needs one. */

:root {
  --bg:      #0b0e13;
  --bg-soft: #11151c;
  --panel:   #151a22;
  --line:    #242b36;
  --line-lit:#38424f;
  --text:    #e6ebf2;
  --dim:     #8b95a3;
  --dimmer:  #5d6875;

  --grass:  #5ec269;
  --ball:   #e2534a;
  --gold:   #f0c453;
  --sky:    #7aa2f7;
  --violet: #a884f3;

  --ok:   var(--grass);
  --warn: var(--gold);
  --bad:  var(--ball);

  --pixel: "Silkscreen", ui-monospace, monospace;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, "JetBrains Mono", Menlo, Consolas, monospace;

  --radius: 12px;
  --wrap: 62rem;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.6 var(--sans);
  -webkit-font-smoothing: antialiased;
}

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

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 1.25rem; }

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

.mark {
  display: inline-flex; align-items: center; gap: .6rem;
  font-family: var(--pixel); font-size: .95rem; letter-spacing: .02em;
  color: var(--text); text-decoration: none;
}
.mark .ball {
  width: 1.15em; height: 1.15em; flex: none; border-radius: 50%;
  background: linear-gradient(var(--ball) 0 45%, #e9edf3 55% 100%);
  box-shadow: inset 0 0 0 2px #0b0e13, 0 0 0 2px var(--line-lit);
  position: relative;
}
.mark .ball::after {
  content: ""; position: absolute; inset: 38% 38%;
  background: #0b0e13; border-radius: 50%; box-shadow: 0 0 0 2px #e9edf3;
}

/* --- site chrome --------------------------------------------------------- */

.topbar {
  position: sticky; top: 0; z-index: 20;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}
.topbar .wrap {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; min-height: 3.75rem;
}
.topbar nav { display: flex; align-items: center; gap: 1.4rem; }
.topbar nav a.quiet {
  color: var(--dim); text-decoration: none; font-size: .9rem;
}
.topbar nav a.quiet:hover { color: var(--text); }
@media (max-width: 34rem) { .topbar nav a.quiet { display: none; } }

/* --- buttons ------------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  padding: .68rem 1.15rem; border-radius: 9px; border: 1px solid transparent;
  font: 600 .95rem/1 var(--sans); text-decoration: none; cursor: pointer;
  transition: transform .12s ease, background .12s ease, border-color .12s ease;
}
.btn:active { transform: translateY(1px); }
.btn[disabled] { opacity: .5; cursor: not-allowed; }

.btn-primary { background: var(--grass); color: #08130a; }
.btn-primary:hover { background: #6ed77a; }

.btn-ghost { background: transparent; color: var(--text); border-color: var(--line-lit); }
.btn-ghost:hover { border-color: var(--dim); background: var(--bg-soft); }

.btn-lg { padding: .85rem 1.5rem; font-size: 1rem; }

/* --- hero ---------------------------------------------------------------- */

.hero { position: relative; overflow: hidden; padding: 4.5rem 0 3.5rem; }
.hero::before {
  /* One soft light source behind the headline. Cheap, and it stops the page
     from reading as a flat wall of dark grey. */
  content: ""; position: absolute; inset: -30% 0 auto; height: 40rem;
  background: radial-gradient(50% 50% at 50% 40%, rgba(94,194,105,.13), transparent 70%);
  pointer-events: none;
}
/* Centred on purpose: with the copy left-aligned the right half of a desktop
   screen sits empty, and there is no illustration to put there. */
.hero .wrap { position: relative; text-align: center; }
.hero h1, .hero .lede { margin-left: auto; margin-right: auto; }
.hero .cta-row { justify-content: center; }

.eyebrow {
  font-family: var(--pixel); font-size: .72rem; letter-spacing: .12em;
  color: var(--grass); text-transform: uppercase; margin: 0 0 1.1rem;
}
h1 {
  font-size: clamp(2.1rem, 6.5vw, 3.7rem); line-height: 1.06;
  letter-spacing: -.03em; font-weight: 800; margin: 0 0 1.1rem; max-width: 16ch;
}
h1 .hl { color: var(--grass); }
.lede {
  font-size: clamp(1.02rem, 2.2vw, 1.18rem); color: var(--dim);
  max-width: 48ch; margin: 0 0 2rem;
}
.cta-row { display: flex; flex-wrap: wrap; gap: .75rem; align-items: center; }
.cta-note { color: var(--dimmer); font-size: .85rem; margin: 1rem 0 0; }

/* --- sections ------------------------------------------------------------ */

section { padding: 3.5rem 0; }
h2 {
  font-size: clamp(1.4rem, 3.4vw, 1.9rem); letter-spacing: -.02em;
  font-weight: 750; margin: 0 0 .6rem;
}
.section-sub { color: var(--dim); margin: 0 0 2rem; max-width: 52ch; }

.rule { border: 0; border-top: 1px solid var(--line); margin: 0; }

/* --- cards --------------------------------------------------------------- */

.cards { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
.card {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1.4rem;
}
.card .ico { font-size: 1.6rem; line-height: 1; display: block; margin-bottom: .8rem; }
.card h3 { font-size: 1.02rem; margin: 0 0 .45rem; font-weight: 700; }
.card p { margin: 0; color: var(--dim); font-size: .93rem; }

/* --- the joke banner ----------------------------------------------------- */

.banner {
  border: 1px dashed var(--line-lit); border-radius: var(--radius);
  padding: 1.5rem 1.6rem; background: var(--bg-soft);
  display: flex; gap: 1.1rem; align-items: flex-start;
}
.banner .ico { font-size: 1.7rem; line-height: 1.2; flex: none; }
.banner p { margin: 0; color: var(--dim); font-size: .97rem; }
.banner p strong { color: var(--text); font-weight: 650; }

/* --- steps --------------------------------------------------------------- */

.steps { list-style: none; counter-reset: step; padding: 0; margin: 0; display: grid; gap: .9rem; }
.steps li {
  counter-increment: step; position: relative; padding: 1.05rem 1.2rem 1.05rem 3.6rem;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
}
.steps li::before {
  content: counter(step); position: absolute; left: 1.15rem; top: 1.05rem;
  width: 1.7rem; height: 1.7rem; border-radius: 7px;
  background: var(--bg); border: 1px solid var(--line-lit); color: var(--grass);
  font: 700 .85rem/1.7rem var(--mono); text-align: center;
}
.steps b { display: block; font-weight: 650; margin-bottom: .15rem; }
.steps span { color: var(--dim); font-size: .93rem; }

/* --- live status --------------------------------------------------------- */

.status-strip {
  display: flex; flex-wrap: wrap; gap: 1.6rem 2.4rem; align-items: center;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1.15rem 1.4rem;
}
.stat .k {
  display: block; font-size: .68rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--dimmer); margin-bottom: .25rem;
}
.stat .v { font: 600 1.05rem/1.2 var(--mono); }
.dot {
  display: inline-block; width: .55em; height: .55em; border-radius: 50%;
  margin-right: .45em; vertical-align: .05em;
}
.dot.ok { background: var(--ok); box-shadow: 0 0 0 3px rgba(94,194,105,.18); }
.dot.bad { background: var(--bad); box-shadow: 0 0 0 3px rgba(226,83,74,.18); }
.dot.warn { background: var(--warn); }
.ok { color: var(--ok); } .bad { color: var(--bad); } .warn { color: var(--warn); }

/* --- invite -------------------------------------------------------------- */

.invite {
  background: linear-gradient(160deg, rgba(168,132,243,.10), rgba(94,194,105,.07));
  border: 1px solid var(--line-lit); border-radius: 16px; padding: 2rem;
}
.invite-msg {
  font: .92rem/1.6 var(--mono); color: var(--dim); white-space: pre-wrap;
  background: var(--bg); border: 1px solid var(--line); border-radius: 9px;
  padding: 1rem 1.1rem; margin: 0 0 1.1rem; word-break: break-word;
}

/* --- forms --------------------------------------------------------------- */

label.field { display: block; margin-bottom: 1rem; }
label.field .lbl {
  display: block; font-size: .82rem; color: var(--dim); margin-bottom: .4rem;
}
input[type="text"] {
  width: 100%; padding: .7rem .9rem; border-radius: 9px;
  background: var(--bg); border: 1px solid var(--line-lit);
  color: var(--text); font: 1rem var(--mono);
}
input[type="text"]:focus { outline: 2px solid var(--grass); outline-offset: 1px; }
.hint { color: var(--dimmer); font-size: .82rem; margin: .45rem 0 0; }

.notice {
  border-radius: 9px; padding: .8rem 1rem; font-size: .92rem;
  border: 1px solid var(--line-lit); background: var(--bg-soft); margin: 1rem 0 0;
}
.notice.bad { border-color: rgba(226,83,74,.5); color: #f4a49e; }
.notice.ok  { border-color: rgba(94,194,105,.5); color: #a9e5b1; }

/* --- choice grid (welcome gift) ------------------------------------------ */

.choices { display: grid; gap: .75rem; grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr)); }
.choice {
  background: var(--bg); border: 1px solid var(--line-lit); border-radius: 10px;
  padding: 1rem; cursor: pointer; text-align: left; color: var(--text);
  font: inherit; transition: border-color .12s ease, background .12s ease;
}
.choice:hover { border-color: var(--grass); background: var(--bg-soft); }
.choice[aria-pressed="true"] { border-color: var(--grass); background: rgba(94,194,105,.09); }
.choice b { display: block; font-size: 1rem; margin-bottom: .2rem; }
.choice span { color: var(--dim); font-size: .82rem; font-family: var(--mono); }

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

footer {
  border-top: 1px solid var(--line); padding: 2.5rem 0 3.5rem;
  color: var(--dimmer); font-size: .87rem;
}
footer .wrap { display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between; }
footer a { color: var(--dim); }

/* --- utility ------------------------------------------------------------- */

.skeleton { color: var(--dimmer); }
[hidden] { display: none !important; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* --- admin table ---------------------------------------------------------
   The admin queue is a list of decisions, not a spreadsheet, so rows are tall
   and the action sits at the end of each one rather than in a toolbar that
   needs a selection first. */

.queue { display: grid; gap: .7rem; }

.queue-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: .9rem 1.2rem;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1rem 1.15rem;
}
.queue-row.is-pending { border-color: rgba(240,196,83,.45); }

.queue-who { flex: 1 1 14rem; min-width: 0; }
.queue-who b { display: block; font: 650 1rem/1.3 var(--mono); }
.queue-who span {
  display: block; color: var(--dimmer); font-size: .82rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.queue-when { color: var(--dimmer); font-size: .8rem; flex: 0 0 auto; }

.badge {
  display: inline-block; padding: .18rem .55rem; border-radius: 999px;
  font: 600 .72rem/1.5 var(--sans); letter-spacing: .02em;
  border: 1px solid currentColor;
}
.badge.pending  { color: var(--gold); }
.badge.approved { color: var(--grass); }
.badge.rejected { color: var(--ball); }

.queue-actions { display: flex; gap: .5rem; flex: 0 0 auto; }
.btn-sm { padding: .45rem .8rem; font-size: .85rem; }
.btn-danger { background: transparent; color: #f4a49e; border-color: rgba(226,83,74,.5); }
.btn-danger:hover { background: rgba(226,83,74,.12); }

.count-pill {
  display: inline-block; margin-left: .55rem; padding: .1rem .5rem;
  border-radius: 999px; background: var(--gold); color: #221a05;
  font: 700 .78rem/1.5 var(--sans); vertical-align: .12em;
}

/* --- stickers ------------------------------------------------------------
   Decoration, and treated as such: aria-hidden in the markup, and every
   absolutely-positioned one disappears on narrow screens rather than landing
   on top of the words. They are the group's own WhatsApp stickers, so they do
   more work for the tone than any illustration commissioned for the job. */

.sticker {
  position: absolute; pointer-events: none; user-select: none;
  filter: drop-shadow(0 8px 18px rgba(0,0,0,.5));
  z-index: 1;
}

/* Inline variants sit in the text flow, so they need none of the above. */
.sticker-inline {
  position: static; display: inline-block; vertical-align: middle;
  filter: drop-shadow(0 4px 10px rgba(0,0,0,.45));
}

.sticker-hero-l { left: -1rem;  top: 3.5rem;  width: 8rem; transform: rotate(-13deg); }
.sticker-hero-r { right: -1rem; top: 8.5rem;  width: 7rem; transform: rotate(11deg); }
.sticker-steps  { right: 0;     top: 1.2rem;  width: 6.5rem; transform: rotate(9deg); }
.sticker-invite { right: 1rem;  bottom: 1rem; width: 7.5rem; transform: rotate(-8deg); }

/* Below this the columns are too narrow for anything to float beside them,
   and a sticker over the headline is worse than no sticker. */
@media (max-width: 68rem) {
  .sticker-hero-l, .sticker-hero-r { display: none; }
}
@media (max-width: 46rem) {
  .sticker-steps, .sticker-invite { display: none; }
}

/* The invite card and the steps heading become positioning contexts only so
   their stickers have something to anchor to. */
.invite { position: relative; overflow: hidden; }
.section-head { position: relative; }

/* Sticker used where an emoji icon used to be. Sized in rem so it tracks the
   card's own type scale rather than being pinned to a pixel size. */
.ico-sticker {
  display: block; width: 3.4rem; height: 3.4rem;
  object-fit: contain; margin: -.3rem 0 .7rem -.35rem;
  filter: drop-shadow(0 5px 12px rgba(0,0,0,.45));
}

/* The one that rides along with the "server is asleep" message. It only ever
   appears when the game server is unreachable, so it is the page's way of
   admitting bad news without a red error box. */
.sticker-offline {
  width: 3.2rem; height: 3.2rem; object-fit: contain;
  margin-left: auto; transform: rotate(-6deg);
  filter: drop-shadow(0 5px 12px rgba(0,0,0,.45));
}

.sticker-admin {
  width: 4.5rem; height: 4.5rem; object-fit: contain;
  vertical-align: -1.1rem; margin-left: .6rem;
  filter: drop-shadow(0 5px 12px rgba(0,0,0,.45));
}

.sticker-beside {
  width: 4rem; height: 4rem; object-fit: contain; flex: none;
  filter: drop-shadow(0 5px 12px rgba(0,0,0,.45));
}

/* --- starter picker ------------------------------------------------------
   385 options cannot be a grid of buttons, so this is a search box over a
   filtered, capped list. The cap matters: rendering all 385 cards means 385
   sprite requests on a page nobody asked to browse. */

.picker-controls { display: grid; gap: .8rem; margin-bottom: 1rem; }

.picker-search { position: relative; }
.picker-search input { padding-left: 2.4rem; font-family: var(--sans); }
.picker-search::before {
  content: "🔎"; position: absolute; left: .8rem; top: 50%;
  transform: translateY(-50%); font-size: .95rem; opacity: .6; pointer-events: none;
}

.type-chips { display: flex; flex-wrap: wrap; gap: .4rem; }
.chip {
  padding: .3rem .65rem; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--line-lit); background: transparent; color: var(--dim);
  font: 600 .76rem/1.4 var(--sans); text-transform: capitalize;
  transition: border-color .12s ease, color .12s ease, background .12s ease;
}
.chip:hover { color: var(--text); border-color: var(--dim); }
.chip[aria-pressed="true"] { color: #08130a; background: var(--grass); border-color: var(--grass); }

.picker-count { color: var(--dimmer); font-size: .82rem; }

.picker-grid {
  display: grid; gap: .55rem; max-height: 24rem; overflow-y: auto;
  grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
  padding: .3rem; margin: 0 -.3rem;
  /* Its own scroll container: the list is long and the confirm button below it
     must stay reachable without scrolling past 385 entries. */
  scrollbar-width: thin;
}

.mon {
  background: var(--bg); border: 1px solid var(--line-lit); border-radius: 10px;
  padding: .6rem .5rem .55rem; cursor: pointer; color: var(--text);
  font: inherit; text-align: center; transition: border-color .12s ease, background .12s ease;
}
.mon:hover { border-color: var(--grass); background: var(--bg-soft); }
.mon[aria-pressed="true"] { border-color: var(--grass); background: rgba(94,194,105,.12); }
.mon img {
  display: block; width: 56px; height: 56px; margin: 0 auto .25rem;
  image-rendering: pixelated; object-fit: contain;
}
.mon b { display: block; font-size: .82rem; font-weight: 650; line-height: 1.25; }
.mon span { display: block; color: var(--dimmer); font-size: .68rem; text-transform: capitalize; }

.picker-empty { color: var(--dim); font-size: .9rem; padding: 1.5rem .3rem; }

.picked-banner {
  display: flex; align-items: center; gap: .8rem; margin-top: 1rem;
  padding: .7rem .9rem; border-radius: 10px;
  background: rgba(94,194,105,.09); border: 1px solid rgba(94,194,105,.45);
}
.picked-banner img { width: 44px; height: 44px; image-rendering: pixelated; }
.picked-banner b { font-size: 1rem; }

/* --- what a player owns in-game -----------------------------------------
   Read from the world save, which the game writes every few seconds for the
   party and every few minutes for the bag. Near-live, never live, and the
   freshness line says so rather than letting the page imply otherwise. */

.owned-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem;
}
.owned-fresh { color: var(--dimmer); font-size: .78rem; font-family: var(--mono); }

.team { display: grid; gap: .6rem; grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr)); }

.pkmn {
  position: relative; background: var(--bg); border: 1px solid var(--line-lit);
  border-radius: 10px; padding: .7rem .5rem .6rem; text-align: center;
}
.pkmn.is-shiny { border-color: var(--gold); background: rgba(240,196,83,.07); }
.pkmn img { width: 60px; height: 60px; image-rendering: pixelated; object-fit: contain; display: block; margin: 0 auto .3rem; }
.pkmn b { display: block; font-size: .86rem; font-weight: 650; line-height: 1.25; }
.pkmn .lvl { display: block; color: var(--dim); font-size: .74rem; font-family: var(--mono); }
.pkmn .tipos { display: block; color: var(--dimmer); font-size: .66rem; text-transform: capitalize; margin-top: .15rem; }
.pkmn .star { position: absolute; top: .35rem; right: .45rem; font-size: .8rem; }
.pkmn .mote { display: block; color: var(--gold); font-size: .7rem; font-style: italic; }

.bag { display: grid; gap: .4rem; grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr)); }
.slot {
  display: flex; align-items: center; gap: .5rem;
  background: var(--bg); border: 1px solid var(--line); border-radius: 8px;
  padding: .45rem .6rem; font-size: .8rem;
}
.slot .n {
  flex: none; min-width: 1.9rem; text-align: right;
  font: 700 .82rem var(--mono); color: var(--grass);
}
.slot .l { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dim); }

.empty-note { color: var(--dimmer); font-size: .88rem; margin: 0; }
