html, body {
  height: 100%;
}

/* Form controls don't inherit the body's font-family by default in any
   browser (they use the platform's own UI font unless told otherwise) --
   without this, every button and input on the page silently falls back
   to Arial/system UI instead of Londrina Solid. */
button, input {
  font-family: inherit;
}

body {
  font-family: "Londrina Solid", system-ui, sans-serif;
  margin: 0;
  color: #f1eade;
  background: #0d0a06;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

/* Our audience overwhelmingly plays on a phone, so on an actual phone
   (viewport <= 480px) the frame fills the real screen edge-to-edge --
   whatever the device's own aspect ratio is, since that's what a player
   is actually holding. The 9:16 (16:9 portrait) shape only matters as a
   fixed preview frame on desktop, where there's no real device shape to
   match against; see the media query below. */
#app-frame {
  position: relative;
  width: 100%;
  max-width: 420px;
  min-height: 100vh;
  box-sizing: border-box;
  padding: calc(0.7rem + 10px) 1rem 0.7rem;
  background: url("images/bg.png") center / cover no-repeat;
  display: flex;
  flex-direction: column;
  /* #confetti-layer intentionally extends past #card-wrapper's edges
     (confetti bursting around the card, not clipped to it) -- without
     this, that negative inset made the page itself scroll horizontally,
     since nothing else constrained it. Confetti still renders past the
     card, just clipped at the app frame's own edge instead of the whole
     page's. */
  overflow-x: hidden;
}

@media (min-width: 481px) {
  #app-frame {
    min-height: 0;
    aspect-ratio: 9 / 16;
    border-radius: 32px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
    overflow-y: auto;
  }
}

header {
  margin-bottom: 0.25rem;
}

main {
  display: flex;
  flex-direction: column;
  flex: 1;
  /* Centers the card+action-section group vertically instead of pinning
     the card to the top and the action section to the very bottom (the
     old #action-section auto-top-margin trick) -- that left a large dead
     gap in the middle on tall/narrow phones, since the card's fixed 2:3
     aspect ratio caps its height well below 100vh on those screens. */
  justify-content: center;
}

.player-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  flex-wrap: wrap;
}

#identity-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin-bottom: 0.35rem;
}

#identity-colon {
  margin-left: -0.5rem;
  font-weight: bold;
  color: #4a1826;
}

#player-id {
  max-width: 45%;
  overflow: hidden;
  text-overflow: ellipsis;
  color: #4a1826;
  font-size: 1.1rem;
  font-weight: bold;
}

#balance {
  text-align: left;
  font-size: 1.1rem;
  font-weight: bold;
  color: #e8b84b;
}

#action-section #balance {
  color: #4a1826;
}

.grant-banner {
  margin: calc(0.5rem - 4px) auto 0;
  padding: 10px;
  background: #365c2a;
  border-radius: 6px;
  font-size: 0.9rem;
  text-align: center;
  width: fit-content;
  transform: translateY(-15px);
}

.grant-banner.hidden {
  display: none;
}

.tier-stepper {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.2rem;
}

#action-section {
  background: #abc265;
  /* Same width/centering as #card-area (not edge-to-edge anymore). Sits
     right below #card-wrapper now -- main's justify-content:center (see
     above) centers the two as one group, rather than this being pushed
     all the way to the bottom on its own. The fixed 10px bottom margin
     keeps it from ever touching the very bottom edge, so the background
     art shows through underneath it. */
  width: 100%;
  max-width: 310px;
  box-sizing: border-box;
  margin: 0 auto 10px;
  border: 3px solid #4a1826;
  border-radius: 14px;
  padding: 0.45rem 1rem calc(0.35rem - 5px);
  color: #3a3018;
}

#action-section #status {
  color: #3a3018;
}

#tier-selector {
  margin-bottom: 0.3rem;
}

.tier-stepper .value {
  min-width: 6rem;
  text-align: center;
  font-size: 1.3rem;
  font-weight: bold;
  color: #e8b84b;
}

#action-section .tier-stepper .value {
  color: #4a1826;
}

.tier-stepper button {
  /* >=44px on either axis -- the commonly recommended minimum touch
     target size (Apple HIG/Material) -- 2.4rem measured at ~38px, too
     tight on a real phone. */
  width: 2.75rem;
  height: 2.75rem;
  border: 2px solid #fff;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.35);
  background: #5a9c3f;
  color: white;
  border-radius: 50%;
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
}

.tier-stepper button:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

/* Sizing/position lives on the wrapper, not #card-area itself, because
   #card-area needs overflow:hidden to clip the canvas/prize-layer to its
   rounded corners -- and overflow:hidden on an element also clips that
   same element's own box-shadow, which would silently hide the win-glow
   effect below if it were applied directly to #card-area. */
#card-wrapper {
  position: relative;
  width: 100%;
  max-width: 310px;
  /* Matches the cover artwork's own aspect ratio (1024x1536 = 2:3)
     exactly, so it fills the card edge-to-edge with no letterbox strip
     showing the fallback background color on the sides. */
  aspect-ratio: 2 / 3;
  margin: 0 auto 0.9rem;
  border-radius: 10px;
}

#card-area {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 10px;
  overflow: hidden;
  background: #222;
  /* Above #confetti-layer on purpose -- confetti starts dead-center,
     hidden behind the (opaque) card, and only becomes visible once it
     drifts past the card's own edges. */
  z-index: 2;
}

#prize-layer {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  font-size: 2rem;
  font-weight: bold;
  background: linear-gradient(160deg, #6b8f4e, #3a5a30);
}

#prize-illustration {
  width: 62%;
  max-width: 170px;
}

#prize-illustration svg,
#prize-illustration img {
  display: block;
  width: 100%;
  height: auto;
}

#prize-illustration img {
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}

#scratch-canvas {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
}

/* A diagonal highlight band that periodically sweeps across the cover
   art while the card is waiting to be scratched -- pure attention-drawing
   decoration, toggled off (via .hidden) the moment the reveal animation
   actually starts stripping the cover, in app.js. */
#scratch-shine {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  overflow: hidden;
  border-radius: inherit;
}

#scratch-shine.hidden {
  display: none;
}

#scratch-shine::before {
  content: "";
  position: absolute;
  top: -20%;
  left: -60%;
  width: 12%;
  height: 140%;
  background: linear-gradient(120deg, transparent 0%, rgba(255, 255, 255, 0.55) 50%, transparent 100%);
  transform: skewX(-20deg);
  animation: shine-sweep 3.2s ease-in-out infinite;
}

@keyframes shine-sweep {
  0% {
    left: -60%;
  }
  35% {
    left: 130%;
  }
  100% {
    left: 130%;
  }
}

/* Same idle attention-drawing treatment (gentle pulse + shine sweep) on
   the card and the play button, both toggled by the .idle-attention
   class in app.js at the same moments #scratch-shine shows/hides. */
@keyframes idle-pulse {
  0%,
  100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.03);
  }
}

#card-area.idle-attention,
#btn-play.idle-attention {
  animation: idle-pulse 2.4s ease-in-out infinite;
}

#btn-play {
  position: relative;
  overflow: hidden;
}

#btn-play.idle-attention::before {
  content: "";
  position: absolute;
  top: -60%;
  left: -60%;
  width: 12%;
  height: 220%;
  background: linear-gradient(120deg, transparent 0%, rgba(255, 255, 255, 0.6) 50%, transparent 100%);
  transform: skewX(-20deg);
  animation: shine-sweep 3.2s ease-in-out infinite;
  pointer-events: none;
}

/* Explicit press feedback (not just :active, which only covers however
   long the pointer stays down -- often too brief on a fast tap to read
   as anything). Toggled by app.js on click and cleared on animationend,
   so it always plays out fully. Placed after .idle-attention in the
   stylesheet so it wins the very first click, when both classes can be
   present for a moment. */
@keyframes btn-press {
  0% {
    transform: scale(1);
  }
  40% {
    transform: scale(0.86);
  }
  100% {
    transform: scale(1);
  }
}

#btn-play.pressed,
.tier-stepper button.pressed {
  animation: btn-press 0.25s ease-out;
}

/* Win celebration, triggered in app.js right after the reveal animation
   finishes (only when the round actually won something). Phases, timed
   against the total 0.5s duration below:
     0%  - 10% (0.05s) quick press down, glow flashes in immediately
     10% - 70% (0.3s)  shakes side to side while held pressed, glow fading out
     70% - 100% (0.15s) settles back to rest, silent
   The glow pays off at the press itself, not the release. */
@keyframes card-win-press {
  0% {
    transform: scale(1) translateX(0);
    box-shadow: 0 0 0 rgba(255, 213, 79, 0);
  }
  10% {
    transform: scale(0.95) translateX(0);
    box-shadow: 0 0 26px 8px rgba(255, 213, 79, 0.85);
  }
  25% {
    transform: scale(0.95) translateX(-6px);
    box-shadow: 0 0 12px 4px rgba(255, 213, 79, 0.4);
  }
  40% {
    transform: scale(0.95) translateX(6px);
  }
  55% {
    transform: scale(0.95) translateX(-4px);
    box-shadow: 0 0 0 rgba(255, 213, 79, 0);
  }
  70% {
    transform: scale(0.95) translateX(4px);
  }
  100% {
    transform: scale(1) translateX(0);
    box-shadow: 0 0 0 rgba(255, 213, 79, 0);
  }
}

#card-wrapper.win-pop {
  animation: card-win-press 0.5s ease-out;
}

/* Confetti burst for a big win (>10x, triggered in app.js after the
   reveal), in the card's own palette (cream/maroon/green/gold -- see
   CONFETTI_COLORS in app.js) instead of generic party colors, so it
   reads as "this card" celebrating, not a generic effect pasted on top.
   Radiates from dead-center outward to random points past the card's
   edges -- each piece starts exactly at center, hidden behind #card-area
   (which sits above this layer, see its z-index), and only becomes
   visible once it drifts past the card's own boundary, so it reads as
   bursting out from behind the card rather than raining down on it.
   Extends past #card-wrapper's own edges on purpose (clipped at
   #app-frame's edge instead, see its overflow-x). Pieces are plain divs
   created/removed by app.js, this file only defines their shared
   animation. */
#confetti-layer {
  position: absolute;
  inset: -15% -25%;
  overflow: visible;
  pointer-events: none;
  z-index: 1;
}

.confetti-piece {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 8px;
  height: 14px;
  opacity: 0;
  border-radius: 2px;
  animation: confetti-burst var(--fall-duration, 0.9s) ease-out var(--fall-delay, 0s) forwards;
}

@keyframes confetti-burst {
  0% {
    opacity: 1;
    transform: translate(calc(-50% + var(--start-x, 0px)), calc(-50% + var(--start-y, 0px))) rotate(0deg);
  }
  100% {
    opacity: 0;
    transform: translate(calc(-50% + var(--drift-x, 0px)), calc(-50% + var(--drift-y, 0px)))
      rotate(var(--spin, 480deg));
  }
}

.countdown-num {
  font-size: 1.35rem;
}

#play-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.4rem;
}

#play-row #btn-play {
  margin: 0;
}

#btn-play {
  margin: 0 auto;
  font-size: 1rem;
  font-weight: 600;
  border: 2px solid #fff;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.35);
  background: #5a9c3f;
  color: white;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 4.8rem;
  height: 4.8rem;
  padding: 0;
  border-radius: 50%;
  font-size: 0.95rem;
  line-height: 1.15;
  text-align: center;
}

#btn-play:disabled {
  background: #555;
  cursor: not-allowed;
}

#btn-play.stop-mode {
  background: #b23b3b;
}

.icon-btn {
  /* Same >=44px touch-target reasoning as .tier-stepper button above. */
  width: 2.75rem;
  height: 2.75rem;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid #6b5a3f;
  background: #2a2118;
  color: #f1eade;
  border-radius: 50%;
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
}

/* Same visual identity as #btn-play (green fill, white border, drop
   shadow) for both side buttons -- just smaller, matching their place
   beside the main button. #btn-turbo.active below overrides just the
   background to yellow when turbo is toggled on, keeping the same white
   icon/border. */
#btn-auto,
#btn-turbo {
  background: #5a9c3f;
  border: 2px solid #fff;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.35);
  color: white;
}

#btn-turbo.active {
  background: #ffd400;
  color: #000;
  box-shadow: 0 0 8px rgba(255, 212, 0, 0.6);
}

.icon-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

#status {
  margin: 0;
  text-align: center;
  min-height: 0.9em;
}

/* Bottom sheet: slides up from the bottom edge and covers the lower half
   of the game, same interaction as a hamburger-triggered sidebar drawer
   but sliding vertically instead of horizontally. The backdrop stays in
   the DOM at all times (never display:none) so its opacity and the
   sheet's transform can both transition smoothly. */
.modal {
  position: absolute;
  inset: 0;
  z-index: 20;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(0, 0, 0, 0.55);
  border-radius: inherit;
  opacity: 1;
  visibility: visible;
  /* Clips the sheet's own translateY(100%) resting position -- without
     this, the transformed-but-hidden sheet still extends the scrollable
     overflow area of #app-frame (which has overflow-y: auto), producing a
     phantom scrollbar even though nothing is visually cut off. */
  overflow: hidden;
  transition: opacity 0.25s ease, visibility 0s linear 0s;
}

.modal.hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.25s ease, visibility 0s linear 0.25s;
}

.modal-content {
  width: 100%;
  height: 50%;
  max-width: none;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  background: #2a2118;
  border: 1px solid #6b5a3f;
  border-bottom: none;
  border-radius: 20px 20px 0 0;
  padding: 1.25rem;
  overflow-y: auto;
  transform: translateY(0);
  transition: transform 0.3s ease;
}

.modal.hidden .modal-content {
  transform: translateY(100%);
}

@media (min-width: 481px) {
  .modal-content {
    border-radius: 20px 20px 32px 32px;
  }
}

.modal-content h3 {
  margin: 0;
  text-align: center;
  font-size: 1.05rem;
}

.modal-field {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
}

.modal-field label {
  font-size: 0.85rem;
  color: #aaa;
}

.quantity-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.4rem;
  width: 100%;
}

.qty-btn {
  padding: 0.4rem 0;
  border-radius: 6px;
  border: 1px solid #6b5a3f;
  background: #1c1712;
  color: #f1eade;
  font-size: 0.9rem;
  cursor: pointer;
}

.qty-btn.active {
  background: #4a3a00;
  border-color: #e8b84b;
  color: #e8b84b;
  font-weight: 700;
}

#btn-auto-start {
  padding: 0.6rem;
  border: none;
  border-radius: 10px;
  background: #5a9c3f;
  color: white;
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
}

.modal-cancel {
  background: transparent;
  border: none;
  color: #999;
  font-size: 0.85rem;
  cursor: pointer;
  padding: 0.2rem;
}

/* Centered popup (as opposed to .modal's bottom sheet) -- same palette
   and card styling as .modal-content, just anchored to the middle of the
   screen instead of sliding up from the bottom. Used for errors that need
   the player's attention right away (e.g. insufficient balance). */
.center-modal {
  position: absolute;
  inset: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.55);
  border-radius: inherit;
  opacity: 1;
  visibility: visible;
  padding: 1.5rem;
  box-sizing: border-box;
  transition: opacity 0.2s ease, visibility 0s linear 0s;
}

.center-modal.hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.2s ease, visibility 0s linear 0.2s;
}

.center-modal-content {
  width: 100%;
  max-width: 360px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 1.25rem;
  background: #2a2118;
  border: 1px solid #6b5a3f;
  border-radius: 16px;
  padding: 2.25rem 1.75rem;
  text-align: center;
  transform: scale(1);
  transition: transform 0.2s ease;
}

.center-modal.hidden .center-modal-content {
  transform: scale(0.9);
}

.center-modal-content p {
  margin: 0;
  color: #f1eade;
  font-size: 1.3rem;
  font-weight: 700;
}

.center-modal-close {
  /* min-height guarantees the >=44px touch-target minimum regardless of
     font metrics -- padding alone measured ~34px tall on a real render. */
  min-height: 2.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.6rem;
  border: none;
  border-radius: 10px;
  background: #5a9c3f;
  color: white;
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
}
