/* Table presentation: 3D dice, checker motion, and match-moment polish.
   Additive only — styles.css is untouched. */

/* ================================================================ 3D dice */
.nova-dice {
  display: flex;
  gap: 14px;
  perspective: 700px;
  perspective-origin: 50% 40%;
}

.nova-die {
  --size: clamp(38px, 4.4vw, 52px);
  --throw-x: 0px;
  --throw-y: 0px;
  --throw-rot: 0deg;
  --roll-duration: .85s;
  --roll-delay: 0s;
  position: relative;
  width: var(--size);
  height: var(--size);
  transform-style: preserve-3d;
  cursor: pointer;
  transition: filter .25s, opacity .25s;
}

.nova-die-cube {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transition: transform .45s cubic-bezier(.2, .8, .3, 1);
}

.nova-die-face {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template: repeat(3, 1fr) / repeat(3, 1fr);
  gap: 2px;
  padding: 15%;
  border-radius: calc(var(--size) * .19);
  background: linear-gradient(148deg, #fffaf0 0%, #f3e9d6 46%, #d9cbb2 100%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, .75),
    inset 0 -6px 12px rgba(140, 118, 86, .35),
    inset 0 6px 10px rgba(255, 255, 255, .5);
  backface-visibility: hidden;
}

/* Pips: recessed, with a highlight so they read as drilled rather than printed. */
.nova-die-face i {
  place-self: center;
  width: 74%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 34% 30%, #4a5560 0%, #1d262e 55%, #0a0f14 100%);
  box-shadow:
    inset 0 1px 2px rgba(0, 0, 0, .85),
    0 1px 0 rgba(255, 255, 255, .55);
}

/* The six faces of the cube. translateZ is half the die size. */
.nova-die-face.f1 { transform: translateZ(calc(var(--size) / 2)); }
.nova-die-face.f6 { transform: rotateY(180deg) translateZ(calc(var(--size) / 2)); }
.nova-die-face.f2 { transform: rotateY(90deg)  translateZ(calc(var(--size) / 2)); }
.nova-die-face.f5 { transform: rotateY(-90deg) translateZ(calc(var(--size) / 2)); }
.nova-die-face.f3 { transform: rotateX(90deg)  translateZ(calc(var(--size) / 2)); }
.nova-die-face.f4 { transform: rotateX(-90deg) translateZ(calc(var(--size) / 2)); }

.nova-die-shadow {
  position: absolute;
  left: 8%;
  right: 8%;
  bottom: -18%;
  height: 22%;
  border-radius: 50%;
  background: radial-gradient(ellipse, rgba(0, 0, 0, .55), transparent 72%);
  filter: blur(3px);
  transform: translateZ(-1px);
  transition: transform .3s, opacity .3s;
  pointer-events: none;
}

/* Waiting for a roll: faint, no pips showing. */
.nova-die.blank .nova-die-cube { opacity: .34; filter: grayscale(.6); }
.nova-die.blank .nova-die-face i { opacity: .25; }

/* The throw arc, running alongside the cube's own rotation. */
.nova-die.throwing {
  animation: novaDiceThrow var(--roll-duration) cubic-bezier(.3, .6, .3, 1) var(--roll-delay) both;
}
.nova-die.throwing .nova-die-shadow {
  animation: novaDiceShadow var(--roll-duration) cubic-bezier(.3, .6, .3, 1) var(--roll-delay) both;
}

@keyframes novaDiceThrow {
  0%   { transform: translate(0, 0) rotate(0deg) scale(1); }
  22%  { transform: translate(calc(var(--throw-x) * .7), var(--throw-y)) rotate(var(--throw-rot)) scale(1.14); }
  55%  { transform: translate(var(--throw-x), calc(var(--throw-y) * .35)) rotate(calc(var(--throw-rot) * -.6)) scale(1.06); }
  78%  { transform: translate(calc(var(--throw-x) * .3), 3px) rotate(0deg) scale(.97); }
  90%  { transform: translate(0, -3px) scale(1.03); }
  100% { transform: translate(0, 0) scale(1); }
}

@keyframes novaDiceShadow {
  0%   { transform: scale(1); opacity: .5; }
  22%  { transform: scale(.55); opacity: .16; }
  78%  { transform: scale(1.1); opacity: .6; }
  100% { transform: scale(1); opacity: .5; }
}

/* A brief flash as the die settles. */
.nova-die.landed .nova-die-face {
  animation: novaDieLand .4s ease-out;
}
@keyframes novaDieLand {
  0%   { box-shadow: inset 0 0 0 1px rgba(255,255,255,.75), 0 0 0 0 rgba(231, 187, 87, .9); }
  35%  { box-shadow: inset 0 0 0 1px rgba(255,255,255,.9), 0 0 22px 6px rgba(231, 187, 87, .55); }
  100% { box-shadow: inset 0 0 0 1px rgba(255,255,255,.75), 0 0 0 0 rgba(231, 187, 87, 0); }
}

/* A die whose value has been played. */
.nova-die.spent { opacity: .38; filter: grayscale(.75); }
.nova-die.spent .nova-die-shadow { opacity: .2; }

/* No legal move with this roll. */
.nova-die.no-move { animation: novaDieShake .5s ease-in-out; }
@keyframes novaDieShake {
  0%, 100% { transform: translateX(0); }
  15% { transform: translateX(-6px) rotate(-5deg); }
  35% { transform: translateX(6px) rotate(5deg); }
  55% { transform: translateX(-4px) rotate(-3deg); }
  75% { transform: translateX(4px) rotate(3deg); }
}

.nova-dice.is-rolling { pointer-events: none; }

/* ================================================================ checker motion */
/* A ghost checker flies from source to destination on every move, so the board
   reads as a physical action rather than a redraw. */
.checker-ghost {
  position: fixed;
  z-index: 60;
  border-radius: 50%;
  pointer-events: none;
  box-shadow: 0 6px 16px rgba(0, 0, 0, .55), inset 0 0 0 2px rgba(255, 255, 255, .2);
  will-change: transform;
}
.checker-ghost.light {
  background: radial-gradient(circle at 35% 25%, #fbefd6, #d9c6a6 54%, #907d60 100%);
}
.checker-ghost.dark {
  background: radial-gradient(circle at 35% 25%, #40515c, #111b21 55%, #02080c 100%);
}

/* The checker that just arrived. */
.checker.just-landed { animation: novaCheckerLand .42s cubic-bezier(.2, 1.5, .4, 1); }
@keyframes novaCheckerLand {
  0%   { transform: scale(1.35); filter: brightness(1.5); }
  60%  { transform: scale(.94); }
  100% { transform: scale(1); filter: brightness(1); }
}

/* A checker being hit. */
.checker-ghost.hit { animation: novaHitSpin .5s ease-in; }
@keyframes novaHitSpin {
  from { transform: rotate(0deg) scale(1); }
  to   { transform: rotate(420deg) scale(.65); }
}

.point.was-hit::before { animation: novaHitFlash .5s ease-out; }
@keyframes novaHitFlash {
  0%   { filter: brightness(2.6) saturate(1.6); }
  100% { filter: brightness(1); }
}

/* ================================================================ turn state */
.board-stage.my-turn {
  box-shadow: 0 0 0 1px rgba(231, 187, 87, .4), 0 0 34px -6px rgba(231, 187, 87, .3);
}
.board-stage { transition: box-shadow .5s; }

.roll-btn.ready {
  animation: novaRollPulse 2.1s ease-in-out infinite;
}
@keyframes novaRollPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(231, 187, 87, .45); }
  50%      { box-shadow: 0 0 0 9px rgba(231, 187, 87, 0); }
}

/* The clock in the last 30 seconds. */
#myClock.low, #oppClock.low { animation: novaClockFlash 1s steps(2, jump-none) infinite; }
@keyframes novaClockFlash { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

/* ================================================================ cube */
.cube { transition: transform .35s cubic-bezier(.2, 1.6, .4, 1), box-shadow .35s; }
.cube.bumped { animation: novaCubeBump .6s cubic-bezier(.2, 1.5, .4, 1); }
@keyframes novaCubeBump {
  0%   { transform: translate(-50%, -50%) rotate(4deg) scale(1); }
  40%  { transform: translate(-50%, -50%) rotate(-190deg) scale(1.5); }
  100% { transform: translate(-50%, -50%) rotate(4deg) scale(1); }
}

/* ================================================================ victory */
.nova-confetti {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 90;
  overflow: hidden;
}
.nova-confetti i {
  position: absolute;
  top: -14px;
  width: 9px;
  height: 14px;
  border-radius: 2px;
  opacity: .95;
  animation: novaConfettiFall linear forwards;
}
@keyframes novaConfettiFall {
  to { transform: translateY(105vh) rotate(760deg); opacity: .1; }
}

/* ================================================================ sound control */
.sound-popover {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 0;
  z-index: 30;
  width: 190px;
  padding: 13px 14px;
  border-radius: 14px;
  background: linear-gradient(180deg, rgba(17, 34, 46, .98), rgba(9, 20, 29, .98));
  border: 1px solid rgba(108, 145, 163, .3);
  box-shadow: 0 16px 36px rgba(0, 0, 0, .5);
}
.sound-popover b { display: block; font-size: 11px; letter-spacing: .8px; color: var(--muted); }
.sound-popover input[type="range"] { width: 100%; margin-top: 10px; accent-color: var(--gold); }
.side-utilities { position: relative; }
#soundToggle.muted { opacity: .5; }

/* ================================================================ reduced motion */
@media (prefers-reduced-motion: reduce) {
  .nova-die.throwing,
  .nova-die.throwing .nova-die-shadow,
  .nova-die.landed .nova-die-face,
  .checker.just-landed,
  .roll-btn.ready,
  .nova-confetti i {
    animation: none !important;
  }
  .nova-die-cube { transition: transform .18s linear; }
  .checker-ghost { display: none; }
}
