/* ============================================================
   Variant B — standalone stylesheet, fresh slate.

   The only stylesheet index_b.html loads; nothing from
   css/styles.css applies. Shell concept (tokens, ground, bar,
   legal footer) borrowed from party_packs.css, but this is a
   normal scrolling homepage document, not the fixed one-act
   app frame Party Packs uses.
   ============================================================ */

/* ---- Tokens (Party Packs ground; adjust as the design lands) ---- */
:root {
  --vb-ink-0: #07080c;
  --vb-ink-1: #0d0f16;
  --vb-ink-2: #141824;
  --vb-ink-3: #1c2130;
  --vb-line: rgba(255, 255, 255, .07);
  --vb-line-2: rgba(255, 255, 255, .13);
  --vb-text: #f2f4f9;
  --vb-dim: #99a1b5;
  --vb-dimmer: #626b80;
  --vb-gold: #e9cd97;
  --vb-gold-2: #d8b57a;
  --vb-gold-deep: #a9834a;
  --vb-mint: #6fe3b0;
  --vb-rose: #ff8fa5;
  --vb-holo: linear-gradient(115deg, #8ee9ff 0%, #c9a6ff 22%, #ffd9a8 45%, #9dffd2 68%, #a9c8ff 88%);
  --vb-ease: cubic-bezier(.2, .9, .25, 1);
  /* active pack accent as an r,g,b triple — set live from vb.js */
  --vb-acc: 158, 212, 255;
  --vb-gutter: 20px;
  --vb-max-width: 72rem;
}

/* ---- Reset + ground ---- */
* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }

html { -webkit-text-size-adjust: 100%; }

body {
  min-height: 100vh;
  overflow-x: clip; /* full-viewport breakouts must never pan the page */
  display: flex;
  flex-direction: column;
  color: var(--vb-text);
  background:
    radial-gradient(120% 90% at 50% -10%, #0c101e 0%, #07080d 55%, #05060a 100%);
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

img, svg, video { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; color: inherit; }
button { border: 0; background: none; cursor: pointer; }
a { color: inherit; }

/* ---- Aurora ground: dark holo field tinted by the active pack ---- */
.vb-aurora {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
/* the light engine: a low-res canvas, CSS-stretched — the upscale is
   what makes the edge lume read as soft light rather than a gradient */
.vb-aurora-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}



/* page chrome sits above the sky */
.vb-bar, .vb-main, .vb-legal-footer { position: relative; z-index: 1; }

/* ---- Header bar ---- */
.vb-bar {
  position: sticky;
  top: 0;
  z-index: 70;
  min-height: 68px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: calc(env(safe-area-inset-top) + 14px) var(--vb-gutter) 12px;
  border-bottom: 1px solid rgba(255, 255, 255, .08);
  background: rgba(7, 8, 12, .54);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
}

.vb-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--vb-text);
  text-decoration: none;
}
.vb-brand img { width: 34px; height: 34px; object-fit: contain; }
.vb-brand > span { font-size: 20px; line-height: 1; font-weight: 800; }
.vb-brand small { color: var(--vb-gold); font-size: .62em; }

.vb-bar-actions { display: flex; align-items: center; gap: 10px; }

.vb-balance {
  display: grid;
  min-width: 92px;
  padding: 7px 12px;
  color: var(--vb-text);
  text-decoration: none;
  text-align: right;
  border: 1px solid rgba(255, 255, 255, .12);
  background: rgba(10, 12, 18, .72);
}
.vb-balance small {
  color: var(--vb-dim);
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
  text-transform: uppercase;
}
.vb-balance strong { margin-top: 4px; color: var(--vb-gold); font-size: 14px; line-height: 1; }
.vb-balance.is-login { display: inline-flex; justify-content: center; align-items: center; font-weight: 800; }

/* ---- the ledger: Balance and Rewards, one card, two rows. Each row is its
   own link (balance -> account, rewards -> the vault's redeem panel). The
   rewards row is driven by points_widget.js; it reserves its space while the
   fetch is in flight so the bar never jumps, and drops out if the program is
   dark. ---- */
.vb-ledger {
  display: grid;
  gap: 3px;
  min-width: 164px;
  padding: 6px 12px 7px;
  border: 1px solid rgba(255, 255, 255, .12);
  background: rgba(10, 12, 18, .72);
}
.vb-ledger .vb-balance,
.vb-rewards {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: baseline;
  gap: 12px;
  min-width: 0;
  padding: 0;
  border: 0;
  background: transparent;
  text-align: right;
  color: var(--vb-text);
  text-decoration: none;
}
.vb-ledger .vb-balance small,
.vb-rewards small {
  color: var(--vb-dim);
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: .05em;
  text-transform: uppercase;
  text-align: left;
}
.vb-ledger .vb-balance strong { margin-top: 0; font-variant-numeric: tabular-nums; }
.vb-rewards strong {
  display: inline-flex;
  justify-content: flex-end;
  align-items: baseline;
  gap: 4px;
  color: #dccbff;
  font-size: 14px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.vb-rewards strong b { font-weight: inherit; line-height: 1; }
.vb-rewards strong i { font-style: normal; font-size: 11px; line-height: 1; color: #c4b5fd; filter: drop-shadow(0 0 4px rgba(196, 181, 253, .7)); }
.vb-rewards.is-pending { visibility: hidden; }
.vb-rewards.is-off { display: none; }
.vb-rewards.is-ready small { color: #f0abfc; }
.vb-rewards.is-ready strong { color: #ffffff; text-shadow: 0 0 10px rgba(240, 171, 252, .9); }
@media (hover: hover) {
  .vb-ledger a:hover strong { filter: brightness(1.18); }
}
/* the ledger label abbreviates on phones ("Balance" -> "BAL:") so the card
   stops crowding the hamburger. The rewards half is swapped in
   points_widget.js, which owns that text. */
.vb-lbl-abbr { display: none; }
@media (max-width: 480px) {
  .vb-lbl-full { display: none; }
  .vb-lbl-abbr { display: inline; }
}

/* narrow phones: the wordmark gives up its ".com" and a couple of points so
   the ledger never has to squeeze */
@media (max-width: 430px) {
  .vb-bar.has-ledger .vb-brand small { display: none; }
  .vb-bar.has-ledger .vb-brand > span { font-size: 17px; }
  .vb-ledger { min-width: 0; padding: 6px 10px 7px; }
  .vb-ledger .vb-balance, .vb-rewards { gap: 10px; }
}

.vb-menu { position: relative; }
.vb-menu summary {
  width: 42px;
  height: 42px;
  display: grid;
  place-content: center;
  gap: 4px;
  cursor: pointer;
  list-style: none;
  border: 1px solid rgba(255, 255, 255, .14);
  background: rgba(10, 12, 18, .72);
}
.vb-menu summary::-webkit-details-marker { display: none; }
.vb-menu summary i { width: 17px; height: 2px; background: var(--vb-text); }
.vb-menu nav {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  width: 220px;
  padding: 8px;
  border: 1px solid rgba(255, 255, 255, .14);
  background: rgba(9, 11, 17, .98);
  box-shadow: 0 24px 50px rgba(0, 0, 0, .45);
}
.vb-menu nav a,
.vb-menu nav button {
  width: 100%;
  display: block;
  padding: 11px 12px;
  color: var(--vb-text);
  text-decoration: none;
  text-align: left;
  font-size: 13px;
  font-weight: 700;
}
.vb-menu nav a:hover,
.vb-menu nav button:hover { background: rgba(255, 255, 255, .07); }
.vb-menu form { margin: 0; }

/* ---- Promo ribbon: thin strip fused to the bottom of the bar ---- */
.vb-promo {
  position: relative;
  z-index: 60;
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: .45rem;
  padding: 7px var(--vb-gutter) 8px;
  border-bottom: 1px solid rgba(255, 255, 255, .08);
  background: rgba(10, 12, 18, .6);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  color: #e8edf7;
  font-size: 12.5px;
  font-weight: 800;
  letter-spacing: .01em;
  text-align: center;
  white-space: nowrap;
}
.vb-promo small {
  color: var(--vb-dim);
  font-size: 10px;
  font-weight: 750;
  letter-spacing: .07em;
  text-transform: uppercase;
}

/* shared living-iridescence text utility */
.vb-iris {
  background: linear-gradient(100deg,
    #8fe8ff 0%, #b9a7ff 16%, #ffb0e6 32%, #ffe1a1 48%,
    #a9ffcf 64%, #8fc9ff 82%, #8fe8ff 100%);
  background-size: 200% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 1px 9px rgba(140, 170, 255, .2));
  animation: vb-iris 8s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .vb-iris { animation: none; }
}

/* ---- Main / layout primitives ---- */
.vb-main { flex: 1 0 auto; }

.vb-container {
  width: 100%;
  max-width: var(--vb-max-width);
  margin-inline: auto;
  padding-inline: var(--vb-gutter);
}

/* ---- Legal footer ---- */
.vb-legal-footer {
  min-height: 62px;
  padding: 14px clamp(20px, 4vw, 64px) calc(env(safe-area-inset-bottom) + 14px);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px 28px;
  border-top: 1px solid rgba(255, 255, 255, .08);
  color: var(--vb-dim);
  background: rgba(7, 8, 12, .9);
}
.vb-legal-copy { min-width: 0; display: grid; gap: 2px; }
.vb-legal-copy span { color: #c7ccda; font-size: 11px; font-weight: 750; }
.vb-legal-copy small { max-width: 790px; font-size: 9px; line-height: 1.35; }
.vb-legal-footer nav { flex: none; display: flex; align-items: center; gap: 20px; }
.vb-legal-footer nav a {
  color: #c7ccda;
  font-size: 11px;
  font-weight: 750;
  text-decoration: none;
}
.vb-legal-footer nav a:hover { color: var(--vb-gold); }

/* ============================================================
   1. RIP DEMO STAGE
   ============================================================ */
.vb-demo {
  /* Pack geometry lives here so the card stage, the contact shadow and
     the stage light can all derive from it and stay in lockstep. */
  --pack-h: min(44vh, 400px);
  --pack-top: 74px;
  position: relative;
  padding: 18px 0 30px;
  overflow-x: clip;
  overflow-y: visible;
}

/* ---- Pack rail: scroll-snap carousel, center slide featured,
        neighbors peeking on both sides ---- */
/* stage light: the centre pack is lit from behind, which separates it
   from the ground and makes the rack feel like a display, not a list */
.vb-demo::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 0;
  width: min(92vw, 480px);
  height: calc(var(--pack-h) + 48px);
  transform: translateX(-50%);
  background:
    radial-gradient(48% 46% at 50% 44%, rgba(var(--vb-acc), .15) 0%, rgba(var(--vb-acc), .04) 46%, rgba(0, 0, 0, 0) 72%);
  pointer-events: none;
  z-index: 0;
}
/* contact shadow so the pack sits on something */
.vb-demo::after {
  content: "";
  position: absolute;
  left: 50%;
  top: calc(var(--pack-top) + var(--pack-h) - 9px);
  width: min(46vw, 210px);
  height: 26px;
  transform: translateX(-50%);
  background: radial-gradient(50% 50% at 50% 50%, rgba(0, 0, 0, .58), rgba(0, 0, 0, 0) 72%);
  filter: blur(3px);
  pointer-events: none;
  z-index: 0;
}

.vb-demo-rail {
  display: flex;
  gap: 0;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  /* side padding so first/last slides can center */
  padding-inline: calc(50% - min(33vw, 150px));
  /* above the card stage: cards ride BEHIND the pack until they clear it */
  position: relative;
  z-index: 2;
}
.vb-demo-rail::-webkit-scrollbar { display: none; }

.vb-demo-slide {
  flex: 0 0 min(60vw, 270px);
  scroll-snap-align: center;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0 4px;
  /* scale/light are driven per-frame by JS from real scroll distance
     (updateRailVisuals) — transitioning them here would smear that.
     The static values below are only the pre-JS first paint. */
  transition: opacity .34s var(--vb-ease);
  transform: scale(.78) translateY(6px);
  /* dim by darkening, never by transparency — the packs stay solid
     objects in front of the dome, they just fall out of the light */
  filter: brightness(.42) saturate(.65);
  /* the rail animates constantly while scrolling — stay composited */
  will-change: transform, filter;
}
.vb-demo-slide.is-active {
  transform: scale(1) translateY(0);
  filter: none;
}
/* One identical art box for every pack: same height, contained fit,
   no per-pack special treatment. */
.vb-demo-art {
  height: var(--pack-h);
  width: auto;
  max-width: 100%;
  object-fit: contain;
  user-select: none;
  -webkit-user-drag: none;
  filter: drop-shadow(0 26px 44px rgba(0, 0, 0, .55));
  /* invisible until decoded — a pack fades in, an empty box never shows */
  opacity: 0;
  transition: opacity .35s ease;
}
.vb-demo-art.is-ready { opacity: 1; }
.vb-demo-slide.is-active { cursor: pointer; }

/* the action label riding the top of the pack — frost pill, only on the
   pack that's on stage; doubles as the status line while a sim opens */
.vb-pack-cta {
  position: absolute;
  left: 50%;
  top: 3.2%;
  z-index: 9;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 14px;
  border-radius: 999px;
  border: 1px solid rgba(var(--vb-acc), .45);
  /* dark glass, lit from within — matches the CTA's lit-tube language
     instead of reading as a sticker on the art */
  background: linear-gradient(180deg, rgba(13, 20, 36, .82), rgba(7, 10, 20, .88));
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: #f2f7ff;
  font-size: 9.5px;
  font-weight: 850;
  letter-spacing: .14em;
  text-transform: uppercase;
  white-space: nowrap;
  text-shadow: 0 0 8px rgba(var(--vb-acc), .55);
  box-shadow:
    0 0 0 1px rgba(6, 19, 47, .4),
    0 0 12px rgba(var(--vb-acc), .26),
    inset 0 1px 0 rgba(255, 255, 255, .14),
    inset 0 0 12px rgba(var(--vb-acc), .1);
  transition: opacity .28s var(--vb-ease), box-shadow 700ms var(--vb-ease), border-color 700ms var(--vb-ease);
  opacity: 0;
  transition: opacity .28s var(--vb-ease);
  pointer-events: none;
  animation: vb-chip-breathe 3.8s ease-in-out infinite;
}

/* live dot: the small pulse that says "this is the interactive one" */
.vb-pack-cta::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: rgb(var(--vb-acc));
  box-shadow: 0 0 7px rgba(var(--vb-acc), .9);
  transition: background 700ms var(--vb-ease), box-shadow 700ms var(--vb-ease);
  animation: vb-chip-dot 2.2s ease-in-out infinite;
}

@keyframes vb-chip-breathe {
  0%, 100% {
    border-color: rgba(178, 216, 255, .34);
    box-shadow:
      0 0 0 1px rgba(6, 19, 47, .4),
      0 0 10px rgba(120, 195, 255, .16),
      inset 0 1px 0 rgba(255, 255, 255, .12),
      inset 0 0 10px rgba(120, 195, 255, .06);
  }
  50% {
    border-color: rgba(206, 234, 255, .6);
    box-shadow:
      0 0 0 1px rgba(6, 19, 47, .4),
      0 0 16px rgba(120, 195, 255, .34),
      inset 0 1px 0 rgba(255, 255, 255, .18),
      inset 0 0 14px rgba(120, 195, 255, .12);
  }
}
@keyframes vb-chip-dot {
  0%, 100% { opacity: .55; transform: scale(.9); }
  50% { opacity: 1; transform: scale(1.15); }
}

.vb-demo-slide.is-active .vb-pack-cta { opacity: 1; }
/* the top of the pack is dissolving — the label steps aside */
.vb-pack-shell.is-opened .vb-pack-cta { opacity: 0 !important; }
.vb-pack-shell { transition: transform .18s var(--vb-ease); }
.vb-demo-slide.is-active:active .vb-pack-shell { transform: scale(.988); }

.vb-demo-slide.is-active .vb-demo-art {
  filter: drop-shadow(0 30px 54px rgba(0, 0, 0, .6)) drop-shadow(0 0 34px rgba(233, 205, 151, .12));
}

/* ---- Info block synced to the active slide ----
   Every block below the rack holds its height, so swiping between packs
   never shifts the layout — only the words change. ---- */
.vb-demo-info {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 420px;
  margin-inline: auto;
  padding-inline: var(--vb-gutter);
  text-align: center;
}

/* identity: name → promise → qualifier, anchored to its own baseline so
   the slider below never moves when the copy runs long */
.vb-demo-tagline {
  margin-top: 18px;
  font-size: clamp(17px, 5.4vw, 22px);
  font-weight: 850;
  letter-spacing: -.005em;
  line-height: 1.2;
  color: #f4f8ff;
  white-space: nowrap;
  text-shadow: 0 2px 18px rgba(0, 0, 0, .5);
}

/* ---- close wrapper ---- */
.vb-demo-info {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 420px;
  margin-inline: auto;
  padding-inline: var(--vb-gutter);
  text-align: center;
}

/* Feature strip: three sectioned cells — left / middle / right — divided
   by hairlines, one condensed benefit each. Fixed grid, so nothing
   reflows between packs. */
.vb-feats {
  width: 100%;
  margin: 18px 0 0;
  padding: 14px 0 16px;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  list-style: none;
  border-top: 1px solid rgba(255, 255, 255, .09);
  border-bottom: 1px solid rgba(255, 255, 255, .09);
}
.vb-feats li {
  display: grid;
  gap: 5px;
  justify-items: center;
  align-content: start;
  padding: 2px 8px;
  text-align: center;
  min-width: 0;
  /* one beat taller: room for wrapped lines on narrow screens */
  min-height: 3.4rem;
}
.vb-feats li + li { border-left: 1px solid rgba(255, 255, 255, .09); }
.vb-feats b {
  color: #eaf1fb;
  transition: color 700ms var(--vb-ease);
  font-size: 12.5px;
  font-weight: 850;
  letter-spacing: .005em;
  line-height: 1.2;
  text-wrap: balance;
}
.vb-feats small {
  color: rgba(153, 161, 181, .92);
  font-size: 9px;
  font-weight: 750;
  letter-spacing: .09em;
  text-transform: uppercase;
  line-height: 1.4;
  text-wrap: balance;
}
/* single-line facts: a stacked ruled list instead of cramped columns */
.vb-feats.is-lines { grid-template-columns: 1fr; padding: 6px 0; }
.vb-feats.is-lines li {
  min-height: 0;
  padding: 8px 8px;
}
.vb-feats.is-lines li + li {
  border-left: 0;
  border-top: 1px solid rgba(255, 255, 255, .09);
}
.vb-feats.is-lines b { font-size: 13.5px; }

/* the headline fact of each pack: the same living iridescent ribbon
   as the proof band — one line per pack earns the shine */
.vb-feats em {
  font-style: normal;
  font-weight: 850;
  background: linear-gradient(100deg,
    #8fe8ff 0%, #b9a7ff 16%, #ffb0e6 32%, #ffe1a1 48%,
    #a9ffcf 64%, #8fc9ff 82%, #8fe8ff 100%);
  background-size: 200% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 1px 9px rgba(140, 170, 255, .2));
  animation: vb-iris 8s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .vb-feats em { animation: none; }
}

/* the close: buy + details, centred under the stage */
.vb-pitch {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: 420px;
  margin: 6px auto 0;
  padding-inline: var(--vb-gutter);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

/* Animatable bloom radius for the buy button's cursor-origin fill. */
@property --vb-fill-r {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}

/* Self-hosted pixel face for the arcade CTA (OFL, latin subset, 4.7KB). */
@font-face {
  font-family: "Press Start 2P";
  src: url("../fonts/press-start-2p-latin.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* Arcade buy button: dark pixel slab wrapped in a drifting holo-neon ring,
   matching the Party Pack creative. The corners are true 8-bit staircases —
   one shared stepped polygon clips the face, the ring, and the bloom. */
.vb-buy {
  /* two-step pixel corners, 5px per step */
  --vb-pixel-clip: polygon(
    0 10px, 5px 10px, 5px 5px, 10px 5px, 10px 0,
    calc(100% - 10px) 0, calc(100% - 10px) 5px, calc(100% - 5px) 5px, calc(100% - 5px) 10px, 100% 10px,
    100% calc(100% - 10px), calc(100% - 5px) calc(100% - 10px), calc(100% - 5px) calc(100% - 5px),
    calc(100% - 10px) calc(100% - 5px), calc(100% - 10px) 100%,
    10px 100%, 10px calc(100% - 5px), 5px calc(100% - 5px), 5px calc(100% - 10px), 0 calc(100% - 10px)
  );
  position: relative;
  width: 100%;
  margin-top: 20px;
  padding: 19px 24px 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  border: 0;
  /* the button IS the holo ring: gradient clipped to the pixel shape, with
     the dark face painted 4px inside it by ::before */
  clip-path: var(--vb-pixel-clip);
  background: linear-gradient(100deg, #3ee6ff, #7c5cff 30%, #ff5ce1 55%, #ffd35c 78%, #3ee6ff);
  background-size: 300% 100%;
  color: #ffffff;
  font-family: "Press Start 2P", "Courier New", monospace;
  font-size: 11.5px;
  font-weight: 400;
  line-height: 1;
  letter-spacing: .04em;
  text-transform: uppercase;
  text-decoration: none;
  text-shadow: 0 2px 0 rgba(0, 0, 0, .7), 0 0 10px rgba(150, 210, 255, .35);
  /* neon bloom: drop-shadows trace the stepped silhouette exactly */
  filter:
    drop-shadow(0 0 7px rgba(62, 230, 255, .5))
    drop-shadow(0 0 18px rgba(155, 92, 255, .38))
    drop-shadow(0 8px 22px rgba(0, 0, 0, .45));
  animation: vb-buy-holo 7s linear infinite;
  transition: filter .18s ease, transform .12s ease;
}

/* the dark pixel slab, leaving a 4px gradient rim all the way around */
.vb-buy::before {
  content: "";
  position: absolute;
  inset: 4px;
  z-index: 0;
  clip-path: var(--vb-pixel-clip);
  background: linear-gradient(180deg, #191c30 0%, #0d0f1d 52%, #14102a 100%);
  pointer-events: none;
}

/* hover fill: the face tiles over in iridescent pixels, sweeping in from
   the right like the party-plaza floor, and holds while hovered */
.vb-buy::after {
  content: "";
  position: absolute;
  inset: 4px;
  z-index: 0;
  clip-path: var(--vb-pixel-clip);
  pointer-events: none;
  /* the fill IS the border: the ring's gradient flooding inward, dimmed
     just enough that the label stays crisp. Same keyframes as the ring, so
     face and border shimmer as one continuous holo surface. */
  background:
    linear-gradient(rgba(10, 10, 26, .42), rgba(10, 10, 26, .42)),
    linear-gradient(100deg, #3ee6ff, #7c5cff 30%, #ff5ce1 55%, #ffd35c 78%, #3ee6ff);
  background-size: auto, 300% 100%;
  animation: vb-buy-holo 7s linear infinite;
  /* the fill BLOOMS from the cursor's touch point (vb.js feeds --hx/--hy),
     the radius expanding in stepped digital rings */
  -webkit-mask-image: radial-gradient(circle at var(--hx, 50%) var(--hy, 50%),
    #000 calc(var(--vb-fill-r) - 0.5%), transparent var(--vb-fill-r));
  mask-image: radial-gradient(circle at var(--hx, 50%) var(--hy, 50%),
    #000 calc(var(--vb-fill-r) - 0.5%), transparent var(--vb-fill-r));
  transition: --vb-fill-r .38s steps(8);
}

/* the bloom is a hover story — only devices that can truly hover get it,
   so taps on touch never trigger a sticky half-fill */
@media (hover: hover) and (pointer: fine) {
  .vb-buy:hover::after {
    --vb-fill-r: 140%;
    transition: --vb-fill-r .55s steps(11);
  }
}

.vb-buy:focus-visible::after {
  --vb-fill-r: 140%;
  transition: --vb-fill-r .55s steps(11);
}

/* touch: a crisp press-flash instead — the face floods instantly while the
   finger is down, releases with the tap */
@media (hover: none), (pointer: coarse) {
  .vb-buy:active::after {
    --vb-fill-r: 140%;
    transition: --vb-fill-r .12s ease-out;
  }
}

.vb-buy > span {
  position: relative;
  z-index: 1;
}

/* the text catches the same shine: white base with the iridescent band
   clipped into the letters, marching in the same pixel steps */
/* on the lit tile floor the label deepens its shadow to stay crisp */
.vb-buy:focus-visible > span,
.vb-buy:active > span {
  text-shadow: 0 2px 0 rgba(0, 0, 0, .9), 0 0 10px rgba(6, 8, 18, .8);
}

@media (hover: hover) and (pointer: fine) {
  .vb-buy:hover > span {
    text-shadow: 0 2px 0 rgba(0, 0, 0, .9), 0 0 10px rgba(6, 8, 18, .8);
  }
}

/* pixel chevron riding the label */
.vb-buy > span::after {
  content: " >";
  color: #7deaff;
  text-shadow: 0 0 8px rgba(62, 230, 255, .8);
}

@media (hover: hover) and (pointer: fine) {
  .vb-buy:hover {
    transform: translateY(-1px);
    filter:
      drop-shadow(0 0 9px rgba(62, 230, 255, .75))
      drop-shadow(0 0 24px rgba(255, 92, 225, .5))
      drop-shadow(0 10px 24px rgba(0, 0, 0, .5));
  }
}

.vb-buy:focus-visible {
  transform: translateY(-1px);
  filter:
    drop-shadow(0 0 9px rgba(62, 230, 255, .75))
    drop-shadow(0 0 24px rgba(255, 92, 225, .5))
    drop-shadow(0 10px 24px rgba(0, 0, 0, .5));
}

.vb-buy:active { transform: translateY(1px) scale(.995); }

@keyframes vb-buy-holo {
  0% { background-position: 0% 0; }
  100% { background-position: 300% 0; }
}

@media (prefers-reduced-motion: reduce) {
  .vb-buy, .vb-buy::before, .vb-buy::after, .vb-buy > span { animation: none; }
}

/* quiet secondary — the pack art opens the same sheet */
.vb-details {
  display: block;
  margin: 12px auto 0;
  padding: 4px 10px;
  color: rgba(160, 200, 236, .7);
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
  background: none;
  border: 0;
  transition: color .18s ease;
}
/* variant: rides directly under the pack, before the tagline */
.vb-details-underpack {
  margin: 0 auto 12px;
}
.vb-details span {
  margin-left: 4px;
  font-size: 12px;
  vertical-align: -.5px;
}
.vb-details:hover,
.vb-details:focus-visible { color: #dcefff; }

/* ---- Pack open cinematic: the cut is a canvas particle dissolve
        along a seam curve (ported from playPackTopDissolve on the rip
        stage). The pack top disintegrates — nothing slices off. ---- */
.vb-pack-shell {
  /* seam height; the dissolve computes the exact curve and writes
     --pack-cut-* back onto this element */
  --pack-tear-left: 18%;
  --pack-tear-right: 25%;
  --pack-cut-left-y: 20%;
  --pack-cut-right-y: 20%;
  --pack-cut-curve: 26% 20%, 50% 19%, 74% 20%;
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

.vb-pack-dissolve {
  position: absolute;
  inset: 0;
  z-index: 7;
  display: block;
  width: 100%;
  height: 100%;
  opacity: 0;
  pointer-events: none;
  transform: translateZ(0);
}
.vb-pack-dissolve.is-live { opacity: 1; }

/* the pack body clips to the dissolved seam and holds open */
.vb-pack-shell.is-opened .vb-demo-art {
  clip-path: polygon(0 var(--pack-cut-left-y), var(--pack-cut-curve), 100% var(--pack-cut-right-y), 100% 100%, 0 100%);
  transition: clip-path 220ms ease;
}

/* ---- Card stage: the whole pack empties AT ONCE — every card bursts
        out together, fully clears the pack, and lands in front of it as
        a fanned stack. Then the stack iterates. ---- */
.vb-pack-stage {
  position: absolute;
  left: 50%;
  top: var(--pack-top);
  width: min(60vw, 270px);
  height: var(--pack-h);
  transform: translateX(-50%);
  pointer-events: none;
  /* starts BEHIND the pack (rail is z-index 2) so the cards are hidden
     inside it while they rise; flips in front the moment they clear */
  z-index: 1;
  --vb-card-width: min(51vw, 212px);
}
.vb-pack-stage.is-front { z-index: 30; }

.vb-flyer {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--vb-card-width);
  opacity: 0;
  /* keep every card on the compositor: transform-only motion, no paint */
  will-change: transform, opacity;
  backface-visibility: hidden;
  transform: translate(-50%, -42%) scale(0.76);
  perspective: 1200px;
  z-index: calc(30 - var(--bulk-stack, 0));
}

.vb-flyer-inner {
  position: relative;
  width: 100%;
  aspect-ratio: 0.72;
  transform-style: preserve-3d;
  transition: transform 240ms ease;
}

.vb-flyer-face {
  position: absolute;
  inset: 0;
  border-radius: 12px;
  overflow: hidden;
  backface-visibility: hidden;
  background:
    radial-gradient(circle at 50% 48%, rgba(100, 176, 255, 0.22) 0%, rgba(100, 176, 255, 0.08) 18%, rgba(11, 26, 58, 0) 40%),
    linear-gradient(180deg, #1b3f78 0%, #18315a 52%, #0e1b33 100%);
  box-shadow: 0 18px 28px rgba(3, 8, 20, 0.34);
}
.vb-flyer-face-front { transform: rotateY(180deg); }
.vb-flyer-face-back {
  background:
    url("/static/images/homepage/misc/pokemon-cardback.jpg") center / cover no-repeat,
    linear-gradient(180deg, #1b3f78 0%, #18315a 52%, #0e1b33 100%);
}
.vb-flyer-face img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 12px;
}

/* the burst: every card out of the pack together, clear of it, then
   down in front as a stack */
.vb-flyer.is-live {
  animation: vb-burst-out 1560ms cubic-bezier(.28,.72,.28,1) var(--burst-delay, 0ms) both;
}
@keyframes vb-burst-out {
  /* Flight scale is 0.76 — the largest the card can be and still hide
     inside the pack art on the way up. The stagger + scatter make it a
     fountain, not an elevator: cards loosen in the air, gather landing. */
  0% {
    opacity: 1;
    transform: translate(-50%, -42%) scale(0.76) rotate(0deg);
  }
  58% {
    opacity: 1;
    transform:
      translate(calc(-50% + var(--scatter-x, 0rem)), -150%)
      scale(0.78)
      rotate(var(--scatter-rot, 0deg));
  }
  /* a whisper past the resting spot, then settle — a landing, not a stop */
  86% {
    opacity: 1;
    transform:
      translate(calc(-50% + (var(--bulk-stack, 0) * 0.07rem) + (var(--scatter-x, 0rem) * 0.12)),
                calc(-50% + (var(--bulk-stack, 0) * 0.045rem) + 0.14rem))
      scale(1.006)
      rotate(calc(var(--scatter-rot, 0deg) * 0.12));
  }
  100% {
    opacity: 1;
    transform:
      translate(calc(-50% + (var(--bulk-stack, 0) * 0.07rem)), calc(-50% + (var(--bulk-stack, 0) * 0.045rem)))
      scale(1)
      rotate(0deg);
  }
}

/* at rest as a pile, plain transform — the clean base for what follows */
.vb-flyer.is-settled {
  animation: none;
  opacity: 1;
  transform:
    translate(calc(-50% + (var(--bulk-stack, 0) * 0.07rem)), calc(-50% + (var(--bulk-stack, 0) * 0.045rem)))
    scale(1);
}

/* is-staged owns visibility for a card's entire presentation life —
   every later state only layers transforms on top of it */
.vb-flyer.is-staged {
  opacity: 1;
  z-index: 40;
}
/* the lift: off the pile, up to the presentation spot, one soft motion —
   each card sits a hair off-axis, the way a hand would place it */
.vb-flyer.is-lift {
  transform: translate(-50%, calc(-50% - 0.4rem)) scale(1.12) rotate(var(--tilt, 0deg));
  transition: transform 340ms cubic-bezier(.24,.66,.18,1);
}

/* iteration: flip face-up, then fly away revealing the next */
.vb-flyer.is-revealed .vb-flyer-inner {
  animation: vb-card-reveal 560ms cubic-bezier(.34,.06,.16,1) forwards;
}
/* the hit's flip is slower — it's carrying the luminous sheet */
.vb-flyer.is-hit.is-revealed .vb-flyer-inner {
  animation-duration: 900ms;
  animation-timing-function: cubic-bezier(.38,.05,.13,1);
}
/* no sheen band on the hit: the reveal supplies its own light */
.vb-flyer.is-hit.is-revealed .vb-flyer-face-front::after { animation: none; }
/* holo sheen: a light band crosses the face as it lands face-up */
.vb-flyer-face-front::after {
  content: "";
  position: absolute;
  inset: -30%;
  background: linear-gradient(112deg,
    transparent 34%,
    rgba(255, 255, 255, .04) 44%,
    rgba(255, 255, 255, .18) 50%,
    rgba(190, 225, 255, .1) 55%,
    transparent 66%);
  transform: translateX(-70%);
  opacity: 0;
  pointer-events: none;
}
.vb-flyer.is-revealed .vb-flyer-face-front::after {
  animation: vb-sheen-sweep 900ms cubic-bezier(.33,.5,.2,1) 260ms forwards;
}
@keyframes vb-sheen-sweep {
  0% { opacity: 1; transform: translateX(-70%); }
  100% { opacity: 0; transform: translateX(70%); }
}
.vb-flyer.is-exit {
  z-index: 40;
  animation: vb-filter-flick 560ms cubic-bezier(.3,.55,.3,1) forwards;
}

/* the hit's goodbye: it ascends and fades on its own terms — never a
   hard cut to nothing */
.vb-flyer.is-outro {
  z-index: 45;
  animation: vb-outro 720ms cubic-bezier(.4,.05,.6,.9) forwards;
}
@keyframes vb-outro {
  0% { opacity: 1; transform: translate(-50%, calc(-50% - 0.9rem)) scale(1.3); }
  100% { opacity: 0; transform: translate(-50%, calc(-50% - 2.7rem)) scale(1.22); }
}

/* the hit holds front and centre with a gold frame */
/* no frame on the hit — the card is LIT: a hair of white-hot rim where
   light wraps the edge, and an accent halo falling off into the dark */
.vb-flyer.is-hit .vb-flyer-face-front {
  /* no hairline ring: a crisp edge draws a CONTAINER around the card.
     Soft glow only — the card is the object, not a box holding it. */
  box-shadow:
    0 0 22px rgba(255, 255, 255, .42),
    0 0 70px rgba(var(--vb-acc), .55),
    0 18px 28px rgba(3, 8, 20, 0.34);
}
.vb-flyer.is-hit-hold { z-index: 45; }

/* the nameplate: clean, centred, cinematic — a gold rule opens from the
   middle and the card's name tracks in above it. The game says the name
   of the card out loud. */
.vb-hit-plate {
  position: absolute;
  left: 50%;
  bottom: -3.6rem;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
  pointer-events: none;
}
.vb-plate-rule {
  order: 2;
  display: block;
  width: 9.5rem;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(233, 205, 151, .9) 22%, rgba(233, 205, 151, .9) 78%, transparent);
  transform: scaleX(0);
  animation: vb-plate-rule 560ms cubic-bezier(.2,.7,.2,1) forwards;
}
@keyframes vb-plate-rule { to { transform: scaleX(1); } }
.vb-hit-plate b {
  order: 1;
  color: #f4efe2;
  font-size: 14px;
  font-weight: 680;
  text-transform: uppercase;
  letter-spacing: .34em;
  text-indent: .34em; /* balances the trailing tracking */
  opacity: 0;
  animation: vb-plate-name 720ms cubic-bezier(.2,.7,.2,1) 120ms forwards;
}
@keyframes vb-plate-name {
  0% { opacity: 0; letter-spacing: .5em; }
  100% { opacity: 1; letter-spacing: .22em; }
}
.vb-hit-plate em {
  order: 3;
  font-style: normal;
  color: var(--vb-gold);
  font-size: 12.5px;
  font-weight: 800;
  letter-spacing: .1em;
  opacity: 0;
  animation: vb-plate-price 600ms ease 460ms forwards;
}
@keyframes vb-plate-price { to { opacity: 1; } }

/* the flip: ONE keyframe segment, one unbroken curve. A midpoint keyframe
   re-applies the easing per segment — a velocity hitch at 90° that reads
   as "deh…deh". Butter is a single 0→180 with nothing in between; the
   3D perspective supplies all the depth the turn needs. */
@keyframes vb-card-reveal {
  0% { transform: rotateY(0deg); }
  100% { transform: rotateY(180deg); }
}

@keyframes vb-filter-flick {
  /* misses are sorted aside to EITHER side — a dealer's toss, not a
     conveyor belt */
  0% {
    opacity: 1;
    transform: translate(-50%, calc(-50% - 0.4rem)) rotate(var(--tilt, 0deg)) scale(1.12);
  }
  45% {
    opacity: 1;
    transform:
      translate(calc(-50% + (min(14rem, 36vw) * var(--flick-dir, 1))), calc(-50% - 1.6rem))
      rotate(calc((6deg + (var(--bulk-lane, 0) * 0.6deg)) * var(--flick-dir, 1)))
      scale(1.04);
  }
  100% {
    opacity: 0;
    transform:
      translate(calc(-50% + (min(34rem, 84vw) * var(--flick-dir, 1))), calc(-50% - 0.5rem + (var(--bulk-lane, 0) * 0.25rem)))
      rotate(calc((11deg + (var(--bulk-lane, 0) * 0.9deg)) * var(--flick-dir, 1)))
      scale(0.97);
  }
}

/* the lit card rises out of the floodlight in one weighted glide */
@keyframes vb-hit-hold {
  0% { transform: translate(-50%, calc(-50% - 0.5rem)) scale(1.2); }
  100% { transform: translate(-50%, calc(-50% - 0.9rem)) scale(1.3); }
}
.vb-flyer.is-hit-hold {
  animation: vb-hit-hold 1400ms cubic-bezier(.18,.7,.12,1) forwards;
}

/* anticipation: still face-down, the card lifts a breath and its back
   begins to burn from within (rises straight from the pile — the charge
   IS the promotion) */
.vb-flyer.is-charging {
  z-index: 45;
  transform: translate(-50%, calc(-50% - 0.5rem)) scale(1.2);
  transition: transform 950ms cubic-bezier(.2,.6,.16,1);
}
.vb-flyer.is-charging .vb-flyer-face-back {
  animation: vb-charge-burn 950ms ease-in forwards;
}
@keyframes vb-charge-burn {
  0% { box-shadow: 0 18px 28px rgba(3, 8, 20, 0.34); filter: brightness(1); }
  100% {
    box-shadow:
      0 0 18px rgba(255, 255, 255, .35),
      0 0 52px rgba(var(--vb-acc), .5),
      0 18px 28px rgba(3, 8, 20, 0.34);
    filter: brightness(1.35);
  }
}

/* ---- the party-packs reveal, turned sideways ----
   The base art is blown to pure light; a lit duplicate on top is masked
   at --rev-x and follows a traveling beam out of the glare. */
/* the art is NEVER visible between states: the face goes white -> black
   by crossfading covers ON TOP of it — fading a cover away to expose a
   filter mid-transition is what produced the etched hiccup */
.vb-flyer.is-concealed .vb-flyer-face-front > img:not(.vb-flyer-lit),
.vb-flyer.is-dark .vb-flyer-face-front > img:not(.vb-flyer-lit),
.vb-flyer.is-sweeping .vb-flyer-face-front > img:not(.vb-flyer-lit) {
  filter: brightness(4.8) saturate(0) contrast(.08) blur(1.5px);
}
/* the black cover fades IN over the white sheet — a pure light-to-dark
   crossfade with nothing peeking through */
.vb-flyer.is-concealed .vb-flyer-face-front::before,
.vb-flyer.is-dark .vb-flyer-face-front::before,
.vb-flyer.is-sweeping .vb-flyer-face-front::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: #05060a;
  opacity: 0;
  /* fast fall, whisper of a tail — the exponential decay of a real flash */
  transition: opacity 220ms cubic-bezier(.1,.75,.25,1);
}
.vb-flyer.is-dark .vb-flyer-face-front::before,
.vb-flyer.is-sweeping .vb-flyer-face-front::before { opacity: 1; }
/* the face itself is WHITE-HOT while concealed: a solid luminous sheet
   over the ghosted art, so it reads as pure light — never a sketch */
.vb-flyer.is-concealed .vb-flyer-face-front::after,
.vb-flyer.is-dark .vb-flyer-face-front::after,
.vb-flyer.is-sweeping .vb-flyer-face-front::after {
  content: "";
  inset: 0;
  transform: none;
  opacity: 1;
  background: radial-gradient(95% 95% at 50% 44%,
    rgba(255, 255, 255, .97) 0%,
    rgba(242, 249, 255, .88) 55%,
    rgba(214, 235, 255, .72) 100%);
}
/* the landing is a FLASH: blinding at the instant of contact, decaying
   hard and fast — triggered by is-flash AT the landing, never earlier */
.vb-flyer.is-concealed .vb-flyer-face-front {
  box-shadow:
    0 0 2px 2px rgba(255, 255, 255, .9),
    0 0 34px rgba(255, 255, 255, .55),
    0 0 90px rgba(163, 222, 255, .5),
    0 18px 28px rgba(3, 8, 20, 0.34);
}
.vb-flyer.is-flash .vb-flyer-face-front {
  animation: vb-lume-flare 360ms cubic-bezier(.1,.8,.2,1) forwards;
}
@keyframes vb-lume-flare {
  0% {
    box-shadow:
      0 0 8px 5px rgba(255, 255, 255, 1),
      0 0 120px 48px rgba(255, 255, 255, 1),
      0 0 260px 100px rgba(163, 222, 255, .9),
      0 18px 28px rgba(3, 8, 20, 0.34);
  }
  100% {
    box-shadow:
      0 0 0 0 rgba(255, 255, 255, 0),
      0 0 0 0 rgba(255, 255, 255, 0),
      0 0 0 0 rgba(163, 222, 255, 0),
      0 18px 42px rgba(0, 0, 0, .8);
  }
}
/* and the ROOM blinks with it — a flash lights more than its source */
.vb-hit-veil.is-flash::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(66% 56% at 50% 44%,
    rgba(255, 255, 255, .72) 0%,
    rgba(255, 250, 235, .24) 55%,
    transparent 82%);
  animation: vb-room-flash 380ms cubic-bezier(.04,.7,.16,1) forwards;
}
@keyframes vb-room-flash {
  0% { opacity: 1; }
  100% { opacity: 0; }
}
.vb-flyer.is-dark .vb-flyer-face-front,
.vb-flyer.is-sweeping .vb-flyer-face-front {
  box-shadow: 0 18px 42px rgba(0, 0, 0, .8);
  transition: box-shadow 220ms cubic-bezier(.1,.75,.25,1);
}
.vb-flyer-lit {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 12px;
  opacity: 0;
  pointer-events: none;
  /* the torch-lit art: hotter than life, glowing warm at the beam line —
     it has to READ bright against the black silhouette it replaces */
  filter:
    brightness(1.16) saturate(1.1)
    drop-shadow(0 0 11px rgba(255, 239, 193, .82))
    drop-shadow(0 0 26px rgba(117, 205, 255, .48));
}
.vb-flyer.is-sweeping .vb-flyer-lit,
.vb-flyer.is-flood .vb-flyer-lit {
  opacity: 1;
}
.vb-flyer.is-sweeping .vb-flyer-lit {
  -webkit-mask-image: linear-gradient(to right,
    #000 0%,
    #000 calc(var(--rev-x, -30%) - 26%),
    rgba(0, 0, 0, .96) calc(var(--rev-x, -30%) - 12%),
    rgba(0, 0, 0, .6) calc(var(--rev-x, -30%) + 6%),
    transparent calc(var(--rev-x, -30%) + 28%),
    transparent 100%);
  mask-image: linear-gradient(to right,
    #000 0%,
    #000 calc(var(--rev-x, -30%) - 26%),
    rgba(0, 0, 0, .96) calc(var(--rev-x, -30%) - 12%),
    rgba(0, 0, 0, .6) calc(var(--rev-x, -30%) + 6%),
    transparent calc(var(--rev-x, -30%) + 28%),
    transparent 100%);
}
/* the beam: a vertical blade of light riding the reveal line */
.vb-rev-beam {
  position: absolute;
  inset: -8%;
  z-index: 3;
  pointer-events: none;
  border-radius: 14px;
  background: radial-gradient(
    ellipse 25% 72% at var(--rev-x, -30%) 50%,
    rgba(255, 252, 232, .78) 0%,
    rgba(218, 240, 255, .38) 28%,
    rgba(153, 210, 255, .14) 52%,
    transparent 76%);
  mix-blend-mode: screen;
  filter: blur(7px);
  opacity: 0;
}
.vb-flyer.is-sweeping .vb-rev-beam { opacity: .9; }
/* the floodlight: the sweep completes, the mask is gone, and the glow
   breathes in over a second — the party handoff, no jump */
.vb-flyer.is-flood .vb-flyer-lit {
  animation: vb-flood-breathe 1200ms ease forwards;
}
@keyframes vb-flood-breathe {
  0% {
    filter:
      brightness(1.08) saturate(1.08)
      drop-shadow(0 0 11px rgba(255, 239, 193, .78))
      drop-shadow(0 0 26px rgba(117, 205, 255, .42));
  }
  100% {
    filter:
      brightness(1) saturate(1)
      drop-shadow(0 0 26px rgba(255, 246, 228, .6))
      drop-shadow(0 0 52px rgba(148, 214, 255, .34));
  }
}

/* the room dims with the same breath — no separate step */
.vb-hit-veil {
  position: fixed;
  inset: 0;
  z-index: 25;
  pointer-events: none;
  background: radial-gradient(62% 50% at 50% 44%,
    rgba(4, 6, 10, 0) 36%,
    rgba(4, 6, 10, .42) 72%,
    rgba(4, 6, 10, .66) 100%);
  opacity: 0;
  transition: opacity 1100ms ease;
}
.vb-hit-veil.is-live { opacity: 1; }
/* the building: the room goes near-black while the silhouette waits —
   but the veil sits ABOVE the page (fixed, body-level), so it must keep
   an open centre over the card. The card darkens by its own filter, the
   room by this; the two must never be the same layer. */
.vb-hit-veil.is-building {
  background: radial-gradient(56% 46% at 50% 44%,
    rgba(2, 2, 5, 0) 30%,
    rgba(2, 2, 5, .55) 52%,
    rgba(2, 2, 5, .88) 72%,
    rgba(2, 2, 5, .97) 100%);
  transition: opacity 1100ms ease, background 700ms ease;
}


@media (prefers-reduced-motion: reduce) {
  .vb-hit-veil { transition: none; }
  .vb-flyer.is-hit-hold::before { animation: none; opacity: 1; }
  .vb-rev-beam { opacity: 0 !important; }
}



/* ---- Result line after the cycle ---- */
.vb-demo-result {
  display: grid;
  gap: 3px;
  justify-items: center;
  max-width: 420px;
  margin: 14px auto 0;
  padding-inline: var(--vb-gutter);
  text-align: center;
}
.vb-demo-result[hidden] { display: none; }
.vb-demo-result strong { font-size: 15px; font-weight: 850; }
.vb-demo-result strong.is-hit { color: var(--vb-gold); }
.vb-demo-result-tag {
  color: var(--vb-dim);
  font-size: 10px;
  font-weight: 750;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* ---- Pack details: a cut-glass window floating over the stage.
        The page's own text fades away behind it (see .vb-glass-mode);
        the pack stays visible, only barely dimmed. ---- */
.vb-sheet {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: grid;
  place-items: center;
  padding: max(18px, env(safe-area-inset-top)) 14px calc(env(safe-area-inset-bottom) + 18px);
}
.vb-sheet[hidden] { display: none; }
.vb-sheet-backdrop {
  position: absolute;
  inset: 0;
  /* the faintest veil — the pack behind reads clearly through it */
  background: rgba(3, 5, 10, .26);
}
.vb-sheet-panel {
  position: relative;
  width: min(92vw, 420px);
  max-height: min(78vh, 640px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 22px 20px calc(env(safe-area-inset-bottom) + 20px);
  border-radius: 22px;
  border: 1px solid rgba(255, 255, 255, .16);
  background: linear-gradient(
    158deg,
    rgba(255, 255, 255, .10),
    rgba(255, 255, 255, .035) 34%,
    rgba(var(--vb-acc), .06) 78%,
    rgba(255, 255, 255, .05)
  );
  backdrop-filter: blur(10px) saturate(1.2);
  -webkit-backdrop-filter: blur(10px) saturate(1.2);
  box-shadow:
    0 34px 90px rgba(0, 0, 0, .55),
    0 0 46px rgba(var(--vb-acc), .1),
    inset 0 1px 0 rgba(255, 255, 255, .25),
    inset 0 -1px 0 rgba(255, 255, 255, .06);
  animation: vb-glass-in .38s var(--vb-ease);
}
/* the cut: one still specular facet across the top-left corner */
.vb-sheet-panel::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(118deg, rgba(255, 255, 255, .14), rgba(255, 255, 255, 0) 42%);
  pointer-events: none;
}
@keyframes vb-glass-in {
  from { transform: translateY(16px) scale(.965); opacity: 0; }
}
.vb-sheet-close {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, .14);
  background: rgba(255, 255, 255, .06);
  color: rgba(255, 255, 255, .75);
  font-size: 13px;
  line-height: 1;
}

/* while the glass is up: page text fades out entirely, the pack stays */
.vb-bar, .vb-main > *, .vb-legal-footer, .vb-demo > * {
  transition: opacity .35s ease;
}
.vb-glass-mode .vb-bar,
.vb-glass-mode .vb-legal-footer,
.vb-glass-mode .vb-main > :not(.vb-demo),
.vb-glass-mode .vb-demo > :not(.vb-demo-rail):not(.vb-sheet) {
  opacity: 0;
  pointer-events: none;
}
.vb-glass-mode .vb-pack-cta { opacity: 0 !important; }
.vb-glass-mode .vb-demo-slide:not(.is-active) { opacity: 0; }
.vb-glass-mode .vb-demo-slide.is-active {
  /* ever so slightly faded, still unmistakably there — !important beats
     the JS-driven inline filter while the glass is up */
  filter: brightness(.8) saturate(.92) !important;
}
.vb-sheet-title { font-size: 19px; font-weight: 850; }
.vb-sheet-lede { margin-top: 6px; color: #cdd6e4; font-size: 13.5px; }
.vb-sheet-odds-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin: 18px 0 10px;
}
.vb-sheet-odds-head span {
  font-size: 11px;
  font-weight: 850;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.vb-sheet-odds-head em {
  color: var(--vb-gold);
  font-size: 10.5px;
  font-style: normal;
  font-weight: 750;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.vb-odd {
  display: grid;
  grid-template-columns: 96px 1fr 68px;
  align-items: center;
  gap: 10px;
  padding: 6px 0;
}
.vb-odd-label { font-size: 12px; font-weight: 750; color: var(--vb-text); }
.vb-odd-bar {
  height: 8px;
  border-radius: 4px;
  background: rgba(255, 255, 255, .08);
  overflow: hidden;
}
.vb-odd-bar i {
  display: block;
  width: 0;
  height: 100%;
  border-radius: 4px;
  background: linear-gradient(90deg, var(--vb-gold-deep), var(--vb-gold));
  transition: width .7s var(--vb-ease) .12s;
}
.vb-sheet[data-open] .vb-odd-bar i { width: var(--w); }
.vb-odd-rate { color: var(--vb-dim); font-size: 11px; font-weight: 750; text-align: right; }
.vb-sheet-note {
  margin-top: 14px;
  color: var(--vb-dim);
  font-size: 12px;
  line-height: 1.45;
}
.vb-sheet-cta { margin-top: 18px; }

/* ---- interactive parties browser (party sheet) ---- */
.vb-party-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 16px;
}
.vb-party-arrow {
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  display: grid;
  place-content: center;
  border: 1px solid var(--vb-line-2);
  border-radius: 50%;
  background: rgba(10, 12, 18, .6);
  color: var(--vb-text);
  font-size: 18px;
  line-height: 1;
  transition: border-color .18s ease, background .18s ease;
}
.vb-party-arrow:hover { border-color: rgba(178, 216, 255, .5); background: rgba(142, 202, 255, .1); }
.vb-party-title {
  min-width: 0;
  display: grid;
  gap: 2px;
  text-align: center;
}
.vb-party-title strong {
  font-size: 14px;
  font-weight: 850;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.vb-party-title small { color: var(--vb-gold); font-size: 11px; font-weight: 750; }

.vb-party-pages { margin-top: 14px; }
.vb-party-page {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 6px;
}
.vb-party-page[hidden] { display: none; }
.vb-party-card {
  position: relative;
  aspect-ratio: .72;
  border-radius: 6px;
  overflow: hidden;
  background: rgba(255, 255, 255, .05);
}
.vb-party-card img { width: 100%; height: 100%; object-fit: cover; }
.vb-party-card.is-grail {
  box-shadow: 0 0 0 1.5px var(--vb-gold), 0 0 16px rgba(233, 205, 151, .4);
}

.vb-party-dots {
  display: flex;
  justify-content: center;
  gap: 6px;
  margin-top: 14px;
}
.vb-party-dots i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .18);
  cursor: pointer;
  transition: background .2s ease, transform .2s ease;
}
.vb-party-dots i.is-active { background: var(--vb-gold); transform: scale(1.25); }

.vb-sheet-steps {
  display: grid;
  gap: 10px;
  margin-top: 16px;
  list-style: none;
  counter-reset: vbstep;
}
.vb-sheet-steps li {
  display: grid;
  gap: 2px;
  padding: 11px 13px 11px 44px;
  position: relative;
  border: 1px solid var(--vb-line);
  border-radius: 10px;
  background: rgba(10, 12, 18, .6);
  counter-increment: vbstep;
}
.vb-sheet-steps li::before {
  content: counter(vbstep);
  position: absolute;
  left: 13px;
  top: 50%;
  transform: translateY(-50%);
  width: 20px;
  height: 20px;
  display: grid;
  place-content: center;
  border-radius: 50%;
  background: rgba(233, 205, 151, .14);
  color: var(--vb-gold);
  font-size: 11px;
  font-weight: 900;
}
.vb-sheet-steps strong { font-size: 13px; font-weight: 800; }
.vb-sheet-steps span { color: var(--vb-dim); font-size: 11.5px; }

.vb-sheet-ladder { display: grid; gap: 8px; margin-top: 16px; }
.vb-rung {
  display: grid;
  gap: 2px;
  padding: 11px 13px;
  border-radius: 10px;
  border: 1px solid var(--vb-line);
  /* darker ground: the frosted glass washes out lighter panels */
  background: rgba(8, 10, 15, .78);
}
.vb-rung b { color: #f4f7fc; font-size: 13px; }
.vb-rung span { color: #c3cbdb; font-size: 11.5px; }
.vb-rung.is-stop { border-color: rgba(233, 205, 151, .38); }
.vb-rung.is-stop b { color: var(--vb-gold); }
.vb-rung.is-keep b { color: var(--vb-mint); }

/* ---- Desktop refinements ---- */
/* desktop rail arrows: hidden until the desktop stage */
.vb-demo-arrow { display: none; }

@media (min-width: 760px) {
  /* desktop: the stage owns the top of the page — packs grow into the
     vertical room the phone never had */
  .vb-demo {
    --pack-h: min(56vh, 540px);
    padding-top: 30px;
  }
  .vb-demo-arrow {
    display: grid;
    place-items: center;
    position: absolute;
    z-index: 5;
    top: calc(var(--pack-top) + var(--pack-h) / 2);
    width: 52px;
    height: 52px;
    transform: translateY(-50%);
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, .2);
    background: rgba(12, 9, 20, .55);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    color: #fff;
    cursor: pointer;
    transition: background .18s, border-color .18s, opacity .18s;
  }
  .vb-demo-arrow svg { width: 22px; height: 22px; fill: currentColor; }
  .vb-demo-arrow--prev { left: calc(50% - 330px); }
  .vb-demo-arrow--next { right: calc(50% - 330px); }
  .vb-demo-arrow:hover { background: rgba(30, 24, 48, .8); border-color: rgba(var(--vb-acc), .75); }
  .vb-demo-arrow[disabled] { opacity: .22; cursor: default; pointer-events: none; }
  .vb-demo::before { width: min(92vw, 620px); }
  .vb-demo-slide { flex-basis: 340px; }
  .vb-demo-rail { padding-inline: calc(50% - 170px); }
  .vb-pack-stage {
    width: 340px;
    --vb-card-width: min(42vw, 284px);
  }
  .vb-pack-cta { font-size: 13px; }
  /* the copy column widens and scales with the bigger stage */
  .vb-demo-info, .vb-pitch { max-width: 520px; }
  .vb-demo-tagline { font-size: clamp(22px, 2.6vw, 28px); }
  .vb-feats b { font-size: 14px; }
  .vb-feats small { font-size: 10px; }
  .vb-feats li { min-height: 3.8rem; }
  .vb-details { font-size: 12.5px; }
}

/* pointer affordances: only where a real hover exists */
@media (hover: hover) and (min-width: 760px) {
  .vb-demo-slide:not(.is-active):hover {
    cursor: pointer;
    filter: brightness(.62) saturate(.85) !important;
  }
  .vb-demo-slide.is-active:hover .vb-pack-shell { transform: translateY(-5px); }
  .vb-demo-slide.is-active:hover .vb-pack-cta {
    border-color: rgba(var(--vb-acc), .85);
    color: #fff;
  }
}

/* desktop details window: same cut glass, roomier and larger type */
@media (min-width: 760px) {
  .vb-sheet-panel {
    width: min(560px, 92vw);
    max-height: min(80vh, 700px);
    padding: 30px 32px 28px;
  }
  .vb-sheet-close { top: 14px; right: 14px; width: 34px; height: 34px; }
  .vb-sheet-title { font-size: 24px; }
  .vb-sheet-lede { font-size: 15px; }
  .vb-sheet-odds-head { margin: 24px 0 12px; }
  .vb-sheet-odds-head span { font-size: 12px; }
  .vb-odd { grid-template-columns: 150px 1fr 92px; padding: 8px 0; }
  .vb-odd-label { font-size: 13.5px; }
  .vb-odd-bar { height: 9px; }
  .vb-odd-rate { font-size: 12px; }
  .vb-sheet-note { font-size: 13px; }
  .vb-sheet-steps strong { font-size: 14px; }
  .vb-sheet-steps span { font-size: 12.5px; }
  .vb-sheet-cta { margin-top: 24px; }
  /* trackpad-friendly: snap guides rather than yanks */
  .vb-demo-rail { scroll-snap-type: x proximity; }
}

@media (prefers-reduced-motion: reduce) {
  .vb-demo-slide, .vb-odd-bar i, .vb-sheet-panel, .vb-reveal-card { transition: none; animation: none; opacity: 1; transform: none; }
  .vb-buy, .vb-buy::before { animation: none; }
  .vb-pack-cta, .vb-pack-cta::before { animation: none; }
}


/* ============================================================
   2. REAL DISCORD REVIEWS — the main page's spotlight wall,
      restyled for the dark stage. Same geometry and behaviour;
      light panel surfaces swapped for dark glass.
   ============================================================ */
/* ============================================================
   LIVE HIT FEED — the main page's recent-hits rack, same design
   and layout, recolored for the dark transparent theme.
   ============================================================ */
.home3-recent-hits {
  box-sizing: border-box;
  width: 100%;
  margin: clamp(1.4rem, 3vw, 2.4rem) auto 0;
}

.home3-recent-hits-head {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
  padding: 0 var(--vb-gutter);
}

.home3-section-label {
  color: rgba(var(--vb-acc), .95);
  font-size: .72rem;
  font-weight: 900;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.home3-recent-hits-head h2 {
  margin: 0.08rem 0 0;
  color: #f2f5fb;
  font-size: clamp(1.65rem, 2.5vw, 2.35rem);
  font-weight: 850;
  line-height: 1.04;
}

.home3-recent-hits-head > strong {
  color: var(--vb-dim);
  font-size: 0.94rem;
  font-weight: 900;
  text-align: right;
}

/* full-bleed band: edge to edge like every other surface on this page */
.home3-recent-hits-window {
  position: relative;
  overflow: hidden;
  border-block: 1px solid rgba(255, 255, 255, .1);
  background: rgba(255, 255, 255, .025);
  box-shadow: 0 18px 40px rgba(0, 0, 0, .3);
}

.home3-recent-hits-track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(13.4rem, 15.6rem);
  gap: 0.85rem;
  overflow-x: auto;
  padding: 1rem var(--vb-gutter);
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
}

.home3-recent-hit-card {
  scroll-snap-align: start;
  background: rgba(13, 16, 25, .78);
  border: 1px solid rgba(255, 255, 255, .1);
  box-shadow: 0 12px 28px rgba(0, 0, 0, .3);
  overflow: hidden;
  min-width: 0;
  animation: home3RecentHitSlide 480ms cubic-bezier(.2, .85, .2, 1);
}

.home3-recent-hit-card.is-major {
  border-color: rgba(var(--vb-acc), .5);
  box-shadow:
    0 0 0 3px rgba(var(--vb-acc), .1),
    0 20px 42px rgba(var(--vb-acc), .16);
}

.home3-recent-hit-art {
  position: relative;
  aspect-ratio: 3 / 4;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: rgba(255, 255, 255, .04);
  padding: 0.72rem;
}

.home3-recent-hit-art img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 14px 20px rgba(0, 0, 0, .45));
  animation: home3RecentHitImageFade 1s ease both;
}

@keyframes home3RecentHitImageFade {
  from { opacity: 0; }
  to { opacity: 1; }
}

.home3-recent-hit-art span {
  position: absolute;
  top: 0.55rem;
  left: 0.55rem;
  background: #c9302f;
  color: #fff;
  padding: 0.32rem 0.52rem;
  font-size: 0.64rem;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  box-shadow: 0 8px 18px rgba(201, 48, 47, 0.35);
}

.home3-recent-hit-info {
  display: grid;
  gap: 0.42rem;
  padding: 0.85rem;
}

.home3-recent-hit-info > strong {
  color: #f2f5fb;
  font-size: 0.95rem;
  font-weight: 800;
  line-height: 1.16;
}

.home3-recent-hit-info > small,
.home3-recent-hit-info time {
  color: var(--vb-dim);
  font-size: 0.72rem;
  font-weight: 750;
  line-height: 1.25;
}

.home3-recent-hit-meta {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  flex-wrap: wrap;
}

.home3-recent-hit-meta span,
.home3-recent-hit-meta b {
  display: inline-flex;
  align-items: center;
  min-height: 1.55rem;
  padding: 0.24rem 0.44rem;
  background: rgba(var(--vb-acc), .16);
  color: #eaf1fb;
  font-size: 0.66rem;
  font-weight: 950;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.home3-recent-hit-meta b.is-selected {
  background: rgba(69, 212, 131, .16);
  color: #6fe3b0;
}

.home3-recent-hit-meta b.is-missed {
  background: rgba(255, 143, 165, .14);
  color: var(--vb-rose);
}

.home3-recent-hit-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.45rem;
}

.home3-recent-hit-stats span {
  display: grid;
  gap: 0.08rem;
  padding: 0.52rem;
  background: rgba(255, 255, 255, .05);
}

.home3-recent-hit-stats em {
  color: var(--vb-dimmer);
  font-size: 0.58rem;
  font-style: normal;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.home3-recent-hit-stats b {
  color: #f2f5fb;
  font-size: 0.88rem;
  font-weight: 850;
}

.home3-recent-hit-card.is-major .home3-recent-hit-stats span:first-child b {
  color: var(--vb-gold);
  font-size: 1rem;
}

.home3-recent-hits-empty {
  padding: 1.1rem;
  color: var(--vb-dim);
  font-weight: 850;
  text-align: center;
}

.home3-recent-hits-empty.is-hidden {
  display: none;
}

@keyframes home3RecentHitSlide {
  0% {
    opacity: 0;
    transform: translateX(-1.2rem) scale(0.98);
  }
  100% {
    opacity: 1;
    transform: none;
  }
}

/* ---- Proof band: three trust facts between the stage and reviews.
        No box, no rules — icon in an accent ring, fact, label. ---- */
.vb-proof {
  width: 100%;
  max-width: 640px;
  margin: 30px auto 0;
  padding: 0 var(--vb-gutter);
}
.vb-proof-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
  list-style: none;
}
.vb-proof-row li {
  display: grid;
  gap: 7px;
  justify-items: center;
  align-content: start;
  text-align: center;
  min-width: 0;
}
.vb-proof-ico {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  margin-bottom: 3px;
  border-radius: 50%;
  border: 1px solid rgba(var(--vb-acc), .6);
  background:
    radial-gradient(120% 120% at 50% 0%, rgba(var(--vb-acc), .3), rgba(var(--vb-acc), .08) 72%);
  color: #fff;
  box-shadow:
    0 0 22px rgba(var(--vb-acc), .35),
    inset 0 0 12px rgba(var(--vb-acc), .18);
  transition: border-color 700ms var(--vb-ease), box-shadow 700ms var(--vb-ease), background 700ms var(--vb-ease);
}
/* the glyphs are iridescent too: a saturated chroma base whose hue
   cycles the full spectrum — hue rotation loops perfectly, no seam */
.vb-proof-ico svg {
  width: 21px;
  height: 21px;
  color: #8fd6ff;
  animation: vb-ico-iris 8s linear infinite;
}
@keyframes vb-ico-iris {
  from { filter: drop-shadow(0 0 5px rgba(var(--vb-acc), .7)) hue-rotate(0deg); }
  to { filter: drop-shadow(0 0 5px rgba(var(--vb-acc), .7)) hue-rotate(360deg); }
}
/* living iridescence: a wide chromatic ribbon sliding through the text.
   background-size 200% + travel of exactly 200% = one full gradient
   tile per loop, so the cycle is seamless (240%/-240% left a visible
   jump every 8s — the travel wasn't a whole number of tiles). */
.vb-proof-row b {
  font-size: 13.5px;
  font-weight: 850;
  letter-spacing: .005em;
  line-height: 1.2;
  text-wrap: balance;
  background: linear-gradient(100deg,
    #8fe8ff 0%, #b9a7ff 16%, #ffb0e6 32%, #ffe1a1 48%,
    #a9ffcf 64%, #8fc9ff 82%, #8fe8ff 100%);
  background-size: 200% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 1px 10px rgba(140, 170, 255, .22));
  animation: vb-iris 8s linear infinite;
}
@keyframes vb-iris {
  to { background-position: 200% 0; }
}
.vb-proof-row b em { font-style: normal; font-weight: 850; }
@media (prefers-reduced-motion: reduce) {
  .vb-proof-row b, .vb-proof-ico svg { animation: none; }
}
.vb-proof-row small {
  color: rgba(153, 161, 181, .92);
  font-size: 9.5px;
  font-weight: 750;
  letter-spacing: .09em;
  text-transform: uppercase;
  line-height: 1.4;
  text-wrap: balance;
}
@media (min-width: 760px) {
  .vb-proof { max-width: 820px; }
  .vb-proof-ico { width: 50px; height: 50px; }
  .vb-proof-ico svg { width: 24px; height: 24px; }
  .vb-proof-row b { font-size: 15.5px; }
  .vb-proof-row small { font-size: 10.5px; }
}

.vb-reviews {
  width: 100%;
  max-width: 640px;
  margin: 14px auto 0;
  padding: 14px var(--vb-gutter) 8px;
}

.vb-reviews-head {
  display: grid;
  gap: 6px;
  justify-items: center;
  text-align: center;
}
.vb-reviews-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  color: #eef3fb;
  font-size: clamp(1.35rem, 5.6vw, 1.9rem);
  font-weight: 850;
  letter-spacing: -.01em;
  line-height: 1.1;
}
.vb-reviews-eyebrow-icon { width: 1.3em; height: 1.3em; fill: #5865F2; flex: 0 0 auto; }
.vb-reviews-eyebrow a {
  color: #8b96ff;
  font-weight: 950;
  text-decoration: none;
  white-space: nowrap;
  border-bottom: 2px solid rgba(139, 150, 255, .45);
  transition: color 180ms ease, border-color 180ms ease;
}
.vb-reviews-eyebrow a:hover,
.vb-reviews-eyebrow a:focus-visible { color: #aab3ff; border-bottom-color: #8b96ff; }
.vb-reviews-head p {
  color: var(--vb-dim);
  font-size: 12.5px;
  font-weight: 600;
}

/* ---- Review stories player: header over a fading blur, then the hit
        photo edge-to-edge from one shared top line, then the Discord
        bubble typing itself out, then transport controls. The whole
        thing flows — taller photos simply push the bubble down. ---- */
/* the stories player: a standard header band, then the photo at one
   fixed top line, the bubble floating below. The blur runs behind it
   all and dissolves to nothing at the top — no frame edge, the player
   grows out of the page. */
.vb-story {
  --vb-story-head-h: 108px; /* the standard header band above the photo */
  position: relative;
  margin-top: 16px;
  margin-inline: calc(-1 * var(--vb-gutter)); /* full-bleed past the gutter */
  /* svh, not dvh: dvh tracks the browser chrome collapsing during scroll,
     which made the photo box resize mid-view. svh is stable. */
  height: 100svh;
  min-height: 560px;
  overflow: hidden;
  isolation: isolate;
  user-select: none;
  -webkit-user-select: none;
}
/* blurred echo behind everything: extends up past the header but fades
   to full transparency at the top; softens out again at the foot */
.vb-story-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-size: cover;
  background-position: center;
  filter: blur(42px) brightness(.45) saturate(1.1);
  -webkit-mask-image: linear-gradient(180deg,
    transparent 0%, rgba(0, 0, 0, .55) 8%, #000 15%,
    #000 85%, rgba(0, 0, 0, .55) 92%, transparent 100%);
  mask-image: linear-gradient(180deg,
    transparent 0%, rgba(0, 0, 0, .55) 8%, #000 15%,
    #000 85%, rgba(0, 0, 0, .55) 92%, transparent 100%);
  transition: opacity .3s ease;
}
/* the header: a standard, compact band directly above the photo */
.vb-story .vb-reviews-head {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--vb-story-head-h);
  z-index: 3;
  align-content: center;
  padding: 10px var(--vb-gutter) 0;
}
.vb-story .vb-reviews-eyebrow {
  font-size: clamp(1.7rem, 7.4vw, 2.4rem);
  gap: .6rem;
}
.vb-story .vb-reviews-head p {
  font-size: 13.5px;
  font-weight: 650;
}

/* the photo: exactly frame-width, its top pinned to the same line just
   under the header for every review; crops into a standard box whose
   height JS flexes within a small tolerance (see applyFit). Its edges
   melt into the blur — no hard cut lines. */
.vb-story-img {
  position: absolute;
  top: var(--vb-story-head-h);
  left: 0;
  width: 100%;
  height: 62%;
  object-fit: cover;
  object-position: center 28%;
  z-index: 1;
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 7%, #000 92%, transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 7%, #000 92%, transparent 100%);
  transition: opacity .3s ease;
}
/* ---- review-to-review transition: directional, cinematic ----
   Leave: the photo drifts toward where you came from, softening away.
   Enter: the next one glides in from where you're going, settling from
   blur to sharp; the bubble follows a beat behind. --dir = 1 or -1. */
.vb-story { --dir: 1; }
.vb-story-img {
  transition:
    opacity .42s cubic-bezier(.22, 1, .36, 1),
    transform .42s cubic-bezier(.22, 1, .36, 1),
    filter .42s ease;
}
.vb-story.is-leave .vb-story-img {
  opacity: 0;
  transform: translateX(calc(-30px * var(--dir))) scale(.975);
  filter: blur(6px);
  transition: opacity .28s ease-in, transform .28s ease-in, filter .28s ease-in;
}
.vb-story.is-leave .vb-story-bg { opacity: 0; transition: opacity .28s ease-in; }
.vb-story.is-enter-set .vb-story-img {
  transition: none;
  opacity: 0;
  transform: translateX(calc(40px * var(--dir))) scale(1.02);
  filter: blur(12px);
}
.vb-story.is-enter-set .vb-story-bg { transition: none; opacity: 0; }

/* no scrims: the blur itself fades to transparency at both ends, and
   the bubble/controls carry their own backgrounds */
.vb-story-scrim { display: none; }

/* quiet position marker, riding the photo's top-right corner */
.vb-story-count {
  position: absolute;
  z-index: 5;
  top: calc(var(--vb-story-head-h) + 10px);
  right: 12px;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .13em;
  color: rgba(255, 255, 255, .62);
  text-shadow: 0 2px 8px rgba(0, 0, 0, .75);
  font-variant-numeric: tabular-nums;
}

/* the Discord message bubble, floating over the photo's lower third.
   Bottom-anchored: with the ghost pre-sizing (JS), it appears at its
   final size instantly — nothing grows or shifts while text types. */
.vb-story-bubble-zone {
  position: absolute;
  z-index: 4;
  left: 14px;
  right: 14px;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 108px);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}
.vb-story-bubble {
  width: 100%;
  max-width: 34rem;
  border-radius: 18px;
  background: rgba(43, 45, 49, .94);
  border: 1px solid rgba(255, 255, 255, .06);
  box-shadow: 0 24px 60px -18px rgba(0, 0, 0, .8);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  padding: .85rem 1rem .9rem;
  font-family: "gg sans", "Noto Sans", "Helvetica Neue", system-ui, sans-serif;
  /* enters a beat behind the photo */
  transition: opacity .38s ease .1s, transform .38s var(--vb-ease) .1s;
}
.vb-story.is-leave .vb-story-bubble {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity .24s ease-in, transform .24s ease-in;
}
.vb-story.is-enter-set .vb-story-bubble {
  transition: none;
  opacity: 0;
  transform: translateY(16px);
}

.vb-story-head { display: flex; align-items: center; gap: .7rem; }
.vb-story-avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  object-fit: cover;
  flex: 0 0 auto;
  background: #1e2024;
}
.vb-story-id { display: flex; align-items: baseline; gap: .55rem; min-width: 0; flex-wrap: wrap; }
.vb-story-id strong {
  font-size: 1.08rem;
  font-weight: 600;
  color: #f2f3f5;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.vb-story-id span { font-size: .74rem; font-weight: 500; color: #949ba4; }

.vb-story-body {
  position: relative;
  margin: .45rem 0 0 calc(40px + .7rem);
  color: #dbdee1;
  font-size: 1.22rem;
  font-weight: 400;
  line-height: 1.4;
  overflow-wrap: anywhere;
  min-height: 1.42em;
}
.vb-story-body p { margin: 0; }
.vb-story-body p + p { margin-top: .4rem; }
.vb-story-body p:empty { display: none; }
/* the ghost holds the message's FINAL height from the first frame, so
   the bubble — and everything under it — never moves while text types */
.vb-story-ghost { visibility: hidden; }
.vb-story-live { position: absolute; inset: 0; }

/* blinking type caret */
.vb-story-caret {
  display: inline-block;
  width: 2px;
  height: 1.05em;
  margin-left: 2px;
  vertical-align: text-bottom;
  background: #dbdee1;
  animation: vb-story-blink 1s steps(1) infinite;
}
@keyframes vb-story-blink { 50% { opacity: 0; } }

/* discord typing indicator (pre-roll) */
.vb-story-typing { display: inline-flex; align-items: center; gap: 5px; padding: .15em 0; }
.vb-story-typing i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #949ba4;
  animation: vb-story-bounce 1.2s ease-in-out infinite;
}
.vb-story-typing i:nth-child(2) { animation-delay: .15s; }
.vb-story-typing i:nth-child(3) { animation-delay: .3s; }
@keyframes vb-story-bounce {
  0%, 60%, 100% { transform: translateY(0); opacity: .55; }
  30% { transform: translateY(-4px); opacity: 1; }
}

/* transport controls */
.vb-story-controls {
  position: absolute;
  z-index: 5;
  left: 0;
  right: 0;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 22px);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.15rem;
}
.vb-story-btn {
  appearance: none;
  cursor: pointer;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, .22);
  background: rgba(12, 9, 20, .55);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: #fff;
  transition: transform .18s cubic-bezier(.22, 1, .36, 1), background .18s, border-color .18s;
}
.vb-story-btn svg { width: 20px; height: 20px; fill: currentColor; }
.vb-story-btn:hover { background: rgba(30, 24, 48, .75); border-color: rgba(255, 255, 255, .4); transform: translateY(-1px); }
.vb-story-btn:active { transform: scale(.94); }
.vb-story-btn:focus-visible { outline: 2px solid rgba(var(--vb-acc), .9); outline-offset: 3px; }
.vb-story-btn--main {
  width: 60px;
  height: 60px;
  border-color: rgba(255, 255, 255, .5);
  box-shadow: 0 0 22px rgba(var(--vb-acc), .4), inset 0 0 14px rgba(var(--vb-acc), .12);
}
.vb-story-btn--main svg { width: 24px; height: 24px; }

/* ---- desktop: a full-width cinematic band. The blur field spans the
        whole viewport; inside it the photo sits left as a large framed
        card and the Discord bubble types beside it on the right. ---- */
@media (min-width: 900px) {
  .vb-story {
    --vb-story-head-h: 132px;
    /* the photo column's geometry, shared by photo + counter */
    --vb-story-photo-l: max(7vw, calc(50vw - 560px));
    --vb-story-photo-w: min(42vw, 500px);
    margin-inline: calc(50% - 50vw); /* break out to the full viewport */
    height: min(82vh, 780px);
    min-height: 620px;
  }
  .vb-story .vb-reviews-head { padding-top: 26px; }
  .vb-story .vb-reviews-eyebrow { font-size: clamp(2rem, 2.6vw, 2.7rem); }
  .vb-story .vb-reviews-head p { font-size: 15px; }

  .vb-story-img {
    left: var(--vb-story-photo-l);
    width: var(--vb-story-photo-w);
    border-radius: 18px;
    box-shadow: 0 40px 90px -30px rgba(0, 0, 0, .8);
    /* a framed card wants crisp edges — the fade masks come off */
    -webkit-mask-image: none;
    mask-image: none;
  }
  /* desktop backdrop: not a heavy blur wall — a translucent ghost of the
     photo, barely softened, dissolving into the page at both ends */
  .vb-story-bg {
    filter: blur(7px) brightness(.55) saturate(1.05);
    opacity: .28;
  }
  .vb-story-count {
    left: calc(var(--vb-story-photo-l) + var(--vb-story-photo-w) - 12px);
    right: auto;
    transform: translateX(-100%);
    top: calc(var(--vb-story-head-h) + 14px);
  }

  /* the bubble becomes the right column, centered beside the photo */
  .vb-story-bubble-zone {
    left: calc(var(--vb-story-photo-l) + var(--vb-story-photo-w) + clamp(28px, 4vw, 64px));
    right: var(--vb-story-photo-l);
    bottom: auto;
    top: 46%;
    transform: translateY(-50%);
  }
  .vb-story-bubble { max-width: 32rem; padding: 1.05rem 1.2rem 1.1rem; }
  .vb-story-body { font-size: 1.3rem; }

  .vb-story-controls { bottom: 30px; }
}
@media (prefers-reduced-motion: reduce) {
  .vb-story-caret { animation: none; }
  .vb-story-typing i { animation: none; }
  .vb-story-img, .vb-story-bubble { transition: none; }
}

/* ============================================================
   3. FAQ — a single ruled column: hairlines, generous rhythm,
      the accent only where the reader is. Native details.
   ============================================================ */
.vb-faq {
  width: 100%;
  max-width: 640px;
  margin: 10px auto 0;
  padding: 34px var(--vb-gutter) 26px;
}

.vb-faq-head {
  display: grid;
  gap: 6px;
  justify-items: center;
  text-align: center;
  margin-bottom: 10px;
}
.vb-faq-eyebrow {
  color: rgba(var(--vb-acc), .8);
  font-size: 10px;
  font-weight: 850;
  letter-spacing: .2em;
  text-transform: uppercase;
  transition: color 700ms var(--vb-ease);
}
.vb-faq-head h2 {
  color: #f0f5fd;
  font-size: clamp(1.35rem, 5.4vw, 1.8rem);
  font-weight: 850;
  letter-spacing: -.01em;
}

.vb-faq-list {
  border-top: 1px solid rgba(255, 255, 255, .09);
}
.vb-faq-item {
  border-bottom: 1px solid rgba(255, 255, 255, .09);
}
.vb-faq-item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px 2px;
  list-style: none;
  cursor: pointer;
  color: #e8eef9;
  font-size: 14px;
  font-weight: 750;
  line-height: 1.35;
  transition: color .18s ease;
  -webkit-tap-highlight-color: transparent;
}
.vb-faq-item summary::-webkit-details-marker { display: none; }
.vb-faq-item summary:hover { color: #ffffff; }

/* the marker: a thin plus that folds into a minus, in the pack accent */
.vb-faq-item summary i {
  position: relative;
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
}
.vb-faq-item summary i::before,
.vb-faq-item summary i::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 12px;
  height: 1.5px;
  border-radius: 1px;
  background: rgba(var(--vb-acc), .85);
  transform: translate(-50%, -50%);
  transition: transform .32s var(--vb-ease), background 700ms var(--vb-ease);
}
.vb-faq-item summary i::after { transform: translate(-50%, -50%) rotate(90deg); }
.vb-faq-item[open] summary i::after { transform: translate(-50%, -50%) rotate(0deg); }
.vb-faq-item[open] summary { color: #ffffff; }

.vb-faq-item p {
  margin: 0;
  padding: 0 26px 18px 2px;
  color: rgba(178, 189, 208, .95);
  font-size: 13px;
  font-weight: 480;
  line-height: 1.65;
  animation: vb-faq-reveal .34s var(--vb-ease);
}

@keyframes vb-faq-reveal {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .vb-faq-item p { animation: none; }
}

/* On a wide monitor the brand sat against the far left edge and the menu
   against the far right, because the bar only had gutter padding. The bar
   itself stays full bleed (it is sticky and needs to span), but its
   CONTENTS now stop at the same 72rem the page sections use, so the
   lockup lines up with the content underneath instead of drifting out to
   the corners. */
.vb-bar {
  /* The bar's contents stop a little OUTSIDE the 72rem content column (80rem
     when the screen allows): the lockup sits a touch left of the content
     edge and the menu a touch right, so the nav reads as the frame around
     the page rather than one more column inside it. Narrow screens still
     fall back to the gutter. */
  padding-inline: max(var(--vb-gutter), (100% - var(--vb-nav-max-width, 80rem)) / 2);
}

/* Flash toasts on the homepage. Same placement and classes as the site
   stylesheet's .flash-stack so a message reads the same wherever it lands;
   this page does not load styles.css, so the rules live here too. */
.flash-stack {
  position: fixed;
  top: calc(env(safe-area-inset-top) + 82px);
  left: 50%;
  z-index: 1200;
  width: min(32rem, calc(100vw - 2rem));
  transform: translateX(-50%);
  display: grid;
  gap: 0.6rem;
  margin: 0;
  pointer-events: none;
}
.flash {
  padding: 0.95rem 1rem;
  border-radius: 12px;
  border: 1px solid rgba(158, 212, 255, 0.18);
  background: rgba(16, 22, 38, 0.94);
  color: #e8eef7;
  font-weight: 600;
  box-shadow: 0 18px 42px rgba(3, 8, 20, 0.5);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  animation: flash-in 320ms ease both;
}
.flash.success { border-color: rgba(74, 211, 155, 0.4); }
.flash.error { border-color: rgba(255, 122, 136, 0.45); }
.flash.is-gone { opacity: 0; transition: opacity 500ms ease; }
@keyframes flash-in { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }
