/* Wikicards landing. Tokens: apps/mobile/theme (palette « Prisme »), dark only. */

@font-face {
  font-family: "Dela Gothic One";
  src: url("../fonts/dela-gothic-one.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-400.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-600.woff2") format("woff2");
  font-weight: 600;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("../fonts/jetbrains-mono-400.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("../fonts/jetbrains-mono-700.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}

:root {
  --bg: #07070c;
  --hollow: #0e0e15;
  --surface: #111119;
  --text: #f2f2f8;
  --muted: #8b8b9e;
  --text-62: rgba(242, 242, 248, 0.62);
  --text-56: rgba(242, 242, 248, 0.56);
  --border: rgba(242, 242, 248, 0.1);
  --cyan: #3df2ff;
  --magenta: #ff3da6;
  --violet: #9b7cff;
  --lime: #c8ff4a;
  --amber: #ffb13d;
  --prisme: linear-gradient(90deg, #3df2ff 0%, #9b7cff 48%, #ff3da6 100%);
  --font-display: "Dela Gothic One", "Arial Black", sans-serif;
  --font-body: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
  /* Motion: settled, never elastic. */
  --ease-out: cubic-bezier(0.33, 1, 0.68, 1);
  --gutter: 20px;
  color-scheme: dark;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  /* Anchors and focused elements stay clear of the fixed nav. */
  scroll-padding-top: 84px;
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 400 1rem / 1.5 var(--font-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  /* biome-ignore lint/suspicious/noDuplicateProperties: hidden is the fallback for Safari before 16, which ignores clip */
  overflow-x: clip;
}

img,
video,
svg {
  display: block;
  max-width: 100%;
}

a {
  color: inherit;
}

:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 3px;
  border-radius: 4px;
}

/* Skip link: off screen until it takes focus. */
.skip {
  position: absolute;
  left: 16px;
  top: -64px;
  z-index: 30;
  padding: 12px 16px;
  border-radius: 8px;
  background: var(--text);
  color: var(--bg);
}
.skip:focus {
  top: 16px;
}

.sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.wrap {
  width: min(100%, 1120px + 2 * var(--gutter));
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 56px;
  margin: 0;
  padding: 0 28px;
  border-radius: 999px;
  /* Shrinks under 390 px so the store label still fits a 320 px screen. */
  font: 400 clamp(0.8125rem, 4.1vw, 1rem) / 1 var(--font-display);
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 0.16s var(--ease-out);
}
.btn--primary {
  background: var(--cyan);
  color: var(--bg);
}
.btn--primary:hover {
  background: #8af7ff;
}
.btn--ghost {
  border: 1px solid rgba(242, 242, 248, 0.22);
  color: var(--text);
}
.btn--s {
  position: relative;
  height: 40px;
  padding: 0 18px;
  font-size: 0.8125rem;
}
/* 40 px tall, 52 px to the finger. */
.btn--s::after {
  content: "";
  position: absolute;
  inset: -6px 0;
}
.btn__icon {
  width: 20px;
  height: 20px;
  margin-top: -3px;
}

/* ---------- Nav ---------- */

.nav {
  position: fixed;
  inset: 0 0 auto;
  z-index: 20;
  border-bottom: 1px solid transparent;
  transition:
    background-color 0.24s var(--ease-out),
    border-color 0.24s var(--ease-out);
}
.nav.is-stuck {
  background: rgba(7, 7, 12, 0.78);
  border-color: var(--border);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
}
.nav__in {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 68px;
}
.nav__links {
  display: none;
  gap: 28px;
  margin-left: auto;
  font-size: 0.9375rem;
}
.nav__links a {
  white-space: nowrap;
  color: var(--text-62);
  text-decoration: none;
  transition: color 0.16s var(--ease-out);
}
.nav__links a:hover {
  color: var(--text);
}
.nav__discord {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  position: relative;
  height: 40px;
  margin-left: auto;
  font-size: 0.9375rem;
  color: var(--text-62);
  text-decoration: none;
  transition: color 0.16s var(--ease-out);
}
.nav__discord:hover {
  color: var(--text);
}
/* 44 px tap target around the 20 px icon, without moving the bar. */
.nav__discord::after {
  content: "";
  position: absolute;
  inset: -2px -12px;
}
.nav__discord svg {
  flex: none;
  width: 20px;
  height: 20px;
}
/* Phones: the icon alone. */
.nav__discord span {
  display: none;
}

.logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  /* Tap target. */
  min-height: 44px;
  text-decoration: none;
}
.logo__icon {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 24%;
  background: var(--bg);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
}
.logo__icon svg {
  width: 20px;
  height: 16px;
}
.logo__word {
  font: 400 1rem / 1 var(--font-display);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #fff;
}

/* ---------- Hero ---------- */

.hero {
  position: relative;
  /* Halos bleed into the next section instead of being cut at the edge. */
  overflow-x: clip;
  padding: 108px 0 64px;
}
.hero__in {
  position: relative;
  display: grid;
  /* minmax(0, ...): a long nowrap child must not widen the column past the screen. */
  grid-template-columns: minmax(0, 1fr);
  gap: 40px;
}
.hero__title {
  margin: 20px 0 0;
  font: 400 clamp(1.4rem, 7.4vw, 3.25rem) / 1.06 var(--font-display);
  text-transform: uppercase;
  text-wrap: balance;
}
.prisme {
  display: block;
  background: var(--prisme);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.hero__sub {
  max-width: 32em;
  margin: 20px 0 0;
  font-size: 1.0625rem;
  color: var(--text-62);
}
.hero__note {
  margin: 16px 0 0;
  font-size: 0.875rem;
  color: var(--text-56);
}
/* Plain inline text: an inline-flex box would take its baseline from the star and sit higher
   than the rest of the line. */
.rating {
  color: var(--text);
}
.nowrap {
  white-space: nowrap;
}
.rating svg {
  display: inline-block;
  width: 13px;
  height: 13px;
  margin-right: 6px;
  vertical-align: -1px;
  color: var(--amber);
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 7px 12px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  background: rgba(7, 7, 12, 0.62);
  font: 400 0.6875rem / 1 var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.pill__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--lime);
}

.cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 20px;
  margin-top: 28px;
}
.cta--center {
  justify-content: center;
}

/* Background light: big soft blots on the near-black ground, drifting slowly. */
.halo {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  animation: drift 9s ease-in-out infinite alternate;
}
.halo--magenta {
  left: -260px;
  bottom: -320px;
  width: 760px;
  height: 760px;
  background: radial-gradient(closest-side, rgba(255, 61, 166, 0.34), rgba(255, 61, 166, 0));
}
.halo--violet {
  right: -220px;
  top: -300px;
  width: 760px;
  height: 760px;
  background: radial-gradient(closest-side, rgba(155, 124, 255, 0.3), rgba(155, 124, 255, 0));
  animation-duration: 11s;
  animation-direction: alternate-reverse;
}
.halo--cyan {
  right: 4%;
  bottom: -220px;
  width: 460px;
  height: 460px;
  background: radial-gradient(closest-side, rgba(61, 242, 255, 0.16), rgba(61, 242, 255, 0));
  animation-duration: 8s;
}
@keyframes drift {
  from {
    translate: -18px 10px;
  }
  to {
    translate: 22px -14px;
  }
}

/* ---------- Hero stage: phone, cards, booster (all sizes in cqw of the stage) ---------- */

.stage {
  position: relative;
  /* 96%: the tilted card on the left keeps its corner clear of the screen edge. */
  width: min(96%, 440px);
  margin-inline: auto;
  aspect-ratio: 560 / 690;
  container-type: inline-size;
}
.stage__item {
  position: absolute;
}
.stage__phone {
  --pw: 54cqw;
  left: 26cqw;
  top: 3cqw;
  z-index: 2;
  width: var(--pw);
}
.stage__left {
  --card-w: 31cqw;
  left: 1cqw;
  top: 10cqw;
  /* Behind the phone, which only covers the card's right edge. */
  z-index: 1;
  rotate: -9deg;
}
.stage__right {
  --card-w: 32cqw;
  left: 69cqw;
  top: 63cqw;
  z-index: 3;
  rotate: 7deg;
}
.stage__booster {
  --booster-w: 27cqw;
  left: 2cqw;
  top: 78cqw;
  z-index: 3;
  rotate: -8deg;
}

/* Pause control (WCAG 2.2.2): stops the video and every looping animation of the page. */
.stage__pause {
  position: absolute;
  left: 50%;
  bottom: 0;
  z-index: 4;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid rgba(242, 242, 248, 0.22);
  border-radius: 50%;
  background: rgba(7, 7, 12, 0.78);
  color: var(--text-62);
  translate: -50% 50%;
  cursor: pointer;
}
.stage__pause svg {
  width: 16px;
  height: 16px;
}
.stage__pause-play,
.is-paused .stage__pause-bars {
  display: none;
}
.is-paused .stage__pause-play {
  display: inline;
}
.is-paused *,
.is-paused *::before,
.is-paused *::after,
.is-idle *,
.is-idle *::before,
.is-idle *::after {
  /* biome-ignore lint/complexity/noImportantStyles: the pause has to win over every animation rule */
  animation-play-state: paused !important;
}

.float {
  animation: float 7s ease-in-out infinite alternate;
}
.float--b {
  animation-duration: 8.5s;
  animation-direction: alternate-reverse;
}
.float--c {
  animation-duration: 6s;
}
@keyframes float {
  from {
    translate: 0 -5px;
  }
  to {
    translate: 0 6px;
  }
}

/* The phone is one big button: a tap pauses or resumes the video and the looping animations. */
.phone {
  display: block;
  width: 100%;
  border: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  padding: calc(var(--pw) * 0.032);
  border-radius: calc(var(--pw) * 0.165);
  background: linear-gradient(150deg, #34343f 0%, #14141c 38%, #23232e 100%);
  box-shadow:
    inset 0 0 0 1px rgba(242, 242, 248, 0.22),
    0 30px 60px rgba(0, 0, 0, 0.6);
}
.phone__screen {
  position: relative;
  display: block;
  aspect-ratio: 1106 / 2404;
  overflow: hidden;
  border-radius: calc(var(--pw) * 0.136);
  background: var(--bg);
}
/* Paused: a play mark over the frozen screen (a disc, and a triangle cut with clip-path). */
.phone__screen::before,
.phone__screen::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  opacity: 0;
  transition: opacity 0.2s var(--ease-out);
}
.phone__screen::before {
  z-index: 1;
  width: 22%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: rgba(7, 7, 12, 0.72);
  box-shadow: inset 0 0 0 1px rgba(242, 242, 248, 0.22);
}
.phone__screen::after {
  z-index: 2;
  width: 7.5%;
  aspect-ratio: 0.88;
  background: var(--text);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
  translate: 12% 0;
}
.is-paused .phone__screen::before,
.is-paused .phone__screen::after {
  opacity: 1;
}
/* While the video loads (it is fetched after the page): the logo's W, pulsing gently. */
.phone__loader {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  animation: blink 1.4s ease-in-out infinite alternate;
}
.phone__loader svg {
  width: 26%;
  height: auto;
  aspect-ratio: 10 / 8;
}
@keyframes blink {
  from {
    opacity: 0.2;
  }
  to {
    opacity: 1;
  }
}
.phone__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.4s var(--ease-out);
}
noscript .phone__video {
  opacity: 1;
}
.phone__screen.is-ready .phone__video {
  opacity: 1;
}
/* The W stays under the video: if the video never shows, the logo does. */
.phone__screen.is-ready .phone__loader {
  animation: none;
}

/* ---------- Card v2: 216 x 332 base, every length scales with the card width (--k) ---------- */

/* Same face as the app (components/Card.tsx): photo, one frame image per rarity laid over it
   (window cut out, fade baked in), then name, description and footer as live text. */
.card {
  --ink: var(--text);
  --soft: var(--muted);
  --foot: var(--muted);
  position: relative;
  width: var(--card-w, 216px);
  aspect-ratio: 216 / 332;
  container-type: inline-size;
}
/* Tilt only where a pointer drives it: on touch the 3D transform just costs a layer per card. */
@media (hover: hover) and (pointer: fine) {
  .card,
  .booster {
    transform: perspective(900px) rotateX(calc(var(--ty, 0) * 1deg))
      rotateY(calc(var(--tx, 0) * 1deg));
    transition: transform 0.32s var(--ease-out);
  }
}
.card--pc {
  --soft: rgba(242, 242, 248, 0.66);
  --foot: #3df2ff;
}
.card--r {
  --ink: #fff;
  --soft: rgba(255, 255, 255, 0.72);
  --foot: #ff9ccf;
}
.card--sr {
  --ink: #fff;
  --soft: rgba(255, 255, 255, 0.78);
  --foot: #d9ccff;
}
.card--ur {
  --ink: #fff;
  --soft: rgba(255, 255, 255, 0.8);
  --foot: #c8ff4a;
}
.card--l {
  --ink: #fff;
  --soft: rgba(255, 255, 255, 0.78);
  --foot: #ffb13d;
}

.card__in {
  --k: calc(100cqw / 216);
  position: absolute;
  inset: 0;
  border-radius: calc(var(--k) * 12);
  text-align: center;
}
/* Card put forward (hero): deep black drop shadow, no colored glow, the frame carries the tier. */
.card--lift .card__in {
  background: var(--hollow);
  box-shadow: 0 calc(var(--k) * 22) calc(var(--k) * 40) rgba(0, 0, 0, 0.6);
}

.card__photo {
  position: absolute;
  left: calc(var(--k) * 9);
  top: calc(var(--k) * 9);
  width: calc(var(--k) * 198);
  height: calc(var(--k) * 192);
  overflow: hidden;
  isolation: isolate;
  background: var(--surface);
}
.card__blur,
.card__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
}
/* Only wide logos and narrow portraits carry a blurred copy: the sharp image sits on it whole. */
.card__blur {
  scale: 1.3;
  filter: blur(calc(var(--k) * 12));
}
.card--contain .card__img {
  object-fit: contain;
}
.card__frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
}
.card__credit {
  position: absolute;
  right: calc(var(--k) * 16);
  top: calc(var(--k) * 189);
  font: 400 calc(var(--k) * 5) / calc(var(--k) * 7) var(--font-mono);
  letter-spacing: 0.08em;
  color: rgba(255, 255, 255, 0.6);
}

.card__texts {
  position: absolute;
  left: calc(var(--k) * 16);
  top: calc(var(--k) * 208);
  display: flex;
  flex-direction: column;
  align-items: center;
  width: calc(var(--k) * 184);
  height: calc(var(--k) * 84);
  overflow: hidden;
}
.card__title,
.card__text {
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
}
.card__title {
  align-self: stretch;
  margin: 0;
  font: 400 calc(var(--k) * 16) / calc(var(--k) * 20) var(--font-display);
  color: var(--ink);
  -webkit-line-clamp: 2;
  line-clamp: 2;
}
.card__sub {
  margin: calc(var(--k) * 4) 0 0;
  font: 400 calc(var(--k) * 8.5) / calc(var(--k) * 13) var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--soft);
}
.card__text {
  width: calc(var(--k) * 180);
  margin: calc(var(--k) * 4) 0 0;
  font: 400 calc(var(--k) * 10) / calc(var(--k) * 13) var(--font-body);
  color: var(--soft);
  -webkit-line-clamp: 3;
  line-clamp: 3;
}
.card__sub + .card__text {
  margin-top: 0;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}

.card__foot {
  position: absolute;
  left: calc(var(--k) * 16);
  top: calc(var(--k) * 304);
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: calc(var(--k) * 184);
  height: calc(var(--k) * 12);
  margin: 0;
  font: 400 calc(var(--k) * 8.5) / calc(var(--k) * 11) var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
}
.card__rarity {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--k) * 4);
  font-weight: 700;
  color: var(--foot);
}
.card__rarity svg {
  width: calc(var(--k) * 8);
  height: calc(var(--k) * 8);
}

/* Ultra rare: lime foil on the frame and four-point sparkles (the app's HoloOverlay, mode 1).
   Both are brighter near a light that wanders over the card, or follows the pointer. */
.card__shine {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: calc(var(--k) * 12);
  -webkit-mask:
    radial-gradient(
      circle closest-side,
      #000,
      rgba(0, 0, 0, 0.9) 15%,
      rgba(0, 0, 0, 0.68) 30%,
      rgba(0, 0, 0, 0.37) 50%,
      rgba(0, 0, 0, 0.2) 70%,
      rgba(0, 0, 0, 0.12)
    )
    62% 60% / 200% 200% no-repeat;
  mask:
    radial-gradient(
      circle closest-side,
      #000,
      rgba(0, 0, 0, 0.9) 15%,
      rgba(0, 0, 0, 0.68) 30%,
      rgba(0, 0, 0, 0.37) 50%,
      rgba(0, 0, 0, 0.2) 70%,
      rgba(0, 0, 0, 0.12)
    )
    62% 60% / 200% 200% no-repeat;
  pointer-events: none;
  animation: light 13s ease-in-out infinite;
}
/* The mask is twice the card: at position p the light sits at (100 % - p). */
@keyframes light {
  0%,
  100% {
    -webkit-mask-position: 62% 60%;
    mask-position: 62% 60%;
  }
  25% {
    -webkit-mask-position: 36% 68%;
    mask-position: 36% 68%;
  }
  50% {
    -webkit-mask-position: 30% 38%;
    mask-position: 30% 38%;
  }
  75% {
    -webkit-mask-position: 60% 30%;
    mask-position: 60% 30%;
  }
}
.card.is-lit .card__shine {
  -webkit-mask-position: calc(50% - var(--hx, 0) * 38%) calc(50% - var(--hy, 0) * 38%);
  mask-position: calc(50% - var(--hx, 0) * 38%) calc(50% - var(--hy, 0) * 38%);
  animation: none;
}
/* Foil on the frame only: the second mask layer cuts the photo window out. */
.card__foil {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(125deg, #c8ff4a, #8cff5c, #61ff9e, #4deddb, #61ff9e, #8cff5c, #c8ff4a) 0 0 /
    300% 300%;
  opacity: 0.34;
  -webkit-mask:
    linear-gradient(#000 0 0) calc(var(--k) * 10) calc(var(--k) * 10) / calc(var(--k) * 196)
    calc(var(--k) * 190) no-repeat,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  animation: foil 9s linear infinite alternate;
}
@keyframes foil {
  to {
    background-position: 100% 100%;
  }
}
/* Touch screens: the light and the foil stay still. Both animate a mask or a background, which
   the browser repaints on its main thread 60 times a second. The sparkles keep twinkling. */
@media (hover: none), (pointer: coarse) {
  .card__shine,
  .card__foil {
    animation: none;
  }
}
.card__shine svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  animation: twinkle 2.1s ease-in-out infinite;
}
.card__shine svg:nth-of-type(2) {
  animation-duration: 1.8s;
  animation-delay: -0.6s;
}
.card__shine svg:nth-of-type(3) {
  animation-duration: 2.4s;
  animation-delay: -1.3s;
}
@keyframes twinkle {
  0%,
  100% {
    opacity: 0.3;
  }
  50% {
    opacity: 1;
  }
}

/* Legendary: full art under the frame's veil, foil name, holo band and a prism rim that turns. */
.card--l .card__photo {
  height: calc(var(--k) * 314);
  background: var(--bg);
}
.card--l .card__img {
  object-position: 50% 28%;
}
.card--l .card__title {
  background: linear-gradient(90deg, #8df3ff, #bfaeff, #ff9cd0, #ffdfa3);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 calc(var(--k) * 1) calc(var(--k) * 2) rgba(0, 0, 0, 0.55));
}
.card--l .card__text {
  text-shadow: 0 calc(var(--k) * 1) calc(var(--k) * 3) rgba(0, 0, 0, 0.6);
}
.card__holo {
  position: absolute;
  inset: 0;
  overflow: hidden;
  mix-blend-mode: color-dodge;
  opacity: 0.45;
  pointer-events: none;
}
.card__holo::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: -100%;
  width: 300%;
  background: linear-gradient(
    115deg,
    rgba(61, 242, 255, 0) 30%,
    rgba(61, 242, 255, 0.75) 42%,
    rgba(255, 61, 166, 0.75) 50%,
    rgba(200, 255, 74, 0.65) 58%,
    rgba(200, 255, 74, 0) 70%
  );
  translate: calc(var(--hx, 0) * 9%) 0;
  animation: holo 6s linear infinite;
}
@keyframes holo {
  from {
    transform: translateX(-33.33%);
  }
  to {
    transform: translateX(33.33%);
  }
}
/* Ring = padding of the box: the mask keeps the padding and drops the content box. */
.card__rim {
  position: absolute;
  inset: 0;
  padding: calc(var(--k) * 1.5);
  overflow: hidden;
  border-radius: calc(var(--k) * 12);
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
}
/* A square of conic gradient that spins: a transform, so nothing is repainted. */
.card__rim::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 190%;
  aspect-ratio: 1;
  background: conic-gradient(#3df2ff, #7c5cff, #ff3da6, #ffb13d, #c8ff4a, #3df2ff);
  translate: -50% -50%;
  animation: rim 5s linear infinite;
}
@keyframes rim {
  to {
    rotate: 360deg;
  }
}

/* ---------- Booster: cut-out of the app's 3D pouch ---------- */

.booster {
  width: var(--booster-w, 240px);
  filter: drop-shadow(0 22px 30px rgba(0, 0, 0, 0.6));
}
.booster img {
  width: 100%;
  height: auto;
}

/* ---------- Sections ---------- */

.section {
  position: relative;
  padding-block: clamp(72px, 10vw, 128px);
}
.title {
  margin: 0;
  font: 400 clamp(1.5rem, 4.6vw, 2.5rem) / 1.1 var(--font-display);
  text-transform: uppercase;
  text-wrap: balance;
}
.lead {
  max-width: 36em;
  margin: 16px 0 0;
  font-size: 1.0625rem;
  color: var(--text-62);
}
.lead a,
.faq__list a {
  color: var(--cyan);
  text-underline-offset: 3px;
}

/* How it works */
.steps {
  display: grid;
  gap: 20px;
  margin: 40px 0 0;
  padding: 0;
  list-style: none;
}
.step {
  overflow: hidden;
  padding-bottom: 28px;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: var(--surface);
}
.step__shot {
  position: relative;
  height: 280px;
  overflow: hidden;
  background: var(--bg);
}
.step__shot img {
  /* Capped: on a wide single column the capture would zoom into a thin slice of the screen. */
  width: min(100%, 400px);
  height: auto;
  margin-inline: auto;
  /* --crop: share of the capture hidden above the frame, the same at every width. */
  translate: 0 calc(var(--crop, 0%) * -1);
}
.step__shot::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  height: 96px;
  background: linear-gradient(180deg, rgba(17, 17, 25, 0), var(--surface));
}
.step__num {
  margin: 20px 24px 10px;
  font: 700 0.8125rem / 1 var(--font-mono);
  letter-spacing: 0.1em;
}
.step__num--cyan {
  color: var(--cyan);
}
.step__num--magenta {
  color: var(--magenta);
}
.step__num--lime {
  color: var(--lime);
}
.step__title {
  margin: 0 24px;
  font: 400 1.25rem / 1.2 var(--font-display);
}
.step__text {
  margin: 10px 24px 0;
  color: var(--text-62);
}

/* Rarities: horizontal strip on phones, fan on wide screens */
.section--raretes {
  overflow: clip;
}
/* Scrollable strip: the focus ring is drawn inside, its sides would be clipped otherwise. */
.fan:focus-visible {
  outline-offset: -2px;
}
.fan {
  --card-w: min(62vw, 236px);
  display: flex;
  gap: 16px;
  margin: 0;
  padding: 72px var(--gutter);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  list-style: none;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.fan::-webkit-scrollbar {
  display: none;
}
.fan__item {
  flex: none;
  scroll-snap-align: center;
}
/* On the phone strip the rarest card comes first (the markup stays Commune to Légendaire). */
.fan__item:nth-child(1),
.legend li:nth-child(1) {
  order: 6;
}
.fan__item:nth-child(2),
.legend li:nth-child(2) {
  order: 5;
}
.fan__item:nth-child(3),
.legend li:nth-child(3) {
  order: 4;
}
.fan__item:nth-child(4),
.legend li:nth-child(4) {
  order: 3;
}
.fan__item:nth-child(5),
.legend li:nth-child(5) {
  order: 2;
}
.fan__item:nth-child(6),
.legend li:nth-child(6) {
  order: 1;
}
.legend {
  /* Fixed columns (2, then 3, then 6) so no rarity is left alone on a row. */
  display: grid;
  grid-template-columns: repeat(2, max-content);
  justify-content: center;
  gap: 10px 24px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.875rem;
  color: var(--text-62);
}
.legend li {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.legend svg {
  width: 12px;
  height: 12px;
}

/* FAQ */
.faq {
  display: grid;
  gap: 40px;
}
.faq__list details {
  border-top: 1px solid var(--border);
}
.faq__list details:last-child {
  border-bottom: 1px solid var(--border);
}
.faq__list summary {
  position: relative;
  padding: 22px 44px 22px 0;
  font-weight: 600;
  font-size: 1.0625rem;
  list-style: none;
  cursor: pointer;
}
.faq__list summary::-webkit-details-marker {
  display: none;
}
.faq__list summary::before,
.faq__list summary::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 4px;
  width: 16px;
  height: 2px;
  margin-top: -1px;
  border-radius: 1px;
  background: var(--text-62);
  transition: rotate 0.24s var(--ease-out);
}
.faq__list summary::after {
  rotate: 90deg;
}
.faq__list details[open] summary::after {
  rotate: 0deg;
}
.faq__list p {
  max-width: 38em;
  margin: 0 0 24px;
  color: var(--text-62);
}

/* Final call */
.final {
  position: relative;
  overflow-x: clip;
  padding-block: clamp(88px, 12vw, 152px);
  text-align: center;
}
.final .halo--magenta {
  left: -320px;
  bottom: -420px;
}
.final .halo--cyan {
  right: -120px;
  top: -160px;
  bottom: auto;
}
.final__in {
  position: relative;
}
.final__booster {
  --booster-w: 148px;
  width: var(--booster-w);
  margin: 0 auto 40px;
  rotate: -4deg;
}
.final__title {
  margin: 0;
  font: 400 clamp(1.7rem, 8.6vw, 4rem) / 1.04 var(--font-display);
  text-transform: uppercase;
}
.final .cta {
  margin-top: 36px;
}

/* Footer */
.footer {
  position: relative;
  overflow: clip;
  padding-top: 48px;
  border-top: 1px solid var(--border);
  font-size: 0.875rem;
  color: var(--text-62);
}
.footer__in {
  display: grid;
  gap: 32px;
}
.footer__brand p {
  max-width: 34em;
  margin: 16px 0 0;
  color: var(--text-56);
}
.footer__links {
  display: flex;
  flex-wrap: wrap;
  align-content: start;
  gap: 0 24px;
  margin-block: -12px;
}
/* The row gap lives in the link padding: same rhythm, taller tap target. */
.footer__links a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding-block: 12px;
  text-decoration: none;
  transition: color 0.16s var(--ease-out);
}
.footer__links a:hover {
  color: var(--text);
}
.footer__links svg {
  width: 14px;
  height: 14px;
}
.credits {
  margin-top: 28px;
  color: var(--text-56);
}
.credits summary {
  width: fit-content;
  /* Taller tap target, same place. */
  margin-block: -12px;
  padding-block: 12px;
  cursor: pointer;
}
.credits p {
  max-width: 60em;
  margin: 10px 0 0;
}
.footer__mark {
  /* With this line height the letters sit on the bottom of the box: the padding is the air
     under them, close to what the word leaves on its sides. */
  margin: 40px 0 0;
  padding-bottom: max(20px, 0.3em);
  font: 400 11.7vw / 0.8 var(--font-display);
  letter-spacing: 0.02em;
  text-align: center;
  text-transform: uppercase;
  white-space: nowrap;
  color: rgba(242, 242, 248, 0.05);
  /* Its tall box overlaps the image credits above: clicks go through. */
  pointer-events: none;
  user-select: none;
}

/* ---------- Small screens ---------- */

@media (max-width: 699px) {
  /* Static halos: the drift is hardly seen on a phone and costs three large layers. */
  .halo {
    animation: none;
  }
}

/* One column wider than the capture: its sides (the app's own margin) melt into the tile. */
@media (min-width: 440px) and (max-width: 699px) {
  .step__shot img {
    --fade: linear-gradient(90deg, transparent, #000 24px, #000 calc(100% - 24px), transparent);
    -webkit-mask-image: var(--fade);
    mask-image: var(--fade);
  }
}

@media (max-width: 479px) {
  /* The store button spans the column. */
  .cta .btn--primary {
    flex: 1 1 100%;
    justify-content: center;
    padding-inline: 20px;
  }
}

@media (max-width: 389px) {
  .nav__in {
    gap: 8px;
  }
  .nav .logo {
    gap: 8px;
  }
  .nav .btn--s {
    padding: 0 14px;
  }
}

@media (max-width: 357px) {
  .pill {
    font-size: 0.5625rem;
    letter-spacing: 0.04em;
    white-space: nowrap;
  }
}

@media (max-width: 374px) {
  .nav .logo {
    gap: 8px;
  }
  .nav .logo__icon {
    width: 28px;
    height: 28px;
  }
  /* Room for the Discord icon: the mark alone, without the word. */
  .nav .logo__word {
    display: none;
  }
  .nav .btn--s {
    padding: 0 14px;
    font-size: 0.75rem;
  }
}

/* Phones held sideways: tighter hero so the store button stays above the fold. */
@media (orientation: landscape) and (max-height: 480px) and (max-width: 1023px) {
  .hero {
    padding-top: 88px;
  }
  .hero__title {
    margin-top: 14px;
    font-size: clamp(1.4rem, 4vw, 2.25rem);
  }
  .hero__sub {
    max-width: 40em;
    margin-top: 12px;
  }
  .hero .cta {
    margin-top: 20px;
  }
}

/* ---------- Download dock: QR card pinned to the bottom right, desktop only ---------- */

/* Sticky inside <main>: it follows the viewport, then stops above the footer on its own. */
.dock {
  display: none;
}
@media (min-width: 900px) and (min-height: 600px) and (hover: hover) and (pointer: fine) {
  .dock {
    position: sticky;
    bottom: 0;
    z-index: 15;
    display: block;
    height: 0;
    pointer-events: none;
  }
}
.dock__card {
  position: absolute;
  right: 24px;
  /* On the card, not on the sticky box: it also holds once the dock rests above the footer. */
  bottom: 24px;
  width: 172px;
  padding: 40px 16px 18px;
  border: 1px solid rgba(242, 242, 248, 0.14);
  border-radius: 20px;
  /* Glass: the page shows through, blurred. */
  background: rgba(17, 17, 25, 0.5);
  -webkit-backdrop-filter: blur(18px) saturate(1.3);
  backdrop-filter: blur(18px) saturate(1.3);
  box-shadow: 0 22px 40px rgba(0, 0, 0, 0.6);
  text-align: center;
  pointer-events: auto;
  transition:
    opacity 0.24s var(--ease-out),
    visibility 0s;
}
/* Set by the script while the dock would cover the hero's front card. */
.dock.is-away .dock__card {
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
  transition:
    opacity 0.24s var(--ease-out),
    visibility 0s 0.24s;
}
/* No flash before the script has placed it. */
@media (max-width: 1511px) {
  .js .dock:not(.is-ready) .dock__card {
    opacity: 0;
  }
}
/* Below 1512 px the dock overlaps the page column: the FAQ rows stop short of it. */
@media (min-width: 900px) and (max-width: 1511px) and (min-height: 600px) and (hover: hover) and (
    pointer: fine
  ) {
  .faq__list {
    margin-right: calc(212px - max(var(--gutter), (100vw - 1120px) / 2));
  }
}
.dock__icon {
  position: absolute;
  top: -28px;
  left: 50%;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 24%;
  background: var(--bg);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
  translate: -50% 0;
}
.dock__icon svg {
  width: 35px;
  height: 28px;
}
.dock__text {
  margin: 0 0 14px;
  font-size: 0.875rem;
  line-height: 1.35;
  color: var(--text-62);
}
/* Viewfinder: a cyan outline of which the mask keeps the four corners only. */
.dock__qr {
  position: relative;
  display: block;
  padding: 10px;
}
.dock__qr::before {
  content: "";
  position: absolute;
  inset: 0;
  border: 2px solid var(--cyan);
  border-radius: 6px;
  -webkit-mask:
    linear-gradient(#000 0 0) 0 0 / 16px 16px no-repeat,
    linear-gradient(#000 0 0) 100% 0 / 16px 16px no-repeat,
    linear-gradient(#000 0 0) 0 100% / 16px 16px no-repeat,
    linear-gradient(#000 0 0) 100% 100% / 16px 16px no-repeat;
  mask:
    linear-gradient(#000 0 0) 0 0 / 16px 16px no-repeat,
    linear-gradient(#000 0 0) 100% 0 / 16px 16px no-repeat,
    linear-gradient(#000 0 0) 0 100% / 16px 16px no-repeat,
    linear-gradient(#000 0 0) 100% 100% / 16px 16px no-repeat;
}
.dock__qr img {
  width: 100%;
  height: auto;
  padding: 7px;
  border-radius: 8px;
  background: var(--text);
}
.dock__logo {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  margin: auto;
  border-radius: 6px;
  background: var(--bg);
  box-shadow: 0 0 0 2px var(--text);
}
.dock__logo svg {
  width: 15px;
  height: 12px;
}

/* Phones and tablets held upright: pill, then the visual, then the text. The text wrapper
   dissolves so its children line up with the stage in the hero grid. */
@media (max-width: 699px) and (min-height: 481px), (max-width: 1023px) and (orientation: portrait) {
  /* The hero is exactly the first screen: the visual takes the height the text and the store
     button leave, so the button and its note sit above the fold. svh: Safari's bars shown.
     No Smart App Banner on this page: it would take 68 pt off that height. */
  .hero {
    padding: 80px 0 28px;
  }
  .hero__in {
    grid-template-rows: auto 1fr;
    gap: 0;
    min-height: calc(100svh - 108px);
  }
  .hero__title {
    margin-top: 28px;
  }
  /* 15 px keeps the subtitle on three lines on a 390 px phone. */
  .hero__sub {
    margin-top: 12px;
    font-size: 0.9375rem;
  }
  .hero .cta {
    margin-top: 20px;
  }
  .hero__note {
    margin-top: 12px;
  }
  .hero__text {
    display: contents;
  }
  .hero__text > * {
    order: 2;
  }
  .hero__text > .pill {
    order: 0;
    justify-self: center;
  }
  .hero__text > .hero__note {
    text-align: center;
  }
  /* Wider than a phone, the button no longer spans the column: centre it with the note. */
  .hero__text > .cta {
    justify-content: center;
  }
  /* No pause control on phones and upright tablets (owner's call). */
  .stage__pause {
    display: none;
  }
  /* --hero-rest is everything but the visual, from the top of the page to the bottom of the
     hero: fixed boxes, gaps and paddings (298 px), the two-line title (7.4vw x 1.06 x 2) and
     the subtitle. The visual is as tall as what is left, never under 180 px wide (the phone
     would stop reading as one). Where its width caps it first, it sits in the middle of the
     room left. */
  .hero__in > .stage {
    --hero-sub: 4.22rem;
    --hero-rest: calc(298px + min(15.7vw, 111px) + var(--hero-sub));
    order: 1;
    align-self: center;
    max-width: max(180px, calc((100svh - var(--hero-rest)) * 560 / 690));
    margin-block: 14px 0;
  }
}
/* From 460 px the subtitle fits on two lines instead of three (at 440 it does by half a pixel). */
@media (min-width: 460px) {
  .hero__in > .stage {
    --hero-sub: 2.82rem;
  }
}
/* Android variant: its note under the button takes two lines on a phone. */
@media (max-width: 599px) {
  .is-android .hero__in > .stage {
    --hero-rest: calc(319px + min(15.7vw, 111px) + var(--hero-sub));
  }
}

/* ---------- Wider screens ---------- */

@media (min-width: 480px) {
  .legend {
    grid-template-columns: repeat(3, max-content);
  }
}

@media (min-width: 700px) {
  :root {
    --gutter: 32px;
  }
  .stage {
    width: min(100%, 520px);
  }
  .steps {
    grid-template-columns: repeat(3, 1fr);
  }
  .step__shot {
    height: 300px;
  }
  .footer__in {
    grid-template-columns: 1fr auto;
  }
  .footer__links {
    flex-direction: column;
    margin-block: -5px;
  }
  .footer__links a {
    padding-block: 5px;
  }
}

/* Room for the page links and the Discord label next to the store button. */
@media (min-width: 860px) {
  .nav__in {
    gap: 32px;
  }
  .nav__links {
    display: flex;
  }
  .nav__discord {
    margin-left: 0;
  }
  .nav__discord span {
    display: inline;
  }
}

/* From here the six rarities fit on one row. */
@media (min-width: 760px) {
  .legend {
    grid-template-columns: repeat(6, max-content);
  }
}

@media (min-width: 900px) {
  .fan {
    --card-w: clamp(140px, 15.4vw, 196px);
    justify-content: center;
    gap: 0;
    padding: 72px 0 64px;
    overflow: visible;
  }
  .fan__item {
    position: relative;
    margin-inline: -9px;
    rotate: var(--r);
    translate: 0 var(--y);
    transition:
      rotate 0.32s var(--ease-out),
      translate 0.32s var(--ease-out);
  }
  .fan__item:nth-child(1) {
    --r: -12deg;
    --y: 38px;
  }
  .fan__item:nth-child(2) {
    --r: -7.2deg;
    --y: 14px;
  }
  .fan__item:nth-child(3) {
    --r: -2.4deg;
    --y: 0px;
  }
  .fan__item:nth-child(4) {
    --r: 2.4deg;
    --y: 0px;
  }
  .fan__item:nth-child(5) {
    --r: 7.2deg;
    --y: 14px;
  }
  .fan__item:nth-child(6) {
    --r: 12deg;
    --y: 38px;
  }
  /* The fan reads left to right, Commune to Légendaire. */
  .fan .fan__item:nth-child(n),
  .legend li:nth-child(n) {
    order: 0;
  }
  .faq {
    grid-template-columns: 0.8fr 1.2fr;
    gap: 64px;
  }
}

@media (min-width: 900px) and (hover: hover) and (pointer: fine) {
  .fan__item:hover {
    z-index: 5;
    rotate: 0deg;
    translate: 0 -18px;
  }
}

/* 1024: an iPad held sideways gets the two-column hero too. */
@media (min-width: 1024px) {
  .hero {
    padding: 120px 0 88px;
  }
  .hero__in {
    grid-template-columns: minmax(0, 1fr) minmax(0, 46%);
    align-items: center;
    /* Wider than it reads: the tilted card on the left hangs about 30 px out of the visual. */
    gap: clamp(64px, 6.2vw, 88px);
  }
  .hero__title {
    font-size: clamp(2.2rem, 3.9vw, 3rem);
  }
  .stage {
    width: 100%;
  }
  .stage__phone {
    --pw: 50cqw;
    left: 25cqw;
  }
  .stage__left {
    left: -4cqw;
  }
  .stage__right {
    --card-w: 34cqw;
    left: 67cqw;
    top: 57cqw;
  }
}

/* ---------- Scroll reveal (only when JS runs) ---------- */

.js [data-reveal] {
  opacity: 0;
  translate: 0 18px;
  transition:
    opacity 0.5s var(--ease-out),
    translate 0.5s var(--ease-out);
}
.js [data-reveal].is-in {
  opacity: 1;
  translate: 0 0;
}

/* ---------- Android: no store link yet ---------- */

.only-android {
  display: none;
}
.is-android .hide-android {
  display: none;
}
.is-android .only-android {
  display: block;
}
.is-android .btn.only-android {
  display: inline-flex;
}
/* Over the magenta halo the usual note colour falls under 4.5:1. */
.hero__note.only-android {
  color: rgba(242, 242, 248, 0.72);
}
/* Reduced motion: the script disables the pause controls, nothing is left to stop. */
.phone:disabled {
  cursor: default;
}
.stage__pause:disabled {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    /* biome-ignore lint/complexity/noImportantStyles: reduced motion has to win over every rule */
    animation: none !important;
    /* biome-ignore lint/complexity/noImportantStyles: reduced motion has to win over every rule */
    transition: none !important;
  }
  .js [data-reveal] {
    opacity: 1;
    translate: 0 0;
  }
}
