/* ================================================================
   GLOW SLIDER (assets/glow.js) and the rating controls around it.
   Transform, opacity and clip-path only; the spring is one curve.
   ================================================================ */
:root { --gs-spring: cubic-bezier(.34, 1.56, .64, 1); }

.gs {
  --gs-c: var(--gold);
  position: relative; flex: 1 1 auto; min-width: 0; height: 56px;
  display: flex; align-items: center;
  touch-action: none; -webkit-user-select: none; user-select: none; cursor: grab;
  -webkit-tap-highlight-color: transparent;
}
.gs.gs-drag { cursor: grabbing; }
/* The real input: invisible, but focusable and the source of truth. */
.gs .gs-native { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; pointer-events: none; }

.gs-track {
  position: relative; width: 100%; height: 46px; border-radius: 999px; overflow: hidden;
  background: rgba(255,255,255,.045);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.09), inset 0 6px 14px rgba(0,0,0,.35);
  transition: transform 560ms var(--gs-spring), box-shadow 300ms ease;
  will-change: transform;
}
.gs-drag .gs-track { transition: box-shadow 300ms ease; }
.gs-dots { position: absolute; inset: 0 22px; display: flex; align-items: center; justify-content: space-between; }
.gs-dots i { width: 4px; height: 4px; border-radius: 50%; background: rgba(255,255,255,.22); }
.gs-fill {
  position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(90deg, color-mix(in srgb, var(--gs-c) 18%, transparent), color-mix(in srgb, var(--gs-c) 72%, transparent) 70%, color-mix(in srgb, var(--gs-c) 92%, #fff));
  box-shadow: inset 0 0 18px color-mix(in srgb, var(--gs-c) 40%, transparent);
  transition: clip-path 420ms var(--gs-spring);
}
.gs-drag .gs-fill { transition: none; }
/* Sparkles drifting inside the fill. A pixel tile, so the loop never snaps. */
.gs-sparks {
  position: absolute; inset: 0; opacity: .7;
  background-image:
    radial-gradient(1.2px 1.2px at 12px 14px, #fff, transparent 60%),
    radial-gradient(1px 1px at 44px 30px, #fff, transparent 60%),
    radial-gradient(1.4px 1.4px at 78px 20px, #fff, transparent 60%),
    radial-gradient(1px 1px at 101px 36px, #fff, transparent 60%);
  background-size: 120px 46px;
  animation: gsDrift 3.2s linear infinite;
}
@keyframes gsDrift { to { background-position: 120px 0; } }

.gs-thumb {
  position: absolute; left: 0; top: 50%; z-index: 2; margin-top: -19px;
  height: 38px; min-width: 64px; padding: 0 16px; border-radius: 999px;
  display: grid; place-items: center; pointer-events: none;
  background: linear-gradient(180deg, #fff, #f1ede6);
  color: #15120d; font: 700 16px/1 var(--font-mono); font-variant-numeric: tabular-nums;
  box-shadow: 0 0 0 1px rgba(255,255,255,.7), 0 2px 8px rgba(0,0,0,.35),
              0 0 22px 2px color-mix(in srgb, var(--gs-c) 65%, transparent);
  transition: transform 520ms var(--gs-spring), margin-left 520ms var(--gs-spring), box-shadow 260ms ease;
  will-change: transform;
}
.gs-thumb::before {   /* the bloom behind the pill */
  content: ''; position: absolute; inset: -18px -26px; z-index: -1; border-radius: 999px; pointer-events: none;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--gs-c) 55%, transparent), transparent);
  opacity: .55; transition: opacity 260ms ease, transform 260ms ease;
}
.gs-drag .gs-thumb { transition: box-shadow 200ms ease; box-shadow: 0 0 0 1px #fff, 0 4px 12px rgba(0,0,0,.4), 0 0 30px 6px color-mix(in srgb, var(--gs-c) 80%, transparent); }
.gs-drag .gs-thumb::before { opacity: 1; transform: scale(1.25); }
.gs-max .gs-track { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--gs-c) 80%, transparent), 0 0 26px color-mix(in srgb, var(--gs-c) 45%, transparent); }

/* Letting go: one ring leaves the pill. */
.gs-bloom .gs-thumb::after {
  content: ''; position: absolute; inset: -2px; border-radius: inherit; pointer-events: none;
  box-shadow: 0 0 0 2px var(--gs-c); animation: gsRing 560ms ease-out forwards;
}
@keyframes gsRing { from { opacity: .9; transform: scale(1); } to { opacity: 0; transform: scale(1.6, 2); } }
.gs:has(.gs-native:focus-visible) .gs-track { outline: 2px solid var(--gs-c); outline-offset: 3px; }


.gs-ym { margin: 4px 0 2px; }

@media (prefers-reduced-motion: reduce) {
  html:not([data-motion="full"]) .gs-sparks { animation: none; }
  html:not([data-motion="full"]) .gs-track, html:not([data-motion="full"]) .gs-thumb, html:not([data-motion="full"]) .gs-fill { transition-duration: 1ms !important; }
}

/* ---- For You: the same light on its native slider ----------------------
   That range must keep `touch-action: pan-y` so a vertical swipe still moves
   the feed, so it keeps its own input and only gains the glow. */
.fy-rate input[type="range"]::-webkit-slider-thumb { box-shadow: 0 0 0 4px rgba(0,0,0,.28), 0 0 18px 4px var(--fy-tint, #efb927), 0 0 44px 10px color-mix(in srgb, var(--fy-tint, #efb927) 35%, transparent); }
.fy-rate input[type="range"]:active::-webkit-slider-thumb { transform: scale(1.22); }

/* ---- Mobile: Rate sits where a thumb already is ------------------------ */
@media (max-width: 699px) {
  #view-album-detail #rate-album-btn {
    position: fixed; z-index: 150; left: 50%; transform: translateX(-50%);
    bottom: calc(var(--nav-h) + var(--s3) + env(safe-area-inset-bottom, 0px));
    width: calc(100% - var(--gutter) * 2); max-width: 460px; min-height: 52px;
    border-radius: 18px; font-size: 16px;
    box-shadow: 0 14px 34px -10px rgba(0,0,0,.8), 0 0 28px -6px var(--gold-glow);
    transition: bottom 260ms var(--ease), transform 160ms var(--ease);
  }
  #view-album-detail #rate-album-btn:active { transform: translateX(-50%) scale(.98); }
  /* The player bar takes that slot when something is playing; Rate rides above it. */
  body:has(#player-bar.up) #view-album-detail #rate-album-btn { bottom: calc(var(--nav-h) + var(--s3) + 76px + env(safe-area-inset-bottom, 0px)); }
  #view-album-detail { padding-bottom: 76px; }
}

/* ---- The Spin ----------------------------------------------------------
   The reel's motion lives in the Draw module (WAAPI keyframes); this is the
   light around it. Box-shadow on the window, transform on one tile. */
.draw-window { transition: box-shadow 600ms ease, border-color 400ms ease; }
.draw-window.charge-epic      { box-shadow: 0 0 46px rgba(196,107,255,.45), inset 0 0 40px rgba(196,107,255,.18); border-color: #c46bff; }
.draw-window.charge-legendary { box-shadow: 0 0 60px rgba(255,200,70,.5),  inset 0 0 46px rgba(255,200,70,.2);  border-color: #ffd24a; }
.draw-window.charge-mythic    { box-shadow: 0 0 80px rgba(255,45,111,.6),  inset 0 0 56px rgba(255,45,111,.24); border-color: #ff2d6f; animation: drawCharge .5s ease-in-out infinite alternate; }
@keyframes drawCharge { to { box-shadow: 0 0 110px rgba(255,45,111,.75), inset 0 0 70px rgba(255,45,111,.3); } }
.draw-needle { transform-origin: 50% 0; }
.draw-tile { position: relative; }
.draw-tile.dt-won { z-index: 1; animation: dtWon 720ms cubic-bezier(.34,1.56,.64,1) both; border-color: currentColor; }
.draw-tile.t-rare.dt-won      { color: #2fe0ff; box-shadow: 0 0 26px rgba(47,224,255,.45); }
.draw-tile.t-epic.dt-won      { color: #c46bff; box-shadow: 0 0 32px rgba(196,107,255,.55); }
.draw-tile.t-legendary.dt-won { color: #ffd24a; box-shadow: 0 0 40px rgba(255,210,74,.6); }
.draw-tile.t-mythic.dt-won    { color: #ff2d6f; box-shadow: 0 0 52px rgba(255,45,111,.7); }
.draw-tile.t-common.dt-won    { color: rgba(255,255,255,.45); }
@keyframes dtWon { 0% { transform: scale(1); } 45% { transform: scale(1.1); } 100% { transform: scale(1.05); } }
/* One pass of light across the window as it lands. */
.draw-window.landed::before {
  content: ''; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  background: linear-gradient(100deg, transparent 35%, rgba(255,255,255,.22) 50%, transparent 65%);
  animation: drawFlash 700ms ease-out forwards;
}
@keyframes drawFlash { from { transform: translateX(-100%); } to { transform: translateX(100%); opacity: 0; } }
/* Rays behind the biggest prizes. */
.draw-result { isolation: isolate; }
.draw-result.tier-legendary::before, .draw-result.tier-mythic::before {
  content: ''; position: absolute; left: 50%; top: 50%; width: 360px; height: 360px; margin: -180px 0 0 -180px; z-index: -1;
  border-radius: 50%; pointer-events: none; opacity: 0;
  background: repeating-conic-gradient(from 0deg, rgba(255,210,74,.22) 0 8deg, transparent 8deg 22deg);
  -webkit-mask-image: radial-gradient(closest-side, #000 20%, transparent); mask-image: radial-gradient(closest-side, #000 20%, transparent);
  animation: drawRays 9s linear infinite, drawRaysIn 600ms ease-out forwards;
}
.draw-result.tier-mythic::before { background: repeating-conic-gradient(from 0deg, rgba(255,45,111,.26) 0 7deg, rgba(47,224,255,.14) 7deg 14deg, transparent 14deg 24deg); }
@keyframes drawRays { to { transform: rotate(1turn); } }
@keyframes drawRaysIn { to { opacity: 1; } }
.draw-result.in .dr-tier { animation: drTier 600ms cubic-bezier(.2,.8,.2,1) both; }
@keyframes drTier { from { letter-spacing: .6em; opacity: 0; } }

/* The wind-up, while the server answers: the strip draws back (script), the
   needle charges and the window gathers light at its centre. Opacity and
   transform only. */
.draw-strip { position: relative; z-index: 1; }   /* above the flare, below the needle */
.draw-window.priming .draw-needle { animation: needleCharge .18s ease-in-out infinite alternate; }
@keyframes needleCharge { from { opacity: .6; } to { opacity: 1; } }
.draw-window.priming::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none; opacity: 0;
  background: radial-gradient(ellipse 34% 75% at 50% 50%, var(--gold-glow), transparent 72%);
  animation: primeGlow 360ms ease-out forwards;
}
@keyframes primeGlow { to { opacity: 1; } }
#draw-go { position: relative; }
#draw-go.charging::after {
  content: ''; position: absolute; inset: -4px; border-radius: inherit; pointer-events: none;
  box-shadow: 0 0 0 2px var(--gold), 0 0 22px var(--gold-glow);
  animation: goCharge .22s ease-in-out infinite alternate;
}
@keyframes goCharge { from { opacity: .25; } to { opacity: 1; } }

/* Speed lines over the fast stretch; the script drives its opacity. */
.draw-streak {
  position: absolute; inset: 0; z-index: 1; pointer-events: none; opacity: 0;
  background:
    repeating-linear-gradient(180deg, transparent 0 11px, rgba(255,255,255,.07) 11px 12px),
    linear-gradient(90deg, rgba(0,0,0,.45), transparent 26%, transparent 74%, rgba(0,0,0,.45));
}

/* The light behind the prize. Sits under the strip, so it shows in the gaps
   and above and below the tile — behind it, not over it. The script puts its
   centre where the prize stopped. Common gets none. */
.draw-window.hit-rare      { --dc: 47,224,255; }
.draw-window.hit-epic      { --dc: 196,107,255; }
.draw-window.hit-legendary { --dc: 255,210,74; }
.draw-window.hit-mythic    { --dc: 255,45,111; }
.draw-flare {
  position: absolute; left: 50%; top: 50%; width: 280px; height: 280px; margin: -140px 0 0 -140px;
  z-index: 0; pointer-events: none; opacity: 0; border-radius: 50%;
  background:
    radial-gradient(closest-side, rgba(var(--dc, 255,255,255), .95), rgba(var(--dc, 255,255,255), .35) 40%, transparent 72%),
    repeating-conic-gradient(rgba(var(--dc, 255,255,255), .55) 0 6deg, transparent 6deg 20deg);
  -webkit-mask-image: radial-gradient(closest-side, #000 30%, transparent);
          mask-image: radial-gradient(closest-side, #000 30%, transparent);
}
.draw-flare::after {
  content: ''; position: absolute; inset: 32%; border-radius: 50%; opacity: 0;
  border: 2px solid rgba(var(--dc, 255,255,255), .9);
}
.draw-window.landed:is(.hit-rare, .hit-epic) .draw-flare { animation: drawFlare 900ms cubic-bezier(.2,.8,.3,1) forwards; }
.draw-window.landed:is(.hit-legendary, .hit-mythic) .draw-flare { animation: drawFlareBig 1500ms cubic-bezier(.2,.8,.3,1) forwards; }
.draw-window.landed:not(.hit-common) .draw-flare::after { animation: drawRing 640ms cubic-bezier(.2,.8,.3,1) forwards; }
.draw-window.landed.hit-mythic .draw-flare {
  background:
    radial-gradient(closest-side, rgba(255,255,255,.95), rgba(255,45,111,.45) 40%, transparent 72%),
    repeating-conic-gradient(rgba(255,45,111,.6) 0 6deg, rgba(34,227,255,.45) 6deg 12deg, transparent 12deg 22deg);
}
@keyframes drawFlare { 0% { opacity: 0; transform: scale(.3); } 22% { opacity: .85; } 100% { opacity: 0; transform: scale(1.25) rotate(25deg); } }
@keyframes drawFlareBig {
  0% { opacity: 0; transform: scale(.3); } 15% { opacity: 1; transform: scale(1.05); }
  60% { opacity: .75; } 100% { opacity: 0; transform: scale(1.5) rotate(70deg); }
}
@keyframes drawRing { 0% { opacity: 1; transform: scale(.4); } 100% { opacity: 0; transform: scale(2.6); } }

/* The edges of the screen, briefly, for the two tiers worth feeling outside
   the reel. One fixed layer; its shadow paints once and only opacity moves. */
.draw-edge {
  position: fixed; inset: 0; z-index: 9998; pointer-events: none; opacity: 0;
  animation: drawEdge 1300ms ease-out forwards;
}
.draw-edge.t-legendary { box-shadow: inset 0 0 90px 6px rgba(255,200,70,.55); }
.draw-edge.t-mythic    { box-shadow: inset 0 0 110px 10px rgba(255,45,111,.6), inset 0 0 40px 2px rgba(34,227,255,.45); }
@keyframes drawEdge { 0% { opacity: 0; } 14% { opacity: 1; } 45% { opacity: .8; } 100% { opacity: 0; } }

/* The reveal, scaled by tier. Common keeps the plain rise. The shimmer has to
   stay in the list for the top two — the shorthand replaces it (trap 2). */
.draw-result.in:is(.tier-rare, .tier-epic) .dr-label { animation: drPop 520ms cubic-bezier(.34,1.56,.64,1) 60ms both; }
.draw-result.in.tier-legendary .dr-label { animation: drawShimmer 2.4s linear infinite, drPopBig 680ms cubic-bezier(.34,1.56,.64,1) 90ms both; }
.draw-result.in.tier-mythic .dr-label    { animation: drawShimmer 1.6s linear infinite, drPopBig 760ms cubic-bezier(.34,1.56,.64,1) 90ms both; }
@keyframes drPop    { from { opacity: 0; transform: scale(.7); } }
@keyframes drPopBig { from { opacity: 0; transform: scale(1.6); } }
.draw-result:is(.tier-legendary, .tier-mythic) .dr-tier { padding: 6px 12px 6px calc(12px + .26em); border-radius: 999px; }
.draw-result.tier-legendary .dr-tier { background: rgba(255,210,74,.14); box-shadow: inset 0 0 0 1px rgba(255,210,74,.5); }
.draw-result.tier-mythic .dr-tier {
  color: #fff; text-shadow: 0 0 10px #ff2d6f;
  background: linear-gradient(90deg, rgba(255,45,111,.24), rgba(177,107,255,.2), rgba(34,227,255,.22));
  box-shadow: inset 0 0 0 1px rgba(255,45,111,.6), 0 0 22px rgba(255,45,111,.35);
}

@media (prefers-reduced-motion: reduce) {
  html:not([data-motion="full"]) .draw-window.priming .draw-needle,
  html:not([data-motion="full"]) .draw-window.priming::after,
  html:not([data-motion="full"]) #draw-go.charging::after,
  html:not([data-motion="full"]) .draw-window.landed .draw-flare,
  html:not([data-motion="full"]) .draw-window.landed .draw-flare::after,
  html:not([data-motion="full"]) .draw-edge,
  html:not([data-motion="full"]) .draw-result.in .dr-label { animation: none !important; }
}
/* Motion set to reduced in Settings, whatever the system says. */
html[data-motion="none"] .draw-window.priming .draw-needle,
html[data-motion="none"] .draw-window.priming::after,
html[data-motion="none"] #draw-go.charging::after,
html[data-motion="none"] .draw-window.landed .draw-flare,
html[data-motion="none"] .draw-window.landed .draw-flare::after,
html[data-motion="none"] .draw-edge,
html[data-motion="none"] .draw-result.in .dr-label { animation: none !important; }

@media (prefers-reduced-motion: reduce) {
  html:not([data-motion="full"]) .draw-window.charge-mythic,
  html:not([data-motion="full"]) .draw-tile.dt-won,
  html:not([data-motion="full"]) .draw-window.landed::before,
  html:not([data-motion="full"]) .draw-result.tier-legendary::before,
  html:not([data-motion="full"]) .draw-result.tier-mythic::before,
  html:not([data-motion="full"]) .draw-result.in .dr-tier { animation: none !important; }
}

/* ---- Account menu: who you are, then four doors --------------------- */
.acct-menu { min-width: 248px; padding: 8px; border-radius: 18px; transform-origin: top right; }
.acct-menu.open { animation: acctIn 200ms cubic-bezier(.2,.8,.2,1); }
@keyframes acctIn { from { opacity: 0; transform: translateY(-4px) scale(.97); } }
.acct-menu-item { display: flex; align-items: center; gap: 10px; min-height: 42px; padding: 0 12px; border-radius: 11px; transition: background-color 160ms ease; }
.acct-menu-item svg { width: 16px; height: 16px; flex: none; opacity: .8; }
.acct-id { gap: 12px; min-height: 60px; padding: 8px 10px; margin-bottom: 4px; background: rgba(255,255,255,.035); }
.acct-id-av { width: 40px; height: 40px; flex: none; border-radius: 50%; overflow: hidden; display: grid; place-items: center;
  background: var(--surface-3); font: 700 15px/1 var(--font-display); color: var(--text); }
.acct-id-av img { width: 100%; height: 100%; object-fit: cover; }
.acct-id-t { display: grid; gap: 2px; min-width: 0; }
.acct-id-t b { font: 700 14.5px/1.2 var(--font-display); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.acct-id-t small { font-size: 12px; color: var(--text-faint); }
.acct-sep { height: 1px; margin: 6px 8px; background: var(--border); }
@media (prefers-reduced-motion: reduce) { html:not([data-motion="full"]) .acct-menu.open { animation: none; } }

/* ---- Hub tabs: the Crate's bar, for You and People -------------------- */
.hub-tabs { overflow-x: auto; scrollbar-width: none; flex-wrap: nowrap; }
.hub-tabs::-webkit-scrollbar { display: none; }
.hub-tabs button { flex: none !important; white-space: nowrap; }
.hub-tabs .hub-act { color: var(--text-faint); }
.hub-tabs[hidden] { display: none !important; }
/* Narrow phones: wrap into a tidy grid instead of scrolling tabs off-screen —
   a tab you have to discover by swiping is a tab nobody finds. */
@media (max-width: 520px) {
  .hub-tabs { flex-wrap: wrap; overflow: visible; gap: 4px; }
  /* Seven tabs since Passport: four over three, never three, three and an orphan. */
  .hub-tabs button { flex: 1 1 22% !important; min-width: 0; padding-inline: 4px; font-size: 12px; }
}

/* ---- For You: the glow drag in the rating tray ------------------------
   pan-y keeps a vertical swipe on the slider moving the feed; the axis
   lock in glow.js takes sideways drags. The value rides in the pill, so
   the separate numeral beside it goes. */
.gs-fy { touch-action: pan-y; height: 46px; }
.gs-fy .gs-track { height: 38px; }
.gs-fy .gs-thumb { height: 30px; min-width: 48px; margin-top: -15px; padding: 0 12px; font-size: 15px; }
.gs-fy .gs-dots { inset: 0 18px; }
.fy-rate:has(.gs-fy) output { display: none; }
.fy-rate:has(.gs-fy) { padding-block: 6px; }
