/* ==========================================================================
   BOARD.CSS - High-Contrast 6x7 Grid Board, Acrylic Light Chassis & Slot Depth
   ========================================================================== */

.board-arena {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  max-width: 700px;
  position: relative;
  margin: 0 auto;
}

/* Drop Selector Indicator Bar (Hover / Ghost token guides) */
.drop-selector-bar {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 12px;
  width: 100%;
  padding: 0 16px;
  /* This row is invisible until you hover a column, so it earns very little
     height. What it gives up here goes straight into the board. */
  margin-bottom: 6px;
  height: 34px;
}

.drop-col-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  cursor: pointer;
  position: relative;
  border-radius: var(--radius-sm);
  transition: background 0.15s ease;
}

.drop-col-btn:hover {
  background: rgba(255, 255, 255, 0.08);
}

.drop-ghost-token {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  opacity: 0;
  transform: translateY(-8px) scale(0.85);
  transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.2rem;
}

.drop-col-btn:hover .drop-ghost-token {
  opacity: 0.95;
  transform: translateY(0) scale(1);
}

.drop-col-btn.full {
  cursor: not-allowed;
  opacity: 0.3;
}
.drop-col-btn.full:hover .drop-ghost-token {
  display: none;
}

/* Ghost Token Variations — the same art as the piece you are about to drop */
.drop-ghost-token.red,
.drop-ghost-token.yellow,
.drop-ghost-token.purple,
.drop-ghost-token.green {
  border-radius: 0;
  background: center / contain no-repeat;
}
.drop-ghost-token.red {
  background-image: url('../img/token-red.png');
  filter: drop-shadow(0 0 10px var(--accent-red-glow));
}
.drop-ghost-token.yellow {
  background-image: url('../img/token-yellow.png');
  filter: drop-shadow(0 0 10px var(--accent-yellow-glow));
}
.drop-ghost-token.purple {
  background-image: url('../img/token-purple.png');
  filter: drop-shadow(0 0 16px var(--accent-purple-glow));
  animation: pulseGhostPurple 1s infinite alternate ease-in-out;
}
.drop-ghost-token.green {
  background-image: url('../img/token-green.png');
  filter: drop-shadow(0 0 16px rgba(16, 185, 129, 0.85));
  animation: pulseGhostGreen 1s infinite alternate ease-in-out;
}

@keyframes pulseGhostPurple {
  from { transform: translateY(0) scale(1); filter: brightness(1); }
  to { transform: translateY(0) scale(1.1); filter: brightness(1.3); }
}

@keyframes pulseGhostGreen {
  from { transform: translateY(0) scale(1); filter: brightness(1); }
  to { transform: translateY(0) scale(1.1); filter: brightness(1.35); }
}

/* ==========================================================================
   BOARD CHASSIS — the real board art, lit from behind

   The frame is one PNG with the 42 slots punched out as transparent
   octagons, so the tokens sit BEHIND it and the bezels overlap their edges.
   Its neon strips ship unlit; a second masked layer paints them, which is why
   one asset covers every colour the game needs. --board-neon drives it.
   ========================================================================== */

body {
  --board-neon: #4fc3f7;
  --board-neon-glow: rgba(79, 195, 247, 0.55);
}

/* The existing grid-theme button now picks the colour of the light. */
body.theme-white {
  --board-neon: #eaf6ff;
  --board-neon-glow: rgba(230, 245, 255, 0.5);
}

body.theme-cobalt {
  --board-neon: #2f6bff;
  --board-neon-glow: rgba(47, 107, 255, 0.65);
}

/* Opt-in: the board takes the colour of whoever is to move. */
body[data-turn-light="on"][data-turn="1"] {
  --board-neon: #ff2d55;
  --board-neon-glow: rgba(255, 45, 85, 0.6);
}

body[data-turn-light="on"][data-turn="2"] {
  --board-neon: #ffc400;
  --board-neon-glow: rgba(255, 196, 0, 0.55);
}

/* An armed special move floods the whole board and beats every other rule. */
body[data-surge="purple"] {
  --board-neon: #ea2bff;
  --board-neon-glow: rgba(234, 43, 255, 0.8);
}

body[data-surge="green"] {
  --board-neon: #21e6a0;
  --board-neon-glow: rgba(33, 230, 160, 0.75);
}

.board-wrapper {
  /* Where the playfield sits inside the chassis art. The slots are on a 148.5px
     pitch from (137.75, 109.25) in a 1355x1161 frame. Everything that has to
     line up with a row or a column reads these. */
  --grid-left: 10.166%;
  --grid-top: 9.410%;
  --grid-w: 76.72%;
  --grid-h: 76.74%;
  --grid-row-h: 12.79%;

  position: relative;
  width: 100%;
  /* The frame art's own proportions, so the slots land where the holes are. */
  aspect-ratio: 1355 / 1161;
  background: none;
  border: none;
  border-radius: 0;
  padding: 0;
  box-shadow: none;
  /* Keeps a dropping token hidden until it clears the top rail. */
  overflow: hidden;
  /* On the wrapper, not a child, so it escapes that clip. */
  filter: drop-shadow(0 22px 34px rgba(0, 0, 0, 0.8));
  transition: filter 0.4s ease;
}

/* The chassis itself, over the tokens. */
.board-wrapper::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  background: url('../img/board-frame-clean.png') center / 100% 100% no-repeat;
}

/* The light in the strips. White mask, painted in whatever colour is current,
   and the drop-shadow follows the mask so the glow is strip-shaped. */
.board-wrapper::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  background: var(--board-neon);
  -webkit-mask: url('../img/board-neon.png') center / 100% 100% no-repeat;
  mask: url('../img/board-neon.png') center / 100% 100% no-repeat;
  filter:
    drop-shadow(0 0 6px var(--board-neon-glow))
    drop-shadow(0 0 18px var(--board-neon-glow));
  transition: background 0.45s ease, filter 0.45s ease;
}

/* Armed: the board breathes so you cannot miss what is about to happen. */
body[data-surge] .board-wrapper::after {
  animation: neonSurge 1.05s infinite alternate ease-in-out;
}

@keyframes neonSurge {
  from {
    filter: drop-shadow(0 0 6px var(--board-neon-glow)) drop-shadow(0 0 16px var(--board-neon-glow));
  }
  to {
    filter:
      drop-shadow(0 0 14px var(--board-neon-glow))
      drop-shadow(0 0 44px var(--board-neon-glow))
      brightness(1.35);
  }
}

@media (max-width: 768px) {
  .drop-selector-bar {
    /* Touch players tap the board itself, so a hover-only preview row should
       not push the board down the screen. */
    display: none;
  }

  .drop-ghost-token {
    width: 28px;
    height: 28px;
    font-size: 0.9rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  body[data-surge] .board-wrapper::after {
    animation: none;
  }
}

/* The 6x7 Grid Container. Sits behind the chassis, inset so each cell lands
   on one punched slot. The numbers come from the art: the holes are on a
   148.5px pitch starting at (137.75, 109.25) in a 1355x1161 image. */
.board-frame {
  position: absolute;
  left: var(--grid-left);
  top: var(--grid-top);
  width: var(--grid-w);
  height: var(--grid-h);
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  grid-template-rows: repeat(6, 1fr);
  gap: 0;
  z-index: 1;
}

/* One slot. The chassis supplies the bezel and the octagon, so this only has
   to be the darkness you see down the hole. */
.board-cell {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(circle at 50% 30%, #121826 0%, #05070d 72%);
  border-radius: 0;
  box-shadow: none;
  overflow: visible;
  cursor: pointer;
  transition: background 0.2s ease;
}

.board-cell:hover {
  background: radial-gradient(circle at 50% 30%, #1d2740 0%, #070a12 72%);
  transform: none;
}

/* ==========================================================================
   GAME PIECES / TOKENS — the moulded octagons from the art sheet
   ========================================================================== */

.token-piece {
  position: absolute;
  /* Slightly wider than the punched hole, so the bezel laps its edge and the
     token reads as sitting down inside the board rather than on top of it.
     The hole is 70.7% of a cell; this overlaps it by a few pixels. */
  width: 79%;
  height: 79%;
  border: none;
  border-radius: 0;
  background: center / contain no-repeat;
  box-shadow: none;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 1.1rem;
  color: #ffffff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85);
  filter: drop-shadow(0 5px 7px rgba(0, 0, 0, 0.8));
  z-index: 2;
}

.token-piece.red { background-image: url('../img/token-red.png'); }
.token-piece.yellow { background-image: url('../img/token-yellow.png'); color: #1b1200; text-shadow: 0 1px 2px rgba(255, 255, 255, 0.55); }
.token-piece.purple { background-image: url('../img/token-purple.png'); }
.token-piece.green { background-image: url('../img/token-green.png'); }

/* The two special tokens keep glowing once they have landed. */
.token-piece.purple {
  animation: surgePiecePulse 1.2s infinite alternate ease-in-out;
}

.token-piece.green {
  animation: greenPiecePulse 1.2s infinite alternate ease-in-out;
}

@keyframes surgePiecePulse {
  from { filter: drop-shadow(0 5px 7px rgba(0, 0, 0, 0.8)) drop-shadow(0 0 8px var(--accent-purple-glow)); }
  to { filter: drop-shadow(0 5px 7px rgba(0, 0, 0, 0.8)) drop-shadow(0 0 22px var(--accent-purple-bright)) brightness(1.2); }
}

@keyframes greenPiecePulse {
  from { filter: drop-shadow(0 5px 7px rgba(0, 0, 0, 0.8)) drop-shadow(0 0 8px rgba(16, 185, 129, 0.8)); }
  to { filter: drop-shadow(0 5px 7px rgba(0, 0, 0, 0.8)) drop-shadow(0 0 22px #34d399) brightness(1.2); }
}

/* Winning Token Highlight */
.token-piece.winning-token {
  animation: winTokenGlow 0.8s infinite alternate ease-in-out;
  z-index: 3;
}

/* Brightness rather than an outward halo: the chassis sits over this, so any
   glow spilling onto the metal would simply be hidden behind it. */
@keyframes winTokenGlow {
  from {
    transform: scale(1);
    filter: drop-shadow(0 5px 7px rgba(0, 0, 0, 0.8)) brightness(1);
  }
  to {
    transform: scale(1.06);
    filter: drop-shadow(0 5px 7px rgba(0, 0, 0, 0.8)) brightness(1.75) drop-shadow(0 0 14px #ffffff);
  }
}

/* Row Dissolving FX state */
.board-cell.row-dissolving .token-piece {
  animation: laserVaporize 0.8s forwards cubic-bezier(0.25, 1, 0.5, 1);
}

/* SVG Win Line Overlay */
.win-line-svg {
  position: absolute;
  left: var(--grid-left);
  top: var(--grid-top);
  width: var(--grid-w);
  height: var(--grid-h);
  pointer-events: none;
  z-index: 20;
}

.win-line-path {
  stroke: #ffffff;
  stroke-width: 9;
  stroke-linecap: round;
  filter: drop-shadow(0 0 14px var(--accent-purple-bright)) drop-shadow(0 0 30px #ffffff);
  stroke-dasharray: 1000;
  stroke-dashoffset: 1000;
  animation: drawWinLine 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

@keyframes drawWinLine {
  to {
    stroke-dashoffset: 0;
  }
}

/* Laser Beam Row Vaporizer */
.laser-beam {
  position: absolute;
  left: var(--grid-left);
  width: var(--grid-w);
  height: var(--grid-row-h);
  pointer-events: none;
  opacity: 0;
  z-index: 15;
  background: linear-gradient(90deg, 
    transparent 0%, 
    rgba(217, 70, 239, 0.5) 15%, 
    rgba(255, 255, 255, 1) 50%, 
    rgba(217, 70, 239, 0.5) 85%, 
    transparent 100%);
  box-shadow: 
    0 0 40px 12px var(--accent-purple-glow),
    0 0 90px 25px rgba(255, 0, 128, 0.7);
  transition: opacity 0.2s ease;
}

.laser-beam.active {
  opacity: 1;
  animation: laserSweep 0.75s ease-in-out forwards;
}

@keyframes laserSweep {
  0% { transform: scaleY(0.1) scaleX(0.1); opacity: 0; }
  30% { transform: scaleY(1.3) scaleX(1); opacity: 1; filter: brightness(2); }
  70% { transform: scaleY(0.9) scaleX(1); opacity: 0.9; }
  100% { transform: scaleY(0) scaleX(1.1); opacity: 0; }
}

/* Last Placed Piece Highlight Indicator for Move History Review */
.board-cell.last-move-cell {
  position: relative;
}

.board-cell.last-move-cell::after {
  content: '';
  position: absolute;
  /* Inside the punched hole, so the ring is not clipped in half by the bezel. */
  inset: 18%;
  border-radius: 50%;
  border: 2.5px solid #ffffff;
  box-shadow: 0 0 16px rgba(255, 255, 255, 0.9), inset 0 0 10px rgba(255, 255, 255, 0.5);
  pointer-events: none;
  animation: pulseLastMove 1.4s infinite alternate ease-in-out;
  z-index: 3;
}

@keyframes pulseLastMove {
  from { transform: scale(0.94); opacity: 0.75; }
  to { transform: scale(1.04); opacity: 1; border-color: #ffd166; box-shadow: 0 0 20px #ffd166; }
}
