/* games.css - Sliding Puzzle (/games). Reuses tokens from styles.css and
   the .course-shell/.course-hero chrome from account.css. */

.puzzle-picker-section,
.puzzle-game-section {
  max-width: 760px;
  width: 100%;
  margin: 0 auto;
}

.puzzle-section-heading {
  font-family: Georgia, serif;
  font-size: 20px;
  color: var(--text);
  margin: 0 0 14px;
}

.puzzle-loading,
.puzzle-empty {
  color: var(--muted);
  font-size: 14px;
}

.puzzle-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
}

.puzzle-thumb {
  width: 96px;
  padding: 0;
  border: 2px solid transparent;
  border-radius: 12px;
  background: var(--panel);
  cursor: pointer;
  overflow: hidden;
  box-shadow: var(--shadow);
  transition: transform .15s ease, border-color .15s ease;
}

.puzzle-thumb:hover {
  transform: translateY(-2px);
}

.puzzle-thumb.selected {
  border-color: var(--accent);
}

.puzzle-thumb img {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
}

.puzzle-thumb-label {
  display: block;
  font-size: 11px;
  color: var(--muted);
  padding: 6px 8px 8px;
  text-align: center;
  line-height: 1.3;
}

.puzzle-thumb.selected .puzzle-thumb-label {
  color: var(--accent);
  font-weight: 600;
}

/* -- Custom (per-owner uploaded) tiles ---------------------------------- */

.puzzle-thumb-custom {
  position: relative;
}

.puzzle-thumb-delete {
  position: absolute;
  top: 4px;
  right: 4px;
  z-index: 2;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(20, 16, 8, .6);
  color: #fff;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
}

.puzzle-thumb-delete:hover {
  background: #b6432a;
}

.puzzle-thumb-add {
  border: 2px dashed var(--border);
  background: transparent;
  display: flex;
  flex-direction: column;
  align-items: center;
  box-shadow: none;
}

.puzzle-thumb-add:hover {
  border-color: var(--accent);
}

.puzzle-thumb-add-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 1 / 1;
  font-size: 28px;
  font-weight: 300;
  color: var(--muted);
}

.puzzle-thumb-add:hover .puzzle-thumb-add-icon {
  color: var(--accent);
}

/* -- Difficulty (board size) ------------------------------------------- */

.puzzle-difficulty-heading {
  margin-top: 28px;
}

.puzzle-difficulty {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.puzzle-diff-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: 78px;
  padding: 10px 14px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  cursor: pointer;
  transition: transform .12s ease, box-shadow .2s ease, border-color .15s ease;
}

.puzzle-diff-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(50, 35, 10, .08);
}

.puzzle-diff-btn.is-active {
  border-color: var(--accent);
  background: var(--accent2);
}

.puzzle-diff-name {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}

.puzzle-diff-btn.is-active .puzzle-diff-name {
  color: var(--accent);
}

.puzzle-diff-size {
  font-size: 11px;
  color: var(--muted);
}

/* -- Game section ----------------------------------------------------- */

.puzzle-game-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}

.puzzle-stats {
  display: flex;
  align-items: center;
  gap: 16px;
}

.puzzle-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 1.1;
  min-width: 48px;
}

.puzzle-stat-label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .08em;
  font-weight: 600;
  color: var(--muted);
}

.puzzle-stat-value {
  font-size: 18px;
  font-weight: 700;
  color: var(--text);
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
}

/* The currently-selected puzzle's thumbnail, worked into the same row as
   the Moves/Time/Coins stats rather than sitting off on its own. */
.puzzle-stat-thumb {
  min-width: 0;
}

.puzzle-head-thumb {
  display: block;
  width: 36px;
  height: 36px;
  object-fit: cover;
  border-radius: 8px;
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

.puzzle-shuffle-btn,
.puzzle-retry-btn {
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 9px 16px;
  border-radius: 10px;
  cursor: pointer;
  transition: transform .12s ease, box-shadow .2s ease;
}

.puzzle-shuffle-btn:hover,
.puzzle-retry-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(50, 35, 10, .08);
}

/* .puzzle-retry-btn sits right after the .puzzle-empty message inside the
   picker's own flex-wrap row (see renderPicker()) -- a plain top margin
   is enough since the message text above it is a block-level <p>. */
.puzzle-retry-btn {
  margin-top: 4px;
}

.puzzle-board-wrap {
  /* %, not vw -- this now lives inside the constrained game-shell frame
     on larger viewports (see game-shell.css), where vw would measure
     the full browser window instead of the ~430px frame actually
     available, overflowing past the frame's edge. */
  width: min(100%, 480px);
  margin: 0 auto;
}

/* Positioning context for the board + its overlays (flash, complete
   image) ONLY -- deliberately separate from .puzzle-board-wrap, which
   also contains the win card below. inset:0 on the overlays needs to
   match the board's own box exactly; if it were sized off the wrap
   instead, the win card's normal-flow height would stretch the overlays
   tall enough to cover the win card itself. */
.puzzle-board-stage {
  position: relative;
  width: 100%;
}

.puzzle-board {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.puzzle-tile {
  position: absolute;
  width: 25%;
  height: 25%;
  box-sizing: border-box;
  border: 2px solid var(--bg);
  background-repeat: no-repeat;
  cursor: pointer;
  /* Subtle raised-tile bevel: whiten (lighten) the top and left edges
     by a couple of pixels and darken the bottom and right edges, so
     each tile reads as slightly raised off the board. Inset shadows
     sit on top of the tile's photo slice but are translucent enough
     to keep the picture legible. */
  box-shadow:
    inset 0 2px 0 rgba(255, 255, 255, .28),
    inset 2px 0 0 rgba(255, 255, 255, .20),
    inset 0 -2px 3px rgba(0, 0, 0, .22),
    inset -2px 0 3px rgba(0, 0, 0, .16);
  transition: left .16s ease, top .16s ease, border-color .3s ease, box-shadow .3s ease;
}

.puzzle-tile:hover {
  filter: brightness(1.05);
}

.puzzle-tile:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: -3px;
  z-index: 2;
}

/* Faded checkmark shown for ~2s (see flashCorrect() in games.js) when a
   tile slides into its own correct/home cell -- per-move feedback while
   the puzzle is still in progress, separate from the end-of-game
   flash/reveal. */
.puzzle-tile-check {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 46%;
  height: 46%;
  border-radius: 50%;
  background: rgba(255, 255, 255, .62);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #2f6b2f;
  opacity: 0;
  pointer-events: none;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .15);
  transition: opacity .35s ease;
}

.puzzle-tile-check.is-visible {
  opacity: 1;
}

.puzzle-tile-check svg {
  width: 58%;
  height: 58%;
}

.puzzle-blank {
  position: absolute;
  width: 25%;
  height: 25%;
  box-sizing: border-box;
  border: 2px dashed var(--border);
  background: var(--surface);
  transition: border-color .3s ease;
}

/* On solve: drop the tile gutters so the picture reads as one whole
   image instead of a visible grid -- see .puzzle-board.is-solved below.
   The bevel goes too, for the same reason: a finished picture must not
   show faint tile edges across it. */
.puzzle-board.is-solved .puzzle-tile {
  border-color: transparent;
  box-shadow: none;
  cursor: default;
}

.puzzle-board.is-solved .puzzle-blank {
  border-color: transparent;
}

/* -- Win celebration: when the puzzle is solved, the finished board
   pops out and glows for 7 seconds before the high-score flow covers
   it -- the same winner treatment as Puzzles. The stage holds the
   board, the complete image, and the flash, so scaling it scales the
   finished picture as one unit (scaling the board alone would leave
   the complete image behind). The pulsing glow hugs the BOARD square
   itself (the finished puzzle), not the stage: it is a box-shadow on
   the board, and the stage's overflow is open so the glow is not
   clipped at the stage's edges. */
@keyframes sliders-win-pop {
  0% { transform: scale(1); }
  35% { transform: scale(1.06); }
  65% { transform: scale(1.03); }
  100% { transform: scale(1.03); }
}
@keyframes sliders-win-glow {
  0%, 100% {
    box-shadow: inset 0 0 0 3px rgba(242, 177, 52, .9),
      inset 0 0 28px rgba(242, 177, 52, .35),
      0 0 28px 6px rgba(242, 177, 52, .55),
      0 0 72px 18px rgba(242, 177, 52, .28);
  }
  50% {
    box-shadow: inset 0 0 0 3px rgba(242, 177, 52, .9),
      inset 0 0 28px rgba(242, 177, 52, .35),
      0 0 46px 12px rgba(242, 177, 52, .85),
      0 0 110px 28px rgba(242, 177, 52, .45);
  }
}
.puzzle-board-stage.is-celebrating {
  /* Hold the popped size once the pop animation finishes. */
  transform: scale(1.03);
  animation: sliders-win-pop .6s ease-out;
  z-index: 5;
}
/* The glow lives on the board square: a golden edge plus the pulsing
   outer halo, so the finished puzzle itself glows. */
.puzzle-board-stage.is-celebrating .puzzle-board {
  box-shadow: inset 0 0 0 3px rgba(242, 177, 52, .9),
    inset 0 0 28px rgba(242, 177, 52, .35);
  animation: sliders-win-glow 1.5s ease-in-out .6s infinite;
}

/* Full, uncut original image shown once solved -- covers the tiles AND
   the one corner that was never part of the puzzle (the piece removed
   at the start), so the player sees the complete picture they uploaded,
   not 15 gutter-less tiles with a gap where the 16th would be. Cross-
   fades in as .puzzle-flash fires (see below), so it feels like the
   flash "reveals" the finished picture. */
.puzzle-complete-img {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  border-radius: var(--radius);
  opacity: 0;
  transition: opacity .5s ease .15s;
  z-index: 3;
  pointer-events: none;
}

.puzzle-complete-img.is-visible {
  opacity: 1;
}

.puzzle-complete-img[hidden] {
  display: none;
}

/* One gentle brightness pulse on solve -- .is-flashing is added and
   removed (with a reflow in between so re-solving the same session can
   replay it) by the win-detection code in games.js. */
.puzzle-flash {
  position: absolute;
  inset: 0;
  background: #fff;
  opacity: 0;
  border-radius: var(--radius);
  pointer-events: none;
  z-index: 4;
}

.puzzle-flash.is-flashing {
  animation: puzzle-gentle-flash .7s ease-out;
}

@keyframes puzzle-gentle-flash {
  0%   { opacity: 0; }
  30%  { opacity: .45; }
  100% { opacity: 0; }
}

/* The win message sits BELOW the board, not on top of it, so the
   completed picture stays fully visible once solved. */
.puzzle-win {
  margin-top: 16px;
  text-align: center;
}

.puzzle-win[hidden] {
  display: none;
}

.puzzle-win-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 28px 32px;
  text-align: center;
}

.puzzle-win-title {
  font-family: Georgia, serif;
  font-size: 26px;
  color: var(--text);
  margin-bottom: 6px;
}

.puzzle-win-stats {
  color: var(--muted);
  font-size: 14px;
  margin-bottom: 18px;
}

.puzzle-hint {
  text-align: center;
  color: var(--muted);
  font-size: 12px;
  margin-top: 14px;
}

@media (max-width: 640px) {
  .puzzle-thumb { width: 80px; }
}

/* Real mobile: extra breathing room below the puzzle content so it never
   sits flush against the bottom of the scrollable game-shell-stage --
   distinct from game-shell.css's own reserved strip below the whole
   shell (a hardware-safe-area concern), this is purely a within-content
   gap so the board/hint text visually sit up off the bottom edge. */
@media (max-width: 480px) {
  .game-shell-stage .course-shell {
    padding-bottom: 64px;
  }
}

/* -- Crop-and-pan modal (upload flow) ------------------------------------ */

.puzzle-crop-modal {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(20, 16, 8, .55);
  padding: 20px;
}

.puzzle-crop-modal[hidden] {
  display: none;
}

.puzzle-crop-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 24px;
  max-width: 420px;
  width: 100%;
  text-align: center;
}

.puzzle-crop-title {
  font-family: Georgia, serif;
  font-size: 20px;
  margin: 0 0 8px;
  color: var(--text);
}

.puzzle-crop-hint {
  font-size: 13px;
  color: var(--muted);
  margin: 0 0 16px;
  line-height: 1.5;
}

.puzzle-crop-viewport {
  position: relative;
  width: min(80vw, 320px);
  aspect-ratio: 1 / 1;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--bg);
  cursor: grab;
  touch-action: none;
}

.puzzle-crop-viewport:active {
  cursor: grabbing;
}

.puzzle-crop-img {
  position: absolute;
  max-width: none;
  user-select: none;
  -webkit-user-drag: none;
  pointer-events: none;
}

.puzzle-crop-zoom {
  width: 100%;
  margin: 16px 0 4px;
  accent-color: var(--accent);
}

.puzzle-crop-msg {
  min-height: 18px;
  font-size: 13px;
  color: #b6432a;
  margin: 4px 0 0;
}

.puzzle-crop-actions {
  display: flex;
  gap: 12px;
  margin-top: 12px;
}

.puzzle-crop-actions .course-primary {
  flex: 1;
}

.puzzle-crop-cancel-btn {
  flex: 1;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  padding: 12px 14px;
  border-radius: 10px;
  cursor: pointer;
  transition: border-color .15s ease, color .15s ease;
}

.puzzle-crop-cancel-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}
