/* ============================================================
   VICE RIPS — shop styles.
   Brand (13 Nov, from the logo in brand/vice/): Vice pink #FC0187, white, and a
   heavy black outline, the "sticker" look. Base #1F2123, page behind #121314.
   --go #FF2D9B (the logo pink lifted a little so small text passes 4.5:1 on the
   base) is money and the one primary action; --pink #FF4DAE -> --magenta
   #FC0187 is the brand gradient for brand moments. Chips rgba(35,35,38,.5)
   with a 1px rgba(255,255,255,.28) ring.

   Type rules: UI type is never italic and never letter-spaced; small labels are
   uppercase, pill buttons are title case; text is never a gradient (gradients
   are fills). Headings use the display faces (--display / --display-cond).

   LAYOUT: phone first (a column: top bar, page, rip dock, bottom nav). From
   1024px it is blockrips' desktop (without its strip): top bar + live ticker, left rail,
   stage, her card on the right — the grid at "DESKTOP" below.
   z-index scale: backdrop 0 · app 1 · fan slots 1–100 (own stacking context)
   · top 20 · rip overlay 100 · toast 200 · dialogs: top layer.
   ============================================================ */

@property --c-acc { syntax: '<color>'; inherits: true; initial-value: #FF4DAE; }
@property --c-acc2 { syntax: '<color>'; inherits: true; initial-value: #FC0187; }

:root {
  --rank-ice: #C9D8FF;     /* the site ranks' colour (Chill .. Absolute Zero) */
  --bg: #1F2123;
  --bg-deep: #121314;
  --surface: #26282B;
  --surface-2: #2F3135;
  --text: #FFFFFF;
  --muted: rgba(255, 255, 255, .66);
  --faint: rgba(255, 255, 255, .42);
  --line: rgba(255, 255, 255, .10);
  --go: #FF2D9B;
  --go-rgb: 255, 45, 155;
  --pink: #FF4DAE;
  --magenta: #FC0187;
  --brand-grad: linear-gradient(135deg, var(--pink), var(--magenta));
  --chip-bg: rgba(35, 35, 38, .5);
  --chip-ring: rgba(255, 255, 255, .28);
  --c-acc: var(--pink);            /* the girl in focus, set per page / per centred pack */
  --c-acc2: var(--magenta);

  --radius: 18px;
  --pill: 999px;
  --ease-out: cubic-bezier(.2, .9, .25, 1);
  --ease-spring: cubic-bezier(.34, 1.4, .5, 1);
  --shadow-1: 0 1px 0 rgba(255, 255, 255, .04) inset, 0 10px 30px -12px rgba(0, 0, 0, .6);

  /* Rubik (Google Fonts, index.html), the face closest to the logo: heavy with
     softly rounded corners. 900 uppercase for display, 400-800 for the UI.
     Never italic, never tracked. */
  --font: 'Rubik', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --display: 'Rubik', system-ui, sans-serif;
  --display-cond: 'Rubik', system-ui, sans-serif;

  /* hold.js ring vars (blockrips names) */
  --acc: var(--go);
  --acc-rgb: var(--go-rgb);
  --rip-skew: 0deg;
  --slant: none;
  --ring-out-w: 0px;
  --ring-out: transparent;

  color-scheme: dark;
  transition: --c-acc 600ms ease-out, --c-acc2 600ms ease-out;
}

/* BIG SCREENS: the whole shop scales up so it fills a monitor the way it fills a MacBook (Luke,
   13 Nov: "Everything should take up the same amount of space on the page as it does on my laptop").
   index.html's head script sets --z: 1 up to 1799px wide (every MacBook's default size), above that
   the smaller of width/1512 and height/860 (a 14" MacBook Pro's Chrome viewport), so a 2560x1440
   monitor gets ~1.4. CSS zoom leaves viewport units alone, so every vh/vw inside a zoomed box is
   divided by --z (calc(Nvh / var(--z, 1))). The rip stage (.rip) is not zoomed: it is full screen. */
.app, dialog, .toast { zoom: var(--z, 1); }
.rip { --z: 1; }

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

/* A scrolling list that fades out at whichever end has more to scroll to, never a hard cut through a
   row (Luke, 13 Nov). app.js fadeEnds() sets is-up / is-down on any .fade-ends element. */
.fade-ends, .sheet__body, .gp__scroll, .chat__log {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 var(--fade-t, 0px), #000 calc(100% - var(--fade-b, 0px)), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 var(--fade-t, 0px), #000 calc(100% - var(--fade-b, 0px)), transparent 100%);
}
:is(.fade-ends, .sheet__body, .gp__scroll, .chat__log).is-up { --fade-t: var(--fade, 36px); }
:is(.fade-ends, .sheet__body, .gp__scroll, .chat__log).is-down { --fade-b: var(--fade, 36px); }
html { -webkit-text-size-adjust: 100%; background: var(--bg-deep); }
html:has(dialog[open]), html.no-scroll { overflow: hidden; }
body {
  margin: 0; min-height: 100dvh; background: var(--bg-deep); color: var(--text);
  font-family: var(--font); font-size: 15px; line-height: 1.45;
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
  overflow: hidden;
}
img, video, canvas { display: block; max-width: 100%; }
button { font: inherit; color: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
button:disabled { cursor: not-allowed; }
a { color: inherit; -webkit-tap-highlight-color: transparent; }
h1, h2, h3, p, ul, dl, dd { margin: 0; }
ul { padding: 0; list-style: none; }
h1, h2 { text-wrap: balance; }
:focus-visible { outline: 2px solid var(--go); outline-offset: 3px; border-radius: 10px; }
.sr-only { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
[hidden] { display: none !important; }
.tnum { font-variant-numeric: tabular-nums; }
.skip { position: fixed; z-index: 300; left: 12px; top: -60px; padding: 10px 16px; border-radius: var(--pill); background: #fff; color: #111; font-weight: 800; text-decoration: none; }
.skip:focus { top: 12px; }

/* ── page backdrop: the dark base, her colour, a halftone and a little grain ── */
.backdrop {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(70vmax 50vmax at 50% 46%, color-mix(in srgb, var(--c-acc) 18%, transparent), transparent 62%),
    radial-gradient(60vmax 50vmax at 0% 0%, rgba(255, 77, 174, .10), transparent 60%),
    radial-gradient(60vmax 50vmax at 100% 100%, rgba(252, 1, 135, .10), transparent 60%),
    var(--bg-deep);
}
.backdrop::before { /* halftone dots, strongest at the edges */
  content: ''; position: absolute; inset: 0; opacity: .5;
  background-image: radial-gradient(rgba(255, 255, 255, .09) 1px, transparent 1.6px);
  background-size: 14px 14px;
  -webkit-mask-image: radial-gradient(closest-side at 50% 46%, transparent 35%, #000 120%);
  mask-image: radial-gradient(closest-side at 50% 46%, transparent 35%, #000 120%);
}
.backdrop::after { /* grain */
  content: ''; position: absolute; inset: 0; opacity: .07; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ============================================================
   THE SHELL — phone
   ============================================================ */
.app {
  position: relative; z-index: 1; height: calc(100dvh / var(--z, 1)); min-height: 0;
  display: grid; grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr) auto auto;
  grid-template-areas: "top" "main" "cta" "bnav";
  padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right);
}
.rail, .side, .live, .srank, .climb { display: none; }

/* ── top bar ── */
.top {
  grid-area: top; position: relative; z-index: 20; display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: calc(6px + env(safe-area-inset-top)) 12px 6px 16px; min-height: 58px;
  background: rgba(31, 33, 35, .82); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}
/* the one-line logo (brand/vice/vicerips-horizontal.webp, 1377x433). Its
   sticker outline is part of the art, so no shadow or ring is added here. */
.wordmark {
  color: #fff; text-decoration: none; padding: 6px 2px; min-height: 44px;
  display: inline-flex; align-items: center; flex: 0 0 auto; border-radius: 8px;
}
.wordmark img { display: block; height: 34px; width: auto; }
.top__end { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
/* the right of the top bar keeps its full size (sound, your site rank, your name and balance); the live
   strip is what gives up room (Luke, 13 Nov: "making the live feed smaller ... not squashing everything") */
.top__end > *, .bal__chip > * { flex-shrink: 0; }
.bal { display: flex; align-items: center; gap: 6px; }
/* the gem chip is a button (it opens Get gems): 40px tall, its hit
   area grown to 44 by the ::after; Sign in is the brand pill beside nothing */
.bal__chip {
  position: relative; display: inline-flex; gap: 6px; height: 40px; padding: 0 14px 0 12px; align-items: center;
  border: 0; border-radius: var(--pill); background: var(--chip-bg); box-shadow: inset 0 0 0 1px var(--chip-ring);
  color: #fff; font: inherit; cursor: pointer;
  transition: background-color 150ms, transform 150ms var(--ease-out);
}
.bal__chip::after { content: ''; position: absolute; inset: -2px; }
.bal__chip:hover { background: rgba(255, 255, 255, .1); }
.bal__chip:active { transform: scale(.96); }
.bal__chip:focus-visible, .bal__in:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.bal__in { min-height: 40px; padding: 0 18px; font-size: 14px; cursor: pointer; }
.bal__amt { color: var(--go); font-weight: 800; font-size: 15px; font-variant-numeric: tabular-nums; }
.bal__net { font-size: 9px; font-weight: 800; text-transform: uppercase; color: var(--pink); padding: 2px 6px; border-radius: var(--pill); box-shadow: inset 0 0 0 1px rgba(255, 77, 174, .5); }
@media (max-width: 380px) { .bal__chip { padding: 0 12px; } }
.bal__chip.is-bump .bal__amt { animation: balBump 420ms var(--ease-out); }
@keyframes balBump { 0% { color: #fff; transform: translateY(-2px); } 100% { color: var(--go); transform: none; } }

.iconbtn {
  width: 44px; height: 44px; flex: 0 0 auto; display: inline-grid; place-items: center; padding: 0; border: 0;
  border-radius: 50%; background: var(--chip-bg); box-shadow: inset 0 0 0 1px var(--chip-ring); color: #fff;
  transition: background-color 150ms, transform 150ms var(--ease-out), opacity 150ms;
}
.iconbtn:hover { background: rgba(255, 255, 255, .1); }
.iconbtn:active { transform: scale(.96); }
.iconbtn:disabled { opacity: .35; }

/* the sound toggle: one icon each way, crossfaded */
.sndbtn { position: relative; }
.sndbtn .snd-on, .sndbtn .snd-off { transition: opacity 200ms cubic-bezier(.2, 0, 0, 1), transform 200ms cubic-bezier(.2, 0, 0, 1), filter 200ms; }
.sndbtn[aria-pressed="true"] .snd-off, .sndbtn[aria-pressed="false"] .snd-on { opacity: 0; transform: scale(.25); filter: blur(4px); position: absolute; }
.sndbtn.iconbtn .snd-on, .sndbtn.iconbtn .snd-off { grid-area: 1 / 1; }
.chipbtn.sndbtn .snd-on, .chipbtn.sndbtn .snd-off { position: absolute; left: 15px; top: 50%; margin-top: -9px; }
.sndbtn[aria-pressed="false"] { color: var(--muted); }

/* ── the page ── */
.view { grid-area: main; min-height: 0; overflow-y: auto; overflow-x: hidden; outline: none; overscroll-behavior: contain; }
.loading { display: grid; place-items: center; min-height: calc(60vh / var(--z, 1)); }
.spinner { width: 32px; height: 32px; border-radius: 50%; border: 3px solid rgba(255, 255, 255, .15);
  border-top-color: var(--pink); animation: spin 800ms linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

.label { font-size: 11px; font-weight: 800; letter-spacing: 0; text-transform: uppercase; color: var(--muted); }
.tag18 {
  font-size: 10px; font-weight: 800; letter-spacing: 0; padding: 3px 8px; border-radius: var(--pill);
  background: var(--chip-bg); box-shadow: inset 0 0 0 1px var(--chip-ring); color: #fff; line-height: 1.2;
}
.avatar {
  --s: 76px; width: var(--s); height: var(--s); flex: 0 0 auto; border-radius: 50%; padding: 3px; display: block;
  background: var(--brand-grad); box-shadow: 0 6px 24px rgba(255, 77, 174, .35);
}
.avatar img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; border: 3px solid var(--bg); background: var(--surface); }
.avatar--sm { --s: 34px; padding: 2px; box-shadow: none; }
.avatar--sm img { border-width: 2px; }
/* her profile picture as a button: it opens all her photos (app.js openPhotos) */
.avatar--btn { border: 0; cursor: pointer; transition: transform 150ms var(--ease-out), box-shadow 150ms; }
.avatar--btn:hover { box-shadow: 0 0 0 3px rgba(255, 255, 255, .22), 0 6px 24px rgba(255, 77, 174, .45); }
.avatar--btn:active { transform: scale(.96); }
.avatar--btn:focus-visible { outline: 2px solid #fff; outline-offset: 3px; border-radius: 50%; }

/* ============================================================
   THE STAGE (home + her page)
   ============================================================ */
.stage { height: 100%; min-height: 0; display: flex; flex-direction: column; }

/* her row on the phone (desktop: her card is in the right column) */
.mhead { display: flex; align-items: center; gap: 12px; padding: 10px 12px 4px 16px; position: relative; z-index: 3; }
.mhead .avatar { --s: 50px; padding: 2px; box-shadow: 0 4px 16px rgba(255, 77, 174, .3); }
.mhead .avatar img { border-width: 2px; }
.mhead__txt { flex: 1; min-width: 0; }
.mhead__name { font-size: 18px; font-weight: 800; line-height: 1.15; text-transform: uppercase; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mhead__sub { display: flex; align-items: center; gap: 8px; margin-top: 4px; color: var(--muted); font-size: 13px; }
/* chat · top fans · share: one tight group so her name keeps its room at 375px */
.mhead__acts { display: flex; gap: 6px; flex: 0 0 auto; }
@media (max-width: 430px) {
  .mhead { gap: 10px; padding-right: 10px; }
  .mhead .avatar { --s: 46px; }
  .mhead__name { font-size: 16px; }
  .mhead__acts { gap: 4px; }
  .mhead__acts .iconbtn { position: relative; width: 38px; height: 38px; }
  .mhead__acts .iconbtn::after { content: ''; position: absolute; inset: -3px; }   /* still a 44px tap */
}

/* her chat on the phone (app.js openHerChat): the chat fills the sheet, its log scrolls, the box stays */
.chatsheet .sheet__in { height: calc(88dvh / var(--z, 1)); }
.chatsheet__body { display: flex; flex-direction: column; overflow: hidden; padding-bottom: calc(12px + env(safe-area-inset-bottom)); }
.chatsheet__body > .chat { flex: 1 1 auto; height: auto; min-height: 0; }
/* all her photos (app.js openPhotos): the card's grid, four across from 640px */
.photosheet .pcard__photos { margin-top: 0; gap: 8px; }
@media (min-width: 640px) { .photosheet .pcard__photos { grid-template-columns: repeat(4, 1fr); } }

/* the stage title: her name (or "Today's mix") in the display face,
   white, lit by her colour; the handle small beneath. Type only, no box. On her page on the
   phone her row (.mhead) already says it, so it is hidden there. */
.shead { position: relative; z-index: 3; padding: 12px 16px 0; text-align: center; }
[data-page="creator"] .shead { display: none; }
.shead__t {
  display: inline-block; max-width: 100%;
  font-family: var(--display); font-size: 18px; font-weight: 900; line-height: 1.1; letter-spacing: 0; text-transform: uppercase;
  overflow-wrap: anywhere; color: #fff; text-shadow: 0 4px 30px color-mix(in srgb, var(--c-acc) 60%, transparent);
}
.shead__sub { display: none; align-items: center; justify-content: center; gap: 8px; margin-top: 6px; font-size: 13px; color: var(--muted); }
/* share her packs: a quiet round icon at the top right of her packs, never a pink button (HOLD TO
   RIP is the one call to action; Luke, 13 Nov) */
.shead__share { position: absolute; top: 12px; right: 16px; }
.shead__dot { width: 3px; height: 3px; border-radius: 50%; background: var(--faint); }

/* ── the fan ── */
.fan {
  position: relative; flex: 1 1 auto; min-height: 0; overflow: visible; isolation: isolate; z-index: 1;
  touch-action: none; cursor: grab; -webkit-user-select: none; user-select: none;
}
.fan.is-drag { cursor: grabbing; }
.fan__glow { /* her colour, big and soft, behind the centre pack; it fades out
  inside its own box (closest-side), so the page's overflow edge never cuts it */
  position: absolute; inset: -12% 0; pointer-events: none; z-index: -1;
  background:
    radial-gradient(closest-side, color-mix(in srgb, var(--c-acc) 40%, transparent), color-mix(in srgb, var(--c-acc2) 14%, transparent) 55%, transparent 100%);
}
.fslot {
  position: absolute; top: 50%; left: 50%; width: 0; height: 0; padding: 0; border: 0; background: none;
  display: flex; align-items: center; justify-content: center; will-change: transform; outline: none; cursor: inherit;
}
.fpack { /* a 3D still of the pack (site/packstill.js): transparent round its
  silhouette, so no frame, no rounded corners and no rect effects on it */
  --pw: 170px; --sheen: 0;
  position: relative; display: block; flex: 0 0 auto; width: var(--pw); aspect-ratio: 569 / 1000;
  transform-origin: 50% 50%;
}
.fpack::before { /* skeleton shimmer, roughly the pack's body, until the still paints */
  content: ''; position: absolute; inset: 2.5% 1.5%; border-radius: calc(var(--pw) * .03);
  background:
    linear-gradient(100deg, transparent 30%, rgba(255, 255, 255, .14) 50%, transparent 70%) 0 0 / 250% 100%,
    linear-gradient(160deg, var(--surface-2), var(--surface));
  animation: shimmer 1.3s linear infinite;
}
.fpack.is-ready::before { display: none; }
@keyframes shimmer { from { background-position: 150% 0; } to { background-position: -100% 0; } }
.fpack__sh { /* the shadow under the pack, by opacity only (paint() fades it). blockrips
  does the same (stage.css .sl-shadow): a box behind the still rather than a
  filter: drop-shadow, which would re-rasterise every frame the fan moves */
  position: absolute; inset: 3% 4%; border-radius: calc(var(--pw) * .03); opacity: 0; pointer-events: none;
  box-shadow: 0 24px 34px -6px rgba(0, 0, 0, .7), 0 30px 70px -24px color-mix(in srgb, var(--c-acc) 70%, transparent);
}
.fpack__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; pointer-events: none;
  opacity: 0; transition: opacity 260ms; }
.fpack.is-ready .fpack__img { opacity: 1; }
.fpack__dim { /* the still again, blacked out once (static filter), so only its opacity moves */
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; pointer-events: none;
  opacity: 0; filter: brightness(0); will-change: opacity; }
.fpack:not(.is-ready) .fpack__dim { visibility: hidden; }
.fpack__sheen { /* foil sheen that follows the mouse on the centre pack, masked to the still */
  position: absolute; inset: 0; pointer-events: none; mix-blend-mode: overlay;
  -webkit-mask: var(--still, none) center / contain no-repeat; mask: var(--still, none) center / contain no-repeat;
  opacity: calc(.9 * var(--sheen)); transition: opacity 240ms;
  background:
    radial-gradient(circle at var(--mx, 50%) var(--my, 50%), rgba(255, 255, 255, .55), transparent 45%),
    linear-gradient(115deg, transparent 20%, rgba(255, 255, 255, .28) calc(var(--mx, 50%) - 10%), rgba(255, 45, 155, .12) var(--mx, 50%), rgba(252, 1, 135, .22) calc(var(--mx, 50%) + 10%), transparent 80%);
}
.fslot:not(.is-hero) .fpack__sheen { opacity: 0; }
.fslot:focus-visible .fpack { outline: 2px solid var(--go); outline-offset: 6px; }
.fpack__img.is-bounce { animation: fanBounce 520ms cubic-bezier(.34, 1.2, .44, 1) both; }
@keyframes fanBounce { 0% { transform: scale(1); } 28% { transform: scale(1.06) translateY(-2%); } 55% { transform: scale(.975); } 78% { transform: scale(1.015); } 100% { transform: scale(1); } }

/* ── under the fan: name, arrows, what is in it, dots ── */
.fmeta { flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 4px 12px 6px; position: relative; z-index: 3; }
.fmeta__row { display: flex; align-items: center; justify-content: center; gap: 10px; width: 100%; }
.fmeta__title {
  min-width: 0; flex: 0 1 auto; display: flex; align-items: center; justify-content: center; gap: 10px;
  font-family: var(--display); font-size: 18px; font-weight: 900; line-height: 1.1; letter-spacing: 0; text-transform: uppercase; min-height: 40px;
}
.fmeta__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* home: her picture + name are a link to her page */
.fmeta__who { display: inline-flex; align-items: center; gap: 10px; min-width: 0; min-height: 44px; padding: 0 6px 0 0; border-radius: var(--pill);
  color: inherit; text-decoration: none; transition: background-color 150ms; }
.fmeta__who:hover .fmeta__name, .pcard__namelink:hover { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 4px; }
.fmeta__who:focus-visible, .pcard__namelink:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
.pcard__namelink { color: inherit; text-decoration: none; border-radius: 6px; }
.fmeta__price { color: var(--go); }
.fmeta__arrow { width: 40px; height: 40px; }
.fmeta__arrow::after { content: ''; position: absolute; inset: -4px; }
.fmeta__arrow { position: relative; }
.fmeta__sub { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: center;
  font-size: 11px; font-weight: 800; letter-spacing: 0; text-transform: uppercase; color: var(--muted); min-height: 22px; }
.fmeta__odds { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); }
.fmeta__odds .tnum { color: var(--text, #fff); }
/* the reel's own R badge, small, beside the pack's R chance */
.fmeta__rb { --rb-w: 20px; }
.dots { display: flex; justify-content: center; }
.dots button { width: 18px; height: 24px; padding: 0; border: 0; background: none; display: grid; place-items: center; border-radius: 6px; }
.dots button::before { content: ''; width: 6px; height: 6px; border-radius: 3px; background: rgba(255, 255, 255, .24); transition: width 240ms var(--ease-out), background-color 240ms; }
.dots button:hover::before { background: rgba(255, 255, 255, .5); }
.dots button[aria-current="true"] { width: 30px; }
.dots button[aria-current="true"]::before { width: 20px; background: var(--brand-grad); }

/* ============================================================
   THE RIP DOCK
   ============================================================ */
.cta { grid-area: cta; display: flex; flex-direction: column; align-items: stretch; gap: 14px;
  padding: 6px 16px 8px; position: relative; z-index: 5; }
.cta .hring { order: 1; }
.cta__more { order: 0; display: flex; justify-content: center; gap: 8px; }
.cta__hint { order: 2; min-height: 16px; text-align: center; font-size: 12px; color: var(--muted); }
.cta .cta__pulls { display: none; }
/* THE RIP BUTTON — blockrips' RIP PACK sticker (eval/style.css .stick / .rip,
   read 9 Nov; Luke: "make the button a bit cooler like this … without the
   Apple Pay"), in the brand gradient (#FF4DAE -> #FC0187) lit lighter at the top and deeper at the
   foot, a gloss across the top half, a thick #1F2123 rim (the base as
   the keyline), a cream outer ring and a hard drop under it. The type is
   Rubik 800, the UI face, set big and white with a keyline
   shadow. No skew (the brand never slants), no pay marks. */
.cta__btn {
  --ring-out: #FFF6EA; --ring-out-w: 4px;
  position: relative; overflow: hidden; display: block; width: 100%; min-height: 58px; padding: 0 20px;
  border: 3.5px solid #1F2123; border-radius: var(--pill);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .16) 0%, transparent 46%, rgba(80, 0, 40, .22) 100%),
    linear-gradient(90deg, var(--pink), var(--magenta));
  color: #fff; font-size: 18px; line-height: 1; font-weight: 800; letter-spacing: 0; text-transform: uppercase;
  text-shadow: 0 2px 0 rgba(31, 33, 35, .55);
  box-shadow: 0 0 0 var(--ring-out-w) var(--ring-out), 0 6px 0 calc(var(--ring-out-w) - 1px) rgba(0, 0, 0, .38);
  transition: transform 140ms cubic-bezier(.22, .8, .36, 1), opacity 150ms, filter 150ms;
}
.cta__btn::before { /* the gloss: a soft white band across the top half */
  content: ''; position: absolute; left: 14px; right: 14px; top: 3px; height: 42%; pointer-events: none;
  border-radius: 999px 999px 40px 40px / 999px 999px 14px 14px;
  background: linear-gradient(180deg, rgba(255, 255, 255, .55), rgba(255, 255, 255, .14) 70%, transparent);
}
.cta__btn > * { position: relative; z-index: 1; }
.cta__btn:disabled {
  --ring-out: rgba(255, 255, 255, .22);
  background: var(--surface-2); color: var(--faint); text-shadow: none;
}
.cta__btn:disabled::before { display: none; }
.cta__btn:focus-visible { outline-offset: 3px; border-radius: var(--pill); }
/* the hold buttons: the keyboard ring IS the hold ring's own track (6px out,
   inside the 8–10px gap to its neighbours), so the focus ring and the progress
   ring are one shape and never stack */
.hring > .cta__btn:focus-visible { outline: none; }
.hring:has(> .cta__btn:focus-visible):not(.is-holding) .hring__ring { opacity: 1; }
.hring:has(> .cta__btn:focus-visible):not(.is-holding) .hring__track { stroke: #fff; }
.sheet__in:focus, .viewer__in:focus { outline: none; }
.cta__hint button { border: 0; background: none; padding: 13px 6px; margin: -13px 0; color: var(--go); font-weight: 800; text-decoration: underline; text-underline-offset: 3px; font-size: 12px; }

.chipbtn {
  position: relative; display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 16px; border: 0;
  border-radius: var(--pill); background: var(--chip-bg); box-shadow: inset 0 0 0 1px var(--chip-ring);
  font-size: 13px; font-weight: 800; letter-spacing: 0; text-transform: none; color: #fff; text-decoration: none; white-space: nowrap;
  transition: background-color 150ms, transform 150ms var(--ease-out), box-shadow 150ms;
}
.chipbtn:hover { background: rgba(255, 255, 255, .1); }
.chipbtn:active { transform: scale(.96); }
.chipbtn svg { flex: 0 0 auto; }
.chipbtn .count { color: var(--go); font-variant-numeric: tabular-nums; }
.chipbtn .count:empty { display: none; }
.chipbtn.sndbtn { padding-left: 42px; }
.chipbtn--brand { background: linear-gradient(90deg, var(--pink), var(--magenta)); box-shadow: none; justify-content: center; }   /* their Play button: flat, no glow */
.chipbtn--brand:hover { background: linear-gradient(90deg, var(--pink), var(--magenta)); filter: brightness(1.08); }

/* ── HOLD RING — ported from blockrips eval/style.css 1441–1500 (hold.js's
   own CSS), restyled: --go line, no skew, no sticker ring. The
   wrapper carries any transform; the traced path is measured off the
   button's offset box, so the button itself must stay untransformed. ── */
.hring { --hring-gap: 10px; --p: 0; --e: 0; --glow-rgb: 255, 77, 174; position: relative; display: block;
  transform: skewX(var(--rip-skew)) scale(calc(1 - .03 * var(--e))); }
.hring > .cta__btn { display: block; transform: none; margin-top: 0; width: 100%; }
.hring__btn { touch-action: none; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; position: relative; z-index: 1; }
/* AT REST this is exactly the sticker's own shadow (rings + drop); the
   pink glow is a HOLD state, drawn only by --e (blockrips' rule) */
.hring > .cta__btn {
  box-shadow: 0 0 0 var(--ring-out-w) var(--ring-out), 0 6px 0 calc(var(--ring-out-w) - 1px) rgba(0, 0, 0, .38),
              0 14px 40px -12px rgba(var(--glow-rgb), calc(.9 * var(--e))),
              0 0 calc(8px + 40px * var(--e)) rgba(var(--glow-rgb), calc(.5 * var(--e)));
}
@media (hover: hover) { .hring > .cta__btn:not(:disabled):hover { transform: translateY(-2px); } }
.hring > .cta__btn:not(:disabled):active { transform: translateY(2px); }
.hring > .cta__btn:disabled { box-shadow: 0 0 0 var(--ring-out-w) var(--ring-out); }
.hring__ring { position: absolute; left: calc(-1 * var(--hring-gap)); top: calc(-1 * var(--hring-gap));
  width: calc(100% + 2 * var(--hring-gap)); height: calc(100% + 2 * var(--hring-gap));
  overflow: visible; pointer-events: none; transform-origin: 50% 50%;
  opacity: 0; transition: opacity 140ms ease-out; z-index: 2; }
.hring.is-holding .hring__ring { opacity: 1; }
.hring__track { fill: none; stroke: rgba(255, 255, 255, .16); stroke-width: 2.5; }
.hring__line { fill: none; stroke: var(--acc); stroke-width: 2.5; stroke-linecap: round;
  filter: drop-shadow(0 0 6px rgba(var(--acc-rgb), .9)); }
.hring .hring__labels { display: grid; place-items: center; transform: var(--slant); }
.hring__labels .hring__label { grid-area: 1 / 1; white-space: nowrap; display: block; opacity: 0; transform: translateY(3px);
  transition: opacity 130ms ease-out, transform 130ms ease-out; }
.hring__labels .hring__label.is-on { opacity: 1; transform: none; }
.hring__labels .hring__label[data-l="hold"], .hring__labels .hring__label[data-l="tap"] { letter-spacing: 0; }
@keyframes hringBloom { 0% { transform: scale(1); opacity: 1; } 100% { transform: scale(1.12); opacity: 0; } }
@keyframes hringFlash { 0% { filter: brightness(1); } 26% { filter: brightness(1.3); } 100% { filter: brightness(1); } }
.hring.is-done .hring__ring { opacity: 1; animation: hringBloom 420ms ease-out forwards; }
.hring.is-done .hring__line { stroke: #FFF; filter: drop-shadow(0 0 14px rgba(var(--acc-rgb), .95)); }
.hring.is-done .hring__btn { animation: hringFlash 380ms ease-out; }

/* ── phone bottom nav ── */
.bnav {
  grid-area: bnav; display: grid; grid-template-columns: repeat(4, 1fr); position: relative; z-index: 10;
  padding: 4px 6px calc(4px + env(safe-area-inset-bottom));
  background: rgba(24, 25, 27, .92); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--line);
}
.bnav__item {
  position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  min-height: 52px; padding: 4px 2px; border: 0; background: none; border-radius: 14px; color: var(--faint); text-decoration: none;
  font-size: 10px; font-weight: 800; letter-spacing: 0; text-transform: uppercase; transition: color 150ms;
}
.bnav__item:hover { color: var(--muted); }
.bnav__item[aria-current="page"] { color: #fff; }
.bnav__item[aria-current="page"]::before { content: ''; position: absolute; top: -5px; left: 50%; width: 24px; height: 3px; margin-left: -12px; border-radius: 0 0 3px 3px; background: var(--brand-grad); }
.bnav__item:active svg { transform: scale(.92); }
.bnav__item svg { transition: transform 150ms var(--ease-out); }
.bnav__badge { position: absolute; top: 4px; left: calc(50% + 6px); min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
  background: var(--pink); color: #fff; font-size: 10px; line-height: 18px; text-align: center; font-variant-numeric: tabular-nums; letter-spacing: 0; }

/* ============================================================
   MY GIRLS (rail list on desktop, sheet on the phone)
   ============================================================ */
.pins { display: flex; flex-direction: column; gap: 2px; }
.pin { position: relative; max-height: 64px; transition: opacity 160ms ease-out, transform 180ms var(--ease-out), max-height 180ms ease-out; }
.pin.is-leaving { opacity: 0; transform: translateX(-12px); max-height: 0; }
.pin__link {
  display: flex; align-items: center; gap: 10px; min-height: 48px; padding: 6px 38px 6px 8px; border-radius: 14px;
  text-decoration: none; color: rgba(255, 255, 255, .86); transition: background-color 150ms, color 150ms;
}
.pin__link:hover { background: rgba(255, 255, 255, .06); color: #fff; }
.pin__link[aria-current="page"] { background: rgba(255, 255, 255, .09); color: #fff; box-shadow: inset 3px 0 0 var(--pink); }
.pin__av { width: 34px; height: 34px; flex: 0 0 auto; border-radius: 50%; padding: 2px; background: var(--brand-grad); }
.pin__av img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; border: 2px solid var(--bg); }
.pin--visiting .pin__av { background: rgba(255, 255, 255, .3); }
.pin__txt { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.2; }
.pin__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 14px; font-weight: 700; }
.pin__tag { font-size: 9px; font-weight: 800; letter-spacing: 0; text-transform: uppercase; color: var(--faint); }
.pin__x {
  position: absolute; right: 6px; top: 50%; width: 32px; height: 32px; margin-top: -16px; padding: 0; border: 0; border-radius: 50%;
  display: grid; place-items: center; background: rgba(255, 255, 255, .1); color: #fff;
  opacity: 0; transform: scale(.7); transition: opacity 150ms ease-out, transform 150ms var(--ease-out), background-color 150ms;
}
.pin__x::after { content: ''; position: absolute; inset: -6px; }
.pin__x:hover { background: var(--pink); }
.pin__x:active { transform: scale(.96); }
.pin:hover .pin__x, .pin:focus-within .pin__x { opacity: 1; transform: none; }
@media (hover: none) { .pin__x { opacity: 1; transform: none; } }
.pins--sheet .pin__link { min-height: 56px; }
.pin--sugg .pin__link { padding-right: 8px; }   /* no X to make room for */
.sheet__sub { margin: 18px 0 6px; padding: 0 8px; font-size: 11px; font-weight: 800; letter-spacing: 0; text-transform: uppercase; color: var(--faint); }
.pins--sheet .pin__x { opacity: 1; transform: none; width: 40px; height: 40px; margin-top: -20px; }

/* ============================================================
   PROFILE CARD (her page's right column; the home's centred girl)
   ============================================================ */
.pcard {
  position: relative; overflow: hidden; border-radius: 24px; padding: 0 14px 14px; text-align: center;
  background: linear-gradient(180deg, rgba(38, 40, 43, .92), rgba(31, 33, 35, .96));
  box-shadow: inset 0 0 0 1px var(--line), 0 30px 60px -30px rgba(0, 0, 0, .8);
}
.pcard.is-swap { animation: cardSwap 260ms var(--ease-out); }
@keyframes cardSwap { from { opacity: .3; transform: translateY(6px); } }
.pcard__banner { display: block; height: 92px; margin: 0 -14px; position: relative; overflow: hidden; background: linear-gradient(135deg, var(--p1), var(--p2)); }
.pcard__banner img { width: 100%; height: 100%; object-fit: cover; object-position: center 30%; opacity: .85; }
.pcard__banner::after { content: ''; position: absolute; inset: 0; background: linear-gradient(180deg, transparent 30%, rgba(38, 40, 43, .95)); }
.pcard__av { --s: 84px; margin: -48px auto 0; position: relative; }
.pcard__kicker { margin-top: 8px; font-size: 10px; font-weight: 800; letter-spacing: 0; text-transform: uppercase; color: var(--faint); }
/* names are Rubik Black uppercase: the creator-name spec (feed card, 12px/900/uppercase), set larger.
   kept to 900 at a size that fits a 16-letter handle in a 232px card */
.pcard__name { margin-top: 8px; font-size: 20px; font-weight: 800; line-height: 1.15; text-transform: uppercase; overflow-wrap: anywhere; }
.pcard__kicker + .pcard__name { margin-top: 2px; }
.pcard__sub { display: flex; align-items: center; justify-content: center; gap: 8px; margin-top: 6px; color: var(--muted); font-size: 13px; }
.pcard__pitch { margin-top: 10px; font-size: 13px; line-height: 1.4; color: rgba(255, 255, 255, .8); text-wrap: pretty; }
.pcard__pitch b { color: var(--pink); font-weight: 800; }
.pcard__stats { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-top: 12px; }
.pcard__stats > div { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; min-height: 50px; padding: 6px 4px; border-radius: 14px; background: rgba(255, 255, 255, .04); box-shadow: inset 0 0 0 1px var(--line); }
.pcard__stats dt { font-size: 9px; font-weight: 800; line-height: 12px; letter-spacing: 0; text-transform: uppercase; color: var(--faint); white-space: nowrap; }
.pcard__stats dd { font-size: 15px; font-weight: 800; line-height: 1.2; white-space: nowrap; }
/* every box is the same two rows: a one-line label, then the value in a fixed-height row centred on
   one line, so numbers, the gem price and the rating badge all sit level (Luke, 13 Nov: "not lined up") */
.pcard__stats > div { display: grid; grid-template-rows: 12px 26px; justify-items: center; align-items: center; row-gap: 4px; }
.pcard__stats dd { display: flex; align-items: center; justify-content: center; height: 26px; margin: 0; }
.pcard__stats dd .gprice { display: inline-flex; align-items: center; gap: 2px; }
/* waiting for sign-in / your vault: faint bars the size of the real values (no shimmer, nothing moves) */
.pcard__sk { display: block; width: 26px; height: 12px; border-radius: 4px; background: rgba(255, 255, 255, .08); }
.pcard__sk--dt { width: 34px; height: 8px; }
/* her profile photos (Skip in the sorter), three across */
.pcard__photos { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-top: 12px; }
.pcard__ph { padding: 0; border: 0; border-radius: 10px; overflow: hidden; aspect-ratio: 3 / 4; background: var(--surface); cursor: pointer; }
.pcard__ph img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 200ms var(--ease-out); }
.pcard__ph:hover img { transform: scale(1.04); }
.pcard__ph:focus-visible { outline: 2px solid var(--go); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .pcard__ph img { transition: none; } }
.pcard__acts { margin-top: 12px; display: grid; }
.pcard__acts .chipbtn { width: 100%; }

/* her card's tabbed panel: Photos | Top fans | Chat (her page only; Luke, 13 Nov). On desktop it fills
   what is left of the column and scrolls on its own (DESKTOP below). The bar follows the Top fans
   pills (.tf__tabs); the chosen tab wears her colours, so it never reads as the inner All time pill. */
.ptabs { container-type: inline-size; display: flex; flex-direction: column; min-height: 0; margin-top: 12px; overflow: hidden; border-radius: 18px; text-align: left;
  background: linear-gradient(180deg, rgba(255, 255, 255, .05), rgba(255, 255, 255, .02)); box-shadow: inset 0 0 0 1px var(--line); }
/* Luke, 13 Nov: the pill switch "looks like AI slop". Plain text tabs on a hairline: the chosen one is
   white with a 2px underline in her colour; no fills, no pills. Each tab keeps a 44px tap height. */
.ptabs__bar { flex: none; display: flex; justify-content: space-around; gap: 0; margin: 2px 8px 0;
  box-shadow: inset 0 -1px 0 0 var(--line); }
.ptabs__tab { position: relative; flex: 0 0 auto; display: flex; align-items: center; justify-content: center; gap: 6px; min-width: 0; min-height: 44px; padding: 0 6px; border: 0; border-radius: 0;
  background: none; color: var(--muted); font: inherit; font-size: 13px; font-weight: 800; white-space: nowrap; cursor: pointer;
  transition: color 160ms var(--ease-out); }
.ptabs__tab::after { content: ''; position: absolute; left: 6px; right: 6px; bottom: 0; height: 2px; border-radius: 2px 2px 0 0;
  background: var(--c-acc, var(--pink)); transform: scaleX(0); transition: transform 200ms var(--ease-out); }
.ptabs__tab svg { flex: none; }
.ptabs__tab span { overflow: hidden; text-overflow: ellipsis; }
.ptabs__tab:hover { color: #fff; }
.ptabs__tab[aria-selected="true"] { color: #fff; }
.ptabs__tab[aria-selected="true"]::after { transform: scaleX(1); }
.ptabs__tab:focus-visible { outline: 2px solid var(--go); outline-offset: 2px; }
@container (max-width: 299px) { .ptabs__tab svg { display: none; } }        /* labels first; icons where there is room */
@container (min-width: 330px) { .ptabs__tab { font-size: 14px; } }
.ptabs__panel { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; padding: 10px; overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, .22) transparent; }
.ptabs__panel[hidden] { display: none; }
/* the panels fade at whichever end has more to scroll to (.fade-ends, set in app.js herTabsHTML), so
   photos slide softly under the tabs instead of being cut (Luke, 13 Nov) */
.ptabs__panel { --fade: 28px; }
.ptabs__panel > * { flex: none; }
.ptabs__panel:focus-visible { outline: 2px solid var(--go); outline-offset: -2px; border-radius: 18px; }
.ptabs__panel .pcard__photos { margin-top: 0; }
/* Chat ("chat with her" DEMO, site/chat.js + site/chat.css): the chat fills the panel, and its own log
   scrolls, so the box to type in stays at the foot. A panel shorter than the chat's minimum scrolls instead. */
#pp-chat { padding: 10px 12px 12px; }
.ptabs__panel > .chat { flex: 1 1 auto; height: auto; min-height: 250px; gap: 6px; }
/* compact in the card: her avatar is right above, so the chat's own heading is one line */
#pp-chat .chat__av { display: none; }
#pp-chat .chat__head { min-height: 32px; }
#pp-chat .chat__name { font-size: 13px; }
#pp-chat .chat__clear { width: 40px; height: 40px; margin: -4px -8px -4px 0; }
#pp-chat .chat__note { padding: 6px 9px; font-size: 11.5px; line-height: 1.35; }
#pp-chat .chat__log { min-height: 64px; }
@media (prefers-reduced-motion: reduce) { .ptabs__tab, .ptabs__tab::after { transition: none; } }


/* ============================================================
   ALL GIRLS + 404
   ============================================================ */
.page { padding: 18px 16px 28px; }
.page-head { padding: 4px 0 16px; }
.page-head h1 { font-family: var(--display); font-size: 24px; font-weight: 900; line-height: 1.1; text-transform: uppercase; }
.page-head h1 em { font-style: normal; color: var(--pink); }
.page-head p { margin-top: 8px; color: var(--muted); max-width: 60ch; text-wrap: pretty; }
.nf-art { display: grid; place-items: center; width: 64px; height: 64px; border-radius: 50%; background: var(--surface); box-shadow: inset 0 0 0 1px var(--line); margin-bottom: 14px; }

.girls { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 10px; }
.gcard {
  position: relative; display: flex; flex-direction: column; align-items: center; height: 100%;
  padding: 0 10px 12px; border-radius: 22px; overflow: hidden; text-decoration: none; text-align: center;
  background: linear-gradient(180deg, rgba(38, 40, 43, .95), rgba(31, 33, 35, .98));
  box-shadow: inset 0 0 0 1px var(--line), 0 20px 40px -24px rgba(0, 0, 0, .8);
  transition: transform 220ms var(--ease-out), box-shadow 220ms;
  animation: cardIn 420ms var(--ease-out) both; animation-delay: calc(var(--i, 0) * 40ms);
}
@keyframes cardIn { from { opacity: 0; transform: translateY(10px); } }
.gcard:hover { transform: translateY(-3px); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--p1) 70%, transparent), 0 26px 50px -24px color-mix(in srgb, var(--p1) 60%, transparent); }
.gcard:active { transform: scale(.98); }
.gcard:focus-visible { outline-offset: 3px; border-radius: 22px; }
.gcard__banner { display: block; width: calc(100% + 20px); height: 84px; margin: 0 -10px; position: relative; overflow: hidden; background: linear-gradient(135deg, var(--p1), var(--p2)); }
.gcard__banner img { width: 100%; height: 100%; object-fit: cover; object-position: center 30%; opacity: .85; transition: transform 400ms var(--ease-out); }
.gcard:hover .gcard__banner img { transform: scale(1.05); }
.gcard__banner::after { content: ''; position: absolute; inset: 0; background: linear-gradient(180deg, transparent 25%, rgba(38, 40, 43, .95)); }
.gcard__av { --s: 72px; margin-top: -40px; position: relative; }
.gcard__pin { position: absolute; right: -2px; bottom: -2px; z-index: 2; display: none; place-items: center; width: 24px; height: 24px;
  border-radius: 50%; background: var(--go); color: #0B0C0D; box-shadow: 0 0 0 3px var(--bg); }
.gcard.is-pinned .gcard__pin { display: grid; }
.gcard__her { display: none; }
.gcard__name { display: block; max-width: 100%; margin-top: 8px; font-size: 16px; font-weight: 800; line-height: 1.2; text-transform: uppercase; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gcard__sub { display: flex; align-items: center; justify-content: center; gap: 6px; margin-top: 4px; color: var(--muted); font-size: 12px; max-width: 100%; }
.gcard__sub > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gcard__stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; width: 100%; margin-top: 10px; }
.gcard__stats > span { display: flex; flex-direction: column; align-items: center; gap: 1px; padding: 6px 2px; border-radius: 12px; background: rgba(255, 255, 255, .04);
  font-size: 8px; font-weight: 800; letter-spacing: 0; text-transform: uppercase; color: var(--faint); }
.gcard__stats b { font-size: 12px; letter-spacing: 0; color: #fff; white-space: nowrap; }
.gcard__foot { display: flex; width: 100%; margin-top: auto; padding-top: 10px; }
/* phone: packs and items only, no price span (Luke, 13 Nov) */
@media (max-width: 1023px) {
  .gcard__stats > .gcard__price { display: none; }
  .gcard__stats { grid-template-columns: repeat(2, 1fr); }
}
.gcard__go { display: inline-flex; align-items: center; justify-content: center; gap: 6px; width: 100%; min-height: 40px; border-radius: var(--pill);
  background: var(--chip-bg); box-shadow: inset 0 0 0 1px var(--chip-ring); font-size: 12px; font-weight: 800; letter-spacing: 0; text-transform: none; color: var(--go);
  transition: background-color 150ms, color 150ms; }
.gcard:hover .gcard__go { background: var(--go); color: #1F2123; box-shadow: none; }

/* ============================================================
   RIP OVERLAY
   ============================================================ */
.rip {
  position: fixed; inset: 0; z-index: 100; overflow: hidden; cursor: pointer; touch-action: none;
  background:
    radial-gradient(70% 55% at 50% 45%, color-mix(in srgb, var(--c-acc) 22%, transparent), transparent 70%),
    radial-gradient(90% 70% at 50% 110%, rgba(252, 1, 135, .18), transparent 70%),
    var(--bg-deep);
  animation: fadeIn 200ms ease-out;
}
/* THE FOOT. The bottom band of the overlay is kept for the end-of-pull actions
   (Save / Rip again) from the first frame, so the stage never has to move or
   re-frame when they appear. The canvas still covers the whole overlay, but
   rip.js FRAMES the pack and the content in the box above the band (its
   frameBottom: the #ripEnd box's height, which is this variable), so the halo
   and the falling wrapper carry on underneath instead of being cut off at a
   line. The sealed still sits in that same box. During the rip the band holds
   "Tap to skip" and the rarity reel. On a phone the content is width-bound,
   so the band costs it nothing. */
.rip { --rip-foot: calc(196px + env(safe-area-inset-bottom)); }
.rip__canvas { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; transition: opacity 200ms; }
.rip.is-playing .rip__canvas { opacity: 1; }
.rip__sealed {
  /* a 3D still of the pack in rip.js's frame-0 pose (site/packstill.js), placed where rip.js's own
     frame 0 draws it, so the 3D fades in on top of it. MEASURED (9 Nov, the wrapper's projected
     silhouette at frame 0, 1440x900 / 1024x768 / 375x812): 80.6% of the binding dimension
     (rip.js FIT asks .84/.88 of the world box; the silhouette comes out smaller), centred 1.1% of
     its own width left of the middle. --a is the still's aspect, set on load.
     CENTRED BY LAYOUT, NOT BY A TRANSFORM (fix, 9 Nov): it used to sit at left/top 50% and pull
     itself back with transform: translate(-50%, -50%). transform-origin is the UNtransformed box's
     centre, which that left half a pack right of and below the drawn pack, so anything that
     scaled it (the reel's `scale`, the pulse) pivoted about the drawn pack's bottom-right quarter
     and slid it right and down: at scale .76 the pack moved 12% of its width right of centre
     (43px at 1440x900; Luke's "why isn't this central?"). Now the box itself is where the pack
     is drawn (inset 0 + auto margins; an image's height comes from its ratio), so the origin is
     the pack's own centre and every scale is about it. `right` carries the 1.1% offset: auto
     margins centre the box between left 0 and right .022w, i.e. .011w left of the middle. */
  --sw: min(80.6vw, (100dvh - var(--rip-foot)) * .806 * var(--a, .549));   /* the canvas's box: above the foot */
  position: absolute; inset: 0 calc(var(--sw) * .022) var(--rip-foot) 0; margin: auto; width: var(--sw); height: auto;
  /* no shadow: the 3D frame it hands over to has none */
  animation: sealedIn 420ms var(--ease-spring) both, sealedPulse 1.2s ease-in-out 420ms infinite;
  transition: opacity 180ms;
}
.rip__sealed:not([src]), .rip__sealed[src=""] { visibility: hidden; }
.rip.is-playing .rip__sealed { opacity: 0; animation: none; transform: none; }
@keyframes sealedIn { from { transform: translateY(12%) scale(.82); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes sealedPulse { 0%, 100% { transform: none; } 50% { transform: scale(1.015) rotate(-.4deg); } }
.rip__status { position: absolute; left: 0; right: 0; bottom: calc(86px + env(safe-area-inset-bottom)); text-align: center;
  font-size: 12px; font-weight: 800; letter-spacing: 0; text-transform: uppercase; color: var(--muted); }
.rip__skip {
  position: absolute; left: 50%; bottom: calc(22px + env(safe-area-inset-bottom)); transform: translateX(-50%);
  min-height: 44px; padding: 0 18px; border: 0; border-radius: var(--pill); background: var(--chip-bg);
  box-shadow: inset 0 0 0 1px var(--chip-ring); font-size: 12px; font-weight: 800; letter-spacing: 0; text-transform: none; color: var(--muted);
}
@keyframes fadeIn { from { opacity: 0; } }

/* ── the end of a pull: My pulls / Rip again under the content ──
   (it was "Save"; since payments every pull is already kept, Luke 11 Nov)
   My pulls is the gate primary (a WHITE pill, #1F2123 type, title case,
   .age__yes); Rip again is the shop's own sticker CTA (.cta__btn in its hold
   ring), so spending looks and feels the same everywhere. Phone: stacked,
   Rip again at the bottom where the shop's HOLD TO RIP sits. Desktop: a row. */
.rip.is-end { cursor: default; }
.rip.is-end .rip__skip, .rip.is-end .rip__status { display: none; }
.rip__end {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 4; height: var(--rip-foot);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  padding: 0 16px calc(16px + env(safe-area-inset-bottom)); cursor: default;
  visibility: hidden; opacity: 0; transform: translateY(10px);
  transition: opacity 260ms var(--ease-out), transform 260ms var(--ease-out), visibility 0s linear 260ms;
}
.rip.is-end .rip__end { visibility: visible; opacity: 1; transform: none; transition-delay: 120ms, 120ms, 0s; }
.rip__note { margin: 0; min-height: 16px; text-align: center; font-size: 12px; font-weight: 800; line-height: 16px; color: var(--muted); }
.rip__note button { border: 0; background: none; padding: 13px 6px; margin: -13px 0; color: var(--go); font-weight: 800; text-decoration: underline; text-underline-offset: 3px; font-size: 12px; }
.rip__acts { display: flex; flex-direction: column; gap: 16px; width: min(420px, 100%); }
.rip__save {
  display: flex; align-items: center; justify-content: center; width: 100%; min-height: 48px; padding: 0 20px;
  border: 0; border-radius: var(--pill); background: #fff; color: #1F2123;
  font-size: 15px; font-weight: 800; letter-spacing: 0; text-transform: none; -webkit-tap-highlight-color: transparent;
  box-shadow: 0 12px 30px -16px rgba(255, 255, 255, .5);
  transition: background-color 160ms ease-out, transform 160ms var(--ease-out);
}
.rip__save:hover { background: #F1F1F1; }
.rip__save:active { transform: scale(.96); }
.rip__save:focus-visible { outline: 2px solid #fff; outline-offset: 3px; border-radius: var(--pill); }
.rip__x {
  position: absolute; z-index: 4; top: calc(14px + env(safe-area-inset-top)); right: 14px;
  visibility: hidden; opacity: 0; transition: opacity 200ms, visibility 0s linear 200ms;
}
.rip.is-end .rip__x { visibility: visible; opacity: 1; transition-delay: 120ms, 0s; }
/* the pull's <video>: its frames are drawn on the 3D card; the element only has
   to be IN the page and rendered, which is what lets iOS play a muted video
   from script (WebKit's policy: a video outside the DOM, display:none or
   visibility:hidden needs a gesture). 2px, all but transparent, untouchable. */
.rip__vid { position: absolute; left: 0; bottom: 0; width: 2px; height: 2px; opacity: .01; pointer-events: none; }

/* ── THE EXTRAS: the pack's other items, fanned out from BEHIND the hero ──
   (app.js THE HERO AND THE EXTRAS). The layer is the overlay's first child,
   so it paints under the 3D canvas — transparent off the card, so the cards
   are really behind the hero and its halo washes over them. On the end
   screen the canvas lets taps through to them; .rip__herohit (the hero's own
   rect, on top) keeps a tap on the hero from reaching a card under it.
   app.js sets each card's box, rotation and travel; this is the look: the
   hero's thin tier frame (rip.js drawFrame: a tier gradient ring with the
   card's rounded corner) at card size, a rarer card keeps a glow. */
.rip__xtras { position: absolute; inset: 0; z-index: 0; pointer-events: none; visibility: hidden; }
.rip__xtras.is-on { visibility: visible; }
.rip.is-end .rip__canvas, .rip.is-end .rip__sealed { pointer-events: none; }
.rip__herohit { position: absolute; pointer-events: auto; z-index: 1; }
/* the hero's scrub bar (app.js heroScrub): over the bottom of the main card,
   shown on hover (always on touch screens) */
.rip__scrub { position: absolute; z-index: 3; height: 32px; display: flex; align-items: center; padding: 0 12px;
  border-radius: 99px; background: rgba(12, 13, 14, .62); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  opacity: 0; pointer-events: none; transform: translateY(6px); transition: opacity .18s ease-out, transform .18s ease-out; }
.rip__scrub.is-on { opacity: 1; pointer-events: auto; transform: none; }
.rip__scrub input { width: 100%; margin: 0; height: 32px; accent-color: var(--c-acc, #FF4DAE); cursor: pointer; background: transparent; }
.rip__scrub input:focus-visible { outline: 2px solid #fff; outline-offset: 2px; border-radius: 99px; }
.rip:not(.is-end) .rip__scrub { display: none; }
/* the main card's mute button (app.js heroControls), its top-right corner */
.rip__mute { position: absolute; z-index: 3; width: 40px; height: 40px; border-radius: 50%; border: 0; padding: 0;
  display: grid; place-items: center; color: #fff; cursor: pointer;
  background: rgba(12, 13, 14, .62); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  transition: background .15s ease-out, transform .15s ease-out; }
.rip__mute::before { content: ''; position: absolute; inset: -4px; }          /* 48px to tap */
.rip__mute:hover { background: rgba(12, 13, 14, .82); }
.rip__mute:active { transform: scale(.94); }
.rip__mute:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.rip__mute svg { grid-area: 1 / 1; transition: opacity .18s, transform .18s; }
.rip__mute[aria-pressed="true"] .snd-off, .rip__mute[aria-pressed="false"] .snd-on { opacity: 0; transform: scale(.4); }
.rip__mute[hidden], .rip:not(.is-end) .rip__mute { display: none; }
/* a card swapped into the middle: no pointer cursor, it is the main card */
.xcard--hero { cursor: default; z-index: 1; }
@media (hover: hover) { .xcard--hero:hover { filter: none; } }
@media (prefers-reduced-motion: reduce) { .rip__scrub { transition: none; } }
/* the hero's tier glow once the fan is out (stands in for rip.js's halo, which
   is turned down then: see app.js buildExtras). Under the cards. */
.rip__heroglow { position: absolute; pointer-events: none; border-radius: 4%;
  background: color-mix(in srgb, var(--t1) calc(var(--ha, .2) * 60%), transparent);
  box-shadow: 0 0 60px 18px color-mix(in srgb, var(--t1) calc(var(--ha, .2) * 100%), transparent),
              0 0 150px 50px color-mix(in srgb, var(--t2) calc(var(--ha, .2) * 55%), transparent); }
.rip__heroglow.is-breathing { animation: heroBreathe 2.6s ease-in-out infinite; }
@keyframes heroBreathe { 50% { opacity: .78; } }
/* the pull card is up (app.js pcUp): the glow goes, or its hollow box shows round the card (Luke, 13 Nov: "a border under it") */
.rip__heroglow { transition: opacity 180ms ease-out; }
.rip__heroglow.is-covered { opacity: 0; animation: none; }
.xcard {
  --bw: 3px;
  position: absolute; display: block; padding: var(--bw); border: 0; margin: 0;
  border-radius: 3.6% / 2.6%;                         /* rip.js: 27px corner on a 750x1050 face */
  background: linear-gradient(135deg, var(--t1), var(--t2));
  box-shadow: 0 18px 34px -14px rgba(0, 0, 0, .8), 0 0 0 1px rgba(0, 0, 0, .35);
  pointer-events: auto; cursor: pointer; -webkit-tap-highlight-color: transparent;
  transform-origin: 50% 50%; will-change: transform;
  transition: box-shadow 400ms ease-out, filter 150ms, opacity 180ms ease-out;
}
.xcard.is-covered { opacity: 0; pointer-events: none; }   /* the middle card, under the pull card */
.xcard__in { position: relative; display: block; width: 100%; height: 100%; overflow: hidden; border-radius: 2.8% / 2%;
  background: var(--surface); box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .35); }
.xcard__in img, .xcard__in video { display: block; width: 100%; height: 100%; object-fit: cover; pointer-events: none; }
/* the landing burst of a rarer card (18+ and up): its tier colour, out past its edge */
.xcard__glow { position: absolute; inset: -16%; z-index: -1; border-radius: 22%; pointer-events: none; opacity: 0;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--t1) 85%, transparent), color-mix(in srgb, var(--t2) 45%, transparent) 55%, transparent);
  filter: blur(6px); }
.xcard.is-landed {
  box-shadow: 0 18px 34px -14px rgba(0, 0, 0, .8), 0 0 0 1px rgba(0, 0, 0, .35),
              0 0 calc(30px * var(--g, 0)) calc(3px * var(--g, 0)) color-mix(in srgb, var(--t1) 60%, transparent);
}
@media (hover: hover) { .xcard:hover { filter: brightness(1.08); } }
.xcard:active { filter: brightness(.94); }
.xcard:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
/* THE PULL CARD (app.js buildPullCard, pcIn): one more card in the fan, always
   in its right-hand end slot, never in the middle. The Foil card is its own
   frame: no tier ring, panel or box shadow behind it, only the 2D still. It is
   hidden until pcIn pops it out (its still is ready by then). */
.xcard--pc { padding: 0; background: transparent; border-radius: 4.6% / 3.3%; box-shadow: none; visibility: hidden; }
.xcard--pc.is-up { visibility: visible; }
.xcard--pc.is-landed { box-shadow: none; }
.xcard--pc .xcard__in { background: transparent; box-shadow: none; overflow: visible; border-radius: inherit; }
.xcard__pcstill { display: block; width: 100%; height: 100%; pointer-events: none; }
/* "Share my pull", under the middle card (app.js layoutExtras places it and
   keeps room for its height). Sized with My pulls (.rip__save): 48px / 15px on
   the phone, 58px / 17px on desktop (Luke, 13 Nov: "isnt big enough"). */
.rip__share {
  position: absolute; z-index: 3; transform: translateX(-50%); pointer-events: auto;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px; min-height: 48px; min-width: 168px; padding: 0 24px;
  border: 0; border-radius: var(--pill);
  color: #fff; font: inherit; font-size: 15px; font-weight: 800; white-space: nowrap; cursor: pointer;
  background: rgba(30, 31, 34, .72); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .18), 0 10px 26px -12px rgba(0, 0, 0, .8);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); -webkit-tap-highlight-color: transparent;
  transition: background-color 160ms, transform 160ms var(--ease-out);
}
.rip__share svg { flex: none; width: 20px; height: 20px; color: var(--pink); }
.rip__share:hover { background: rgba(48, 49, 53, .86); }
.rip__share:active { transform: translateX(-50%) scale(.96); }
.rip__share:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
.rip:not(.is-end) .rip__share { visibility: hidden; }
@media (min-width: 1024px) {
  .rip { --rip-foot: 136px; }
  .rip__acts { flex-direction: row; align-items: center; justify-content: center; gap: 22px; width: auto; }
  .rip__save { width: auto; min-width: 168px; min-height: 58px; padding: 0 34px; font-size: 17px; }
  .rip__share { min-height: 58px; min-width: 200px; padding: 0 32px; font-size: 17px; gap: 12px; }
  .rip__share svg { width: 22px; height: 22px; }
  .rip__acts .hring { width: 360px; }
  .rip__x { top: 20px; right: 20px; }
}

/* ============================================================
   SHEETS (dialog) — bottom sheets on the phone, centred modals on desktop
   ============================================================ */
dialog { color: var(--text); border: 0; padding: 0; background: transparent; max-width: none; max-height: none; }
dialog::backdrop { background: rgba(8, 9, 10, .66); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
.sheet {
  position: fixed; inset: auto 0 0 0; margin: 0 auto; width: 100%; max-width: 560px;
  max-height: min(calc(88dvh / var(--z, 1)), 860px); overflow: hidden;
}
.sheet--tall { max-height: calc(94dvh / var(--z, 1)); }
.sheet[open] { animation: sheetUp 300ms var(--ease-out); }
.sheet[open]::backdrop { animation: fadeIn 220ms ease-out; }
@keyframes sheetUp { from { transform: translateY(100%); } }
.sheet__in {
  display: flex; flex-direction: column; max-height: inherit; background: var(--bg);
  border-radius: 24px 24px 0 0; box-shadow: 0 -1px 0 var(--line), 0 -20px 60px rgba(0, 0, 0, .5);
}
.sheet--tall .sheet__in { height: calc(94dvh / var(--z, 1)); }
.sheet--tall:has(.empty) .sheet__in { height: auto; }   /* an empty list does not need a full-height sheet */
.sheet__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 12px 10px 20px; position: relative; }
.sheet__head::before { content: ''; position: absolute; top: 6px; left: 50%; width: 36px; height: 4px; margin-left: -18px; border-radius: 2px; background: rgba(255, 255, 255, .2); }
.sheet__head h2 { font-family: var(--display); font-size: 13px; font-weight: 900; line-height: 1.25; text-transform: uppercase; flex: 1; min-width: 0; text-wrap: balance; }
.sheet__head .chipbtn { min-height: 40px; padding: 0 14px; }
.sheet__head .chipbtn--ico { width: 44px; min-height: 44px; padding: 0; justify-content: center; }
.chipbtn--ico .chipbtn__lbl { display: none; }
@media (min-width: 1024px) {
  .sheet__head .chipbtn--ico { width: auto; min-height: 40px; padding: 0 14px; }
  .chipbtn--ico .chipbtn__lbl { display: inline; }
}
.sheet__body { overflow-y: auto; overscroll-behavior: contain; padding: 4px 16px 20px; flex: 1; }
.sheet__foot { display: grid; gap: 8px; padding: 16px 16px calc(12px + env(safe-area-inset-bottom)); border-top: 1px solid var(--line); background: var(--bg); }
.ghost {
  display: flex; align-items: center; justify-content: center; min-height: 48px; padding: 0 18px; border: 0;
  border-radius: var(--pill); background: var(--chip-bg); box-shadow: inset 0 0 0 1px var(--chip-ring);
  font-size: 13px; font-weight: 800; letter-spacing: 0; text-transform: none; color: #fff; text-decoration: none;
}
.ghost:hover { background: rgba(255, 255, 255, .08); }

/* odds */
.seg { display: flex; gap: 6px; overflow-x: auto; scrollbar-width: none; margin: 0 -16px; padding: 2px 16px 12px; }
.seg::-webkit-scrollbar { display: none; }
.seg button {
  flex: 0 0 auto; min-height: 40px; min-width: 56px; padding: 0 14px; border: 0; border-radius: var(--pill);
  background: var(--chip-bg); box-shadow: inset 0 0 0 1px var(--chip-ring); font-weight: 800; font-size: 14px; font-variant-numeric: tabular-nums;
  transition: background-color 150ms, color 150ms;
}
.seg button:hover { background: rgba(255, 255, 255, .1); }
.seg button[aria-pressed="true"] { background: #fff; color: #1F2123; box-shadow: none; }   /* their white pill (OPT IN / Continue) */
/* the pack line: "$100 pack · 8 items [R guaranteed]" */
.odds-intro { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; min-height: 26px; color: var(--muted); font-size: 15px; }
.odds-intro b { color: #fff; font-size: 17px; font-weight: 800; font-variant-numeric: tabular-nums; }
.odds-intro__dot { width: 4px; height: 4px; border-radius: 50%; background: var(--faint); }
.odds-cap { margin: 18px 0 6px; font-size: 12px; font-weight: 700; color: var(--faint); }
/* one row per tier: swatch + name, a bar on the true 0–100% scale, the number */
.olist { display: grid; gap: 4px; }
.orow {
  --w: 0; display: grid; grid-template-columns: 7.5em minmax(0, 1fr) 4.2em; align-items: center; gap: 14px;
  min-height: 48px; padding: 0 14px; border-radius: 14px; background: rgba(255, 255, 255, .035);
  transition: opacity 200ms ease-out;
}
.orow__name { display: flex; align-items: center; gap: 10px; font-size: 14px; font-weight: 800; white-space: nowrap; }
.swatch { width: 12px; height: 12px; flex: 0 0 auto; border-radius: 4px; background: linear-gradient(135deg, var(--t1), var(--t2)); box-shadow: 0 0 10px -2px var(--t1); }
.orow__bar { position: relative; height: 8px; border-radius: 4px; background: rgba(255, 255, 255, .07); overflow: hidden; }
.orow__bar i { position: absolute; inset: 0; border-radius: inherit; background: linear-gradient(90deg, var(--t2), var(--t1));
  transform-origin: 0 50%; transform: scaleX(var(--w)); transition: transform 420ms cubic-bezier(.16, 1, .3, 1); }
.orow__pct { text-align: right; font-size: 16px; font-weight: 800; font-variant-numeric: tabular-nums; color: #fff; }
.orow.is-zero { opacity: .38; }
.orow.is-zero .swatch { box-shadow: none; }
.odds-notes { margin-top: 18px; padding: 14px 16px; border-radius: 14px; background: var(--surface); color: var(--muted); font-size: 13px; line-height: 1.4; display: grid; gap: 6px; }
.odds-notes p { display: flex; gap: 10px; }
.odds-notes p::before { content: ''; flex: 0 0 auto; width: 5px; height: 5px; margin-top: .5em; border-radius: 50%; background: var(--pink); }

/* tiles */
.tchip {
  display: inline-flex; align-items: center; height: 22px; padding: 0 9px; border-radius: var(--pill);
  font-size: 10px; font-weight: 800; letter-spacing: 0; text-transform: uppercase; color: #111; font-style: normal;
  background: linear-gradient(135deg, var(--t1, #fff), var(--t2, #ccc)); white-space: nowrap;
}
.tile {
  position: relative; display: block; width: 100%; padding: 0; border: 2px solid var(--t1); border-radius: 14px; overflow: hidden;
  background: var(--surface); aspect-ratio: 3 / 4; box-shadow: 0 0 22px -8px var(--t1);
  transition: transform 180ms var(--ease-out), filter 150ms;
}
.tile img, .tile video { width: 100%; height: 100%; object-fit: cover; }
.tile .tchip { position: absolute; left: 6px; bottom: 6px; max-width: calc(100% - 12px); }
.grid .tile .tchip { height: 20px; padding: 0 7px; font-size: 9px; letter-spacing: 0; }
.tile .play { position: absolute; right: 6px; top: 6px; width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center;
  background: rgba(0, 0, 0, .55); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .3); }
.tile .count { position: absolute; left: 6px; top: 6px; font-size: 11px; font-weight: 800; padding: 2px 7px; border-radius: var(--pill); background: rgba(0, 0, 0, .6); font-variant-numeric: tabular-nums; }
.tile__who { position: absolute; left: 0; right: 0; bottom: 0; padding: 18px 6px 30px; font-size: 10px; font-weight: 800; text-align: left; background: linear-gradient(transparent, rgba(0, 0, 0, .7)); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tile:hover { filter: brightness(1.06); }
.tile:active { transform: scale(.96); }
.tile--r { border-color: transparent; background: linear-gradient(var(--surface), var(--surface)) padding-box, var(--brand-grad) border-box; }
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-top: 12px; }
.flip { animation: flipIn 520ms var(--ease-out) both; animation-delay: calc(240ms + var(--i, 0) * 40ms); }
@keyframes flipIn { from { transform: perspective(700px) rotateY(-95deg) scale(.9); opacity: 0; } 60% { opacity: 1; } to { transform: none; opacity: 1; } }

.best { position: relative; }
.best__label { display: flex; align-items: center; justify-content: space-between; margin: 4px 0 10px; }
.best .tile { aspect-ratio: 4 / 5; width: min(100%, calc(38dvh / var(--z, 1))); margin-inline: auto; border-width: 3px; box-shadow: 0 0 46px -10px var(--t1); }
.best .tile .tchip { left: 12px; bottom: 12px; height: 26px; font-size: 11px; }
.best__what { margin: 10px 0 0; text-align: center; color: var(--muted); font-size: 14px; }
.best__what b { color: #fff; }
.best .flip { animation-name: bestIn; animation-delay: 60ms; animation-duration: 560ms; }
@keyframes bestIn { from { transform: scale(.86) translateY(16px); opacity: 0; } to { transform: none; opacity: 1; } }

.empty { text-align: center; padding: 40px 16px 48px; color: var(--muted); text-wrap: balance; }
.empty__art { display: block; width: 132px; height: auto; margin: 0 auto 16px; transform: rotate(-4deg); filter: drop-shadow(0 10px 18px rgba(252, 1, 135, .3)); }
.empty b { display: block; color: #fff; font-size: 18px; margin-bottom: 6px; }
.pulls-meta { color: var(--muted); font-size: 13px; margin-bottom: 4px; }
/* the vault's girl chips (app.js vaultGirlsHTML): All, then each girl you have pulled from; the picked
   girl gets a link to her packs underneath */
.vf { margin: 0 0 12px; }
.vf__row { padding-bottom: 4px; }
.vf__row .vf__chip { display: inline-flex; align-items: center; gap: 8px; min-width: 0; padding: 0 14px 0 6px; font-size: 13px; }
.vf__row .vf__chip:first-child { padding-left: 14px; }
.vf__chip b { font-size: 12px; font-weight: 800; color: var(--muted); }
.vf__chip[aria-pressed="true"] b { color: rgba(31, 33, 35, .6); }
.vf__av { width: 28px; height: 28px; flex: 0 0 auto; border-radius: 50%; padding: 2px; background: var(--brand-grad); }
.vf__av img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; border: 1.5px solid var(--bg); }
.vf__go { display: inline-flex; align-items: center; gap: 6px; min-height: 40px; margin-top: 6px; color: var(--go); font-size: 14px; font-weight: 800; text-decoration: none; }
.vf__go:hover { text-decoration: underline; text-underline-offset: 3px; }
.empty__link { color: var(--go); font-weight: 800; text-underline-offset: 3px; }

/* ── ranks (Phase 1: read-only; docs/plans/2026-11-12-ranks-and-referrals-scope.md) ──
   Her rank sits in her card; the vault shows the site rank and one row per girl.
   Brand: flat text (no gradient text, no tracking); the bar is a brand fill. */
.rankbox { margin-top: 12px; padding: 10px 12px 11px; border-radius: 14px; text-align: left;
  background: rgba(255, 255, 255, .04); box-shadow: inset 0 0 0 1px var(--line); }
.rankbox[hidden] { display: none; }
.rankbox__top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.rankbox__k { font-size: 9px; font-weight: 800; text-transform: uppercase; color: var(--faint); }
.rankbox__name { font-size: 15px; font-weight: 800; line-height: 1.2; color: #fff; }
.rankbox__next, .ranks__next { margin-top: 6px; font-size: 12px; color: var(--muted); }
/* her card: your rank as one slim line under your stats (Luke, 13 Nov: the box "takes up too
   much space"). Name | thin bar | what is next; wraps the "next" text under on a narrow card. */
.rankline { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 10px; margin-top: 10px; padding: 0 2px; text-align: left; }
.rankline[hidden] { display: none; }
.rankline__name { font-size: 13px; font-weight: 800; line-height: 1.2; color: #fff; white-space: nowrap; }
.rankline .rankbar { flex: 1 1 60px; height: 4px; margin-top: 0; }
.rankline__next { font-size: 11px; color: var(--muted); white-space: nowrap; }
.tfbadge--sm { height: 20px; padding: 0 8px; font-size: 11px; }
/* your best pull on her card: the reel's rating badge */
.pcard__rb { --rb-w: 24px; }
.pcard__none { font-size: 12px; font-weight: 700; color: var(--faint); }
.rankbar { display: block; height: 6px; margin-top: 8px; border-radius: var(--pill); overflow: hidden; background: rgba(255, 255, 255, .10); }
.rankbar i { display: block; height: 100%; min-width: 6px; border-radius: inherit; background: linear-gradient(90deg, var(--c-acc), var(--c-acc2));
  transition: width 500ms var(--ease-out); }
@media (prefers-reduced-motion: reduce) { .rankbar i { transition: none; } }

.ranks { margin-bottom: 14px; padding: 12px 14px 14px; border-radius: 16px; background: rgba(255, 255, 255, .04); box-shadow: inset 0 0 0 1px var(--line); }
.ranks__site { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px; }
.ranks__site .ranks__next { margin: 0 0 0 auto; }
.sitebadge { display: inline-flex; align-items: center; height: 24px; padding: 0 10px; border-radius: var(--pill); font-size: 13px; font-weight: 800;
  color: #EAFBFF; background: rgba(120, 220, 255, .12); box-shadow: inset 0 0 0 1px rgba(160, 230, 255, .45); }
.ranks__girls { list-style: none; margin: 12px 0 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 8px; }   /* 220: "Kendra Karter" + "Not ranked yet" on one line */
.rankchip { display: grid; grid-template-columns: 1fr auto; align-items: baseline; gap: 2px 8px; padding: 8px 10px 9px; border-radius: 12px; background: rgba(255, 255, 255, .04); box-shadow: inset 0 0 0 1px var(--line); }
.rankchip__who { font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rankchip b { font-size: 13px; font-weight: 800; }
.rankchip .rankbar { grid-column: 1 / -1; margin-top: 6px; height: 4px; }

.hidesw { display: flex; align-items: flex-start; gap: 10px; margin-top: 18px; padding: 12px 14px; border-radius: 14px; cursor: pointer;
  background: rgba(255, 255, 255, .03); box-shadow: inset 0 0 0 1px var(--line); font-size: 12px; line-height: 1.45; color: var(--muted); }
.hidesw b { display: block; color: #fff; font-size: 13px; margin-bottom: 2px; }
.hidesw input { flex: none; width: 18px; height: 18px; margin: 1px 0 0; accent-color: var(--pink); }
.hidesw input:focus-visible { outline: 2px solid var(--go); outline-offset: 2px; }

/* ── her Top fans (Ranks Phase 2; docs/plans/2026-11-12-ranks-and-referrals-scope.md §2.4) ──
   Her card (desktop) and the #fansSheet (phone trophy / "See top N"). Positions, usernames and
   rank names only. Her colours (--c-acc / --c-acc2) carry the top rows and the higher ranks; my
   own row is a white ring with a "You" tag (never colour alone). Flat text, no tracking. */
#herFans { text-align: left; }   /* sits in her card's "Top fans" tab (.ptabs), which is the box */
.tf__tabs { display: grid; grid-template-columns: 1fr 1fr; padding: 3px; border-radius: var(--pill); background: #18191B; box-shadow: inset 0 0 0 1px var(--line); }
.tf__tab { min-height: 32px; border: 0; border-radius: var(--pill); background: transparent; color: var(--muted); font: inherit; font-size: 12px; font-weight: 800;
  cursor: pointer; transition: background-color 180ms var(--ease-out), color 180ms var(--ease-out); }
.tf__tab:hover { color: #fff; }
.tf__tab[aria-selected="true"] { background: rgba(255, 255, 255, .12); color: #fff; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .14); }
.tf__tab:focus-visible { outline: 2px solid var(--go); outline-offset: 2px; }
.tf__list { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 4px; }
.tf__row { position: relative; display: grid; grid-template-columns: 22px 30px minmax(0, 1fr); align-items: center; gap: 8px; min-height: 48px;
  padding: 6px 8px 6px 4px; border-radius: 12px; background: rgba(255, 255, 255, .025);
  animation: tfIn 320ms var(--ease-out) both; animation-delay: calc(var(--i, 0) * 35ms); }
@keyframes tfIn { from { opacity: 0; transform: translateY(6px); } }
.tf__pos { font-family: var(--display); font-size: 12px; font-weight: 900; text-align: center; color: var(--faint); }
.tf__av { width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; font-size: 12px; font-weight: 900; color: #fff;
  background: rgba(255, 255, 255, .07); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .14); }
.tf__who { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; min-width: 0; }   /* her card: the rank under the name */
.tf__name { display: flex; align-items: center; gap: 6px; max-width: 100%; min-width: 0; font-size: 13px; font-weight: 800; line-height: 1.2; }
.tf__u { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tf__tags { display: flex; align-items: center; gap: 5px; flex: none; }
.tf__you { flex: none; display: inline-flex; align-items: center; height: 17px; padding: 0 6px; border-radius: var(--pill);
  font-size: 9px; font-weight: 900; text-transform: uppercase; color: #111; background: #fff; }
/* the podium: her colours, strongest on #1 */
.tf__row[data-pos="1"], .tf__row[data-pos="2"], .tf__row[data-pos="3"] { background: rgba(255, 255, 255, .04); }
.tf__row[data-pos="1"] .tf__pos, .tf__row[data-pos="2"] .tf__pos, .tf__row[data-pos="3"] .tf__pos { color: #fff; }
.tf__row[data-pos="1"] { background: linear-gradient(90deg, color-mix(in srgb, var(--c-acc) 26%, transparent), color-mix(in srgb, var(--c-acc2) 6%, transparent) 80%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c-acc) 55%, transparent), 0 10px 26px -14px var(--c-acc); }
.tf__row[data-pos="1"] .tf__av { background: linear-gradient(135deg, var(--c-acc), var(--c-acc2)); box-shadow: 0 0 0 2px rgba(255, 255, 255, .85); }
.tf__row[data-pos="2"] .tf__av, .tf__row[data-pos="3"] .tf__av { box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--c-acc) 70%, #fff); }
.tf__row.is-me { background: rgba(255, 255, 255, .07); box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, .7); }
.tf__row[data-pos="1"].is-me { background: linear-gradient(90deg, color-mix(in srgb, var(--c-acc) 26%, transparent), color-mix(in srgb, var(--c-acc2) 6%, transparent) 80%);
  box-shadow: inset 0 0 0 1.5px #fff, 0 10px 26px -14px var(--c-acc); }
/* rank badges: her ladder, quiet at Fan, her colours by Devotee, the gradient for the #1 Fan title */
.tfbadge { display: inline-flex; align-items: center; gap: 4px; height: 22px; padding: 0 9px; border-radius: var(--pill); white-space: nowrap;
  font-size: 11px; font-weight: 800; line-height: 1; color: var(--muted); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .18); }
.tfbadge[data-tone="2"] { color: #fff; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .34); }
.tfbadge[data-tone="3"] { color: #fff; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c-acc) 75%, #fff); }
.tfbadge[data-tone="4"] { color: #fff; background: color-mix(in srgb, var(--c-acc) 24%, transparent); box-shadow: inset 0 0 0 1px var(--c-acc); }
.tfbadge[data-tone="5"] { color: #fff; background: color-mix(in srgb, var(--c-acc2) 45%, var(--c-acc) 30%); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .3); }
.tfbadge[data-tone="one"] { color: #fff; background: linear-gradient(135deg, var(--c-acc), var(--c-acc2)); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .28), 0 6px 16px -6px var(--c-acc); }
.tfbadge svg { flex: none; }
.tf__who .tfbadge { height: 18px; padding: 0 7px; font-size: 10px; gap: 3px; }
.tf__who .tfbadge svg { width: 10px; height: 10px; }
.tf__row.is-me .tf__pos { color: #fff; }
.rankbox__name .tfbadge { height: 24px; font-size: 12px; vertical-align: middle; }
/* loading, empty, error */
.tf__row--sk { animation: none; }
.tf__row--sk span { display: block; height: 12px; border-radius: 6px; background: linear-gradient(90deg, rgba(255, 255, 255, .05) 25%, rgba(255, 255, 255, .11) 50%, rgba(255, 255, 255, .05) 75%);
  background-size: 250% 100%; animation: shimmer 1.3s linear infinite; }
.tf__row--sk span:nth-child(1) { width: 14px; justify-self: center; }
.tf__row--sk span:nth-child(2) { width: 28px; height: 28px; border-radius: 50%; }
.tf__row--sk span:nth-child(3) { width: 62%; }
.tf__state { display: grid; justify-items: center; gap: 4px; padding: 18px 10px 8px; text-align: center; font-size: 12px; color: var(--muted); text-wrap: balance; }
.tf__state p { margin: 0; }
.tf__state b { color: #fff; font-size: 14px; }
.tf__state .chipbtn { margin-top: 8px; min-height: 40px; }
.tf__cup { width: 40px; height: 40px; margin-bottom: 4px; border-radius: 50%; display: grid; place-items: center; color: #fff;
  background: linear-gradient(135deg, color-mix(in srgb, var(--c-acc) 40%, transparent), color-mix(in srgb, var(--c-acc2) 25%, transparent));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c-acc) 60%, transparent); }
.tf__gap { display: grid; justify-items: center; gap: 3px; padding: 6px 0 2px; }
.tf__gap i { width: 3px; height: 3px; border-radius: 50%; background: rgba(255, 255, 255, .3); }
.tf__list--me { margin-top: 4px; }
.tf__me { margin: 10px 2px 0; font-size: 12px; color: var(--muted); text-align: center; }
.tf__more { display: flex; align-items: center; justify-content: center; gap: 6px; width: 100%; min-height: 40px; margin-top: 10px; border: 0; border-radius: var(--pill);
  background: var(--chip-bg); box-shadow: inset 0 0 0 1px var(--chip-ring); color: #fff; font: inherit; font-size: 12px; font-weight: 800; cursor: pointer;
  transition: background-color 150ms, transform 150ms var(--ease-out); }
.tf__more:hover { background: rgba(255, 255, 255, .1); }
.tf__more:active { transform: scale(.97); }
.tf__more:focus-visible, .tf__state .chipbtn:focus-visible { outline: 2px solid var(--go); outline-offset: 2px; }
/* the sheet: roomier rows, the tabs stay put while the list scrolls */
.tf--sheet { padding-top: 0; }
.tf--sheet .tf__tabs { position: sticky; top: 0; z-index: 2; margin: 0 0 2px; box-shadow: inset 0 0 0 1px var(--line), 0 -8px 0 8px var(--bg); }
.tf--sheet .tf__tab { min-height: 40px; font-size: 13px; }
.tf--sheet .tf__row { grid-template-columns: 28px 36px minmax(0, 1fr); gap: 10px; min-height: 56px; padding: 8px 10px 8px 6px; border-radius: 14px; }
.tf--sheet .tf__who { flex-direction: row; align-items: center; justify-content: space-between; gap: 10px; }   /* the sheet: the rank on the right */
.tf--sheet .tf__who .tfbadge { flex: none; height: 26px; padding: 0 11px; font-size: 12px; gap: 4px; }
.tf--sheet .tf__who .tfbadge svg { width: 12px; height: 12px; }
.tf--sheet .tf__pos { font-size: 14px; }
.tf--sheet .tf__av { width: 36px; height: 36px; font-size: 14px; }
.tf--sheet .tf__name { font-size: 15px; }
.tf--sheet .tf__me { font-size: 13px; }
.tf__fine { padding: 12px 20px calc(12px + env(safe-area-inset-bottom)); border-top: 1px solid var(--line); font-size: 11px; line-height: 1.45; color: var(--faint); text-align: center; }
.tfsheet:has(.tf__state) .sheet__in { height: auto; }
@media (min-width: 1024px) { .tf__fine { padding: 12px 24px 18px; } .tfsheet { width: min(480px, calc(calc(100vw / var(--z, 1)) - 48px)); } }
@media (prefers-reduced-motion: reduce) { .tf__row, .tf__row--sk span { animation: none; } .tf__tab, .tf__more { transition: none; } }

/* ── viewer ── */
.viewer { position: fixed; inset: 0; width: 100%; height: 100%; margin: 0; }
.viewer::backdrop { background: rgba(5, 5, 6, .98); backdrop-filter: none; }
.viewer[open] { animation: fadeIn 180ms ease-out; }
.viewer__in { display: flex; flex-direction: column; height: 100%; max-width: 980px; margin: 0 auto;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left); }
.viewer__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 12px 10px 16px; }
.viewer__meta { display: flex; align-items: center; gap: 10px; min-width: 0; }
.viewer__meta h2 { font-size: 16px; font-weight: 800; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.viewer__media { flex: 1; min-height: 0; display: grid; place-items: center; padding: 0 12px 16px;
  grid-template: minmax(0, 1fr) / minmax(0, 1fr); }   /* a definite cell, so a tall video's max-height: 100% fits the screen */
.viewer__media img, .viewer__media video { max-width: 100%; max-height: 100%; border-radius: 14px; object-fit: contain; background: #000; outline: 1px solid oklch(1 0 0 / .1); outline-offset: -1px; }
/* a whole video plays in Google's player (api/open.js `full`) */
.viewer__frame { width: 100%; height: 100%; min-height: calc(60vh / var(--z, 1)); border: 0; border-radius: 14px; background: #000; }
#viewerChip[hidden] { display: none; }

/* ── age gate ──
   The packs stay visible behind it, blurred and dimmed (the backdrop), with
   her colour glowing under the card. The card: the stacked Vice Rips logo on
   its native #1F2123, then the question and two clearly separate
   answers. FOCUS: the card takes focus on open (autofocus, tabindex=-1), so
   nothing is ringed on load; a keyboard ring is 2px at a 3px offset = 5px,
   inside half of the 12px gap between the answers, so it never overlaps. */
.age {
  position: fixed; inset: 0; width: 100%; height: 100%; margin: 0; display: grid; place-items: center; overflow-y: auto;
  padding: max(20px, env(safe-area-inset-top)) 16px max(20px, env(safe-area-inset-bottom));
  background: radial-gradient(closest-side at 50% 46%, color-mix(in srgb, var(--c-acc) 26%, transparent), color-mix(in srgb, var(--c-acc2) 9%, transparent) 60%, transparent);
  background-size: min(760px, calc(160vw / var(--z, 1))) min(760px, calc(130dvh / var(--z, 1))); background-position: center; background-repeat: no-repeat;
}
.age:not([open]) { display: none; }
.age::backdrop { background: rgba(14, 15, 16, .56); backdrop-filter: blur(20px) saturate(1.3); -webkit-backdrop-filter: blur(20px) saturate(1.3); }
.age[open] { animation: fadeIn 240ms ease-out; }
.age[open]::backdrop { animation: fadeIn 240ms ease-out; }
.age[open] .age__in { animation: ageIn 460ms cubic-bezier(.16, 1, .3, 1) both; }
@keyframes ageIn { from { opacity: 0; transform: translateY(16px) scale(.96); } }

.age__in {
  position: relative; width: min(100%, 392px); border-radius: 22px; background: var(--bg); text-align: center; outline: none;   /* the gate: #1F2123, radius 22 */
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .08), inset 0 1px 0 rgba(255, 255, 255, .06),
              0 2px 6px rgba(0, 0, 0, .3), 0 40px 90px -28px rgba(0, 0, 0, .9);
}
/* the lockup on its own lit patch of the dark base */
.age__art {
  position: relative; display: grid; place-items: center; padding: 40px 24px 14px; border-radius: 22px 22px 0 0; overflow: hidden;
}
.age__art::before { /* a soft pink light behind the logo */
  content: ''; position: absolute; left: 50%; top: 54%; width: 360px; height: 150px; transform: translate(-50%, -50%); pointer-events: none;
  background: radial-gradient(closest-side, rgba(255, 77, 174, .30), rgba(252, 1, 135, .10) 55%, transparent 100%);
}
.age__art::after { /* halftone, as on the page backdrop, fading to nothing */
  content: ''; position: absolute; inset: 0; pointer-events: none; opacity: .7;
  background-image: radial-gradient(rgba(255, 255, 255, .12) 1px, transparent 1.6px); background-size: 12px 12px;
  -webkit-mask-image: radial-gradient(closest-side at 50% 55%, #000, transparent); mask-image: radial-gradient(closest-side at 50% 55%, #000, transparent);
}
.age__lockup { position: relative; z-index: 1; display: flex; align-items: center; justify-content: center; margin: 0; }
.age__blob { position: relative; display: block; flex: 0 0 auto; width: 210px; }
.age__logo { display: block; width: 100%; height: auto; filter: drop-shadow(0 12px 18px rgba(0, 0, 0, .5)); transform: rotate(-3deg); }
.age__sticker { /* the 18+ sticker on the logo's top-left corner, cut out of the card colour */
  position: absolute; left: -10px; top: -8px; display: grid; place-items: center; height: 24px; padding: 0 8px 0 7px;
  border-radius: var(--pill); background: var(--brand-grad); box-shadow: 0 0 0 3px var(--bg), 0 6px 14px -4px rgba(255, 77, 174, .7);
  font-size: 12px; font-weight: 800; font-style: italic; letter-spacing: 0; line-height: 1; color: #fff; transform: rotate(-12deg);
}
.age__body { padding: 18px 28px 26px; }
/* the gate: the title in rift, uppercase; the
   copy in Rubik Regular at 60% white; a WHITE pill with #1F2123 type in title
   case; "leave" as a plain underlined line, not a second button */
.age h2 { font-family: var(--display-cond); font-size: 32px; font-weight: 700; line-height: 1; text-transform: uppercase; }
.age__text { margin: 10px auto 0; max-width: 30ch; color: rgba(255, 255, 255, .6); font-size: 14px; font-weight: 400; line-height: 1.45; text-wrap: pretty; }
.age__acts { display: grid; gap: 6px; margin-top: 22px; }
.age__yes, .age__no {
  display: flex; align-items: center; justify-content: center; width: 100%; border: 0; border-radius: var(--pill);
  font-weight: 800; text-transform: none; text-decoration: none; -webkit-tap-highlight-color: transparent;
  transition: background-color 160ms ease-out, color 160ms ease-out, box-shadow 160ms ease-out, transform 160ms var(--ease-out);
}
.age__yes {
  min-height: 48px; padding: 0 20px; background: #fff; color: #1F2123; font-size: 14px; letter-spacing: 0;
  box-shadow: 0 12px 30px -16px rgba(255, 255, 255, .5);
}
.age__yes:hover { background: #F1F1F1; }
.age__no {
  min-height: 44px; padding: 0 18px; background: transparent; color: rgba(255, 255, 255, .6); font-size: 12px; font-weight: 400; letter-spacing: 0;
  text-decoration: underline; text-underline-offset: 3px;
}
.age__no:hover { color: #fff; }
.age__yes:active, .age__no:active { transform: scale(.96); }
.age__yes:focus-visible, .age__no:focus-visible { outline: 2px solid #fff; outline-offset: 3px; border-radius: var(--pill); }
.age__fine { margin-top: 14px; font-size: 12px; color: var(--faint); }
@media (max-width: 380px) {
  .age__blob { width: 184px; }
  .age__body { padding: 16px 20px 22px; }
}
@media (max-height: 620px) {
  .age__art { padding-top: 26px; }
  .age__fine { display: none; }
}

/* ── SIGN-UP (username, 18+, Terms): the age gate's card and buttons, with a
   form in it. Left-aligned fields, 16px input text (no iOS zoom on focus),
   44px+ rows for every tick, errors under the field they are about, in pink
   with an icon-free but worded message (never colour alone). ── */
.signup__in { text-align: left; }
.signup__body { padding: 26px 24px 22px; }
.signup h2 { text-align: center; }
.signup__text { text-align: center; margin-bottom: 18px; }
.signup__field { margin: 0 0 6px; }
.signup__label { display: block; margin: 0 0 6px; font-size: 13px; font-weight: 800; color: #fff; }
.signup__input {
  display: block; width: 100%; min-height: 48px; padding: 0 16px; border: 0; border-radius: 14px;
  background: var(--bg-deep); box-shadow: inset 0 0 0 1px var(--chip-ring); color: #fff;
  font: 600 16px/1.2 var(--font); letter-spacing: 0;
  transition: box-shadow 150ms ease-out;
}
.signup__input:focus { outline: none; box-shadow: inset 0 0 0 2px #fff; }
.signup__field.is-bad .signup__input { box-shadow: inset 0 0 0 2px var(--pink); }
.signup__help { margin: 6px 2px 0; font-size: 12px; line-height: 1.4; color: rgba(255, 255, 255, .6); }
.signup__msg { margin: 4px 2px 0; min-height: 18px; font-size: 13px; line-height: 1.4; font-weight: 700; color: #FF7FA0; }
.signup__msg:empty { min-height: 0; margin: 0; }
.signup__current { margin: 0 0 8px; text-align: center; font-size: 14px; color: var(--muted); }
.signup__current b { color: #fff; }
.signup__checks { display: grid; gap: 4px; margin: 10px 0 0; }
.signup__check {
  display: flex; align-items: center; gap: 12px; min-height: 48px; padding: 6px 12px; border-radius: 14px; cursor: pointer;
  font-size: 14px; line-height: 1.35; color: #fff; -webkit-tap-highlight-color: transparent;
  transition: background-color 150ms;
}
.signup__check:hover { background: rgba(255, 255, 255, .05); }
.signup__check input {
  flex: 0 0 auto; width: 22px; height: 22px; margin: 0; accent-color: var(--go); cursor: pointer;
}
.signup__check input:focus-visible { outline: 2px solid #fff; outline-offset: 3px; border-radius: 4px; }
.signup__check a { color: var(--go); font-weight: 800; text-underline-offset: 3px; padding: 6px 0; }
.signup__err { margin: 8px 2px 0; font-size: 13px; line-height: 1.4; font-weight: 700; color: #FF7FA0; text-align: center; }
.signup__err:empty { margin: 0; }
.signup .age__acts { margin-top: 16px; }
.signup__go:disabled { background: rgba(255, 255, 255, .14); color: rgba(255, 255, 255, .5); box-shadow: none; cursor: not-allowed; }
.signup__go:disabled:active { transform: none; }
@media (max-width: 380px) { .signup__body { padding: 22px 16px 18px; } }

/* the Terms / Privacy links: the rail's foot (desktop), the age gate (Get gems has its own, .gp__legal) */
.rail__legal { display: none; }
.rail__legal a, .age__fine a { color: var(--faint); text-underline-offset: 3px; }
.rail__legal a:hover, .age__fine a:hover { color: #fff; }
.bal__user { display: none; font-size: 13px; font-weight: 800; color: #fff; max-width: 16ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── toast ── */
.toast {
  position: fixed; z-index: 200; left: 50%; bottom: calc(196px + env(safe-area-inset-bottom)); transform: translate(-50%, 20px);
  display: flex; align-items: center; gap: 14px;
  max-width: min(calc(92vw / var(--z, 1)), 440px); padding: 12px 18px; border-radius: 14px; background: #fff; color: #1F2123; font-size: 14px; font-weight: 700;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .4); opacity: 0; pointer-events: none; transition: opacity 200ms, transform 240ms var(--ease-out);
}
.toast.is-on { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
.toast button { flex: 0 0 auto; min-height: 36px; margin: -8px -8px -8px 0; padding: 0 12px; border: 0; border-radius: var(--pill); background: #1F2123; color: var(--go);
  font-size: 12px; font-weight: 800; letter-spacing: 0; text-transform: uppercase; }
[data-page="girls"] .toast, [data-page="notfound"] .toast { bottom: calc(80px + env(safe-area-inset-bottom)); }
/* money and error lines: a pink edge and an icon (not colour alone) */
/* left:50% leaves a fixed box only half the screen to shrink-fit into: size it
   to its text instead, capped by max-width, so a long line wraps across the width */
.toast { width: max-content; }
.toast > span { flex: 1 1 auto; min-width: 0; }
.toast--warn { box-shadow: inset 4px 0 0 var(--pink), 0 10px 30px rgba(0, 0, 0, .4); padding-left: 16px; line-height: 1.35; }
.toast__ico { flex: 0 0 auto; color: #D61F55; }

/* ============================================================
   the top-bar chip's gem, and the {gem} token
   ============================================================ */
/* the top-bar chip (site/app.js renderBal): gems only */
.bal__gem { display: block; flex: 0 0 auto; }
/* the {gem} token in hold-button labels (site/hold.js fillLabel) */
.gemi { display: inline-block; width: 1.05em; height: 1.05em; margin: 0 .18em 0 .1em; vertical-align: -.16em; }
.ghost:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* a card picture that will not load (app.js MEDIA_HOSTS), or a card with
   nothing to show: a neutral block in the pull's colour, never a broken icon */
.is-broken { visibility: hidden; }
.has-broken, .nomedia {
  background: radial-gradient(120% 90% at 50% 30%, color-mix(in srgb, var(--t1, #AEB7C2) 30%, var(--surface)), var(--bg) 75%);
}
.nomedia { display: block; width: 100%; height: 100%; min-height: 120px; border-radius: inherit; }

/* the summary's "In My pulls" note (a note, not a button) */
.res__kept { display: inline-flex; align-items: center; gap: 5px; flex: 0 0 auto; margin-right: 4px;
  font-size: 12px; font-weight: 800; color: var(--go); white-space: nowrap; }
#resPulls { cursor: pointer; }
#resPulls:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

.pulls-pending { display: flex; align-items: center; gap: 10px; margin: 6px 0 12px; padding: 10px 12px; border-radius: 12px;
  background: var(--surface); font-size: 13px; color: var(--muted); }
.spinner--sm { width: 16px; height: 16px; border-width: 2px; flex: 0 0 auto; }
.empty .spinner { display: block; margin: 0 auto 14px; }
.empty__act { margin: 18px 0 0; }
.empty__act .chipbtn { cursor: pointer; }
.best__tx { color: var(--muted); text-decoration: underline; text-underline-offset: 3px; display: inline-flex; align-items: center; gap: 3px; }
.best__tx:hover { color: #fff; }

/* ============================================================
   DESKTOP — blockrips' layout, from 1024px
   ============================================================ */
@media (min-width: 1024px) {
  .app {
    --side: clamp(212px, calc(18vw / var(--z, 1)), 290px);
    --side-r: clamp(240px, calc(22vw / var(--z, 1)), 280px);              /* her card's column: wider from 1280 (below) */
    grid-template-columns: var(--side) minmax(0, 1fr) var(--side-r);
    grid-template-rows: 68px minmax(0, 1fr) auto;
    grid-template-areas:
      "top  top  top"
      "rail main side"
      "rail cta  side";
  }
  .app[data-page="girls"], .app[data-page="notfound"], .app[data-page="error"], .app[data-page="loading"] {
    grid-template-areas:
      "top  top  top"
      "rail main main"
      "rail main main";
  }
  [data-page="girls"] .side, [data-page="notfound"] .side, [data-page="error"] .side, [data-page="loading"] .side { display: none; }
  .bnav, .mhead { display: none; }

  /* the top bar + the live ticker */
  .top { gap: 20px; padding: 0 20px; min-height: 0; background: rgba(22, 23, 25, .72); }
  .wordmark img { height: 40px; }
  .live { display: flex; align-items: center; gap: 14px; flex: 1 1 auto; min-width: 0; height: 100%; }
  /* LIVE PULLS: plain text and a dot, no pill (Luke, 13 Nov: "we don't want anything in a pill like that") */
  .live__lbl {
    flex: 0 0 auto; display: inline-flex; align-items: center; gap: 7px;
    color: var(--pink); font-size: 11px; line-height: 1; letter-spacing: 0; text-transform: uppercase; white-space: nowrap;
  }
  .live__lbl b { font-weight: 800; }
  .live__sub { font-weight: 800; color: rgba(255, 255, 255, .6); }
  .live__dot { position: relative; display: grid; place-items: center; width: 8px; height: 8px; }
  .live__dot i { width: 8px; height: 8px; border-radius: 50%; background: var(--pink); }
  .live__list { display: flex; gap: 8px; min-width: 0; flex: 1; overflow: hidden; padding: 4px 0;
    -webkit-mask-image: linear-gradient(90deg, #000 82%, transparent); mask-image: linear-gradient(90deg, #000 82%, transparent); }
  .tick { flex: 0 0 auto; overflow: hidden; max-width: 260px; }
  .tick.is-new { animation: tickIn 480ms var(--ease-out) both; }
  @keyframes tickIn { from { max-width: 0; opacity: 0; } }
  .tick > a, .tick > button {
    display: flex; align-items: center; gap: 9px; height: 46px; padding: 4px 14px 4px 4px; border: 0; border-radius: 12px; text-decoration: none; text-align: left;
    background: var(--chip-bg); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .14); transition: background-color 150ms, box-shadow 150ms;
  }
  .tick > a:hover, .tick > button:hover { background: rgba(255, 255, 255, .08); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .26); }
  .tick--own > button { box-shadow: inset 0 0 0 1px rgba(255, 45, 155, .45); }
  .tick__th { width: 29px; height: 38px; flex: 0 0 auto; border-radius: 6px; overflow: hidden; box-shadow: 0 0 0 2px var(--t1), 0 0 12px -2px var(--t1); background: var(--surface); }
  .tick__th img { width: 100%; height: 100%; object-fit: cover; filter: blur(3px) saturate(1.2); transform: scale(1.25); }
  .tick__tx { display: flex; flex-direction: column; line-height: 1.15; white-space: nowrap; }
  .tick__tx b { font-size: 11px; font-weight: 800; letter-spacing: 0; text-transform: uppercase; color: var(--t1); }
  .tick__tx small { font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
  #sndTop { display: inline-grid; }

  /* the left rail */
  .rail { display: flex; flex-direction: column; gap: 4px; grid-area: rail; min-height: 0; padding: 18px 12px 16px 16px; position: relative; z-index: 6; }
  /* Hug the label, not the whole rail: a full-width 48px pill read as a huge
     hover box (Luke, 9 Nov). */
  .rail__link {
    display: flex; align-items: center; gap: 12px; width: fit-content; max-width: 100%; min-height: 44px; padding: 0 18px 0 14px; border: 0; border-radius: var(--pill);
    background: none; color: rgba(255, 255, 255, .72); text-decoration: none; text-align: left;
    font-size: 15px; font-weight: 800; letter-spacing: 0; text-transform: none;
    transition: background-color 150ms, color 150ms, transform 150ms var(--ease-out);
  }
  .rail__link svg { flex: 0 0 auto; }
  .rail__link:hover { background: rgba(255, 255, 255, .07); color: #fff; }
  .rail__link:active { transform: scale(.96); }
  /* tab pills: active #fff on rgba(255,255,255,.1), inactive dimmed on nothing */
  .rail__link[aria-current="page"] { background: rgba(255, 255, 255, .1); color: #fff; }
  /* the count sits right after the label, as a small --go badge */
  /* plain text beside the label, never a pill (Luke, 13 Nov) */
  .rail__count { margin-left: -2px; color: var(--muted); font-size: 12px; font-weight: 800; line-height: 1.3; font-variant-numeric: tabular-nums; }
  .rail__count:empty { display: none; }
  .rail__link.sndbtn { position: relative; padding-left: 46px; }
  .rail__link.sndbtn .snd-on, .rail__link.sndbtn .snd-off { position: absolute; left: 14px; top: 50%; margin-top: -10px; }
  /* My girls + Suggested girls scroll together as one list */
  /* The list fades out at whichever end has more to scroll to, never a hard cut through a row (Luke,
     13 Nov: "It should fade off as you scroll, not cut off"). app.js railFade sets is-up / is-down;
     the divider is its own line above the list so the fade never eats it. */
  .rail__rule { flex: none; height: 1px; margin-top: 14px; background: var(--line); }
  .rail__sec {
    --fade: 44px;
    display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; padding-top: 14px;
    /* Luke, 13 Nov: no visible scrollbar on My girls / Suggested girls; still scrolls. */
    overflow-y: auto; margin-right: -4px; padding-right: 4px; scrollbar-width: none;
  }
  .rail__sec::-webkit-scrollbar { display: none; }
  .rail__h { padding: 0 16px 8px; font-size: 11px; font-weight: 800; letter-spacing: 0; text-transform: uppercase; color: var(--faint); }
  .rail__h:not([hidden]) ~ .rail__h { margin-top: 18px; }
  .rail .pins { flex: 0 0 auto; margin: 0 -4px; padding: 0 4px; }
  .rail__foot { display: flex; flex-direction: column; gap: 2px; padding-top: 10px; border-top: 1px solid var(--line); }
  .rail__legal { display: flex; gap: 14px; padding: 8px 16px 0; font-size: 12px; }
  .rail__legal a { display: inline-flex; align-items: center; min-height: 32px; }
  /* the username beside the balance, desktop only (the phone's top bar has no room) */
  .bal__user:not([hidden]) { display: block; }   /* the divider is on .bal__who */

  /* her card, right column */
  .side { display: flex; flex-direction: column; grid-area: side; min-height: 0; overflow-y: auto; scrollbar-width: none; padding: 18px 16px 16px 4px; position: relative; z-index: 6; }
  .side::-webkit-scrollbar { display: none; }
  .side > .pcard { flex: none; }
  /* her page: the card is the column's full height; the header stays its size and the tabbed panel takes
     the rest and scrolls (Luke, 13 Nov: "the leaderboard is half off the screen"). Too short for that
     (min-height), the column scrolls as before. */
  .side > .pcard--her { flex: 1 0 0; min-height: 600px; display: flex; flex-direction: column; }
  .pcard--her > * { flex: none; }
  .pcard--her > .ptabs { flex: 1 1 0; min-height: 0; }
  /* her stats in one row, one box with hairlines between (saves a row for the panel) */
  .pcard--her .pcard__stats { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0; padding: 6px 0; border-radius: 14px; background: rgba(255, 255, 255, .04); box-shadow: inset 0 0 0 1px var(--line); }
  .pcard--her .pcard__stats > div { min-height: 0; padding: 4px 2px; border-radius: 0; background: none; box-shadow: none; }
  .pcard--her .pcard__stats > div + div { box-shadow: -1px 0 0 0 var(--line); }
  .pcard--her .pcard__stats dd { font-size: 14px; }
  .pcard--her .pcard__stats .tchip { padding: 2px 6px; }
  /* her rank in two lines: "YOUR RANK Fan · 30 XP to Regular", then the bar */

  /* the stage */
  .shead { padding: 22px 0 0; }
  [data-page="creator"] .shead { display: block; }
  .shead__share { top: 22px; right: 4px; }
  .shead__t { font-size: clamp(24px, calc(2.3vw / var(--z, 1)), 34px); }
  .shead__sub { display: flex; margin-top: 8px; }
  .fan { touch-action: pan-y; }
  .pcard__acts .chipbtn { padding: 0 12px; text-align: center; line-height: 1.15; }
  .fmeta { gap: 4px; padding: 2px 0 4px; }
  .fmeta__row { gap: 18px; }
  .fmeta__title { font-size: clamp(18px, calc(1.7vw / var(--z, 1)), 26px); min-width: clamp(220px, calc(22vw / var(--z, 1)), 360px); min-height: 48px; }
  /* feed prev/next: dark round chips with a light ring, white tailless arrow */
  .fmeta__arrow { width: 44px; height: 44px; }
  .fmeta__arrow:hover { background: rgba(255, 255, 255, .14); }
  .avatar--sm { --s: 40px; }

  /* the dock under the stage */
  .cta { align-items: center; gap: 16px; padding: 12px 0 18px; }
  .cta .hring { order: 0; width: min(400px, 100%); }
  /* See odds / My pulls / Sound live in the left rail on desktop (Luke, 9 Nov) */
  .cta__more { display: none; }
  .cta__hint { order: 2; }
  .cta__btn { min-height: 64px; font-size: 21px; }

  /* pages that scroll (all girls, 404) */
  .page { padding: 28px 28px 40px 8px; }
  .page-head h1 { font-size: 32px; }
  .page-head p { font-size: 16px; }
  .girls { grid-template-columns: repeat(auto-fill, minmax(232px, 1fr)); gap: 16px; }
  .gcard { padding: 0 14px 14px; }
  .gcard__banner { width: calc(100% + 28px); margin: 0 -14px; height: 104px; }
  .gcard__av { --s: 88px; margin-top: -50px; }
  .gcard__name { font-size: 18px; }
  .gcard__sub { font-size: 13px; }
  .gcard__stats { gap: 6px; }
  .gcard__stats > span { font-size: 9px; padding: 8px 2px; }
  .gcard__stats b { font-size: 14px; }
  .gcard__go { min-height: 44px; }
  .gcard__her { display: inline; }

  /* sheets become centred modals */
  .sheet { inset: 0; margin: auto; width: min(560px, calc(calc(100vw / var(--z, 1)) - 48px)); max-width: none; height: fit-content; max-height: min(calc(86dvh / var(--z, 1)), 820px); }
  .sheet--tall { max-height: min(calc(88dvh / var(--z, 1)), 860px); }
  .sheet[open] { animation: popIn 240ms var(--ease-out); }
  @keyframes popIn { from { opacity: 0; transform: translateY(8px) scale(.97); } }
  .sheet__in { border-radius: 24px; box-shadow: 0 0 0 1px var(--line), 0 40px 100px -20px rgba(0, 0, 0, .8); }
  .sheet--tall .sheet__in { height: auto; }
  .sheet__head { padding: 18px 16px 12px 24px; }
  .sheet__head::before { display: none; }
  .sheet__body { padding: 4px 24px 24px; }
  .sheet__foot { padding: 16px 24px 20px; border-radius: 0 0 24px 24px; }
  .sheet--res { width: min(920px, calc(calc(100vw / var(--z, 1)) - 64px)); }
  .sheet--res .sheet__body { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); gap: 28px; align-items: start; }
  .sheet--res.is-single .sheet__body { grid-template-columns: minmax(0, 1fr); }
  .sheet--res .best .tile { width: min(100%, calc(42dvh / var(--z, 1))); }   /* the best pull, its chip and its line all fit above the footer */
  .sheet--res .grid { margin-top: 32px; }
  .sheet--res .sheet__foot { display: flex; justify-content: center; }
  .sheet--res .sheet__foot .hring { width: min(420px, 100%); }
  .sheet--wide { width: min(980px, calc(calc(100vw / var(--z, 1)) - 64px)); }
  .sheet--wide .grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
  .seg { margin: 0; padding: 2px 0 14px; }

  /* top right, under the balance it usually reports on, clear of the stage title */
  .toast { bottom: auto; top: 80px; left: auto; right: 20px; transform: translateY(-12px); }
  .toast.is-on { transform: none; }
  [data-page="girls"] .toast, [data-page="notfound"] .toast { bottom: auto; }
}

/* 1280 up: her card's column is bigger (Luke, 13 Nov: "the whole thing on the right needs to be a bit
   bigger"), 300px at 1280-1430, then 21vw, up to 380px from ~1810. The home's card shares the column. */
@media (min-width: 1280px) {
  .app { --side-r: clamp(300px, calc(21vw / var(--z, 1)), 380px); }
  .side .pcard { padding: 0 16px 16px; }
  .side .pcard__banner { margin: 0 -16px; height: 100px; }
  .side .pcard__av { --s: 88px; margin-top: -50px; }
  .side .pcard__name { font-size: 22px; }
  .side .pcard__sub { font-size: 14px; }
  .side .pcard__pitch { font-size: 14px; }
  .side .pcard__stats dt { font-size: 10px; }
  .side .pcard__stats dd { font-size: 16px; }
  .side .pcard--her .pcard__stats dd { font-size: 15px; }
  .side .rankbox { padding: 11px 14px 12px; }
  .side .pcard--her .rankbox { padding: 10px 12px 11px; }
  .side .rankbox__k { font-size: 10px; }
  .side .rankbox__name { font-size: 16px; }
  .side .rankbox__next { font-size: 13px; }
  .side .pcard--her .rankbox__next { font-size: 12px; }   /* keeps "30 XP to Regular" on the rank's line at 300px */
  .side .ptabs__panel { padding: 12px; }
  .side .pcard__photos { gap: 8px; }
  .side .tf__tab { min-height: 34px; font-size: 13px; }
  .side .tf__row { grid-template-columns: 24px 34px minmax(0, 1fr); gap: 10px; min-height: 54px; }
  .side .tf__pos { font-size: 13px; }
  .side .tf__av { width: 34px; height: 34px; font-size: 13px; }
  .side .tf__name { font-size: 14px; }
  .side .tf__who .tfbadge { height: 20px; font-size: 11px; }
  .side .tf__me, .side .tf__more { font-size: 13px; }
  .side .pcard__acts .chipbtn { min-height: 44px; font-size: 14px; }
}

/* under 1000px tall, her card drops the pitch line so the tabbed panel keeps its room */
@media (min-width: 1024px) and (max-height: 999px) {
  .pcard--her .pcard__pitch { display: none; }
}

/* narrow desktops */
@media (min-width: 1024px) and (max-width: 1279px) {
  .pcard { padding: 0 12px 12px; }
  .pcard__banner { margin: 0 -12px; }
  .pcard__acts .chipbtn { font-size: 11px; letter-spacing: 0; gap: 6px; padding: 0 10px; }   /* one line, never two */
  .pcard__stats dd { font-size: 14px; }
}

/* short desktops (1280×720 and friends): tighten the vertical rhythm */
@media (min-width: 1024px) and (max-height: 800px) {
  .app { grid-template-rows: 60px minmax(0, 1fr) auto; }
  .toast { top: 76px; }
  .shead { padding-top: 14px; }
  .shead__t { font-size: clamp(22px, calc(2vw / var(--z, 1)), 30px); }
  .shead__sub { margin-top: 6px; }
  .fmeta__title { min-height: 42px; }
  .cta { gap: 14px; padding-bottom: 12px; }
  .cta__btn { min-height: 58px; font-size: 19px; }
  .cta__hint { display: none; }
  .cta__hint:has(button) { display: block; }
  .tick > a, .tick > button { height: 42px; }
  .tick__th { width: 26px; height: 34px; }
  .pcard__banner, .side .pcard__banner { height: 76px; }
  .pcard__pitch { display: none; }
  .rail__link { min-height: 44px; }
}

/* short phones (SE-size): give the fan the hint's line, unless the hint is the reset link */
@media (max-width: 1023px) and (max-height: 700px) {
  .cta__hint { display: none; }
  .cta__hint:has(button) { display: block; }
  .mhead { padding-top: 6px; }
}

/* ── reduced motion: keep every state change, drop the travel ── */
@media (prefers-reduced-motion: reduce) {
  :root { transition: none; }
  *, *::before, *::after { animation-duration: 1ms !important; animation-delay: 0ms !important; animation-iteration-count: 1 !important; transition-duration: 1ms !important; scroll-behavior: auto !important; }
  .age__in { animation: none !important; }
  .orow__bar i { transition: none; }
  .fpack::before { animation: none; }
}

/* ============================================================
   GET GEMS (index.html #gemsSheet, site/app.js GEMS): the approved mockup
   (tools/mockups/gems) made real, and made more fun (Luke, 13 Nov: "boring…
   make it look cooler and more fun"). Brand rules (header above): --go is
   money and the one primary action, pink the brand ("Most popular", the
   shortfall), purple (--gem) only for gems. No italics, no letter-spacing, no
   gradient text. Motion is transform and opacity only, and every loop stops
   under prefers-reduced-motion (the block at the end).
   Layout: the sheet's data-step (pick | consent | deposit | done | loading).
   Phone: a tall bottom sheet; on "pick" the bundles scroll and the order is the
   pinned footer; on the other steps the step fills the sheet. Desktop (≥1024):
   a two-column modal, the bundles always on the left, the step on the right.
   ============================================================ */
.gp { --gem: #A646FF; --gem-hi: #D3A4FF; --gem-rgb: 158, 58, 255; --red: #FF5A5A; }
.gp .sheet__in { position: relative; height: min(calc(92dvh / var(--z, 1)), 860px); overflow: hidden; }
.gp .sheet__in::before {                    /* a purple bloom behind the head: the sheet's one brand moment */
  content: ''; position: absolute; inset: -140px -10% auto; height: 320px; pointer-events: none;
  background: radial-gradient(50% 60% at 50% 50%, rgba(var(--gem-rgb), .24), transparent 70%);
}
.gp__head { position: relative; z-index: 2; padding-bottom: 4px; }
.gp__bal {
  display: inline-flex; align-items: center; gap: .3em; min-height: 40px; padding: 0 12px 0 14px; border-radius: var(--pill);
  background: var(--chip-bg); box-shadow: inset 0 0 0 1px var(--chip-ring); font-size: 15px; font-weight: 800;
}
.gp__bal img { width: 20px; height: 20px; filter: drop-shadow(0 0 6px rgba(var(--gem-rgb), .6)); }
.gp__main { position: relative; }
.gp__flow { position: relative; display: flex; flex-direction: column; min-height: 0; }
.gp__step { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.gp__step[hidden] { display: none; }
.gp__scroll { position: relative; flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 4px 16px 20px; }
.gp__foot { display: grid; gap: 10px; padding: 12px 16px calc(12px + env(safe-area-inset-bottom)); border-top: 1px solid var(--line); background: var(--bg); }
/* phone: which part fills the sheet */
.gp[data-step="pick"] .gp__flow { flex: 0 0 auto; }
.gp__step--pick .gp__scroll { display: none; }
.gp[data-step="consent"] .gp__main, .gp[data-step="deposit"] .gp__main, .gp[data-step="done"] .gp__main { display: none; }
.gp:not([data-step="pick"]) .gp__flow { flex: 1; }

.gp__loading { display: grid; justify-items: center; gap: 12px; padding: 80px 0; color: var(--muted); font-size: 14px; font-weight: 700; }
.gp__loading[hidden] { display: none; }
.gp__loading img { width: 96px; height: 96px; animation: gpFloat 2.4s ease-in-out infinite; filter: drop-shadow(0 10px 24px rgba(var(--gem-rgb), .55)); }

/* ── pick: the bundles ── */
.gp__h { margin: 6px 0 0; font-family: var(--display); font-size: 28px; font-weight: 900; line-height: 1.05; text-transform: uppercase; }
.gp__sub { margin: 6px 0 16px; font-size: 14px; color: var(--muted); text-wrap: balance; }
.gp__sub b { color: #fff; }
.gp__need {
  margin: 0 0 16px; padding: 12px 14px; border-radius: 16px; font-size: 14px; font-weight: 700; line-height: 1.4;
  background: rgba(255, 77, 174, .10); box-shadow: inset 0 0 0 1px rgba(255, 77, 174, .45);
}
.gp__bundles { border: 0; margin: 0; padding: 0; min-width: 0; }
.gp__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
@media (max-width: 359px) { .gp__grid { grid-template-columns: minmax(0, 1fr); } }
/* 3 across from 640px (Luke: the 300 bundle centred on the last row): six tracks, cards span 2, the 300 spans the middle 4 */
@media (min-width: 640px) {
  .gp__grid { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 14px; }
  .gp__bundle { grid-column: span 2; }
  .gp__grid .gp__bundle--wide { grid-column: 2 / span 4; }
}
/* --t runs 0 (10 gems) → 1 (300 gems): the glow grows with the bundle */
.gp__bundle {
  --t: 0; --i: 0; --glow-a: calc(.12 + .48 * var(--t));
  position: relative; display: flex; flex-direction: column; min-width: 0; cursor: pointer; isolation: isolate;
  border-radius: var(--radius); background: var(--surface); overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(var(--gem-rgb), calc(.12 + .32 * var(--t))),
    0 calc(6px + 16px * var(--t)) calc(16px + 44px * var(--t)) calc(-10px - 4px * var(--t)) rgba(var(--gem-rgb), var(--glow-a));
  transition: transform 260ms var(--ease-spring), box-shadow 220ms var(--ease-out), background-color 160ms;
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
  animation: gpIn 460ms var(--ease-out) both; animation-delay: calc(var(--i) * 45ms);
}
.gp__bundle input { position: absolute; opacity: 0; pointer-events: none; }
.gp__art { position: relative; aspect-ratio: 10 / 9; overflow: hidden; }
.gp__art::before { content: ''; position: absolute; inset: 0;
  background: radial-gradient(55% 55% at 50% 58%, rgba(var(--gem-rgb), calc(.10 + .32 * var(--t))), transparent 72%); }
/* the art's backdrop is ~#212327; "lighten" lets the card show through it, so the square never shows */
.gp__art img { position: relative; width: 100%; height: 100%; object-fit: cover; display: block; object-position: 50% 45%;
  transition: transform 360ms var(--ease-spring); }
.gp__art::after {                           /* the shine that sweeps the selected bundle */
  content: ''; position: absolute; inset: -20% -60%; pointer-events: none; opacity: 0;
  background: linear-gradient(105deg, transparent 40%, rgba(255, 255, 255, .34) 50%, transparent 60%);
  transform: translateX(-60%);
}
.gp__spark {                                /* two little 4-point stars that twinkle on the selected bundle */
  position: absolute; top: 18%; left: 22%; width: 14px; height: 14px; opacity: 0; pointer-events: none; background: #fff;
  clip-path: polygon(50% 0, 60% 40%, 100% 50%, 60% 60%, 50% 100%, 40% 60%, 0 50%, 40% 40%);
  filter: drop-shadow(0 0 4px rgba(255, 255, 255, .9));
}
.gp__spark--2 { top: 42%; left: auto; right: 18%; width: 10px; height: 10px; }
.gp__txt { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; padding: 0 14px 14px; }
.gp__n { display: flex; align-items: center; gap: .3em; min-width: 0; }
.gp__n b { font-family: var(--display); font-weight: 900; font-size: 24px; line-height: 1; }
.gp__n img { width: 20px; height: 20px; flex: 0 0 auto; filter: drop-shadow(0 0 5px rgba(var(--gem-rgb), .55)); }
.gp__usd { font-weight: 800; font-size: 14px; color: var(--go); white-space: nowrap; }
.gp__check { position: absolute; top: 10px; right: 10px; z-index: 2; width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  background: rgba(18, 19, 20, .55); box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, .35); color: transparent;
  transition: background-color 160ms, box-shadow 160ms; }
@media (hover: hover) {
  .gp__bundle:hover { transform: translateY(-4px); --glow-a: calc(.24 + .52 * var(--t)); }
  .gp__bundle:hover .gp__art img { transform: scale(1.06) rotate(-1deg); }
}
/* the press: a quick squash, then the spring above brings it back */
.gp__bundle:active { transform: scale(.95); transition-duration: 90ms; }
.gp__bundle:has(input:focus-visible) { outline: 2px solid #fff; outline-offset: 3px; }
.gp__bundle:has(input:checked) { background: #2B2D31;
  box-shadow: inset 0 0 0 2px var(--go), 0 calc(8px + 16px * var(--t)) calc(20px + 44px * var(--t)) calc(-10px - 4px * var(--t)) rgba(var(--gem-rgb), calc(var(--glow-a) + .14)); }
.gp__bundle:has(input:checked) .gp__check { background: var(--go); box-shadow: none; color: #121314; animation: gpCheck 420ms var(--ease-spring) both; }
.gp__bundle:has(input:checked) .gp__art img { animation: gpHop 520ms var(--ease-spring) both; }
.gp__bundle:has(input:checked) .gp__art::after { animation: gpShine 3.2s ease-in-out 450ms infinite; }
.gp__bundle:has(input:checked) .gp__spark { animation: gpTwinkle 2.2s ease-in-out 200ms infinite; }
.gp__bundle:has(input:checked) .gp__spark--2 { animation-delay: 1.3s; }
/* the one badge (Luke, Q13): a pink tab on the card's top edge, never fighting the --go selection */
.gp__badge { position: absolute; top: 0; left: 12px; z-index: 2; padding: 4px 9px 5px; border-radius: 0 0 9px 9px; background: var(--pink); color: #121314;
  font-size: 9px; line-height: 1.1; font-weight: 800; text-transform: uppercase; white-space: nowrap; box-shadow: 0 4px 14px -4px rgba(255, 77, 174, .7); }
.gp__bundle--wide { grid-column: 1 / -1; flex-direction: row; align-items: center; }
.gp__bundle--wide .gp__art { flex: 0 0 54%; }
.gp__bundle--wide .gp__txt { gap: 6px; padding: 14px 16px 14px 4px; }
.gp__bundle--wide .gp__n b { font-size: 34px; }
.gp__bundle--wide .gp__n img { width: 28px; height: 28px; }
.gp__bundle--wide .gp__usd { font-size: 16px; }
.gp__fine { margin: 22px 0 0; padding-top: 14px; border-top: 1px solid var(--line); font-size: 12px; color: var(--faint); }
.gp__legal { display: flex; align-items: center; gap: 16px; margin: 10px 0 0; font-size: 12px; }
.gp__legal a { color: var(--faint); text-underline-offset: 3px; }
.gp__link { margin-left: auto; min-height: 44px; padding: 0; border: 0; background: none; color: var(--faint); font-size: 12px; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.gp__link:hover, .gp__legal a:hover { color: #fff; }

/* ── the order (desktop's panel; the phone shows only its footer) ── */
/* the gem art is transparent (site/gems/*.webp, 13 Nov: the old files had a dark square baked in, hidden
   with mix-blend-mode: lighten, which showed as a box wherever the panel was darker; Luke's laptop) */
.gp__hero { position: relative; width: 100%; max-width: 280px; aspect-ratio: 1; margin: 0 auto 6px; }
.gp__hero::before { content: ''; position: absolute; inset: 8%; border-radius: 50%; background: radial-gradient(closest-side, rgba(var(--gem-rgb), .45), transparent); }
.gp__hero img { position: relative; width: 100%; height: 100%; display: block; animation: gpFloat 4.2s ease-in-out infinite; }
.gp__hero img.is-swap { animation: gpSwap 460ms var(--ease-spring) both, gpFloat 4.2s ease-in-out 460ms infinite; }
.gp__sum { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.gp__sumn { display: inline-flex; align-items: center; gap: .3em; }
.gp__sumn b { font-family: var(--display); font-size: 36px; font-weight: 900; line-height: 1; }
.gp__sumn img { width: 32px; height: 32px; filter: drop-shadow(0 0 8px rgba(var(--gem-rgb), .6)); }
.gp__sumusd { font-size: 20px; font-weight: 800; color: var(--go); }
.gp__opens { margin: 14px 0 0; padding: 12px 14px; border-radius: 14px; background: rgba(var(--gem-rgb), .12); box-shadow: inset 0 0 0 1px rgba(var(--gem-rgb), .35);
  font-size: 13px; font-weight: 700; line-height: 1.5; color: var(--muted); text-wrap: balance; }
.gp__opens:empty { display: none; }
.gp__opens img { display: inline-block; width: 15px; height: 15px; margin-left: 2px; vertical-align: -2px; }
.gp__row { display: flex; align-items: center; justify-content: space-between; margin: 0; font-size: 13px; color: var(--muted); }
.gp__rowv { display: inline-flex; align-items: center; gap: .3em; color: #fff; font-weight: 800; }
.gp__rowv img { width: 16px; height: 16px; }

/* the step's one primary action: --go, in the shop's sticker build (rim, gloss, drop) */
.gp__go {
  position: relative; overflow: hidden; display: flex; align-items: center; justify-content: center; width: 100%; min-height: 56px; padding: 0 20px;
  border: 3px solid #1F2123; border-radius: var(--pill); cursor: pointer;
  background: linear-gradient(180deg, rgba(255, 255, 255, .22) 0%, transparent 48%, rgba(90, 0, 45, .18) 100%), var(--go);
  color: #121314; font: inherit; font-size: 17px; line-height: 1; font-weight: 800; text-transform: none;
  box-shadow: 0 0 0 3px rgba(var(--go-rgb), .35), 0 5px 0 2px rgba(0, 0, 0, .38), 0 12px 32px -10px rgba(var(--go-rgb), .6);
  transition: transform 140ms cubic-bezier(.22, .8, .36, 1), filter 150ms;
}
.gp__go::before { content: ''; position: absolute; left: 14px; right: 14px; top: 3px; height: 40%; pointer-events: none;
  border-radius: 999px 999px 40px 40px / 999px 999px 14px 14px;
  background: linear-gradient(180deg, rgba(255, 255, 255, .6), rgba(255, 255, 255, .12) 70%, transparent); }
.gp__go > span { position: relative; display: inline-flex; align-items: center; gap: .3em; white-space: nowrap; }
.gp__go .gemi { width: 1.15em; height: 1.15em; margin: 0; vertical-align: 0; filter: drop-shadow(0 1px 0 rgba(0, 0, 0, .25)); }
@media (hover: hover) { .gp__go:not(:disabled):hover { transform: translateY(-2px); filter: brightness(1.05); } }
.gp__go:not(:disabled):active { transform: translateY(2px); }
.gp__go:focus-visible { outline: 2px solid #fff; outline-offset: 4px; }
.gp__go:disabled { cursor: default; background: var(--surface-2); color: var(--faint); box-shadow: 0 0 0 3px rgba(255, 255, 255, .12), 0 5px 0 2px rgba(0, 0, 0, .38); }
.gp__go:disabled::before { display: none; }
.gp__more { width: 100%; cursor: pointer; }

/* ── consent ── */
.gp__backlink {
  display: inline-flex; align-items: center; gap: 4px; min-height: 44px; margin: 0 0 2px -8px; padding: 0 12px 0 6px;
  border: 0; border-radius: var(--pill); background: none; color: var(--muted); font: inherit; font-size: 13px; font-weight: 800; cursor: pointer;
}
.gp__backlink:hover { color: #fff; background: rgba(255, 255, 255, .06); }
.gp__h2 { margin: 0; font-family: var(--display); font-size: 24px; font-weight: 900; line-height: 1.1; text-transform: uppercase; text-wrap: balance; }
.gp__lead { margin: 6px 0 0; font-size: 13px; color: var(--muted); }
.gp__c { text-align: center; text-wrap: balance; }
.gp__pill { display: inline-flex; align-items: center; gap: .35em; margin: 18px 0 0; padding: 10px 16px; border-radius: var(--pill);
  background: var(--chip-bg); box-shadow: inset 0 0 0 1px var(--chip-ring); font-size: 14px; font-weight: 800; }
.gp__pill > span { color: var(--muted); }
.gp__pill img { width: 18px; height: 18px; }
.gp__money { color: var(--go); }
.gp__tick { position: relative; display: flex; gap: 14px; align-items: flex-start; margin: 16px 0 0; padding: 16px; cursor: pointer;
  border-radius: 16px; background: var(--surface); box-shadow: inset 0 0 0 1px var(--chip-ring); transition: box-shadow 160ms, background-color 160ms; }
.gp__tick input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.gp__box { flex: 0 0 auto; width: 26px; height: 26px; margin-top: 1px; border-radius: 8px; display: grid; place-items: center;
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .5); color: transparent; transition: background-color 140ms, box-shadow 140ms; }
.gp__ticktxt { font-size: 14px; line-height: 1.5; }
.gp__tick:has(input:checked) { background: #2B2D31; box-shadow: inset 0 0 0 2px var(--go); }
.gp__tick:has(input:checked) .gp__box { background: var(--go); box-shadow: none; color: #121314; animation: gpCheck 380ms var(--ease-spring) both; }
.gp__tick:has(input:focus-visible) { outline: 2px solid #fff; outline-offset: 3px; }
.gp__terms { margin: 14px 0 0; font-size: 13px; }
.gp__terms a { color: var(--muted); text-underline-offset: 3px; }
.gp__terms a:hover { color: #fff; }

/* ── deposit ── */
.gp__send { margin: 0; text-align: center; font-family: var(--display); font-size: 30px; font-weight: 900; line-height: 1.05; text-transform: uppercase; white-space: nowrap; }
.gp__send span { color: var(--go); }         /* the amount is money */
.gp__qrstage { position: relative; width: min(268px, calc(74vw / var(--z, 1))); aspect-ratio: 1; margin: 6px auto 0; display: grid; place-items: center; }
.gp__qrstage::before {                         /* a soft halo that breathes behind the code */
  content: ''; position: absolute; inset: 6%; border-radius: 50%;
  background: radial-gradient(closest-side, rgba(var(--gem-rgb), .5), rgba(var(--gem-rgb), .12) 60%, transparent);
  animation: gpBreathe 2.6s ease-in-out infinite;
}
.gp__qrcard { position: relative; width: 72%; aspect-ratio: 1; padding: 6px; border-radius: 18px; background: #fff;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .2), 0 18px 40px -14px rgba(var(--gem-rgb), .8); }
.gp__qr { width: 100%; height: 100%; }
.gp__qr svg { display: block; width: 100%; height: 100%; border-radius: 12px; }
.gp__qr:empty + .gp__qrgem { display: none; }
/* the gem in the middle: 15% of the card, ~6.6 modules of a version-4 code. Level M still decodes with a
   7x7-module hole in the middle (tests/qr.test.mjs, Core Image); keep the badge at or under 15%. */
.gp__qrgem { position: absolute; left: 50%; top: 50%; width: 15%; height: 15%; transform: translate(-50%, -50%);
  padding: 3px; border-radius: 8px; background: #fff; object-fit: contain; }
/* six gems orbit the code while it waits; faster once the deposit is landing */
.gp__orbit { position: absolute; inset: 0; animation: gpSpin 16s linear infinite; pointer-events: none; }
.gp__orbit i {
  position: absolute; left: 50%; top: 50%; width: 24px; height: 24px; margin: -12px 0 0 -12px;
  background: url(/site/gem-icon-64.webp) center / contain no-repeat;
  transform: rotate(calc(var(--i) * 60deg)) translateY(calc(min(268px, calc(74vw / var(--z, 1))) * -.47));
  filter: drop-shadow(0 0 6px rgba(var(--gem-rgb), .8));
}
.gp__orbit i:nth-child(odd) { width: 18px; height: 18px; margin: -9px 0 0 -9px; opacity: .8; }
.gp__orbit i:nth-child(3n) { animation: gpTwinkleGem 2.4s ease-in-out infinite; animation-delay: calc(var(--i) * .3s); }
#gemsDeposit[data-state="landing"] .gp__orbit { animation-duration: 2.4s; }
.gp__addr { display: flex; align-items: center; gap: 10px; margin: 8px 0 0; padding: 10px 10px 10px 14px; border-radius: 14px;
  background: var(--bg-deep); box-shadow: inset 0 0 0 1px var(--line); }
.gp__addr code { flex: 1; min-width: 0; font-family: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, Consolas, monospace; font-stretch: normal;
  font-size: 13px; line-height: 1.45; color: #fff; word-break: break-all; }
.gp__addr .chipbtn { flex: 0 0 auto; min-width: 76px; justify-content: center; cursor: pointer; }
.gp__only { display: flex; align-items: center; justify-content: center; gap: 8px; margin: 14px 0 0; font-size: 14px; font-weight: 800; }
.gp__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--go); box-shadow: 0 0 8px rgba(var(--go-rgb), .7); flex: 0 0 auto; }
.gp__warn { margin: 4px 0 0; font-size: 12px; font-weight: 800; color: var(--red); text-align: center; text-wrap: balance; }
.gp__warn svg { display: inline-block; margin-right: 5px; vertical-align: -2px; }
.gp__warn span { display: inline; }
.gp__help { margin: 12px 0 0; font-size: 12px; color: var(--faint); text-align: center; text-wrap: balance; }
.gp__help a { color: var(--muted); text-underline-offset: 3px; }
.gp__left { display: block; margin-top: 2px; }
.gp__left:empty { display: none; }
.gp__status { display: flex; align-items: center; justify-content: center; gap: 10px; min-height: 52px; margin: 0; font-size: 14px; font-weight: 800; text-align: center; }
.gp__status[hidden] { display: none; }
.gp__spin { width: 18px; height: 18px; flex: 0 0 auto; border-radius: 50%; border: 2.5px solid rgba(255, 255, 255, .18); border-top-color: var(--gem-hi);
  animation: gpSpin 900ms linear infinite; }
.gp__spin[hidden] { display: none; }

/* ── credited ── */
.gp__scroll--done { display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; }
.gp__burst { position: relative; width: 190px; height: 190px; margin: 4px auto 4px; display: grid; place-items: center; flex: 0 0 auto; }
.gp__rays { position: absolute; inset: -34px; border-radius: 50%;
  background: radial-gradient(closest-side, rgba(var(--gem-rgb), .55), rgba(var(--gem-rgb), .12) 55%, transparent 72%),
    repeating-conic-gradient(from 0deg, rgba(211, 164, 255, .22) 0deg 7deg, transparent 7deg 22.5deg);
  -webkit-mask: radial-gradient(closest-side, #000 45%, transparent 100%); mask: radial-gradient(closest-side, #000 45%, transparent 100%); }
.gp__bigem { position: relative; width: 140px; height: 140px; object-fit: contain; filter: drop-shadow(0 14px 30px rgba(var(--gem-rgb), .6)); }
.gp__burst.is-on .gp__bigem { animation: gpPop 640ms var(--ease-spring) both; }
.gp__burst.is-on .gp__rays { animation: gpRaysIn 900ms var(--ease-out) both, gpSpin 26s linear 900ms infinite; }
.gp__p { position: absolute; left: 50%; top: 50%; width: 26px; height: 26px; margin: -13px 0 0 -13px; opacity: 0; pointer-events: none;
  animation: gpFly 950ms cubic-bezier(.15, .8, .3, 1) both; }
.gp__ok { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 8px; margin: 8px 0 0; font-size: 15px; font-weight: 800; }
.gp__ok:focus { outline: none; }
.gp__ok b { color: var(--go); }
.gp__ok b + span::before { content: '·'; margin-right: 8px; color: var(--muted); }
.gp__okdot { width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; background: var(--go); color: #121314; flex: 0 0 auto; }
.gp__newbal { display: flex; align-items: center; justify-content: center; gap: .3em; margin: 16px 0 0; }
.gp__newbal b { font-family: var(--display); font-size: 48px; font-weight: 900; line-height: 1; }
.gp__newbal img { width: 40px; height: 40px; filter: drop-shadow(0 0 10px rgba(var(--gem-rgb), .7)); }
/* right after a matched deposit: the match is checked, then lands as its own moment (or is held) */
.gp__pending { margin: 14px 0 0; padding: 10px 14px; border-radius: 14px; font-size: 13px; font-weight: 700; line-height: 1.4; color: #fff; text-wrap: balance;
  background: rgba(255, 77, 174, .10); box-shadow: inset 0 0 0 1px rgba(255, 77, 174, .4); }

/* ── the deposit match (13 Nov, tools/mockups/deposit-match/ direction A, approved). app.js
   paintGemsMatch / renderBundles; the sheet's data-match is "on:<pct>" while MY match is open.
   Brand rules kept: --go is money and the one primary action, pink is the brand so the BONUS is
   pink, purple only for gems. Every number on these comes from the server's offer. ── */
/* the sticker: pink, dark type (6.4:1), a dark rim so it reads on any art */
.gp__stamp {
  position: absolute; right: 10px; bottom: 8px; z-index: 2; width: 46px; height: 46px; border-radius: 50%; display: grid; place-items: center;
  background: var(--brand-grad); color: #121314; font-family: var(--display); font-weight: 900; font-size: 15px; line-height: 1; white-space: nowrap;
  transform: rotate(-12deg); box-shadow: 0 0 0 2.5px #121314, 0 0 0 4px rgba(255, 77, 174, .55), 0 8px 18px -4px rgba(255, 77, 174, .75);
}
.gp__bundle:has(input:checked) .gp__stamp { animation: gpStamp 520ms var(--ease-spring) both; }
.gp__bundle--wide .gp__stamp { width: 56px; height: 56px; font-size: 18px; right: 14px; bottom: 12px; }
.gp__stamp--big { width: 70px; height: 70px; font-size: 22px; right: 2px; bottom: 14px; }
/* above the bundles: the ribbon */
.gp__ribbon { position: relative; display: flex; align-items: center; gap: 14px; margin: 0 0 16px; padding: 12px 16px 12px 12px; border-radius: 18px; overflow: hidden; isolation: isolate;
  background: var(--brand-grad); color: #121314; box-shadow: 0 14px 34px -16px rgba(255, 77, 174, .9); }
.gp__ribbon::after { content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: repeating-linear-gradient(115deg, transparent 0 26px, rgba(255, 255, 255, .09) 26px 36px); }
.gp__x2 { flex: 0 0 auto; width: 54px; height: 54px; border-radius: 50%; display: grid; place-items: center; background: #121314; color: var(--pink);
  font-family: var(--display); font-weight: 900; font-size: 19px; line-height: 1; white-space: nowrap; transform: rotate(-8deg); box-shadow: 0 0 0 3px rgba(255, 255, 255, .9); }
.gp__rt { display: grid; gap: 3px; min-width: 0; }
.gp__rt b { font-family: var(--display); font-weight: 900; font-size: 17px; line-height: 1.1; text-transform: uppercase; }
.gp__rt span { font-size: 13px; font-weight: 700; line-height: 1.35; }
/* the bundles: the matched total big, then "10 + 10 bonus", then the price */
.gp[data-match^="on"] .gp__txt { gap: 3px; }
.gp__split { font-size: 12px; font-weight: 700; color: var(--muted); white-space: nowrap; }
.gp__split b { color: var(--pink); font-weight: 800; }
.gp__bundle--wide .gp__split { font-size: 14px; }
/* "any amount is doubled too" under the bundles */
.gp__any { display: flex; align-items: center; gap: 10px; margin: 16px 0 0; padding: 12px 14px; border-radius: 14px; font-size: 13px; line-height: 1.4; color: var(--muted);
  background: rgba(255, 77, 174, .07); box-shadow: inset 0 0 0 1px rgba(255, 77, 174, .28); }
.gp__any b { color: #fff; font-weight: 800; }
.gp__anyic { flex: 0 0 auto; width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; background: rgba(var(--gem-rgb), .22); }
.gp__anyic img { width: 15px; height: 15px; }
/* the order panel: the art with a big sticker, then a receipt */
.gp[data-match^="on"] .gp__hero { max-width: 210px; }
.gp__receipt { margin: 8px 0 0; padding: 4px 16px 6px; border-radius: 18px; background: rgba(18, 19, 20, .55); box-shadow: inset 0 0 0 1px var(--line); }
.gp__rrow { display: flex; align-items: center; justify-content: space-between; min-height: 40px; margin: 0; border-bottom: 1px solid var(--line); font-size: 14px; color: var(--muted); }
.gp__rrow b { display: inline-flex; align-items: center; gap: .3em; color: #fff; font-weight: 800; }
.gp__rrow b img { width: 16px; height: 16px; }
.gp__rrow--bonus > span, .gp__rrow--bonus b { color: var(--pink); font-weight: 800; }
.gp__pct { margin-left: 6px; padding: 2px 7px; border-radius: 999px; background: var(--pink); color: #121314; font-size: 11px; font-weight: 800; font-style: normal; }
.gp__rtot { display: flex; align-items: center; justify-content: space-between; margin: 0; padding: 12px 0 8px; }
.gp__rtot > span { font-family: var(--display); font-weight: 900; font-size: 14px; text-transform: uppercase; }
.gp__rtot b { display: inline-flex; align-items: center; gap: .22em; font-family: var(--display); font-size: 36px; font-weight: 900; line-height: 1; }
.gp__rtot b img { width: 30px; height: 30px; filter: drop-shadow(0 0 8px rgba(var(--gem-rgb), .7)); }
.gp[data-match^="on"] .gp__opens { margin-top: 12px; }
/* the footer: "You get 50 + 50 bonus = 100", the button, the lead's small print */
.gp__pink { color: var(--pink); }
.gp__row--get .gp__rowv { gap: .28em; font-weight: 700; color: var(--muted); }
.gp__row--get .gp__rowv b { font-weight: 800; }
.gp__row--get .gp__rowv b:not(.gp__pink) { color: #fff; }
.gp__small { margin: 0; font-size: 11px; line-height: 1.4; color: var(--faint); text-align: center; text-wrap: balance; }
/* after the match: the Invite line (a button into the invite popup) */
.gp__match {
  display: grid; gap: 2px; width: 100%; margin: 0 0 16px; padding: 12px 14px 12px 46px; position: relative; border: 0; border-radius: 16px; text-align: left; color: #fff; font: inherit; cursor: pointer;
  background: linear-gradient(90deg, rgba(255, 77, 174, .16), rgba(252, 1, 135, .10)); box-shadow: inset 0 0 0 1px rgba(255, 77, 174, .5);
  transition: transform 150ms var(--ease-out), background-color 150ms;
}
.gp__match::before { /* the gift, drawn in the brand gradient */
  content: ''; position: absolute; left: 14px; top: 14px; width: 22px; height: 22px; background: var(--brand-grad);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 11h16v9.5H4zM2.5 7.5h19V11h-19zM12 7.5v13M12 7.5C10.5 4 7 3.5 6.5 5.5S9 7.5 12 7.5zM12 7.5c1.5-3.5 5-4 5.5-2S15 7.5 12 7.5z' fill='none' stroke='%23000' stroke-width='2' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 11h16v9.5H4zM2.5 7.5h19V11h-19zM12 7.5v13M12 7.5C10.5 4 7 3.5 6.5 5.5S9 7.5 12 7.5zM12 7.5c1.5-3.5 5-4 5.5-2S15 7.5 12 7.5z' fill='none' stroke='%23000' stroke-width='2' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
}
.gp__match b { font-family: var(--display); font-size: 14px; font-weight: 900; line-height: 1.2; text-transform: uppercase; }
.gp__match span { font-size: 13px; line-height: 1.4; color: var(--muted); }
.gp__match:active { transform: scale(.98); }
.gp__match:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
@keyframes gpStamp { 0% { transform: scale(.3) rotate(-30deg); opacity: 0; } 60% { transform: scale(1.12) rotate(-6deg); opacity: 1; } 100% { transform: scale(1) rotate(-12deg); } }
@keyframes gpPillIn { 0% { transform: scale(.4); opacity: 0; } 60% { transform: scale(1.08); opacity: 1; } }
@keyframes gpRowIn { from { opacity: 0; transform: translateX(-16px); } }
@media (min-width: 1024px) { .gp[data-match^="on"] .gp__step--pick .gp__scroll { padding-top: 58px; } }
@media (max-width: 1023px) {
  .gp__rt b { font-size: 15px; }
  .gp__row--get .gp__rowv { font-size: 13px; }
}
/* a longer multiplier ("1.5X", "1.25X") still fits the round sticker */
.gp__stamp.is-long { font-size: 11px; }
.gp__bundle--wide .gp__stamp.is-long { font-size: 13px; }
.gp__stamp--big.is-long, .gp__x2.is-long { font-size: 15px; }
@media (prefers-reduced-motion: reduce) { .gp__stamp, .gp__match { animation: none !important; transition: none; } }

/* ── the top-bar chip (Luke, 13 Nov): "@Slusher | 0 💎", the username, a divider, the number, the gem ── */
.bal__chip { gap: 5px; padding: 0 12px 0 14px; }
.bal__chip .bal__who { order: 1; display: none; }
.bal__chip .bal__who:has(.bal__user:not([hidden])) { display: grid; justify-items: start; line-height: 1.1; padding-right: 8px; margin-right: 3px; border-right: 1px solid rgba(255, 255, 255, .24); }
.bal__chip .bal__user:not([hidden]) { display: block; max-width: 12ch; }
/* the phone's site rank: a small line above your name (desktop has its own chip, .srank) */
.bal__rank { display: block; margin-bottom: 2px; font-size: 9px; font-weight: 900; letter-spacing: .04em; line-height: 1; text-transform: uppercase; color: var(--rank-ice); }
.bal__rank[hidden] { display: none; }
@media (min-width: 1024px) { .bal__rank { display: none !important; } }
.bal__chip .bal__amt { order: 2; color: #fff; }
.bal__chip .bal__gem { order: 3; width: 20px; height: 20px; filter: drop-shadow(0 0 6px rgba(158, 58, 255, .65)); }
.bal__chip .bal__net { order: 4; }
@media (max-width: 420px) {
  .bal__chip .bal__net { display: none; }
  .bal__chip .bal__user:not([hidden]) { max-width: 11ch; }
}
/* a pack's price in gems under the fan ("20 💎 PACK") */
.gprice { display: inline-flex; align-items: center; gap: .12em; }
.gprice .gemi { width: .95em; height: .95em; margin: 0; vertical-align: 0; filter: drop-shadow(0 0 6px rgba(158, 58, 255, .6)); }

/* ── the motion ── */
@keyframes gpIn { from { opacity: 0; transform: translateY(14px) scale(.96); } }
@keyframes gpHop { 0% { transform: scale(1); } 35% { transform: scale(1.1) translateY(-4%); } 100% { transform: scale(1); } }
@keyframes gpCheck { 0% { transform: scale(.4); } 100% { transform: scale(1); } }
@keyframes gpShine { 0%, 55% { opacity: 1; transform: translateX(-60%); } 85%, 100% { opacity: 1; transform: translateX(60%); } }
@keyframes gpTwinkle { 0%, 100% { opacity: 0; transform: scale(.3) rotate(0deg); } 45% { opacity: 1; transform: scale(1) rotate(45deg); } 70% { opacity: 0; transform: scale(.5) rotate(90deg); } }
@keyframes gpTwinkleGem { 0%, 100% { opacity: .9; } 50% { opacity: .35; } }
@keyframes gpFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-7px); } }
@keyframes gpSwap { from { opacity: 0; transform: scale(.82) rotate(-4deg); } }
@keyframes gpBreathe { 0%, 100% { transform: scale(.94); opacity: .75; } 50% { transform: scale(1.04); opacity: 1; } }
@keyframes gpSpin { to { transform: rotate(360deg); } }
@keyframes gpPop { 0% { transform: scale(.3) rotate(-14deg); opacity: 0; } 60% { transform: scale(1.1) rotate(3deg); opacity: 1; } 100% { transform: none; } }
@keyframes gpRaysIn { from { opacity: 0; transform: scale(.5); } }
@keyframes gpFly {
  0% { opacity: 0; transform: rotate(var(--a)) translateY(0) rotate(calc(-1 * var(--a))) scale(.3); }
  15% { opacity: 1; }
  100% { opacity: 0; transform: rotate(var(--a)) translateY(calc(-1 * var(--d))) rotate(calc(-1 * var(--a) + 120deg)) scale(var(--s)); }
}

/* ── desktop: the two-column modal ── */
@media (min-width: 1024px) {
  .gp.sheet { width: min(1060px, calc(calc(100vw / var(--z, 1)) - 64px)); max-height: min(calc(88dvh / var(--z, 1)), 820px); }
  .gp .sheet__in { display: grid; grid-template-columns: minmax(0, 1fr) 380px; grid-template-rows: auto minmax(0, 1fr); height: min(calc(88dvh / var(--z, 1)), 820px); }
  .gp__head { grid-column: 1; grid-row: 1; padding: 22px 28px 0; position: static; }
  .gp .sheet__x { position: absolute; top: 16px; right: 16px; z-index: 4; }
  .gp .gp__main, .gp[data-step] .gp__main { display: block; grid-column: 1; grid-row: 2; padding: 6px 28px 24px; }
  .gp__h { font-size: 32px; }
  .gp__flow, .gp[data-step] .gp__flow { grid-column: 2; grid-row: 1 / -1; border-left: 1px solid var(--line);
    background: radial-gradient(80% 40% at 50% 28%, rgba(var(--gem-rgb), .2), transparent 70%), var(--surface); }
  .gp__step--pick .gp__scroll { display: block; padding-top: 70px; }
  .gp__scroll { padding: 18px 28px 12px; }
  .gp__foot { padding: 12px 28px 24px; border-top: 0; background: none; }
  .gp__go { min-height: 60px; font-size: 18px; }
  .gp__qrstage { width: 248px; }
  .gp__orbit i { transform: rotate(calc(var(--i) * 60deg)) translateY(-117px); }
  .gp__send { font-size: 28px; }
  .gp__bundle--wide .gp__art { flex-basis: 50%; }
  .gp__art { aspect-ratio: 6 / 5; }
}
@media (min-width: 1024px) and (max-height: 820px) {
  .gp__qrstage { width: 224px; }
  .gp__orbit i { transform: rotate(calc(var(--i) * 60deg)) translateY(-105px); }
  .gp__hero { max-width: 240px; }
}

/* ── reduced motion: every state still shows; nothing loops, nothing flies ── */
@media (prefers-reduced-motion: reduce) {
  .gp__bundle, .gp__art img, .gp__hero img, .gp__loading img, .gp__orbit, .gp__qrstage::before, .gp__spin,
  .gp__bundle:has(input:checked) .gp__art img, .gp__bundle:has(input:checked) .gp__check { animation: none !important; }
  .gp__art::after, .gp__spark, .gp__p { display: none; }
  .gp__bundle:hover, .gp__bundle:active { transform: none; }
  .gp__spin { border-color: var(--gem-hi); }
}

/* ============================================================
   INVITE: referrals + the 100% deposit match (Luke, 13 Nov). The site's own parts: the
   chip pill in the top bar, a sheet (bottom sheet on the phone, a wide two-column modal on
   desktop), display-face headings, the brand gradient for the one primary action, --go for
   money, the gem purple only for gems. Every claim is worded by app.js from the server's offer.
   ============================================================ */
/* the top bar's Invite chip: a gift and "100% match" (phone: "100%") */
.invbtn { min-height: 40px; padding: 0 14px 0 12px; gap: 6px; background: rgba(255, 77, 174, .12); box-shadow: inset 0 0 0 1px rgba(255, 77, 174, .55); }
.invbtn:hover { background: rgba(255, 77, 174, .2); }
.invbtn svg { color: var(--pink); }
.invbtn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
/* phone: the bottom nav's fifth item instead (the gem chip needs the room) */
.invbtn, .invbtn__short { display: none; }
@media (min-width: 1024px) { .invbtn { display: inline-flex; } }
.bnav:has(.bnav__item--inv) { grid-template-columns: repeat(5, 1fr); }
.bnav__item--inv svg { color: var(--pink); }
/* no "100%" badge on the phone's Invite (Luke, 13 Nov: no pills, and the match is shown where people
   look for it: sign-up, Get gems and the invite sheet) */
.bnav__badge--inv { display: none !important; }
.bnav__badge--inv[hidden] { display: none; }
@media (min-width: 1024px) {
  .rail__count--inv { color: var(--pink); }
}

/* ── MATCH PLACEHOLDERS (lead, 13 Nov): sign-up's box, until the welcome dialog replaces it
   (app.js paintSignupOffer). Get gems' match is designed now: "the deposit match" under Get gems. ── */
/* sign-up: "Invited by @bob" and the match */
.signup__ref { display: grid; gap: 6px; margin: 8px 0 4px; padding: 12px 14px; border-radius: 14px; text-align: center;
  background: rgba(255, 77, 174, .10); box-shadow: inset 0 0 0 1px rgba(255, 77, 174, .4); }
.signup__ref[hidden] { display: none; }
.signup__by { margin: 0; font-size: 14px; color: var(--muted); }
.signup__by b { color: #fff; }
.signup__offer { margin: 0; font-size: 13px; font-weight: 800; line-height: 1.4; color: #fff; }
.signup__by[hidden], .signup__offer[hidden] { display: none; }

/* ── end MATCH PLACEHOLDERS ── */

/* the invite sheet */
.inv .sheet__in { position: relative; overflow: hidden; }
.inv .sheet__in::before {                  /* a pink bloom behind the head, like Get gems' purple one */
  content: ''; position: absolute; inset: -140px -10% auto; height: 320px; pointer-events: none;
  background: radial-gradient(50% 60% at 50% 50%, rgba(255, 77, 174, .22), transparent 70%);
}
.inv .sheet__head, .inv .sheet__body { position: relative; }
.inv__grid { display: grid; gap: 22px; }
.inv__col { display: grid; gap: 22px; align-content: start; min-width: 0; }
.inv__hero { padding: 4px 2px 0; }
.inv__kick { margin: 0; font-size: 11px; font-weight: 800; text-transform: uppercase; color: var(--pink); }
.inv__h { margin: 4px 0 0; font-family: var(--display); font-size: clamp(28px, calc(8vw / var(--z, 1)), 40px); font-weight: 900; line-height: 1; text-transform: uppercase; text-wrap: balance;
  text-shadow: 0 6px 34px rgba(255, 77, 174, .45); }
.inv__lim { margin: 8px 0 0; font-size: 14px; font-weight: 800; color: var(--go); }
.inv__lead { margin: 8px 0 0; color: var(--muted); font-size: 14px; }
.inv__how { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 10px; }
.inv__how li { display: flex; gap: 12px; align-items: flex-start; font-size: 14px; line-height: 1.45; color: rgba(255, 255, 255, .86); }
.inv__ico { flex: 0 0 auto; width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center; background: var(--brand-grad); color: #fff; font-size: 12px; font-weight: 800; }
.inv__mine { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 14px 0 0; font-size: 13px; color: var(--muted); }
.inv__mine b { color: var(--go); display: inline-flex; align-items: center; gap: 3px; }
.inv__sec { min-width: 0; }
.inv__sh { margin: 0 0 10px; font-size: 11px; font-weight: 800; text-transform: uppercase; color: var(--faint); }
.inv__link { display: flex; align-items: center; gap: 8px; padding: 6px 6px 6px 14px; border-radius: 16px; background: var(--surface); box-shadow: inset 0 0 0 1px var(--line); }
.inv__link code { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 700 14px/1.3 ui-monospace, 'SF Mono', Menlo, monospace; color: #fff; user-select: all; }
.inv__link .chipbtn { min-height: 40px; }
.inv__acts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.inv__acts .chipbtn { flex: 1 1 auto; justify-content: center; }
.inv__acts .chipbtn--brand { flex: 2 1 auto; }
.chipbtn--brand:focus-visible, .inv__acts .chipbtn:focus-visible, .inv__link .chipbtn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
/* the best pull: the foil card still, its tier and Share */
.inv__best { display: grid; grid-template-columns: 132px minmax(0, 1fr); gap: 16px; align-items: center; padding: 14px; border-radius: 18px;
  background: radial-gradient(120% 90% at 0% 50%, color-mix(in srgb, var(--t1) 18%, transparent), transparent 70%), var(--surface); box-shadow: inset 0 0 0 1px var(--line); }
.inv__best--empty { display: flex; gap: 12px; color: var(--muted); font-size: 14px; background: var(--surface); }
.inv__logo { width: 68px; height: auto; transform: rotate(-4deg); flex: 0 0 auto; }
.inv__card { position: relative; aspect-ratio: 5 / 7; display: grid; place-items: center; }
.inv__still { width: 100%; height: 100%; display: block; filter: drop-shadow(0 12px 22px rgba(0, 0, 0, .55)); }
.inv__card.is-failed::after { content: 'Card unavailable'; font-size: 12px; color: var(--faint); }
.inv__card.is-failed .spinner { display: none; }
.inv__bestTxt { display: grid; justify-items: start; gap: 6px; min-width: 0; }
.inv__bestTxt b { font-size: 16px; font-weight: 800; line-height: 1.2; overflow-wrap: anywhere; }
.inv__bestTxt small { font-size: 12px; color: var(--muted); }
.inv__bestTxt .chipbtn { margin-top: 6px; }
/* my referrals */
.inv__totals { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin: 0 0 12px; }
.inv__totals div { padding: 10px 12px; border-radius: 14px; background: var(--surface); box-shadow: inset 0 0 0 1px var(--line); min-width: 0; }
.inv__totals dt { font-size: 10px; font-weight: 800; text-transform: uppercase; color: var(--faint); }
.inv__totals dd { margin: 4px 0 0; display: flex; align-items: center; gap: 4px; font-family: var(--display); font-size: 20px; font-weight: 900; line-height: 1; }
.inv__totals div:last-child dd { color: var(--go); }
.inv__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.inv__row { display: grid; grid-template-columns: 36px minmax(0, 1fr) auto; gap: 10px; align-items: center; padding: 10px 12px; border-radius: 14px; background: var(--surface); }
.inv__av { width: 36px; height: 36px; border-radius: 50%; display: grid; place-items: center; background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--chip-ring); font-weight: 800; font-size: 15px; }
.inv__who { display: grid; gap: 2px; min-width: 0; }
.inv__who b { font-size: 14px; font-weight: 800; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.inv__who small { font-size: 12px; color: var(--muted); line-height: 1.35; }
.inv__who small b { font-size: 12px; color: #fff; }
.inv__rw { display: grid; justify-items: end; gap: 4px; }
.inv__gems { display: inline-flex; align-items: center; gap: 3px; font-size: 15px; font-weight: 800; color: var(--muted); }
.inv__gems[data-tone="ok"] { color: var(--go); }
.inv__gems--none { color: var(--faint); }
.inv__pill { display: inline-flex; align-items: center; height: 22px; padding: 0 9px; border-radius: var(--pill); font-size: 10px; font-weight: 800; text-transform: uppercase; white-space: nowrap;
  color: var(--muted); box-shadow: inset 0 0 0 1px var(--chip-ring); }
.inv__pill[data-tone="ok"] { color: #121314; background: var(--go); box-shadow: none; }
.inv__pill[data-tone="pend"] { color: #fff; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .5); }
.inv__pill[data-tone="hold"] { color: #FFC200; box-shadow: inset 0 0 0 1px rgba(255, 194, 0, .55); }
.inv__pill[data-tone="no"] { color: #FF7FA0; box-shadow: inset 0 0 0 1px rgba(255, 77, 174, .5); }
.inv__state { display: flex; align-items: center; gap: 10px; padding: 18px 14px; border-radius: 14px; background: var(--surface); color: var(--muted); font-size: 14px; }
.inv__state--empty { display: block; text-align: center; padding: 26px 18px; text-wrap: balance; }
.inv__state--empty b { display: block; color: #fff; font-size: 16px; margin-bottom: 4px; }
.inv__retry { border: 0; background: none; padding: 12px 4px; margin: -12px 0; color: var(--go); font: inherit; font-weight: 800; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.inv__out { padding-top: 28px; }
.inv__fine { margin: 22px 0 0; padding-top: 14px; border-top: 1px solid var(--line); font-size: 12px; color: var(--faint); text-wrap: pretty; }
.inv__fine a { color: var(--muted); }
@media (min-width: 1024px) {
  .inv { width: min(940px, calc(calc(100vw / var(--z, 1)) - 64px)); }
  .inv__grid { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); gap: 32px; }
  .inv__refs { padding-left: 32px; border-left: 1px solid var(--line); }
  .inv__h { font-size: 36px; }
  .inv__best { grid-template-columns: 150px minmax(0, 1fr); }

  /* No scrolling (Luke, 13 Nov: "on the invite friends screen, now on my laptop, you have to scroll").
     The left column (offer, link, best pull) sets the sheet's height; the referrals column takes that
     height (contain: size, so a long list never makes the sheet taller) and only its list scrolls,
     fading at the ends. The left column is tightened so it fits a 14" MacBook (1512x860 Chrome). */
  .inv .sheet__in { overflow: hidden; }
  .inv__col { gap: 16px; }
  .inv__how { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); gap: 12px; margin-top: 12px; }
  .inv__how li { font-size: 13px; line-height: 1.4; }
  .inv__lim { margin-top: 6px; }
  .inv__mine { margin-top: 10px; }
  .inv__best { grid-template-columns: 92px minmax(0, 1fr); gap: 14px; padding: 10px 14px; }
  .inv__bestTxt { gap: 4px; }
  .inv__bestTxt .chipbtn { margin-top: 2px; }
  .inv__refs { contain: size; min-height: 320px; display: flex; flex-direction: column; }
  .inv__refs > .inv__list { --fade: 40px; flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
    align-content: start; margin-right: -8px; padding-right: 8px; scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, .2) transparent; }
  .inv__fine { margin-top: 16px; padding-top: 12px; }
}

/* the reward popup: the age gate's card, the credited gem burst (.gp__burst) on top */
.rwd { background: radial-gradient(closest-side at 50% 42%, rgba(158, 58, 255, .30), rgba(255, 77, 174, .10) 60%, transparent); background-size: min(760px, calc(160vw / var(--z, 1))) min(760px, calc(130dvh / var(--z, 1))); background-position: center; background-repeat: no-repeat; }
.rwd__in { padding-top: 18px; overflow: visible; }
.rwd__burst { width: 160px; height: 160px; margin: 0 auto -6px; }
.rwd__burst .gp__bigem { width: 116px; height: 116px; }
.rwd__body { padding-top: 6px; }
.rwd__kick { margin: 0 0 6px; font-size: 12px; font-weight: 800; text-transform: uppercase; color: var(--pink); }
.rwd h2 { display: inline-flex; align-items: center; gap: 6px; font-family: var(--display); font-size: 40px; font-weight: 900; color: var(--go); }
.rwd h2 .gemi { width: 30px; height: 30px; filter: drop-shadow(0 0 10px rgba(var(--gem-rgb), .7)); }
.rwd__text { max-width: 32ch; color: rgba(255, 255, 255, .82); font-size: 15px; }
.rwd__text p { margin: 0; }
.rwd__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; text-align: left; }
.rwd__list b { color: #fff; }
.rwd__go { background: var(--brand-grad); color: #fff; box-shadow: 0 12px 30px -14px rgba(255, 77, 174, .8); }
.rwd__go:hover { background: var(--brand-grad); filter: brightness(1.08); }
.rwd__fine { margin-top: 10px; }
/* the deposit match landed (tools/mockups/deposit-match/landed.html; app.js showRewards, a credited
   'match' event only): the pill, the burst in pink with the sticker, "+50 BONUS GEMS", the receipt
   (Deposit / Deposit match / Balance counting up) and "Rip a pack" */
.rwd__pill { display: inline-block; position: relative; z-index: 3; margin: 8px 0 0; padding: 7px 14px; border-radius: 999px; background: var(--brand-grad); color: #121314;
  font-family: var(--display); font-size: 14px; font-weight: 900; line-height: 1.1; text-transform: uppercase;
  box-shadow: 0 10px 26px -10px rgba(255, 77, 174, .9); animation: gpPillIn 560ms var(--ease-spring) both; }
.rwd--match .rwd__burst { width: 180px; height: 180px; margin: 14px auto 0; }
.rwd--match .rwd__burst .gp__bigem { width: 128px; height: 128px; }
.rwd--match .gp__rays { background: radial-gradient(closest-side, rgba(255, 77, 174, .5), rgba(var(--gem-rgb), .18) 55%, transparent 72%),
  repeating-conic-gradient(from 0deg, rgba(255, 160, 200, .26) 0deg 7deg, transparent 7deg 22.5deg); }
.rwd__stamp { right: 0; bottom: 10px; width: 58px; height: 58px; font-size: 19px; animation: gpStamp 560ms var(--ease-spring) 380ms both; }
.rwd--match h2 { display: block; color: #fff; font-size: 30px; line-height: 1.05; text-transform: uppercase; }
.rwd__plus { color: var(--pink); }
.rwd--match .rwd__text { margin-top: 6px; color: var(--muted); font-size: 14px; }
.rwd__rcpt { margin: 18px auto 0; padding: 4px 16px; border-radius: 18px; background: rgba(18, 19, 20, .55); box-shadow: inset 0 0 0 1px var(--line); text-align: left; }
.rwd__li { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 10px; min-height: 44px; margin: 0; border-bottom: 1px solid var(--line); font-size: 14px; font-weight: 700; }
.rwd__li b { display: inline-flex; align-items: center; gap: .3em; font-weight: 800; color: var(--go); }
.rwd__li b img { width: 16px; height: 16px; }
.rwd__ok { width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; background: var(--go); color: #121314; }
.rwd__li--bonus > span:nth-child(2), .rwd__li--bonus b { color: var(--pink); }
.rwd__li--bonus .rwd__ok { background: var(--pink); }

/* ── INVITE PROMPT (after a deposit; app.js showInvitePrompt). The deposit-match popup's shell (.age.rwd):
   two transparent gem piles above, the deal as two halves (your friend | you) with one worked example,
   one primary action, Maybe later, and the opt-out as small text. No pills. ── */
.invp__in { padding-top: 10px; }
.invp__art { position: relative; height: 128px; margin: 0 auto -4px; width: 220px; }
.invp__gem { position: absolute; bottom: 0; width: 128px; height: 128px; filter: drop-shadow(0 10px 22px rgba(var(--gem-rgb), .45)); }
.invp__gem--a { left: 6px; transform: rotate(-8deg) scale(.86); transform-origin: bottom center; }
.invp__gem--b { right: 6px; transform: rotate(6deg); transform-origin: bottom center; }
.invp h2 { display: block; color: #fff; font-size: 30px; line-height: 1.05; text-transform: uppercase; }
.invp__sub { margin: 8px auto 0; max-width: 30ch; color: var(--muted); font-size: 14px; line-height: 1.4; }
.invp__split { display: grid; grid-template-columns: 1fr 1fr; margin: 16px 0 0; border-radius: 18px; background: rgba(18, 19, 20, .55); box-shadow: inset 0 0 0 1px var(--line); }
.invp__split:has(> [hidden]) { grid-template-columns: 1fr; }
.invp__half { display: grid; justify-items: center; align-content: start; gap: 2px; padding: 14px 10px 13px; text-align: center; }
.invp__half[hidden] { display: none; }
.invp__half + .invp__half { box-shadow: -1px 0 0 0 var(--line); }
.invp__who { font-size: 11px; font-weight: 800; text-transform: uppercase; color: var(--faint); }
.invp__pct { font-family: var(--display); font-size: 34px; font-weight: 900; line-height: 1.05; color: #fff; }
.invp__half--you .invp__pct { color: var(--pink); }
.invp__what { max-width: 16ch; font-size: 13px; line-height: 1.3; color: rgba(255, 255, 255, .8); }
.invp__eg { margin: 10px 0 0; font-size: 13px; color: var(--muted); }
.invp__eg[hidden] { display: none; }
.invp__eg .gprice { display: inline-flex; align-items: center; gap: 2px; color: #fff; font-weight: 800; }
.invp .age__acts { margin-top: 18px; }
.invp__never { display: block; min-height: 44px; margin: 2px auto 0; padding: 0 12px; border: 0; background: none; color: var(--faint);
  font: inherit; font-size: 12px; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.invp__never:hover { color: var(--muted); }
.invp__never:focus-visible { outline: 2px solid #fff; outline-offset: 2px; border-radius: 8px; }
.rwd__li--bonus { animation: gpRowIn 520ms var(--ease-spring) 300ms both; }
.rwd__li--tot { grid-template-columns: 1fr auto; border-bottom: 0; min-height: 56px; }
.rwd__li--tot > span { font-family: var(--display); font-size: 13px; font-weight: 900; text-transform: uppercase; color: var(--muted); }
.rwd__li--tot b { color: #fff; font-family: var(--display); font-size: 30px; font-weight: 900; line-height: 1; }
.rwd__li--tot b img { width: 22px; height: 22px; filter: drop-shadow(0 0 8px rgba(var(--gem-rgb), .7)); }
.rwd__rip { min-height: 56px; }
.rwd__stamp.is-long { font-size: 14px; }
@media (prefers-reduced-motion: reduce) { .rwd__pill, .rwd__stamp, .rwd__li--bonus { animation: none !important; } }
@media (prefers-reduced-motion: reduce) { .invbtn, .gp__match { transition: none; } }

/* ============================================================
   WELCOME: the first-deposit match, once after sign-up (Luke, 13 Nov). Built from the
   approved mock tools/mockups/deposit-match/welcome-b.html ("Foil card"), with Luke's two
   changes: a Rare clip plays in the card's window, and the kicker is just the words (no
   pill, no dot). Desktop (900px+): a two-column modal. Below: a bottom sheet with the card
   standing out of its top edge. The words and numbers are app.js showWelcome's.
   ============================================================ */
.wel { --gem-rgb: 158, 58, 255; --wel-muted: rgba(255, 255, 255, .72); --wel-fine: rgba(255, 255, 255, .62);
  width: min(1000px, calc(calc(100vw / var(--z, 1)) - 64px)); min-height: min(596px, calc(calc(100dvh / var(--z, 1)) - 32px)); max-height: calc(calc(100dvh / var(--z, 1)) - 32px); border-radius: 28px; overflow: hidden; background: var(--bg);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .08), 0 50px 120px -30px rgba(0, 0, 0, .9); }
.wel[open] { display: grid; grid-template-columns: 440px minmax(0, 1fr); animation: welRise 480ms var(--ease-out) 40ms both; }
.wel::backdrop { background: rgba(8, 9, 10, .74); backdrop-filter: blur(10px) saturate(1.2); -webkit-backdrop-filter: blur(10px) saturate(1.2); }
.wel[open]::backdrop { animation: fadeIn 260ms ease-out; }
@keyframes welRise { from { opacity: 0; transform: translateY(24px) scale(.97); } }
@keyframes welUp { from { opacity: 0; transform: translateY(12px); } }

/* the stage: dark, pink and magenta light, halftone, the card in the middle */
.wel__stage { position: relative; display: grid; place-items: center; overflow: hidden; perspective: 1100px; isolation: isolate;
  background: radial-gradient(60% 50% at 30% 18%, rgba(255, 77, 174, .38), transparent 70%), radial-gradient(60% 50% at 80% 90%, rgba(252, 1, 135, .34), transparent 70%), #161719; }
.wel__stage::before { content: ''; position: absolute; inset: 0; z-index: -1; opacity: .6;
  background-image: radial-gradient(rgba(255, 255, 255, .10) 1px, transparent 1.6px); background-size: 14px 14px;
  -webkit-mask-image: radial-gradient(closest-side, transparent 30%, #000 110%); mask-image: radial-gradient(closest-side, transparent 30%, #000 110%); }
.wel__stage::after { content: ''; position: absolute; inset: -20%; z-index: -1; opacity: .5; transform: rotate(-24deg);
  background: linear-gradient(90deg, transparent 18%, rgba(255, 77, 174, .22) 19%, transparent 26%, transparent 70%, rgba(252, 1, 135, .2) 71%, transparent 78%); }
.wel__wrap { transform-style: preserve-3d; animation: welDeal 1100ms var(--ease-spring) 200ms both, welSway 6s ease-in-out 1500ms infinite; }
@keyframes welDeal { 0% { opacity: 0; transform: translateY(80px) rotateY(-120deg) rotateX(20deg) scale(.7); } 50% { opacity: 1; } 100% { transform: rotateY(-12deg) rotateX(5deg) rotateZ(-2deg); } }
@keyframes welSway { 0%, 100% { transform: rotateY(-12deg) rotateX(5deg) rotateZ(-2deg); } 50% { transform: rotateY(8deg) rotateX(2deg) rotateZ(-1deg); } }

/* the card: a pink → magenta foil frame, a near-black face (the pull card's look) */
.wel__card { --w: 290px; position: relative; width: var(--w); aspect-ratio: 5 / 7; border-radius: 20px; padding: 9px;
  background: conic-gradient(from 210deg at 50% 50%, #FF4DAE, #FFB3C8, #FC0187, #8F4BFF, #FF9AD5, #FF4DAE, #FFD6E3, #FC0187, #FF4DAE);
  box-shadow: 0 2px 0 rgba(255, 255, 255, .5) inset, 0 40px 70px -24px rgba(0, 0, 0, .9), 0 0 60px -6px rgba(255, 77, 174, .6); }
.wel__face { position: relative; height: 100%; border-radius: 13px; overflow: hidden; display: flex; flex-direction: column; padding: 10px;
  background: repeating-radial-gradient(circle at 50% 120%, rgba(255, 255, 255, .035) 0 1px, transparent 1px 7px), linear-gradient(180deg, #1A1B1E, #0E0F10);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .12); }
.wel__top { display: flex; align-items: center; justify-content: space-between; padding: 2px 4px 8px; }
.wel__wm { display: block; height: 22px; width: auto; }
.wel__tag { padding: 4px 8px; border-radius: 6px; font-size: 9px; font-weight: 800; text-transform: uppercase; line-height: 1; color: #121314;
  background: linear-gradient(90deg, #FFC4D4, #FF4DAE 45%, #FC0187); }
/* the window: her Rare clip, ringed in the Rare tier colour */
.wel__win { position: relative; flex: 1; min-height: 0; border-radius: 9px; overflow: hidden; background: #0E0F10; box-shadow: 0 0 0 1.5px var(--t1, rgba(255, 179, 200, .8)), 0 0 18px -4px var(--t1, transparent); }
.wel__poster, .wel__vid { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 12%; }
.wel__vid { opacity: 0; transition: opacity 300ms ease-out; }
.wel__vid.is-on { opacity: 1; }
.wel__win::after { content: ''; position: absolute; inset: 0; pointer-events: none; background: linear-gradient(180deg, transparent 58%, rgba(14, 15, 16, .88)); }
.wel__tier { position: absolute; left: 8px; top: 8px; z-index: 1; height: 20px; padding: 0 8px; font-size: 9px; box-shadow: 0 4px 12px -4px rgba(0, 0, 0, .6); }
.wel__tier:empty { display: none; }
.wel__name { position: absolute; left: 10px; bottom: 8px; z-index: 1; font-size: 12px; font-weight: 800; line-height: 1.15; text-shadow: 0 1px 6px rgba(0, 0, 0, .5); }
.wel__name small { display: block; font-size: 10px; color: var(--wel-muted); font-weight: 700; }
.wel__plate { padding: 10px 4px 2px; display: flex; align-items: flex-end; justify-content: space-between; gap: 8px; }
/* the printed number, stamped in metal foil (the pull card's .pc-tier does the same) */
.wel__big { flex: 0 0 auto; font-family: var(--display); font-weight: 900; font-size: 38px; line-height: .86; text-transform: uppercase;
  background: linear-gradient(180deg, #fff 0%, #FFC4D4 38%, #FF4DAE 70%, #FC0187 100%); -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 2px 0 rgba(0, 0, 0, .5)); }
.wel__lbl { flex: 0 0 auto; white-space: nowrap; text-align: right; font-size: 9px; font-weight: 800; line-height: 1.25; text-transform: uppercase; color: rgba(255, 255, 255, .85); }
.wel__lbl b { display: block; font-family: var(--display); font-size: 12px; font-weight: 900; color: #fff; }
.wel__holo { position: absolute; inset: 0; border-radius: 20px; pointer-events: none; mix-blend-mode: color-dodge; opacity: .55;
  background: linear-gradient(115deg, transparent 0%, rgba(255, 77, 174, .5) 25%, rgba(143, 75, 255, .45) 45%, rgba(26, 207, 255, .35) 60%, transparent 80%);
  background-size: 250% 250%; animation: welHolo 6s ease-in-out 1500ms infinite alternate; }
@keyframes welHolo { from { background-position: 0% 0%; } to { background-position: 100% 100%; } }
.wel__shine { position: absolute; inset: 0; border-radius: 20px; overflow: hidden; pointer-events: none; }
.wel__shine::before { content: ''; position: absolute; inset: -30% -80%; background: linear-gradient(105deg, transparent 42%, rgba(255, 255, 255, .55) 50%, transparent 58%);
  transform: translateX(-60%); animation: welSweep 1100ms ease-in-out 1000ms both, welSweep 1100ms ease-in-out 4.6s infinite; }
@keyframes welSweep { from { transform: translateX(-60%); } to { transform: translateX(60%); } }

/* the right column: the words and the doubling */
.wel__side { position: relative; display: flex; flex-direction: column; padding: 28px 40px 22px; min-width: 0; min-height: 0; overflow-y: auto; }
.wel__x { position: absolute; top: 18px; right: 18px; z-index: 2; display: grid; place-items: center; width: 44px; height: 44px; border: 0; border-radius: 999px; color: #fff; cursor: pointer;
  background: rgba(255, 255, 255, .06); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .16); }
.wel__x:hover { background: rgba(255, 255, 255, .14); }
/* Luke, 13 Nov: "this pill and dot needs to go ... needs to just be the words" */
.wel__kick { margin: 6px 0 0; font-size: 13px; font-weight: 800; line-height: 1; text-transform: uppercase; color: var(--pink); animation: welUp 400ms var(--ease-out) 500ms both; }
.wel__h { margin: 16px 0 0; padding-right: 48px; font-family: var(--display); font-weight: 900; font-size: 34px; line-height: 1.02; text-transform: uppercase; text-wrap: balance;
  animation: welUp 400ms var(--ease-out) 560ms both; }
.wel__h b { color: var(--pink); font-weight: 900; }
.wel__sub { margin: 12px 0 0; max-width: 40ch; color: var(--wel-muted); font-size: 15px; animation: welUp 400ms var(--ease-out) 620ms both; }
.wel__sub b { color: #fff; }
.wel__dbl { margin-top: 22px; display: grid; grid-template-columns: 132px minmax(0, 1fr); align-items: center; gap: 18px; padding: 14px 20px 14px 14px; border-radius: 22px;
  background: var(--surface); box-shadow: inset 0 0 0 1px rgba(var(--gem-rgb), .45), 0 20px 50px -20px rgba(var(--gem-rgb), .55); animation: welUp 400ms var(--ease-out) 680ms both; }
.wel__art { position: relative; width: 132px; height: 132px; }
.wel__art::before { content: ''; position: absolute; inset: 0; border-radius: 50%; background: radial-gradient(closest-side, rgba(var(--gem-rgb), .5), transparent); }
.wel__art img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.wel__bag { animation: welBagOut 380ms ease-in 1650ms both; }
.wel__chest { animation: welChestIn 620ms var(--ease-spring) 1900ms both; }
@keyframes welBagOut { to { opacity: 0; transform: scale(.6) translateY(10px); } }
@keyframes welChestIn { from { opacity: 0; transform: scale(.4) rotate(-8deg); } }
.wel__spark { position: absolute; width: 16px; height: 16px; background: #fff; opacity: 0; clip-path: polygon(50% 0, 60% 40%, 100% 50%, 60% 60%, 50% 100%, 40% 60%, 0 50%, 40% 40%);
  filter: drop-shadow(0 0 4px #fff); animation: welBurst 900ms ease-out 1950ms both; }
.wel__spark:nth-of-type(1) { top: 6%; left: 8%; }
.wel__spark:nth-of-type(2) { top: 2%; right: 4%; width: 12px; height: 12px; animation-delay: 2050ms; }
.wel__spark:nth-of-type(3) { bottom: 10%; right: 0; width: 10px; height: 10px; animation-delay: 2120ms; }
.wel__spark:nth-of-type(4) { bottom: 4%; left: 2%; width: 11px; height: 11px; animation-delay: 2000ms; }
@keyframes welBurst { 0% { opacity: 0; transform: scale(0) rotate(0); } 30% { opacity: 1; transform: scale(1.3) rotate(45deg); } 100% { opacity: 0; transform: scale(.4) rotate(90deg); } }
.wel__txt { display: grid; gap: 6px; min-width: 0; }
.wel__dlbl { font-size: 12px; font-weight: 800; text-transform: uppercase; color: var(--wel-muted); }
.wel__dlbl b { color: var(--go); }
.wel__n { display: flex; align-items: center; gap: 8px; font-family: var(--display); font-weight: 900; font-size: 56px; line-height: .9; font-variant-numeric: tabular-nums; }
.wel__n img { width: 40px; height: 40px; filter: drop-shadow(0 0 10px rgba(var(--gem-rgb), .8)); }
.wel__count { display: inline-block; font-weight: 900; }
.wel__count.is-pop { animation: welPop 520ms var(--ease-spring) both; }
@keyframes welPop { 40% { transform: scale(1.14); } }
.wel__eq { font-size: 14px; font-weight: 700; color: var(--wel-muted); }
.wel__eq em { font-style: normal; color: var(--pink); font-weight: 800; }
/* more first deposits, and the limit */
.wel__more { margin-top: 14px; display: flex; flex-wrap: wrap; gap: 8px; animation: welUp 400ms var(--ease-out) 760ms both; }
.wel__more span { display: inline-flex; align-items: center; gap: 5px; min-height: 32px; padding: 0 12px; border-radius: 999px; font-size: 13px; font-weight: 800; white-space: nowrap;
  background: var(--chip-bg); box-shadow: inset 0 0 0 1px var(--chip-ring); }
.wel__more span b { color: var(--go); }
.wel__more img { width: 15px; height: 15px; }
.wel__more .wel__nl { background: rgba(255, 77, 174, .14); box-shadow: inset 0 0 0 1px rgba(255, 77, 174, .5); }
.wel__ref { margin: 12px 0 0; font-size: 13px; color: var(--wel-muted); }
.wel__ref b { color: #fff; }
.wel__ref[hidden] { display: none; }
.wel__acts { margin-top: auto; padding-top: 18px; display: grid; gap: 4px; animation: welUp 400ms var(--ease-out) 840ms both; }
.wel__row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 12px; }
.wel__go { position: relative; overflow: hidden; display: flex; align-items: center; justify-content: center; gap: .35em; width: 100%; min-height: 60px; padding: 0 20px; cursor: pointer;
  border: 3.5px solid #1F2123; border-radius: 999px; font: inherit; font-size: 19px; line-height: 1; font-weight: 800; text-transform: uppercase; color: #fff; text-shadow: 0 2px 0 rgba(31, 33, 35, .55);
  background: linear-gradient(180deg, rgba(255, 255, 255, .16) 0%, transparent 46%, rgba(80, 0, 40, .22) 100%), linear-gradient(90deg, var(--pink), var(--magenta));
  box-shadow: 0 0 0 4px #FFF6EA, 0 7px 0 3px rgba(0, 0, 0, .38), 0 18px 44px -12px rgba(255, 77, 174, .75);
  transition: transform 140ms cubic-bezier(.22, .8, .36, 1), filter 150ms; -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
.wel__go::before { content: ''; position: absolute; left: 14px; right: 14px; top: 3px; height: 42%; pointer-events: none;
  border-radius: 999px 999px 40px 40px / 999px 999px 14px 14px; background: linear-gradient(180deg, rgba(255, 255, 255, .5), rgba(255, 255, 255, .08) 70%, transparent); }
.wel__go > * { position: relative; }
@media (hover: hover) { .wel__go:hover { transform: translateY(-2px); filter: brightness(1.06); } }
.wel__go:active { transform: translateY(2px); }
.wel__go:focus-visible { outline: 2px solid #fff; outline-offset: 7px; }
.wel__later { display: block; margin: 0 auto; min-height: 44px; padding: 0 16px; border: 0; background: none; color: var(--wel-muted); cursor: pointer;
  font: inherit; font-size: 14px; font-weight: 700; text-decoration: underline; text-underline-offset: 4px; text-decoration-color: rgba(255, 255, 255, .35); }
.wel__later:hover { color: #fff; }
.wel__x:focus-visible, .wel__later:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
.wel__fine { margin: 8px 0 0; font-size: 12px; line-height: 1.45; color: var(--wel-fine); text-wrap: balance; }

/* phone and tablet: a bottom sheet, the card standing up out of its top edge */
@media (max-width: 899px) {
  .wel { inset: auto 0 0 0; margin: auto auto 0; width: 100%; max-width: 560px; height: auto; min-height: 0; max-height: calc(calc(100dvh / var(--z, 1)) - 140px); overflow: visible; border-radius: 26px 26px 0 0; }
  .wel[open] { grid-template-columns: minmax(0, 1fr); animation: welSheet 460ms var(--ease-out) both; }
  @keyframes welSheet { from { transform: translateY(100%); } }
  .wel::before { content: ''; position: absolute; top: 8px; left: 50%; width: 36px; height: 4px; margin-left: -18px; border-radius: 2px; background: rgba(255, 255, 255, .2); z-index: 3; }
  .wel::after { content: ''; position: absolute; top: -60px; left: 50%; width: 320px; height: 200px; margin-left: -160px; z-index: -1; pointer-events: none;
    background: radial-gradient(closest-side, rgba(255, 77, 174, .45), transparent); }
  .wel__stage { position: absolute; left: 0; right: 0; top: -150px; height: 280px; background: none; overflow: visible; pointer-events: none; z-index: 4; }   /* over the sheet's handle */
  .wel__stage::before, .wel__stage::after { display: none; }
  .wel__card { --w: 172px; padding: 6px; border-radius: 14px; }
  .wel__face { border-radius: 9px; padding: 7px; }
  .wel__holo, .wel__shine { border-radius: 14px; }
  .wel__wm { height: 14px; }
  .wel__tag { font-size: 7px; padding: 3px 5px; }
  .wel__top { padding: 1px 2px 5px; }
  .wel__win { border-radius: 7px; }
  .wel__tier { left: 5px; top: 5px; height: 15px; padding: 0 5px; font-size: 7px; }
  .wel__big { font-size: 22px; }
  .wel__lbl { font-size: 6px; }
  .wel__lbl b { font-size: 7px; }
  .wel__name { font-size: 9px; left: 7px; bottom: 5px; }
  .wel__name small { font-size: 8px; }
  .wel__plate { padding: 6px 2px 1px; }
  .wel__side { max-height: calc(calc(100dvh / var(--z, 1)) - 140px); padding: 146px 20px calc(10px + env(safe-area-inset-bottom)); text-align: center; align-items: stretch; }
  .wel__x { top: 14px; right: 12px; }
  .wel__kick { align-self: center; margin-top: 0; }
  .wel__h { margin-top: 14px; padding: 0; font-size: 24px; }
  .wel__sub { margin: 8px auto 0; font-size: 14px; max-width: 32ch; }
  .wel__dbl { margin-top: 16px; grid-template-columns: 92px minmax(0, 1fr); gap: 12px; padding: 10px 16px 10px 10px; text-align: left; border-radius: 18px; }
  .wel__art { width: 92px; height: 92px; }
  .wel__n { font-size: 40px; }
  .wel__n img { width: 30px; height: 30px; }
  .wel__eq { font-size: 13px; }
  .wel__dlbl { font-size: 11px; }
  .wel__more { justify-content: center; margin-top: 12px; gap: 6px; flex-wrap: nowrap; }
  .wel__more span { font-size: 11.5px; min-height: 30px; padding: 0 9px; gap: 4px; }
  .wel__more img { width: 13px; height: 13px; }
  .wel__acts { padding-top: 18px; }
  .wel__row { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .wel__fine { margin-top: 2px; text-align: center; }
  .wel__go { font-size: 18px; min-height: 58px; }
}
@media (max-width: 899px) and (max-height: 700px) {
  .wel__stage { top: -130px; }
  .wel__card { --w: 140px; padding: 5px; }
  .wel__face { padding: 6px; }
  .wel__wm { height: 12px; }
  .wel__tag { font-size: 6px; padding: 3px 4px; }
  .wel__big { font-size: 18px; }
  .wel__lbl { font-size: 5px; }
  .wel__lbl b { font-size: 6px; }
  .wel__name { font-size: 8px; }
  .wel__name small { font-size: 7px; }
  .wel__side { padding-top: 128px; }
}
/* reduced motion: no deal, sway, sweep or count; the clip stays a still (app.js shows the poster) */
@media (prefers-reduced-motion: reduce) {
  .wel[open], .wel[open]::backdrop, .wel__wrap, .wel__holo, .wel__shine::before, .wel__kick, .wel__h, .wel__sub, .wel__dbl, .wel__more, .wel__acts, .wel__spark, .wel__count.is-pop { animation: none; }
  .wel__wrap { transform: rotateY(-12deg) rotateX(5deg) rotateZ(-2deg); }
  .wel__bag { animation: none; opacity: 0; }
  .wel__chest { animation: none; }
  .wel__go, .wel__vid { transition: none; }
}


/* ============================================================
   YOUR RANKS (Luke, 13 Nov; app.js renderRanks; mockups tools/mockups/ranks)
   ============================================================ */
.rkring { display: block; }
/* phone: her rank under her name, a ring round her picture (no @handle or 18+ here: shown elsewhere) */
.mhead__av { position: relative; flex: 0 0 auto; display: grid; }
.mhead__ring { position: absolute; inset: -6px; pointer-events: none; }
.mhead__ring:empty { display: none; }
.mhead__ring .rkring { width: 100%; height: 100%; }
.mhead__rank { margin: 3px 0 0; display: grid; gap: 1px; line-height: 1.15; }
.mhead__rank[hidden] { display: none; }
.mhead__rank b { font-size: 12px; font-weight: 900; letter-spacing: .02em; text-transform: uppercase; color: #fff; }
.mhead__rank span { font-size: 12px; font-weight: 700; color: var(--pink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* phone: sound is a plain icon by your chip (no pill); off = a red diagonal line (Luke, 13 Nov) */
@media (max-width: 1023px) {
  #sndTop { display: inline-grid; place-items: center; width: 40px; height: 40px; border: 0; background: none; box-shadow: none; color: #fff; }
  #sndTop .snd-off { display: none; }
  #sndTop[aria-pressed="false"] .snd-on { opacity: 1; transform: none; filter: none; position: static; }
  #sndTop[aria-pressed="false"] { color: var(--muted); }
  #sndTop[aria-pressed="false"]::after { content: ''; position: absolute; left: 9px; right: 9px; top: 50%; height: 2.5px; border-radius: 2px;
    background: #FF3B3B; transform: rotate(-45deg); box-shadow: 0 0 0 1.5px var(--bg-deep); pointer-events: none; }
  /* under the packs: no Sound chip (it is in the top bar); See odds is plain text on the left */
  #sndCta { display: none; }
  .cta__more { justify-content: flex-start; padding: 0 20px; }
  #oddsBtn { min-height: 44px; padding: 0 4px; border: 0; background: none; box-shadow: none; color: var(--muted); font-size: 13px; font-weight: 800; }
  #oddsBtn:hover { color: #fff; }
}
@media (min-width: 1024px) {
  /* desktop: your site rank between the sound button and your name */
  .srank:not([hidden]) { display: inline-flex; align-items: center; gap: 8px; height: 44px; padding: 0 14px 0 5px; border-radius: 22px; flex: 0 0 auto;
    background: var(--chip-bg); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .12); color: #fff; }
  .srank__ic { position: relative; display: grid; place-items: center; width: 34px; height: 34px; color: var(--rank-ice); }
  .srank__ic .rkring { position: absolute; inset: 0; }
  .srank__t { display: grid; line-height: 1.1; }
  .srank__t b { font-size: 13px; font-weight: 900; text-transform: uppercase; }
  .srank__t span { font-size: 10.5px; font-weight: 700; color: var(--muted); white-space: nowrap; }
  /* desktop: your rank with her climbs up the right of her packs (placed by app.js placeClimb) */
  .stage { position: relative; }
  .climb:not([hidden]) { position: absolute; z-index: 4; right: 3px; top: 84px; height: 520px; width: 112px; display: flex; flex-direction: column; align-items: flex-end; gap: 12px; pointer-events: none; }
  .climb__end { margin: 0; display: grid; justify-items: end; gap: 1px; text-align: right; }
  .climb__k { font-size: 10px; font-weight: 800; text-transform: uppercase; color: var(--faint); }
  .climb__end b { font-family: var(--display); font-size: 16px; font-weight: 900; line-height: 1.1; text-transform: uppercase; color: #fff; white-space: nowrap; }
  .climb__xp { font-size: 12px; font-weight: 700; color: var(--pink); }
  .climb__track { position: relative; flex: 1; width: 6px; margin-right: 19px; border-radius: 6px; background: rgba(255, 255, 255, .08); box-shadow: inset 0 0 0 1px var(--line); }
  .climb__fill { position: absolute; left: 0; right: 0; bottom: 0; border-radius: 6px; background: linear-gradient(180deg, #FF4DAE, #9E3AFF); box-shadow: 0 0 18px rgba(255, 77, 174, .45);
    transition: height 600ms var(--ease-out); }
  .climb__rungs { list-style: none; margin: 0; padding: 0; position: absolute; inset: 0; }
  .climb__rung { position: absolute; left: 50%; bottom: var(--y); width: 12px; height: 12px; border-radius: 50%; transform: translate(-50%, 50%);
    background: #1F2123; box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .22); }
  .climb__rung.is-done { background: #FF4DAE; box-shadow: 0 0 0 3px rgba(255, 77, 174, .25); }
  .climb__tip { position: absolute; left: 50%; bottom: var(--y); width: 16px; height: 16px; border-radius: 50%; background: #fff; transform: translate(-50%, 50%);
    box-shadow: 0 0 0 4px #FF4DAE, 0 0 18px 4px rgba(255, 77, 174, .6); transition: bottom 600ms var(--ease-out); }
}
@media (prefers-reduced-motion: reduce) { .climb__fill, .climb__tip { transition: none; } }
