/* ============================================================
   PROXY FORGE — dark arcane gaming aesthetic
   ============================================================ */

:root {
  --bg: #06030d;
  --bg-2: #0c0618;
  --panel: rgba(22, 12, 42, 0.55);
  --panel-border: rgba(168, 85, 247, 0.25);
  --neon: #c084fc;
  --neon-hot: #e879f9;
  --neon-deep: #7c3aed;
  --text: #e9e3f5;
  --text-dim: #9d8fbd;
  --glow-sm: 0 0 8px rgba(192, 132, 252, 0.55);
  --glow-md: 0 0 18px rgba(168, 85, 247, 0.5), 0 0 60px rgba(124, 58, 237, 0.25);
  --glow-lg: 0 0 30px rgba(192, 132, 252, 0.6), 0 0 90px rgba(124, 58, 237, 0.45);
  --font-display: 'Cinzel', serif;
  --font-ui: 'Rajdhani', sans-serif;

  /* Height of the fixed nav, and the room the fixed order bar needs at the
     bottom of the document. Both are read from more than one place, so they
     live here instead of being retyped and drifting apart. */
  --nav-h: 72px;
  --order-bar-space: 40px;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* ============================================================
   BREAKPOINTS — three, and only these three.

       900px   tablet / narrow laptop
       760px   phone, portrait and landscape
       420px   small phone

   They used to be picked ad hoc (640px and 760px, chosen independently and
   sitting 500 lines apart), which is how the mobile query ended up handling
   the card grid but not the controls inside it.

   `(hover: hover) and (pointer: fine)` is a SEPARATE axis, not a width — see
   the POINTER-DEPENDENT section near the bottom of this file. A touch laptop
   is wide and cannot hover; a phone in landscape is neither.
   ============================================================ */

html {
  scroll-behavior: smooth;
  /* The nav is fixed, so every in-page anchor and every scrollIntoView() with
     block:'start' would otherwise drop its target underneath it — including
     the jump to the deck after an import. */
  scroll-padding-top: calc(var(--nav-h) + 12px);
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 18px;
  /* A backstop, NOT the fix. Everything that used to be wider than a phone
     (the order bar, the card controls, the About FAQ grid, the version picker)
     is sized to fit now. If you ever suspect a new overflow, comment this out:
     the clipping turns back into a visible horizontal scrollbar, which is the
     fastest way to find which element is too wide. */
  overflow-x: hidden;
}

/* The order bar is fixed to the bottom of the viewport, so without this the
   end of the document sits underneath it. Toggled from updateOrderBar(). */
body.has-order-bar { padding-bottom: var(--order-bar-space); }

::selection { background: var(--neon-deep); color: #fff; }

/* Custom scrollbar */
::-webkit-scrollbar { width: 10px; }
::-webkit-scrollbar-track { background: var(--bg); }
::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, var(--neon-deep), var(--neon));
  border-radius: 6px;
}

a { color: var(--neon); text-decoration: none; }

.neon {
  color: var(--neon);
  text-shadow: var(--glow-sm);
}

.is-hidden { display: none !important; }

/* ============ BACKGROUND LAYERS ============ */

.bg-nebula, .bg-stars, .bg-grid {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: -3;
}

.bg-nebula {
  background:
    radial-gradient(ellipse 60% 45% at 18% 12%, rgba(124, 58, 237, 0.22), transparent 60%),
    radial-gradient(ellipse 55% 40% at 85% 30%, rgba(232, 121, 249, 0.12), transparent 60%),
    radial-gradient(ellipse 70% 55% at 50% 95%, rgba(88, 28, 135, 0.28), transparent 65%),
    linear-gradient(180deg, var(--bg) 0%, var(--bg-2) 50%, var(--bg) 100%);
  animation: nebulaDrift 24s ease-in-out infinite alternate;
}

@keyframes nebulaDrift {
  from { filter: hue-rotate(0deg) brightness(1); }
  to   { filter: hue-rotate(-18deg) brightness(1.18); }
}

.bg-stars {
  z-index: -2;
  background-image:
    radial-gradient(1.5px 1.5px at 12% 22%, rgba(255,255,255,.8), transparent),
    radial-gradient(1px 1px at 32% 68%, rgba(255,255,255,.5), transparent),
    radial-gradient(2px 2px at 51% 14%, rgba(216,180,254,.9), transparent),
    radial-gradient(1px 1px at 64% 81%, rgba(255,255,255,.6), transparent),
    radial-gradient(1.5px 1.5px at 78% 38%, rgba(232,121,249,.8), transparent),
    radial-gradient(1px 1px at 89% 64%, rgba(255,255,255,.5), transparent),
    radial-gradient(1px 1px at 8% 86%, rgba(216,180,254,.7), transparent),
    radial-gradient(1.5px 1.5px at 43% 44%, rgba(255,255,255,.65), transparent),
    radial-gradient(1px 1px at 95% 9%, rgba(255,255,255,.7), transparent),
    radial-gradient(1px 1px at 23% 51%, rgba(232,121,249,.6), transparent);
  background-size: 1200px 800px;
  animation: starTwinkle 6s ease-in-out infinite alternate;
}

@keyframes starTwinkle {
  from { opacity: .55; }
  to   { opacity: 1; }
}

.bg-grid {
  z-index: -1;
  background-image:
    linear-gradient(rgba(124, 58, 237, 0.06) 1px, transparent 1px),
    linear-gradient(90deg, rgba(124, 58, 237, 0.06) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(ellipse 90% 70% at 50% 40%, black 0%, transparent 75%);
  -webkit-mask-image: radial-gradient(ellipse 90% 70% at 50% 40%, black 0%, transparent 75%);
}

/* ============ NAV ============ */

.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 5vw;
  background: linear-gradient(180deg, rgba(6,3,13,0.92), rgba(6,3,13,0.55) 70%, transparent);
  backdrop-filter: blur(8px);
}

.nav__logo {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 24px;
  letter-spacing: 2px;
  color: var(--text);
}

.nav__logo-bolt {
  color: var(--neon-hot);
  text-shadow: var(--glow-md);
}

.nav__links {
  display: flex;
  align-items: center;
  gap: 28px;
  font-weight: 600;
  letter-spacing: 1px;
  text-transform: uppercase;
  font-size: 15px;
}

.nav__links a:not(.btn) { color: var(--text-dim); transition: color .2s, text-shadow .2s; }

/* ============ BUTTONS ============ */

.btn {
  display: inline-block;
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 17px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: #fff;
  background: linear-gradient(135deg, var(--neon-deep), #a21caf);
  border: 1px solid rgba(232, 121, 249, 0.6);
  border-radius: 10px;
  padding: 13px 28px;
  cursor: pointer;
  box-shadow: var(--glow-md), inset 0 0 18px rgba(232, 121, 249, 0.18);
  transition: transform .15s ease, box-shadow .2s ease, filter .2s;
}


.btn:active { transform: translateY(0) scale(.99); }

.btn--big { font-size: 19px; padding: 16px 40px; border-radius: 12px; }
.btn--small { font-size: 14px; padding: 9px 18px; }
.btn--full { width: 100%; }

/* ============ HERO ============ */

.hero {
  position: relative;
  /* svh, not vh: on mobile `100vh` means the viewport with the URL bar
     COLLAPSED, so a 100vh hero is taller than the screen on load and then
     resizes as the bar hides and shows. svh is the small (bar-visible)
     height and stays put. The vh line stays as the fallback. */
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 120px 5vw 80px;
  perspective: 1200px;
  overflow: hidden;
}

.hero__cards {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(8px, 2vw, 36px);
  transform-style: preserve-3d;
  pointer-events: none;
}

.hero-card {
  width: clamp(150px, 17vw, 300px);
  /* The <img> carries width="488" height="680" so the box is reserved before
     the JPEG arrives. Without this line the height attribute wins as a fixed
     680px while the width above scales with the viewport — so every card was
     stretched at any width other than 488px. `auto` lets the attributes act
     as an aspect ratio instead, which still reserves the box. */
  height: auto;
  filter: brightness(0.55) saturate(1.1);
  border-radius: 4.6% / 3.4%;
  box-shadow:
    0 0 24px rgba(124, 58, 237, 0.55),
    0 0 80px rgba(124, 58, 237, 0.3),
    0 30px 60px rgba(0, 0, 0, 0.8);
  opacity: .92;
  will-change: transform;
  animation: cardFloat 7s ease-in-out infinite alternate;
}

.hero-card:nth-child(1) { animation-delay: 0s; }
.hero-card:nth-child(2) { animation-delay: -1.7s; }
.hero-card:nth-child(3) { animation-delay: -3.1s; }
.hero-card:nth-child(4) { animation-delay: -4.6s; }
.hero-card:nth-child(5) { animation-delay: -5.8s; }

.hero-card--center {
  width: clamp(190px, 21vw, 380px);
  opacity: 1;
  filter: brightness(0.6) saturate(1.1);
  box-shadow:
    0 0 36px rgba(232, 121, 249, 0.65),
    0 0 120px rgba(124, 58, 237, 0.45),
    0 40px 80px rgba(0, 0, 0, 0.85);
}

/* `translate`, not `margin-top`: a layout property here counts as a layout
   shift on every frame of the loop and was most of the page's CLS. The
   individual `translate` property composes with the `transform` that
   initParallax() sets from JS, so the two don't fight. */
@keyframes cardFloat {
  from { translate: 0 -14px; }
  to   { translate: 0 14px; }
}

/* The dark pool behind the text, so it reads over the cards. The fade used to
   go from .8 to 0 in the last 45% of a 65%-wide ellipse — a short, linear
   ramp, which the eye reads as a visible ring where the pool "ends". Longer,
   eased ramp now, on an ellipse that reaches past the box, so it is fully
   transparent well before the edges. No border-radius: it only ever gave the
   gradient a shape to be seen against. */
.hero__content {
  position: relative;
  z-index: 2;
  background: radial-gradient(
    ellipse 75% 80% at 50% 50%,
    rgba(6, 3, 13, 0.95) 0%,
    rgba(6, 3, 13, 0.9) 25%,
    rgba(6, 3, 13, 0.7) 45%,
    rgba(6, 3, 13, 0.4) 62%,
    rgba(6, 3, 13, 0.15) 78%,
    rgba(6, 3, 13, 0.04) 90%,
    transparent 100%
  );
  padding: 70px 60px;
}

.hero__sub { text-shadow: 0 2px 12px rgba(0, 0, 0, 0.95); }

.hero__kicker {
  font-weight: 600;
  letter-spacing: 6px;
  font-size: 15px;
  color: var(--neon);
  text-shadow: var(--glow-sm);
  margin-bottom: 18px;
}

.hero__title {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(34px, 8vw, 104px);
  line-height: 1.02;
  margin-bottom: 26px;
}

.hero__title-line { display: block; }

.hero__title-line--neon {
  background: linear-gradient(95deg, #d8b4fe 0%, var(--neon-hot) 45%, var(--neon-deep) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 0 22px rgba(192, 132, 252, 0.65));
  animation: titlePulse 3.6s ease-in-out infinite alternate;
}

@keyframes titlePulse {
  from { filter: drop-shadow(0 0 14px rgba(192, 132, 252, 0.45)); }
  to   { filter: drop-shadow(0 0 34px rgba(232, 121, 249, 0.85)); }
}

.hero__sub {
  color: var(--text-dim);
  font-size: 20px;
  font-weight: 500;
  line-height: 1.55;
  margin-bottom: 38px;
}

.hero__scroll-hint {
  position: absolute;
  bottom: 26px; left: 50%;
  transform: translateX(-50%);
  width: 26px; height: 44px;
  border: 2px solid rgba(192, 132, 252, 0.6);
  border-radius: 14px;
  box-shadow: var(--glow-sm);
}

.hero__scroll-hint span {
  position: absolute;
  top: 8px; left: 50%;
  width: 4px; height: 9px;
  margin-left: -2px;
  border-radius: 3px;
  background: var(--neon);
  box-shadow: var(--glow-sm);
  animation: scrollNudge 1.8s ease-in-out infinite;
}

@keyframes scrollNudge {
  0%, 100% { transform: translateY(0); opacity: 1; }
  60% { transform: translateY(14px); opacity: .2; }
}

/* ============ SECTIONS ============ */

.section-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(30px, 4.6vw, 54px);
  letter-spacing: 3px;
  text-align: center;
  margin-bottom: 56px;
}

.how, .builder {
  position: relative;
  padding: 110px 5vw;
  max-width: 1500px;
  margin: 0 auto;
}

/* Scroll reveal */
.reveal {
  opacity: 0;
  transform: translateY(46px);
  transition: opacity .8s ease, transform .8s cubic-bezier(.2,.7,.3,1);
  /* Failsafe. Every content section on both pages is .reveal, so if the module
     carrying the IntersectionObserver never runs — a failed fetch on a flaky
     mobile connection — the whole page below the nav stays invisible with
     nothing to explain it. This forces the content visible after 4s no matter
     what; the observer normally wins several seconds earlier. 0s duration with
     a 4s delay and fill-mode forwards, so it snaps rather than fading twice. */
  animation: revealFailsafe 0s linear 4s forwards;
}

@keyframes revealFailsafe { to { opacity: 1; transform: none; } }

.reveal.is-visible { opacity: 1; transform: none; animation: none; }

/* How it works */
.how__steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
  gap: 30px;
}

.step {
  background: var(--panel);
  border: 1px solid var(--panel-border);
  border-radius: 18px;
  padding: 42px 34px;
  backdrop-filter: blur(10px);
  position: relative;
  overflow: hidden;
  transition: opacity .8s ease, transform .8s cubic-bezier(.2,.7,.3,1), box-shadow .3s, border-color .3s;
}


.step::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--neon), transparent);
  opacity: .8;
}

.step__num {
  font-family: var(--font-display);
  font-size: 46px;
  font-weight: 900;
  color: var(--neon);
  text-shadow: var(--glow-md);
  margin-bottom: 14px;
}

.step h3 {
  font-family: var(--font-display);
  font-size: 23px;
  margin-bottom: 12px;
  letter-spacing: 1px;
}

.step p { color: var(--text-dim); line-height: 1.6; }

/* ============ IMPORT PANEL ============ */

.import-panel {
  max-width: 860px;
  margin: 0 auto 60px;
  background: var(--panel);
  border: 1px solid var(--panel-border);
  border-radius: 20px;
  padding: 34px;
  backdrop-filter: blur(12px);
  box-shadow: 0 24px 80px rgba(0,0,0,.5);
}

.import-tabs {
  display: flex;
  gap: 10px;
  margin-bottom: 24px;
}

.import-tab {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 16px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--text-dim);
  background: transparent;
  border: 1px solid transparent;
  border-radius: 10px;
  padding: 10px 20px;
  cursor: pointer;
  transition: all .2s;
}

.import-tab.is-active {
  color: var(--neon);
  border-color: var(--panel-border);
  background: rgba(124, 58, 237, 0.12);
  text-shadow: var(--glow-sm);
}

.import-row { display: flex; gap: 14px; }

input[type="text"], input[type="email"], textarea, select {
  flex: 1;
  width: 100%;
  font-family: var(--font-ui);
  font-size: 18px;
  font-weight: 500;
  color: var(--text);
  background: rgba(6, 3, 13, 0.7);
  border: 1px solid var(--panel-border);
  border-radius: 10px;
  padding: 14px 18px;
  outline: none;
  transition: border-color .2s, box-shadow .2s;
}

select {
  appearance: none;
  -webkit-appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--text-dim) 50%), linear-gradient(135deg, var(--text-dim) 50%, transparent 50%);
  background-position: right 20px center, right 14px center;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}

select option { background: #0d0817; color: var(--text); }

input:focus, textarea:focus, select:focus {
  border-color: var(--neon);
  box-shadow: var(--glow-sm);
}

textarea { resize: vertical; margin-bottom: 16px; }

.import-status {
  margin-top: 16px;
  min-height: 24px;
  font-weight: 600;
  color: var(--neon);
  text-shadow: var(--glow-sm);
}

.import-status.is-error { color: #fb7185; text-shadow: 0 0 8px rgba(251, 113, 133, 0.5); }

.import-hint {
  margin-top: 14px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-dim);
}

.import-hint strong { color: var(--neon); font-weight: 600; }
.import-hint em { color: var(--text); font-style: normal; font-weight: 600; }

.import-link { font-weight: 700; text-decoration: underline; text-underline-offset: 3px; }

/* ============ MOXFIELD HELPER ============ */

.mox-helper {
  margin-top: 22px;
  padding: 20px 22px;
  background: rgba(6, 3, 13, 0.5);
  border: 1px solid var(--panel-border);
  border-radius: 14px;
}

.mox-helper__title {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: .5px;
  margin-bottom: 6px;
}

.mox-helper__lead { color: var(--text-dim); margin-bottom: 22px; }

.mox-helper__cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 22px;
}

.mox-way {
  background: var(--panel);
  border: 1px solid var(--panel-border);
  border-radius: 12px;
  padding: 20px;
}

.mox-way p { color: var(--text-dim); font-size: 15px; line-height: 1.5; }
.mox-way strong { color: var(--text); }

.mox-way__badge {
  display: inline-block;
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 2px;
  color: var(--text-dim);
  margin-bottom: 12px;
}

.mox-way__note { margin-top: 12px; font-size: 13.5px; }

.mox-bookmarklet {
  display: inline-block;
  margin: 4px 0 2px;
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 14.5px;
  letter-spacing: .5px;
  color: var(--text);
  background: var(--panel);
  border: 1px solid var(--panel-border);
  border-radius: 9px;
  padding: 9px 18px;
  cursor: grab;
  user-select: none;
}

.mox-bookmarklet:active { cursor: grabbing; }

.mox-steps {
  margin: 10px 0 16px 18px;
  color: var(--text-dim);
  font-size: 14.5px;
  line-height: 1.7;
}

.mox-steps em { color: var(--text); font-style: normal; font-weight: 600; }

/* ============ SINGLE-CARD SEARCH ============ */

.add-card-panel {
  max-width: 860px;
  margin: -30px auto 60px;
  background: var(--panel);
  border: 1px solid var(--panel-border);
  border-radius: 20px;
  padding: 24px 34px 28px;
  backdrop-filter: blur(12px);
}

.add-card-panel__label {
  font-weight: 600;
  font-size: 14px;
  letter-spacing: 2px;
  color: var(--text-dim);
  margin-bottom: 14px;
}

.add-card-box { position: relative; }

.search-results {
  position: absolute;
  top: calc(100% + 6px);
  left: 0; right: 0;
  z-index: 40;
  max-height: 46vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: linear-gradient(160deg, #140a26, #0b0517);
  border: 1px solid rgba(232, 121, 249, 0.4);
  border-radius: 12px;
  box-shadow: var(--glow-md), 0 24px 60px rgba(0,0,0,.7);
  overflow: hidden;
}

.search-results__item {
  padding: 11px 18px;
  font-weight: 600;
  cursor: pointer;
  transition: background .15s, color .15s;
}


.search-results__item + .search-results__item { border-top: 1px solid rgba(124, 58, 237, 0.12); }

.search-results__empty {
  padding: 11px 18px;
  color: var(--text-dim);
}

/* ============ DECK AREA ============ */

.deck-head { text-align: center; margin-bottom: 44px; }

.deck-head h3 {
  font-family: var(--font-display);
  font-size: clamp(26px, 3.6vw, 42px);
  letter-spacing: 2px;
  color: var(--neon);
  text-shadow: var(--glow-md);
}

.deck-head p { color: var(--text-dim); margin-top: 8px; font-size: 17px; }

.deck-tip { letter-spacing: 1px; }

/* Outlined in the site's error red with a soft glow, so it reads as "the
   destructive one" against the purple and does not disappear into the deck
   meta — the first, dim version did. Still a text-button, not a neon block.
   It sits under the deck's name and count because that is where the deck's
   identity is, and a deck-level action reads as belonging there. */
.deck-clear { margin-top: 18px; }

.deck-clear__confirm {
  display: inline-flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 10px;
}

.deck-clear__question { color: var(--text); font-weight: 600; font-size: 15px; }

.deck-clear__btn {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 13px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--text-dim);
  background: rgba(6, 3, 13, 0.6);
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  padding: 8px 14px;
  min-height: 36px;
  cursor: pointer;
  transition: color .2s, border-color .2s, background .2s;
}

.deck-clear__btn:hover { color: var(--text); border-color: var(--neon); }

.deck-clear__btn--danger {
  color: #fb7185;
  border-color: rgba(251, 113, 133, 0.6);
  background: rgba(251, 113, 133, 0.08);
  box-shadow: 0 0 12px rgba(251, 113, 133, 0.25);
  text-shadow: 0 0 8px rgba(251, 113, 133, 0.5);
}

.deck-clear__btn--danger:hover {
  color: #fff;
  background: rgba(251, 113, 133, 0.28);
  border-color: #fb7185;
  box-shadow: 0 0 18px rgba(251, 113, 133, 0.5);
}

.board { margin-bottom: 54px; }

.board__title {
  font-family: var(--font-display);
  font-size: 24px;
  letter-spacing: 3px;
  text-transform: uppercase;
  margin-bottom: 22px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--panel-border);
}

.board__title small { color: var(--text-dim); font-size: 15px; letter-spacing: 1px; }

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(185px, 1fr));
  gap: 22px;
}

.card-tile {
  position: relative;
  border-radius: 12px;
  cursor: pointer;
  transition: transform .18s ease;
  transform-style: preserve-3d;
}


.card-tile__img-wrap {
  position: relative;
  border-radius: 4.6% / 3.4%;
  overflow: hidden;
  box-shadow: 0 8px 26px rgba(0, 0, 0, 0.65);
  transition: box-shadow .25s;
}


.card-tile__img-wrap img {
  display: block;
  width: 100%;
  aspect-ratio: 488 / 680;
  object-fit: cover;
  background: #150b28;
}

.card-tile__qty {
  position: absolute;
  top: 8px; right: 8px;
  min-width: 34px;
  text-align: center;
  font-weight: 700;
  font-size: 16px;
  color: #fff;
  background: rgba(12, 6, 24, 0.85);
  border: 1px solid var(--neon);
  border-radius: 8px;
  padding: 3px 8px;
  box-shadow: var(--glow-sm);
  backdrop-filter: blur(4px);
}

.card-tile__overlay {
  position: absolute;
  inset: auto 0 0 0;
  padding: 30px 10px 10px;
  background: linear-gradient(180deg, transparent, rgba(6,3,13,.92));
  border-radius: 0 0 4.6% 4.6%;
  opacity: 0;
  transition: opacity .2s;
  text-align: center;
  font-weight: 700;
  letter-spacing: 2px;
  font-size: 13px;
  color: var(--neon);
  text-shadow: var(--glow-sm);
  text-transform: uppercase;
  pointer-events: none;
}


.card-tile__meta {
  margin-top: 9px;
  text-align: center;
}

/* Quantity / foil / remove controls */
.card-tile__controls {
  margin-top: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.ctl {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 16px;
  line-height: 1;
  width: 28px;
  height: 28px;
  color: var(--text-dim);
  background: rgba(6, 3, 13, 0.6);
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  cursor: pointer;
  transition: all .2s;
}



.ctl-qty {
  min-width: 32px;
  text-align: center;
  font-weight: 700;
  font-size: 15px;
  color: var(--text);
}

/* Foil toggle + holo shimmer */
.card-tile__foil {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 12.5px;
  letter-spacing: 1.5px;
  height: 28px;
  color: var(--text-dim);
  background: transparent;
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  padding: 0 10px;
  cursor: pointer;
  transition: all .2s;
}


.card-tile.is-foil .card-tile__foil {
  color: #0c0618;
  font-weight: 700;
  background: linear-gradient(100deg, #f0abfc, #93c5fd, #6ee7b7, #fde68a, #f0abfc);
  background-size: 300% 100%;
  border-color: transparent;
  box-shadow: 0 0 14px rgba(192, 132, 252, 0.7);
  animation: foilSweep 3s linear infinite;
}

.card-tile.is-foil .card-tile__img-wrap::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(115deg,
    transparent 18%,
    rgba(240, 171, 252, 0.28) 32%,
    rgba(147, 197, 253, 0.30) 44%,
    rgba(110, 231, 183, 0.26) 54%,
    rgba(253, 230, 138, 0.24) 64%,
    transparent 80%);
  background-size: 250% 250%;
  mix-blend-mode: screen;
  animation: foilSweep 3.6s ease-in-out infinite alternate;
}

.card-tile.is-foil .card-tile__img-wrap {
  box-shadow: 0 0 18px rgba(240, 171, 252, 0.55), 0 0 50px rgba(147, 197, 253, 0.3), 0 10px 30px rgba(0,0,0,.7);
}

@keyframes foilSweep {
  from { background-position: 0% 50%; }
  to   { background-position: 100% 50%; }
}

.card-tile__name {
  font-weight: 600;
  font-size: 15.5px;
  line-height: 1.25;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.card-tile__set {
  color: var(--text-dim);
  font-size: 13.5px;
  text-transform: uppercase;
  letter-spacing: 1px;
}

/* ============ ORDER BAR ============ */

.order-bar {
  position: fixed;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 30px;
  background: rgba(14, 7, 28, 0.88);
  border: 1px solid rgba(232, 121, 249, 0.45);
  border-radius: 18px;
  padding: 14px 16px 14px 30px;
  backdrop-filter: blur(14px);
  box-shadow: var(--glow-md), 0 20px 60px rgba(0,0,0,.6);
  animation: barRise .5s cubic-bezier(.2,.8,.3,1.2);
}

@keyframes barRise {
  from { transform: translate(-50%, 120px); opacity: 0; }
  to   { transform: translate(-50%, 0); opacity: 1; }
}

.order-bar__info { display: flex; flex-direction: column; line-height: 1.2; }

.order-bar__count {
  font-weight: 600;
  font-size: 15px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--text-dim);
}

.order-bar__price {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 28px;
  color: var(--neon);
  text-shadow: var(--glow-sm);
}

.order-bar__note {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .5px;
  color: var(--text-dim);
  white-space: nowrap;
}

/* ============ MODALS ============ */

.modal {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4vh 4vw;
}

.modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(3, 1, 8, 0.8);
  backdrop-filter: blur(6px);
}

.modal__box {
  position: relative;
  width: min(1100px, 100%);
  max-height: 90vh;
  max-height: 88dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: linear-gradient(160deg, #140a26, #0b0517);
  border: 1px solid rgba(232, 121, 249, 0.4);
  border-radius: 22px;
  padding: 38px;
  box-shadow: var(--glow-lg), 0 40px 120px rgba(0,0,0,.8);
  animation: modalPop .3s cubic-bezier(.2,.8,.3,1.15);
}

.modal__box--narrow { width: min(520px, 100%); }

@keyframes modalPop {
  from { transform: scale(.92) translateY(24px); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

.modal__close {
  position: absolute;
  top: 8px; right: 8px;
  /* 44px box rather than a bare 20px glyph: this used to be a ~20x24 tap
     target in the hardest corner of a phone screen to reach one-handed. */
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  color: var(--text-dim);
  background: none;
  border: none;
  cursor: pointer;
  transition: color .2s, text-shadow .2s;
}


.modal__title {
  font-family: var(--font-display);
  font-size: 26px;
  letter-spacing: 1px;
  margin-bottom: 24px;
  padding-right: 40px;
}

.version-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
  gap: 18px;
}

.version-loading {
  grid-column: 1 / -1;
  text-align: center;
  color: var(--text-dim);
  padding: 40px 0;
  letter-spacing: 2px;
}

.version-tile {
  cursor: pointer;
  border-radius: 10px;
  text-align: center;
  transition: transform .15s;
}


.version-tile img {
  width: 100%;
  border-radius: 4.6% / 3.4%;
  box-shadow: 0 6px 20px rgba(0,0,0,.6);
  transition: box-shadow .2s;
  background: #150b28;
  aspect-ratio: 488 / 680;
  object-fit: cover;
}


.version-tile.is-selected img {
  outline: 2px solid var(--neon-hot);
  box-shadow: var(--glow-md);
}

.version-tile__label {
  margin-top: 7px;
  font-size: 13px;
  color: var(--text-dim);
  line-height: 1.3;
}

/* Order form */
#orderForm label {
  display: block;
  font-weight: 600;
  letter-spacing: 1px;
  text-transform: uppercase;
  font-size: 14px;
  color: var(--text-dim);
  margin-bottom: 18px;
}

#orderForm input, #orderForm textarea { margin-top: 7px; }

.order-summary-line {
  color: var(--text-dim);
  margin: -10px 0 22px;
  font-size: 17px;
}

/* Inline failure message for the order form. This used to be a native
   alert() raised over the open modal — the failure path of the one action on
   the site that involves money deserves to be part of the form. */
.form-error {
  margin: -6px 0 16px;
  padding: 11px 14px;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.45;
  color: #fecdd3;
  background: rgba(159, 18, 57, 0.28);
  border: 1px solid rgba(251, 113, 133, 0.55);
  border-radius: 10px;
}

/* Status line under the single-card search, so a failed lookup no longer needs
   an alert() either. */
.search-status {
  margin-top: 10px;
  min-height: 20px;
  font-size: 15px;
  font-weight: 600;
  color: var(--neon);
  text-shadow: var(--glow-sm);
}

.search-status.is-error { color: #fb7185; text-shadow: 0 0 8px rgba(251, 113, 133, 0.5); }

.order-success { text-align: center; padding: 14px 0; }

.order-success__icon {
  font-size: 64px;
  color: var(--neon-hot);
  text-shadow: var(--glow-lg);
  margin-bottom: 12px;
  animation: titlePulse 2.4s ease-in-out infinite alternate;
}

.order-success p { color: var(--text-dim); margin-bottom: 12px; }

.order-success .btn { margin-top: 14px; }

/* ============ ABOUT PAGE ============ */

/* These were inline `style=` attributes on about.html, which no media query
   could reach without !important — so the 160px top padding stayed at 160px on
   a 393px-wide phone. */
.hero--about {
  min-height: 56vh;
  min-height: 56svh;
  padding: 160px 5vw 60px;
}

.about-prose { text-align: left; }
.about-prose p { color: var(--text-dim); line-height: 1.7; font-size: 18px; }
.about-prose p + p { margin-top: 16px; }
.about-centered { text-align: center; }

.about-lead {
  color: var(--text-dim);
  font-size: 18px;
  line-height: 1.7;
  max-width: 640px;
  margin: 0 auto 26px;
}

.about-title-small { margin-bottom: 18px; font-size: clamp(24px, 3.4vw, 34px); }

.about-legal {
  max-width: 820px;
  margin: 0 auto;
  text-align: center;
  color: var(--text-dim);
  font-size: 14px;
  line-height: 1.7;
}

.about-legal strong { color: var(--text); }

/* min() on the track minimum, so the column can never be asked to be wider
   than the space it has. A bare `minmax(380px, 1fr)` does not shrink — it
   overflows, and body{overflow-x:hidden} then scissors off the right-hand
   edge of every FAQ answer on every phone narrower than ~420px. */
.faq-grid { grid-template-columns: repeat(auto-fit, minmax(min(380px, 100%), 1fr)); }

/* ============ FOOTER ============ */

.footer {
  text-align: center;
  padding: 70px 5vw 110px;
  border-top: 1px solid rgba(124, 58, 237, 0.15);
  font-family: var(--font-display);
  font-size: 20px;
  letter-spacing: 2px;
}

.footer__small {
  font-family: var(--font-ui);
  color: var(--text-dim);
  font-size: 14px;
  margin-top: 14px;
  line-height: 1.7;
}

/* The mobile nav hides every link that is not a button, and these are the only
   route to the About page (and back) on a phone. Keep them here even if the
   nav ever grows a menu — a footer link costs nothing and is where people
   look for secondary navigation anyway. */
.footer__nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px 26px;
  margin-top: 26px;
  font-family: var(--font-ui);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 1px;
  text-transform: uppercase;
}

.footer__nav a { color: var(--text-dim); }

/* ============ POINTER-DEPENDENT ============ */

/* Every :hover rule in this stylesheet lives here, gated on the capability
   rather than on a screen width. The two are different axes: a touch laptop is
   wide and cannot hover, a phone in landscape is neither.

   Ungated, these did two bad things on a phone. The "change version" overlay
   is the only affordance for the feature the whole site is built around, and
   it sat at opacity 0 behind :hover, so it never appeared. And mobile browsers
   emulate hover on first tap for any element carrying a hover rule, which
   leaves highlights stuck on after the finger has gone and can cost a tap. */

@media (hover: hover) and (pointer: fine) {
  .nav__links a:not(.btn):hover { color: var(--neon); text-shadow: var(--glow-sm); }

  .btn:hover {
    transform: translateY(-2px) scale(1.02);
    box-shadow: var(--glow-lg), inset 0 0 24px rgba(232, 121, 249, 0.3);
    filter: brightness(1.15);
  }

  .step:hover {
    border-color: rgba(232, 121, 249, 0.6);
    box-shadow: var(--glow-md);
  }

  .import-link:hover { text-shadow: var(--glow-sm); }

  .search-results__item:hover {
    background: rgba(124, 58, 237, 0.25);
    color: var(--neon);
    text-shadow: var(--glow-sm);
  }

  .card-tile:hover { z-index: 3; }

  .card-tile:hover .card-tile__img-wrap {
    box-shadow: 0 0 22px rgba(192, 132, 252, 0.55), 0 0 70px rgba(124, 58, 237, 0.3), 0 14px 36px rgba(0,0,0,.7);
  }

  .card-tile:hover .card-tile__overlay { opacity: 1; }

  .ctl:hover { color: var(--neon); border-color: var(--neon); box-shadow: var(--glow-sm); }

  .ctl--remove:hover { color: #fb7185; border-color: #fb7185; box-shadow: 0 0 8px rgba(251, 113, 133, 0.5); }

  .card-tile__foil:hover { color: var(--neon); border-color: var(--neon); box-shadow: var(--glow-sm); }

  .modal__close:hover { color: var(--neon-hot); text-shadow: var(--glow-sm); }

  .version-tile:hover { transform: translateY(-4px) scale(1.03); }

  .version-tile:hover img { box-shadow: 0 0 18px rgba(192,132,252,.6), 0 10px 26px rgba(0,0,0,.7); }
}

/* ============ RESPONSIVE ============ */

@media (max-width: 900px) {
  .how, .builder { padding: 80px 5vw; }
}

@media (max-width: 760px) {
  :root {
    --nav-h: 58px;
    /* bar (~52px) + 12px off the bottom + breathing room; safe-area is added
       by the bar's own padding, so it is not counted here. */
    --order-bar-space: 80px;
    /* The dim text is dim by design on a desktop, but 12–13px of a condensed
       face in this grey on a dark ground is what fails in sunlight. A touch
       lighter at phone sizes only. */
    --text-dim: #ae9fd0;
  }

  /* --- nav. At 24px with 2px tracking the logo and the order button needed
         ~485px on one line, so the fixed nav silently grew to two rows. --- */
  .nav { padding: 11px 14px; }
  .nav__logo { font-size: 17px; letter-spacing: 1px; white-space: nowrap; }
  .nav__links a:not(.btn) { display: none; }
  .nav__links .btn--small { font-size: 12px; padding: 8px 12px; letter-spacing: 1px; }

  /* --- rhythm. 110px above and below every section is a quarter of a phone
         screen of nothing between each one. --- */
  .how, .builder { padding: 56px 5vw; }
  .section-title { margin-bottom: 32px; }
  .footer { padding: 44px 5vw 90px; }

  /* --- type. Cinzel with 3–6px of tracking is a desktop gesture; at 360px
         it pushed the section titles to three lines and left the kicker
         reading as separate letters. Halved here, and nothing in the UI face
         goes under 13px — Rajdhani is condensed and thin, so 11–12.5px of it
         in dim text was the first thing to become illegible outdoors. The
         one exception is the ≤420px nav button, which is fighting for the
         single row the logo shares with it. --- */
  .hero__kicker { letter-spacing: 3px; font-size: 13px; }
  .hero__title { font-size: clamp(30px, 8vw, 104px); }
  .section-title { letter-spacing: 1.5px; }
  .deck-head h3 { letter-spacing: 1px; }

  /* --- hero --- */
  .hero { padding: 92px 5vw 56px; }
  .hero__content { padding: 40px 18px; }
  .hero__sub { font-size: 17px; margin-bottom: 28px; }
  .hero__scroll-hint { display: none; }
  .hero-card { width: 26vw; }
  .hero-card:nth-child(1), .hero-card:nth-child(5) { display: none; }
  /* AFTER .hero-card, not before. Same specificity, so source order decides,
     and the centre card used to lose its size distinction here. */
  .hero-card--center { width: 34vw; }

  /* --- paint budget. nebulaDrift animates a filter on a fixed full-viewport
         layer, which repaints the entire screen every frame, forever. And the
         quantity badge carries a backdrop-filter, so a 100-card deck put 100
         separate backdrop-blur layers on screen at once. Blur survives on the
         nav, the order bar and the modal backdrop — three elements, all of
         them actually seen against moving content. --- */
  .bg-nebula { animation: none; }
  .card-tile__qty { backdrop-filter: none; background: rgba(12, 6, 24, 0.95); }
  .step, .import-panel, .add-card-panel {
    backdrop-filter: none;
    background: rgba(20, 11, 38, 0.93);
  }

  /* --- import --- */
  .import-row { flex-direction: column; }
  .import-tab { padding: 11px 14px; font-size: 15px; }

  /* The bookmarklet asks you to drag a button onto a bookmarks bar. A phone
     has neither, so this was an impossible option shown FIRST — at the exact
     moment an import has already failed. The paste route works everywhere. */
  .mox-helper__cols { grid-template-columns: 1fr; }
  .mox-way--drag { display: none; }

  /* --- card grid --- */
  .card-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 14px; }
  .card-tile__set { font-size: 13px; }

  /* Most Magic card names do not fit 140px on one line, and a title tooltip
     cannot be shown by a finger — so the name simply was not readable. */
  .card-tile__name {
    white-space: normal;
    font-size: 14px;
    /* Reserve two lines so the controls below stay on one baseline across a
       row, instead of stepping up and down with the length of each name. */
    min-height: 2.5em;
  }

  /* The overlay is the only hint that a card can be tapped to change its
     printing, and hover cannot reveal it here. Show it at rest instead. */
  .card-tile__overlay {
    opacity: 1;
    padding: 22px 6px 7px;
    font-size: 13px;
    letter-spacing: .5px;
    background: linear-gradient(180deg, transparent, rgba(6,3,13,.88));
  }

  /* --- card controls. Five buttons in one unwrapped flex row needed ~208px
         inside a ~170px tile, so flex-shrink squeezed the three square buttons
         from the 28px they are written as down to about 20px — under the 24px
         WCAG 2.2 minimum — and left remove 6px from increment, where the
         cheapest misfire deleted a card. Two grid rows instead: the stepper on
         top, foil and remove underneath, 44px targets throughout, and remove
         on a different row from the +. --- */
  .card-tile__controls {
    display: grid;
    grid-template-columns: 44px minmax(0, 1fr) 44px;
    grid-template-areas:
      "dec qty inc"
      "foil foil rm";
    gap: 6px;
    margin-top: 10px;
  }

  .ctl--dec { grid-area: dec; }
  .ctl-qty  { grid-area: qty; align-self: center; min-width: 0; font-size: 16px; }
  .ctl--inc { grid-area: inc; }
  .ctl--remove { grid-area: rm; }
  .ctl { width: 100%; height: 44px; font-size: 17px; }

  .card-tile__foil {
    grid-area: foil;
    width: 100%;
    height: 44px;
    padding: 0 6px;
    font-size: 13px;
    letter-spacing: .5px;
  }

  /* --- order bar. This used to stack three rows — count, price, the billing
         note, then a full-width button — and stood ~145px tall: nearly a
         quarter of a phone screen, permanently, over the deck being edited.
         Now one ~52px row: price, count, compact button. The billing note is
         dropped here (not moved) because the order modal already shows the
         same sheet arithmetic at the moment it matters. `--order-bar-space`
         above is sized to this. --- */
  .order-bar {
    left: 12px;
    right: 12px;
    bottom: 12px;
    width: auto;
    transform: none;
    gap: 12px;
    padding: 8px 8px 8px 16px;
    padding-bottom: calc(8px + env(safe-area-inset-bottom, 0px));
    border-radius: 14px;
    animation-name: barRiseMobile;
  }

  .order-bar__info {
    flex: 1;
    min-width: 0;
    flex-direction: row;
    align-items: baseline;
    gap: 10px;
    /* The count wraps under the price only if the screen is too narrow for
       the row — never past the button. */
    flex-wrap: wrap;
  }
  /* Price first: it is the number the customer is watching. */
  .order-bar__price { order: -1; font-size: 21px; }
  .order-bar__count { font-size: 13px; letter-spacing: .5px; }
  .order-bar__note { display: none; }
  .order-bar__btn-long { display: none; }
  .order-bar .btn { flex: none; font-size: 15px; padding: 11px 16px; letter-spacing: 1px; }

  /* --- modals. 38px of padding at every width left ~284px of content, so the
         version grid could only ever fit one 170px column: browsing dozens of
         printings one full-width image at a time. Anchored to the top rather
         than centred, so a form stays visible once the keyboard is up. --- */
  .modal { padding: 14px 12px; align-items: flex-start; }
  .modal__box { padding: 24px 14px; border-radius: 16px; }
  .modal__box--narrow { width: 100%; }
  .modal__title { font-size: 21px; margin-bottom: 18px; }
  .version-grid { grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); gap: 10px; }
  .version-tile__label { font-size: 13px; }

  /* --- forms --- */
  .search-results__item { padding: 13px 16px; }
  .order-summary-line { font-size: 16px; }

  /* --- about page. These were inline styles, so 160px of hero padding
         applied at 393px wide too. --- */
  .hero--about { padding: 104px 5vw 40px; }
  .about-prose p, .about-lead { font-size: 16.5px; }
}

/* The centred pill slides up on its own axis; the full-width mobile bar has no
   translateX to preserve, so it needs its own keyframes. */
@keyframes barRiseMobile {
  from { transform: translateY(120px); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

@media (max-width: 420px) {
  /* Below this the logo and the order button stop fitting on one line, so the
     fixed nav grew a second row. Dropping "THE " and a little type buys back
     about 90px, which holds down to 320px. */
  .nav__logo-the { display: none; }
  .nav__logo { font-size: 15px; }
  .nav__links .btn--small { font-size: 11px; padding: 7px 10px; letter-spacing: .5px; }
  .hero__content { padding: 32px 14px; }
  .card-grid { grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); gap: 12px; }
}

/* ============ REDUCED MOTION ============ */

/* Eight infinite animations, a smooth-scrolling document, a parallax hero and
   tilting tiles, and until now nothing here honoured this preference. People
   set it for vestibular reasons as often as for taste, and a drifting,
   pulsing, twinkling page is exactly the trigger. Doubles as a battery saver
   on phones, where the ambient loops never stop. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }

  /* Stated outright rather than left to the failsafe above, so content is
     never sitting at opacity 0 waiting on anything. */
  .reveal { opacity: 1; transform: none; }

  .bg-nebula, .bg-stars, .hero-card,
  .hero__title-line--neon, .hero__scroll-hint span,
  .card-tile.is-foil .card-tile__foil,
  .card-tile.is-foil .card-tile__img-wrap::after,
  .order-success__icon { animation: none !important; }
}
