/* The Lucky Spin wheel — the reward overlay opened from the left-column
 * bubble. Split out of hud.css because the wheel is a self-contained widget
 * with its own coordinate system, and hud.css had outgrown its size budget.
 * The bubble itself (.spin-btn) stays in hud.css with the rest of the column.
 *
 * Geometry contract, shared with src/ui/Spin.js:
     * angles are degrees clockwise from 12 o'clock, where the pointer sits;
     * wedge i covers [i*--seg, (i+1)*--seg) and its label sits at the centre;
     * --seg is written by Spin.js from the reward count, so the plate, the
       spokes, the winner highlight and the labels can never disagree.
   Every size on the stage is derived from --stage: change that one number and
   the whole wheel rescales without any piece drifting off the plate. */
.spin-overlay {
  position: fixed; inset: 0; z-index: 40;
  display: flex; align-items: center; justify-content: center;
  background: rgba(10,6,18,.72);
}
.spin-box {
  --stage: 300px;
  --label-r: calc(var(--stage) * .30);   /* label radius from the hub */
  --label-w: calc(var(--stage) * .29);   /* < the 1-wedge arc, so labels never touch */
  /* Explicit width, not shrink-to-fit: the dialog used to size itself to the
     prize text, so the wheel and buttons jumped sideways the moment a result
     appeared. Sized off --stage so it tracks the wheel at every breakpoint. */
  position: relative; width: calc(var(--stage) + 56px);
  padding: 18px 26px 20px; text-align: center;
  background: linear-gradient(180deg, #2c1d44, #1d122e);
  border: 3px solid #6a4a9a; border-radius: 18px;
  box-shadow: 0 12px 40px rgba(0,0,0,.7), inset 0 0 30px rgba(139,93,240,.15);
}
/* Short or narrow viewports get a smaller wheel — everything follows --stage. */
@media (max-height: 760px) { .spin-box { --stage: 244px; padding: 14px 20px 16px; } }
@media (max-width: 430px)  { .spin-box { --stage: 232px; padding: 14px 16px 16px; } }
/* A landscape phone is the tight case: title, subtitle, wheel, result line and
   two buttons all have to clear 360px of height, and the wheel is the only piece
   that can give. Everything else on the stage tracks --stage, so this is one
   number plus the type around it. */
@media (max-height: 520px) {
  /* The chrome around the wheel — title, subtitle, result line, two buttons and
     padding — measures 181px at this type size. Deriving the stage from the
     viewport instead of pinning it means the dialog fits by construction: 170px
     of wheel on a 360px screen, 130px on a 320px one, rather than a fixed 172px
     that overflowed the short end. */
  /* Width is set independently of the wheel here. Normally `.spin-box` is
     `--stage + 56px` wide, but on a short screen the wheel shrinks to ~130px,
     which made the box narrow enough to wrap the title and subtitle — adding
     back more height than the smaller wheel saved. Fixing the width keeps that
     text on one line, so the height budget below actually holds. */
  .spin-box {
    --stage: min(172px, calc(100vh - 215px));
    width: min(320px, calc(100vw - 32px));
    padding: 10px 16px 12px;
  }
  .spin-title { font-size: 15px; letter-spacing: .1em; }
  .spin-sub { font-size: 9px; white-space: nowrap; }
  .spin-stage { margin: 8px auto 4px; }
  .spin-result { font-size: 12px; min-height: 16px; }
  .spin-actions .mbtn { font-size: 13px; padding: 9px 10px; }
  .spin-actions .mbtn.primary { font-size: 14px; padding: 10px 10px; }
}

.spin-title { font-size: 22px; font-weight: 900; letter-spacing: .14em; color: var(--gold); text-shadow: 0 2px 0 rgba(0,0,0,.8); }
.spin-sub { margin-top: 2px; font-size: 11.5px; font-weight: 700; color: var(--dim); }
.spin-stage { position: relative; width: var(--stage); height: var(--stage); margin: 14px auto 6px; }

/* The rotor is the ONLY element that turns, so the browser has a single
   composited layer to animate. overflow:hidden is the hard guarantee that no
   label can ever spill past the rim, whatever the reward text says. */
.spin-rotor {
  position: absolute; inset: 0; z-index: 1;
  border-radius: 50%; overflow: hidden;
  transform: rotate(0deg);
  will-change: transform; backface-visibility: hidden;
  transition: transform 4.2s cubic-bezier(.16,.84,.28,1);
}
/* Wedge fills — the conic-gradient itself is painted by Spin.js from CONFIG. */
.spin-plate { position: absolute; inset: 0; border-radius: 50%; }
/* Hairline spokes, centred on every wedge border by construction. */
.spin-plate::before {
  content: ''; position: absolute; inset: 0; border-radius: 50%;
  background: repeating-conic-gradient(from -.35deg at 50% 50%,
    rgba(255,238,196,.42) 0deg .7deg, transparent .7deg var(--seg, 60deg));
}
/* Gloss and rim vignette, over the spokes, so the plate reads as a physical
   disc rather than a flat pie chart. */
.spin-plate::after {
  content: ''; position: absolute; inset: 0; border-radius: 50%;
  background:
    radial-gradient(circle at 32% 24%, rgba(255,255,255,.20), rgba(255,255,255,0) 48%),
    radial-gradient(circle at 50% 50%, rgba(0,0,0,0) 56%, rgba(0,0,0,.45) 100%);
}
/* The winning wedge, lit for a beat once the wheel stops. --win is the wedge's
   start angle; it rides inside the rotor, so it stays on its prize. */
.spin-flash {
  position: absolute; inset: 0; z-index: 1; border-radius: 50%;
  opacity: 0; pointer-events: none;
  background: conic-gradient(from var(--win, 0deg),
    rgba(255,244,200,.60) 0deg,
    rgba(255,244,200,.12) var(--seg, 60deg),
    transparent var(--seg, 60deg));
}
.spin-rotor.won .spin-flash { animation: spin-win .85s ease-out 3; }
@keyframes spin-win { 0%, 100% { opacity: 0; } 40% { opacity: 1; } }

/* One label per reward. Spin.js sets --a to the wedge's centre angle; the
   element swings out to the label radius and STAYS turned with its wedge —
   it is deliberately not stood back upright. A label pinned upright would
   inherit the rotor's landing angle and end the spin lying on its side, which
   is what made the wheel look scrambled the moment it stopped. Turned with
   the wedge, label i sits at (rotor + --a) on screen, and the wedge under the
   pointer is by definition at rotor = -(--a) — so the prize you have just won
   always reads perfectly upright at the top, and the rest fan out like a real
   wheel. column-reverse then puts the widest line (the sub) at the rim, where
   the wedge is widest, and the icon nearest the narrow hub end. */
.spin-seg {
  position: absolute; left: 50%; top: 50%; z-index: 2;
  width: var(--label-w);
  transform:
    translate(-50%, -50%)
    rotate(var(--a, 0deg))
    translateY(calc(var(--label-r) * -1));
  display: flex; flex-direction: column-reverse; align-items: center; gap: 1px;
  font-weight: 900; color: #fff;
  text-shadow: 0 2px 0 rgba(0,0,0,.8), 0 0 7px rgba(0,0,0,.55);
  pointer-events: none;
}
.spin-seg .sg-ico { font-size: max(15px, calc(var(--stage) * .068)); line-height: 1; }
.spin-seg .sg-label { font-size: max(9px, calc(var(--stage) * .033)); line-height: 1.15; letter-spacing: .02em; white-space: nowrap; }
.spin-seg .sg-sub { font-size: max(8px, calc(var(--stage) * .029)); line-height: 1.15; font-weight: 700; opacity: .88; white-space: nowrap; }

/* Static frame: rim over the plate edge, hub over the label roots, pointer on
   top of everything. None of it moves, so none of it can shimmer mid-spin. */
.spin-ring {
  position: absolute; inset: 0; z-index: 3; border-radius: 50%;
  pointer-events: none;
  border: 7px solid #3a2a5a;
  box-shadow:
    0 0 0 3px #150c1e,
    0 10px 26px rgba(0,0,0,.6),
    inset 0 0 0 2px rgba(255,236,196,.16);
}
.spin-box.spinning .spin-ring { animation: spin-rim .75s ease-in-out infinite; }
@keyframes spin-rim {
  0%, 100% { box-shadow: 0 0 0 3px #150c1e, 0 10px 26px rgba(0,0,0,.6), inset 0 0 0 2px rgba(255,236,196,.16), 0 0 12px rgba(255,196,84,.30); }
  50%      { box-shadow: 0 0 0 3px #150c1e, 0 10px 26px rgba(0,0,0,.6), inset 0 0 0 2px rgba(255,236,196,.55), 0 0 26px rgba(255,196,84,.85); }
}
.spin-hub {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); z-index: 4;
  width: calc(var(--stage) * .155); height: calc(var(--stage) * .155); border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #ffe9b0, #b8862c 68%, #6a4a12);
  border: 3px solid #150c1e;
  box-shadow: 0 0 0 2px rgba(255,236,196,.22), 0 4px 10px rgba(0,0,0,.6);
  pointer-events: none;
}
/* Pointer: a gold cap pinned to the rim with a blade hanging into the plate,
   so it reads as pointing at one wedge rather than floating above the wheel. */
.spin-pointer {
  position: absolute; left: 50%; top: calc(var(--stage) * -.042); z-index: 5;
  width: 30px; height: 42px; transform: translateX(-50%);
  filter: drop-shadow(0 3px 3px rgba(0,0,0,.75));
  pointer-events: none;
}
.spin-pointer::before {
  content: ''; position: absolute; left: 50%; top: 0; transform: translateX(-50%);
  width: 20px; height: 20px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #fff3c8, #ffb92e 65%, #a86c12);
  border: 2px solid #2a1a3e;
}
.spin-pointer::after {
  content: ''; position: absolute; left: 50%; top: 13px; transform: translateX(-50%);
  width: 0; height: 0;
  border-left: 10px solid transparent; border-right: 10px solid transparent;
  border-top: 27px solid #ffce4a;
}

/* The result line stays in flow at a fixed height and fades in. It used to be
   display:none until a prize landed, which resized the dialog mid-spin and
   shoved the wheel and buttons around. */
.spin-result {
  height: 42px; margin: 6px 0 2px;          /* fixed: two lines of room, no reflow */
  display: flex; align-items: center; justify-content: center;
  font-size: 15px; line-height: 1.2; font-weight: 900; color: #7dff8a;
  text-shadow: 0 2px 0 rgba(0,0,0,.8);
  opacity: 0; transform: translateY(5px);
  transition: opacity .25s ease, transform .25s ease;
}
.spin-result.show { opacity: 1; transform: none; }
.spin-result.bad { color: #ffb0b0; }

.spin-actions { display: flex; gap: 10px; justify-content: center; margin-top: 8px; }
.spin-actions .mbtn { flex: 1 1 0; min-width: 0; }
/* Both buttons are ids, not classes — the old rules targeted .spin-go/.spin-close
   and so never matched, leaving them looking live all through the spin. */
.spin-box.spinning #spin-go,
.spin-box.spinning #spin-close,
.spin-actions .mbtn.spent { opacity: .45; pointer-events: none; filter: grayscale(.55); }

@media (prefers-reduced-motion: reduce) {
  /* Spin.js reads the rotor's transition length back out of CSS, so shortening
     it here keeps the safety timeout in step automatically. */
  .spin-rotor { transition-duration: 900ms; }
  .spin-box.spinning .spin-ring { animation: none; }
  .spin-rotor.won .spin-flash { animation: none; opacity: .75; }
}
