{"version":3,"sources":["/home/runner/work/chess-board/chess-board/dist/index.cjs","../src/components/chess/board.tsx","../src/lib/utils.ts","../src/utils/chess-helpers.ts","../src/utils/theme-utils.ts","../src/components/chess/square.tsx","../src/components/chess/piece.tsx","../src/components/chess/controls.tsx","../src/components/ui/button.tsx","../src/components/ui/dialog.tsx","../src/components/ui/label.tsx","../src/components/ui/textarea.tsx","../src/utils/pgn-utils.ts","../src/components/chess/move-history.tsx","../src/components/ui/scroll-area.tsx","../src/components/chess/timers.tsx","../src/components/chess/engine-controls.tsx","../src/components/ui/badge.tsx","../src/components/ui/slider.tsx","../src/components/chess/game-end-modal.tsx","../src/hooks/use-chess-game.ts","../src/utils/fen-utils.ts","../src/hooks/use-sound.ts","../src/hooks/use-socket.ts"],"names":["motion","jsx","useState","jsxs","formatMoveHistory","Play","Slot","cva","React","evaluation","Chess","useCallback","useMemo","useRef","_a"],"mappings":"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,IAAA;AACC,MAAA;AACT,MAAA;AACF,IAAA;AAEI,IAAA;AACF,MAAA;AACF,IAAA;AAEI,IAAA;AACY,MAAA;AACC,MAAA;AAEC,MAAA;AACF,QAAA;AACC,QAAA;AACA,QAAA;AACb,QAAA;AAGc,QAAA;AACL,UAAA;AACA,YAAA;AACG,cAAA;AACN,cAAA;AACA,cAAA;AACD,YAAA;AACH,UAAA;AACF,QAAA;AACF,MAAA;AAEO,MAAA;AACD,QAAA;AACI,UAAA;AACA,UAAA;AAEF,UAAA;AACF,YAAA;AACU,cAAA;AACT,YAAA;AACH,UAAA;AACY,QAAA;AACJ,UAAA;AACV,QAAA;AACF,MAAA;AAEO,MAAA;AACS,QAAA;AACL,QAAA;AACX,MAAA;AAEO,MAAA;AACO,QAAA;AACC,QAAA;AACH,QAAA;AAGN,QAAA;AACF,UAAA;AACA,UAAA;AAlJVG,YAAAA;AAmJoB,YAAA;AACR,YAAA;AAEC,UAAA;AACL,QAAA;AACF,MAAA;AAEU,MAAA;AACE,IAAA;AACE,MAAA;AACL,MAAA;AACX,IAAA;AACe,EAAA;AAGD,EAAA;AACH,IAAA;AACD,EAAA;AAEOH,EAAAA;AACb,IAAA;AACW,MAAA;AACb,MAAA;AACF,IAAA;AAEc,IAAA;AACF,MAAA;AACA,MAAA;AACZ,IAAA;AAEkB,IAAA;AACf,EAAA;AAEQA,EAAAA;AACkB,IAAA;AAEd,MAAA;AAGE,QAAA;AACb,QAAA;AACF,MAAA;AAEkC,MAAA;AAChC,QAAA;AACA,QAAA;AACW,QAAA;AACX,QAAA;AACF,MAAA;AAEU,MAAA;AACZ,IAAA;AACS,IAAA;AACX,EAAA;AAEkBA,EAAAA;AACa,IAAA;AACtB,MAAA;AACH,QAAA;AACF,MAAA;AAEM,MAAA;AACU,MAAA;AAGH,MAAA;AACC,QAAA;AACR,QAAA;AACF,UAAA;AACF,QAAA;AACF,MAAA;AACF,IAAA;AACC,IAAA;AACH,EAAA;AAGgB,EAAA;AA/NlB,IAAA;AAgOqB,IAAA;AAEf,MAAA;AACF,IAAA;AAEa,IAAA;AACA,MAAA;AACb,IAAA;AACe,EAAA;AAEV,EAAA;AACL,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACF;AvBg5DsB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/chess-board/chess-board/dist/index.cjs","sourcesContent":[null,"\"use client\";\n\nimport type { Square as ChessSquare } from \"chess.js\";\nimport React, { useCallback, useState } from \"react\";\nimport { motion } from \"motion/react\";\n\nimport type { UseChessGameReturn } from \"~/hooks/use-chess-game\";\nimport type { BoardTheme } from \"~/utils/theme-utils\";\nimport { cn } from \"~/lib/utils\";\nimport { getBoardPositions, getSquareFromCoords } from \"~/utils/chess-helpers\";\nimport { getBoardBorderClasses } from \"~/utils/theme-utils\";\nimport { Square } from \"./square\";\n\ninterface BoardProps {\n  game: UseChessGameReturn;\n  theme?: BoardTheme;\n  showCoordinates?: boolean;\n  interactive?: boolean;\n  size?: \"sm\" | \"md\" | \"lg\" | \"xl\";\n  onMove?: (from: ChessSquare, to: ChessSquare) => void;\n}\n\nconst BOARD_SIZES = {\n  sm: \"w-[320px] h-[320px]\",\n  md: \"w-[480px] h-[480px]\",\n  lg: \"w-[640px] h-[640px]\",\n  xl: \"w-[800px] h-[800px]\",\n};\n\n/**\n * Main chess board component\n */\nconst Board: React.FC<BoardProps> = ({\n  game,\n  theme = \"default\",\n  showCoordinates = true,\n  interactive = true,\n  size = \"lg\",\n  onMove,\n}) => {\n  const [draggedSquare, setDraggedSquare] = useState<ChessSquare | null>(null);\n  const positions = getBoardPositions(game.chess);\n  const { orientation, highlights } = game;\n\n  const handleSquareClick = useCallback(\n    (square: ChessSquare) => {\n      if (!interactive) return;\n      game.selectSquare(square);\n    },\n    [interactive, game],\n  );\n\n  const handleDragStart = useCallback((square: ChessSquare) => {\n    setDraggedSquare(square);\n  }, []);\n\n  const handleDragOver = useCallback((e: React.DragEvent) => {\n    e.preventDefault();\n  }, []);\n\n  const handleDrop = useCallback(\n    (targetSquare: ChessSquare) => {\n      if (!draggedSquare || !interactive) return;\n\n      const result = game.makeMove(draggedSquare, targetSquare);\n\n      if (result.success && onMove) {\n        onMove(draggedSquare, targetSquare);\n      }\n\n      setDraggedSquare(null);\n    },\n    [draggedSquare, interactive, game, onMove],\n  );\n\n  const renderBoard = () => {\n    const squares = [];\n\n    for (let row = 0; row < 8; row++) {\n      for (let col = 0; col < 8; col++) {\n        const square = getSquareFromCoords(row, col, orientation);\n        const position = positions.find((p) => p.square === square);\n\n        const isRankEdge = orientation === \"white\" ? row === 7 : row === 0;\n        const isFileEdge = orientation === \"white\" ? col === 0 : col === 7;\n\n        const isSelected = highlights.selected === square;\n        const isValidMove = highlights.validMoves.includes(square);\n        const isLastMove = highlights.lastMove.includes(square);\n        const isCheck = highlights.check === square;\n\n        squares.push(\n          <Square\n            key={square}\n            square={square}\n            piece={position?.piece || null}\n            theme={theme}\n            selected={isSelected}\n            validMove={isValidMove}\n            lastMove={isLastMove}\n            check={isCheck}\n            showCoordinates={showCoordinates}\n            isFileEdge={isFileEdge}\n            isRankEdge={isRankEdge}\n            orientation={orientation}\n            onClick={() => handleSquareClick(square)}\n            onDragStart={handleDragStart}\n            onDragOver={handleDragOver}\n            onDrop={handleDrop}\n          />,\n        );\n      }\n    }\n\n    return squares;\n  };\n\n  return (\n    <motion.div\n      className={cn(\n        \"grid grid-cols-8 grid-rows-8 rounded-lg shadow-2xl\",\n        BOARD_SIZES[size],\n        getBoardBorderClasses(theme),\n      )}\n      initial={{ opacity: 0, scale: 0.9 }}\n      animate={{ opacity: 1, scale: 1 }}\n      transition={{ duration: 0.3 }}\n    >\n      {renderBoard()}\n    </motion.div>\n  );\n};\n\nexport { Board };\nexport type { BoardProps };\n","import type { ClassValue } from \"clsx\";\nimport { clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n","import type { Move, PieceSymbol, Square } from \"chess.js\";\nimport { Chess } from \"chess.js\";\n\n/**\n * Chess helper utilities for board state management and move processing\n */\n\nexport type ChessColor = \"w\" | \"b\";\nexport type ChessPiece = {\n  type: PieceSymbol;\n  color: ChessColor;\n};\n\nexport interface BoardPosition {\n  square: Square;\n  piece: ChessPiece | null;\n}\n\nexport interface MoveHighlight {\n  square: Square;\n  type: \"selected\" | \"valid\" | \"lastMove\" | \"check\";\n}\n\n/**\n * Convert chess.js board state to a flat array of positions\n */\nexport function getBoardPositions(chess: Chess): BoardPosition[] {\n  const positions: BoardPosition[] = [];\n  const board = chess.board();\n\n  for (let row = 0; row < 8; row++) {\n    for (let col = 0; col < 8; col++) {\n      const piece = board[row][col];\n      const square = `${String.fromCharCode(97 + col)}${8 - row}` as Square;\n\n      positions.push({\n        square,\n        piece: piece\n          ? { type: piece.type, color: piece.color as ChessColor }\n          : null,\n      });\n    }\n  }\n\n  return positions;\n}\n\n/**\n * Get valid moves for a piece at a given square\n */\nexport function getValidMoves(chess: Chess, square: Square): Square[] {\n  const moves = chess.moves({ square, verbose: true }) as Move[];\n  return moves.map((move) => move.to);\n}\n\n/**\n * Check if a square is light or dark\n */\nexport function isLightSquare(square: Square): boolean {\n  const file = square.charCodeAt(0) - 97; // a=0, b=1, etc.\n  const rank = parseInt(square[1]);\n  return (file + rank) % 2 !== 0;\n}\n\n/**\n * Get square notation from coordinates\n */\nexport function getSquareFromCoords(\n  row: number,\n  col: number,\n  orientation: \"white\" | \"black\" = \"white\",\n): Square {\n  const actualRow = orientation === \"white\" ? 7 - row : row;\n  const actualCol = orientation === \"white\" ? col : 7 - col;\n  const file = String.fromCharCode(97 + actualCol);\n  const rank = actualRow + 1;\n  return `${file}${rank}` as Square;\n}\n\n/**\n * Get coordinates from square notation\n */\nexport function getCoordsFromSquare(\n  square: Square,\n  orientation: \"white\" | \"black\" = \"white\",\n): { row: number; col: number } {\n  const file = square.charCodeAt(0) - 97;\n  const rank = parseInt(square[1]) - 1;\n\n  if (orientation === \"white\") {\n    return { row: 7 - rank, col: file };\n  } else {\n    return { row: rank, col: 7 - file };\n  }\n}\n\n/**\n * Get piece image path\n */\nexport function getPieceImagePath(piece: ChessPiece): string {\n  const colorSuffix = piece.color === \"w\" ? \"w\" : \"b\";\n  const pieceNames: Record<PieceSymbol, string> = {\n    p: \"pawn\",\n    n: \"knight\",\n    b: \"bishop\",\n    r: \"rook\",\n    q: \"queen\",\n    k: \"king\",\n  };\n\n  return `/pieces/${pieceNames[piece.type]}-${colorSuffix}.svg`;\n}\n\n/**\n * Check if a move is a capture\n */\nexport function isCapture(chess: Chess, move: Move): boolean {\n  return move.captured !== undefined;\n}\n\n/**\n * Check if a move is castling\n */\nexport function isCastling(move: Move): boolean {\n  return move.flags.includes(\"k\") || move.flags.includes(\"q\");\n}\n\n/**\n * Check if a move is en passant\n */\nexport function isEnPassant(move: Move): boolean {\n  return move.flags.includes(\"e\");\n}\n\n/**\n * Check if a move is promotion\n */\nexport function isPromotion(move: Move): boolean {\n  return move.promotion !== undefined;\n}\n\n/**\n * Get game status message\n */\nexport function getGameStatus(chess: Chess): string {\n  if (chess.isCheckmate()) {\n    return `Checkmate! ${chess.turn() === \"w\" ? \"Black\" : \"White\"} wins`;\n  }\n  if (chess.isStalemate()) {\n    return \"Stalemate - Draw\";\n  }\n  if (chess.isThreefoldRepetition()) {\n    return \"Draw by threefold repetition\";\n  }\n  if (chess.isInsufficientMaterial()) {\n    return \"Draw by insufficient material\";\n  }\n  if (chess.isDraw()) {\n    return \"Draw\";\n  }\n  if (chess.isCheck()) {\n    return `${chess.turn() === \"w\" ? \"White\" : \"Black\"} is in check`;\n  }\n  return `${chess.turn() === \"w\" ? \"White\" : \"Black\"} to move`;\n}\n\n/**\n * Format move for display (e.g., \"e2-e4\", \"Nf3\", etc.)\n */\nexport function formatMoveNotation(move: Move): string {\n  return move.san;\n}\n\n/**\n * Get opposite color\n */\nexport function getOppositeColor(color: ChessColor): ChessColor {\n  return color === \"w\" ? \"b\" : \"w\";\n}\n\n/**\n * Parse move string and attempt to make move\n */\nexport function tryMakeMove(\n  chess: Chess,\n  from: Square,\n  to: Square,\n  promotion?: PieceSymbol,\n): Move | null {\n  try {\n    const move = chess.move({\n      from,\n      to,\n      promotion: promotion || \"q\",\n    });\n    return move;\n  } catch (error) {\n    console.error(error);\n    return null;\n  }\n}\n","/**\n * Theme utilities for chess board styling\n */\n\nexport type BoardTheme = \"default\" | \"wood\" | \"marble\" | \"neon\";\n\nexport interface BoardColors {\n  light: string;\n  dark: string;\n  highlight: string;\n  selected: string;\n  lastMove: string;\n  check: string;\n  validMove: string;\n  validMoveCapture: string;\n}\n\n/**\n * Board theme definitions\n */\nexport const BOARD_THEMES: Record<BoardTheme, BoardColors> = {\n  default: {\n    light: \"bg-zinc-200 dark:bg-zinc-700\",\n    dark: \"bg-zinc-400 dark:bg-zinc-900\",\n    highlight: \"bg-yellow-300/50 dark:bg-yellow-500/30\",\n    selected: \"bg-blue-400/60 dark:bg-blue-600/50\",\n    lastMove: \"bg-yellow-400/40 dark:bg-yellow-600/30\",\n    check: \"bg-red-500/50 dark:bg-red-700/50\",\n    validMove: \"bg-green-400/40 dark:bg-green-600/30\",\n    validMoveCapture: \"bg-red-400/40 dark:bg-red-600/30\",\n  },\n  wood: {\n    light: \"bg-amber-100 dark:bg-amber-200\",\n    dark: \"bg-amber-700 dark:bg-amber-900\",\n    highlight: \"bg-yellow-300/50 dark:bg-yellow-500/40\",\n    selected: \"bg-blue-400/50 dark:bg-blue-600/40\",\n    lastMove: \"bg-yellow-500/30 dark:bg-yellow-700/30\",\n    check: \"bg-red-500/60 dark:bg-red-700/50\",\n    validMove: \"bg-green-400/50 dark:bg-green-600/40\",\n    validMoveCapture: \"bg-red-400/50 dark:bg-red-600/40\",\n  },\n  marble: {\n    light: \"bg-slate-50 dark:bg-slate-200\",\n    dark: \"bg-slate-700 dark:bg-slate-900\",\n    highlight: \"bg-cyan-300/50 dark:bg-cyan-500/40\",\n    selected: \"bg-indigo-400/60 dark:bg-indigo-600/50\",\n    lastMove: \"bg-cyan-400/40 dark:bg-cyan-600/30\",\n    check: \"bg-pink-500/60 dark:bg-pink-700/50\",\n    validMove: \"bg-teal-400/50 dark:bg-teal-600/40\",\n    validMoveCapture: \"bg-rose-400/50 dark:bg-rose-600/40\",\n  },\n  neon: {\n    light: \"bg-purple-900 dark:bg-purple-950\",\n    dark: \"bg-pink-900 dark:bg-pink-950\",\n    highlight: \"bg-cyan-400/60 dark:bg-cyan-500/50\",\n    selected: \"bg-fuchsia-500/70 dark:bg-fuchsia-600/60\",\n    lastMove: \"bg-cyan-500/50 dark:bg-cyan-600/40\",\n    check: \"bg-red-500/70 dark:bg-red-600/60\",\n    validMove: \"bg-green-400/60 dark:bg-green-500/50\",\n    validMoveCapture: \"bg-red-400/60 dark:bg-red-500/50\",\n  },\n};\n\n/**\n * Get theme colors\n */\nexport function getThemeColors(theme: BoardTheme): BoardColors {\n  return BOARD_THEMES[theme] || BOARD_THEMES.default;\n}\n\n/**\n * Get square color classes based on square position and theme\n */\nexport function getSquareColorClasses(\n  isLight: boolean,\n  theme: BoardTheme,\n): string {\n  const colors = getThemeColors(theme);\n  return isLight ? colors.light : colors.dark;\n}\n\n/**\n * Get highlight color class\n */\nexport function getHighlightClass(\n  type: \"selected\" | \"valid\" | \"lastMove\" | \"check\" | \"validCapture\",\n  theme: BoardTheme,\n): string {\n  const colors = getThemeColors(theme);\n  switch (type) {\n    case \"selected\":\n      return colors.selected;\n    case \"valid\":\n      return colors.validMove;\n    case \"lastMove\":\n      return colors.lastMove;\n    case \"check\":\n      return colors.check;\n    case \"validCapture\":\n      return colors.validMoveCapture;\n    default:\n      return \"\";\n  }\n}\n\n/**\n * Get all available themes\n */\nexport function getAllThemes(): BoardTheme[] {\n  return Object.keys(BOARD_THEMES) as BoardTheme[];\n}\n\n/**\n * Get theme display name\n */\nexport function getThemeDisplayName(theme: BoardTheme): string {\n  const names: Record<BoardTheme, string> = {\n    default: \"Default\",\n    wood: \"Classic Wood\",\n    marble: \"Marble\",\n    neon: \"Neon\",\n  };\n  return names[theme] || \"Default\";\n}\n\n/**\n * Coordinate label styling\n */\nexport function getCoordinateLabelClasses(theme: BoardTheme): string {\n  const isDark = theme === \"neon\";\n  return isDark\n    ? \"text-cyan-300 font-semibold\"\n    : \"text-zinc-700 dark:text-zinc-300 font-medium\";\n}\n\n/**\n * Get board border classes\n */\nexport function getBoardBorderClasses(theme: BoardTheme): string {\n  const borders: Record<BoardTheme, string> = {\n    default: \"border-2 border-zinc-800 dark:border-zinc-200\",\n    wood: \"border-4 border-amber-800 dark:border-amber-950\",\n    marble: \"border-2 border-slate-800 dark:border-slate-200\",\n    neon: \"border-2 border-cyan-400 shadow-lg shadow-cyan-500/50\",\n  };\n  return borders[theme] || borders.default;\n}\n","\"use client\";\n\nimport type { Square as ChessSquare } from \"chess.js\";\nimport React from \"react\";\nimport { motion } from \"motion/react\";\n\nimport type { ChessPiece } from \"~/utils/chess-helpers\";\nimport type { BoardTheme } from \"~/utils/theme-utils\";\nimport { cn } from \"~/lib/utils\";\nimport { isLightSquare } from \"~/utils/chess-helpers\";\nimport { getHighlightClass, getSquareColorClasses } from \"~/utils/theme-utils\";\nimport { Piece } from \"./piece\";\n\ninterface SquareProps {\n  square: ChessSquare;\n  piece: ChessPiece | null;\n  theme: BoardTheme;\n  selected?: boolean;\n  validMove?: boolean;\n  lastMove?: boolean;\n  check?: boolean;\n  showCoordinates?: boolean;\n  isFileEdge?: boolean;\n  isRankEdge?: boolean;\n  orientation?: \"white\" | \"black\";\n  onClick?: () => void;\n  onDragStart?: (square: ChessSquare) => void;\n  onDragOver?: (e: React.DragEvent) => void;\n  onDrop?: (square: ChessSquare) => void;\n}\n\n/**\n * Individual chess board square with piece rendering\n */\nconst Square: React.FC<SquareProps> = ({\n  square,\n  piece,\n  theme,\n  selected = false,\n  validMove = false,\n  lastMove = false,\n  check = false,\n  showCoordinates = true,\n  isFileEdge = false,\n  isRankEdge = false,\n  onClick,\n  onDragStart,\n  onDragOver,\n  onDrop,\n}) => {\n  const isLight = isLightSquare(square);\n  const file = square[0];\n  const rank = square[1];\n\n  const baseClasses = getSquareColorClasses(isLight, theme);\n\n  // Determine highlight\n  let highlightClass = \"\";\n  if (check) {\n    highlightClass = getHighlightClass(\"check\", theme);\n  } else if (selected) {\n    highlightClass = getHighlightClass(\"selected\", theme);\n  } else if (lastMove) {\n    highlightClass = getHighlightClass(\"lastMove\", theme);\n  } else if (validMove) {\n    highlightClass = piece\n      ? getHighlightClass(\"validCapture\", theme)\n      : getHighlightClass(\"valid\", theme);\n  }\n\n  const handleDragStart = (e: React.DragEvent) => {\n    if (piece && onDragStart) {\n      e.dataTransfer.effectAllowed = \"move\";\n      e.dataTransfer.setData(\"text/plain\", square);\n      onDragStart(square);\n    }\n  };\n\n  const handleDragOver = (e: React.DragEvent) => {\n    if (onDragOver) {\n      e.preventDefault();\n      e.dataTransfer.dropEffect = \"move\";\n      onDragOver(e);\n    }\n  };\n\n  const handleDrop = (e: React.DragEvent) => {\n    e.preventDefault();\n    if (onDrop) {\n      onDrop(square);\n    }\n  };\n\n  const showFileLabel = showCoordinates && isRankEdge;\n  const showRankLabel = showCoordinates && isFileEdge;\n\n  return (\n    <div\n      className={cn(\n        \"relative flex h-full w-full items-center justify-center\",\n        baseClasses,\n        highlightClass,\n        \"transition-colors duration-150\",\n        onClick && \"cursor-pointer hover:brightness-110\",\n      )}\n      onClick={onClick}\n      onDragStart={handleDragStart}\n      onDragOver={handleDragOver}\n      onDrop={handleDrop}\n      draggable={!!piece}\n    >\n      {/* File label (bottom) */}\n      {showFileLabel && (\n        <span className=\"absolute right-0.5 bottom-0.5 text-xs font-semibold opacity-70\">\n          {file}\n        </span>\n      )}\n\n      {/* Rank label (left) */}\n      {showRankLabel && (\n        <span className=\"absolute top-0.5 left-0.5 text-xs font-semibold opacity-70\">\n          {rank}\n        </span>\n      )}\n\n      {/* Valid move indicator */}\n      {validMove && !piece && (\n        <motion.div\n          className=\"absolute h-3 w-3 rounded-full bg-current opacity-30\"\n          initial={{ scale: 0 }}\n          animate={{ scale: 1 }}\n          transition={{ type: \"spring\", stiffness: 400, damping: 15 }}\n        />\n      )}\n\n      {/* Valid capture indicator */}\n      {validMove && piece && (\n        <motion.div\n          className=\"absolute inset-0 rounded-full border-4 border-current opacity-40\"\n          initial={{ scale: 0 }}\n          animate={{ scale: 1 }}\n          transition={{ type: \"spring\", stiffness: 400, damping: 15 }}\n        />\n      )}\n\n      {/* Piece */}\n      {piece && (\n        <div className=\"absolute inset-0 flex items-center justify-center p-1\">\n          <Piece piece={piece} animate={true} />\n        </div>\n      )}\n    </div>\n  );\n};\n\nexport { Square };\n","\"use client\";\n\nimport Image from \"next/image\";\nimport { motion } from \"motion/react\";\n\nimport type { ChessPiece } from \"~/utils/chess-helpers\";\nimport { cn } from \"~/lib/utils\";\nimport { getPieceImagePath } from \"~/utils/chess-helpers\";\n\ninterface PieceProps {\n  piece: ChessPiece;\n  dragging?: boolean;\n  animate?: boolean;\n  size?: number;\n}\n\n/**\n * Chess piece component with animation support\n */\nconst Piece: React.FC<PieceProps> = ({\n  piece,\n  dragging = false,\n  animate = true,\n  size = 60,\n}) => {\n  const imagePath = getPieceImagePath(piece);\n\n  if (!animate) {\n    return (\n      <div className=\"relative\" style={{ width: size, height: size }}>\n        <Image\n          src={imagePath}\n          alt={`${piece.color === \"w\" ? \"White\" : \"Black\"} ${piece.type}`}\n          fill={true}\n          className={cn(\n            \"pointer-events-none object-contain select-none\",\n            dragging && \"opacity-50\",\n          )}\n          draggable={false}\n          priority={true}\n        />\n      </div>\n    );\n  }\n\n  return (\n    <motion.div\n      initial={{ scale: 0, opacity: 0 }}\n      animate={{\n        scale: dragging ? 1.2 : 1,\n        opacity: dragging ? 0.8 : 1,\n      }}\n      exit={{ scale: 0, opacity: 0 }}\n      transition={{\n        type: \"spring\",\n        stiffness: 300,\n        damping: 25,\n      }}\n      style={{\n        minWidth: size,\n        minHeight: size,\n      }}\n      className=\"relative size-full\"\n    >\n      <Image\n        src={imagePath}\n        alt={`${piece.color === \"w\" ? \"White\" : \"Black\"} ${piece.type}`}\n        fill={true}\n        className=\"pointer-events-none object-contain select-none\"\n        draggable={false}\n        priority={true}\n      />\n    </motion.div>\n  );\n};\n\nexport { Piece };\n","\"use client\";\n\nimport React, { useState } from \"react\";\nimport {\n  ArrowLeftRight,\n  Download,\n  RotateCcw,\n  Settings,\n  Undo,\n  Upload,\n  Volume2,\n  VolumeOff,\n} from \"lucide-react\";\nimport { motion } from \"motion/react\";\nimport { toast } from \"sonner\";\n\nimport type { UseChessGameReturn } from \"~/hooks/use-chess-game\";\nimport type { BoardTheme } from \"~/utils/theme-utils\";\nimport { Button } from \"~/components/ui/button\";\nimport {\n  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogHeader,\n  DialogTitle,\n  DialogTrigger,\n} from \"~/components/ui/dialog\";\nimport { Label } from \"~/components/ui/label\";\nimport { Textarea } from \"~/components/ui/textarea\";\nimport { cn } from \"~/lib/utils\";\nimport { downloadPGN } from \"~/utils/pgn-utils\";\n\ninterface ControlsProps {\n  game: UseChessGameReturn;\n  soundEnabled: boolean;\n  onToggleSound: () => void;\n  theme: BoardTheme;\n  onThemeChange: (theme: BoardTheme) => void;\n  className?: string;\n}\n\nconst THEMES: BoardTheme[] = [\"default\", \"wood\", \"marble\", \"neon\"];\n\n/**\n * Game controls component (reset, undo, flip, settings)\n */\nconst Controls: React.FC<ControlsProps> = ({\n  game,\n  soundEnabled,\n  onToggleSound,\n  theme,\n  onThemeChange,\n  className,\n}) => {\n  const [importDialogOpen, setImportDialogOpen] = useState(false);\n  const [exportDialogOpen, setExportDialogOpen] = useState(false);\n  const [settingsOpen, setSettingsOpen] = useState(false);\n  const [fenInput, setFenInput] = useState(\"\");\n  const [pgnInput, setPgnInput] = useState(\"\");\n\n  const handleUndo = () => {\n    const success = game.undoMove();\n    if (success) {\n      toast.success(\"Move undone\");\n    } else {\n      toast.error(\"No moves to undo\");\n    }\n  };\n\n  const handleReset = () => {\n    game.resetGame();\n    toast.success(\"Game reset\");\n  };\n\n  const handleFlip = () => {\n    game.flipBoard();\n  };\n\n  const handleExportPGN = () => {\n    const pgn = game.exportPGN();\n    downloadPGN(pgn, `chess-game-${Date.now()}.pgn`);\n    toast.success(\"Game exported as PGN\");\n  };\n\n  const handleImportFEN = () => {\n    const success = game.loadFEN(fenInput);\n    if (success) {\n      toast.success(\"Position loaded from FEN\");\n      setImportDialogOpen(false);\n      setFenInput(\"\");\n    } else {\n      toast.error(\"Invalid FEN string\");\n    }\n  };\n\n  const handleImportPGN = () => {\n    const success = game.loadPGN(pgnInput);\n    if (success) {\n      toast.success(\"Game loaded from PGN\");\n      setImportDialogOpen(false);\n      setPgnInput(\"\");\n    } else {\n      toast.error(\"Invalid PGN string\");\n    }\n  };\n\n  const handleCopyFEN = () => {\n    const fen = game.exportFEN();\n    navigator.clipboard.writeText(fen);\n    toast.success(\"FEN copied to clipboard\");\n  };\n\n  const handleCopyPGN = () => {\n    const pgn = game.exportPGN();\n    navigator.clipboard.writeText(pgn);\n    toast.success(\"PGN copied to clipboard\");\n  };\n\n  return (\n    <motion.div\n      className={cn(\"flex flex-wrap gap-2\", className)}\n      initial={{ opacity: 0, y: 20 }}\n      animate={{ opacity: 1, y: 0 }}\n      transition={{ delay: 0.2 }}\n    >\n      {/* Undo */}\n      <Button\n        variant=\"outline\"\n        size=\"icon\"\n        onClick={handleUndo}\n        disabled={game.moveHistory.length === 0}\n        title=\"Undo last move\"\n      >\n        <Undo className=\"h-4 w-4\" />\n      </Button>\n\n      {/* Reset */}\n      <Button\n        variant=\"outline\"\n        size=\"icon\"\n        onClick={handleReset}\n        title=\"Reset game\"\n      >\n        <RotateCcw className=\"h-4 w-4\" />\n      </Button>\n\n      {/* Flip board */}\n      <Button\n        variant=\"outline\"\n        size=\"icon\"\n        onClick={handleFlip}\n        title=\"Flip board\"\n      >\n        <ArrowLeftRight className=\"h-4 w-4\" />\n      </Button>\n\n      {/* Sound toggle */}\n      <Button\n        variant=\"outline\"\n        size=\"icon\"\n        onClick={onToggleSound}\n        title={soundEnabled ? \"Mute sounds\" : \"Enable sounds\"}\n      >\n        {soundEnabled ? (\n          <Volume2 className=\"h-4 w-4\" />\n        ) : (\n          <VolumeOff className=\"h-4 w-4\" />\n        )}\n      </Button>\n\n      {/* Import */}\n      <Dialog open={importDialogOpen} onOpenChange={setImportDialogOpen}>\n        <DialogTrigger asChild>\n          <Button variant=\"outline\" size=\"icon\" title=\"Import game\">\n            <Upload className=\"h-4 w-4\" />\n          </Button>\n        </DialogTrigger>\n        <DialogContent>\n          <DialogHeader>\n            <DialogTitle>Import Game</DialogTitle>\n            <DialogDescription>\n              Load a game from FEN or PGN notation\n            </DialogDescription>\n          </DialogHeader>\n          <div className=\"space-y-4\">\n            <div>\n              <Label htmlFor=\"fen-input\">FEN String</Label>\n              <Textarea\n                id=\"fen-input\"\n                placeholder=\"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1\"\n                value={fenInput}\n                onChange={(e) => setFenInput(e.target.value)}\n                rows={2}\n              />\n              <Button\n                onClick={handleImportFEN}\n                disabled={!fenInput}\n                className=\"mt-2\"\n                size=\"sm\"\n              >\n                Load FEN\n              </Button>\n            </div>\n            <div>\n              <Label htmlFor=\"pgn-input\">PGN String</Label>\n              <Textarea\n                id=\"pgn-input\"\n                placeholder=\"1. e4 e5 2. Nf3...\"\n                value={pgnInput}\n                onChange={(e) => setPgnInput(e.target.value)}\n                rows={4}\n              />\n              <Button\n                onClick={handleImportPGN}\n                disabled={!pgnInput}\n                className=\"mt-2\"\n                size=\"sm\"\n              >\n                Load PGN\n              </Button>\n            </div>\n          </div>\n        </DialogContent>\n      </Dialog>\n\n      {/* Export */}\n      <Dialog open={exportDialogOpen} onOpenChange={setExportDialogOpen}>\n        <DialogTrigger asChild>\n          <Button variant=\"outline\" size=\"icon\" title=\"Export game\">\n            <Download className=\"h-4 w-4\" />\n          </Button>\n        </DialogTrigger>\n        <DialogContent>\n          <DialogHeader>\n            <DialogTitle>Export Game</DialogTitle>\n            <DialogDescription>\n              Export current position as FEN or full game as PGN\n            </DialogDescription>\n          </DialogHeader>\n          <div className=\"space-y-4\">\n            <div>\n              <Label>Current Position (FEN)</Label>\n              <Textarea value={game.exportFEN()} readOnly rows={2} />\n              <Button onClick={handleCopyFEN} className=\"mt-2\" size=\"sm\">\n                Copy FEN\n              </Button>\n            </div>\n            <div>\n              <Label>Game Notation (PGN)</Label>\n              <Textarea value={game.exportPGN()} readOnly rows={6} />\n              <div className=\"mt-2 flex gap-2\">\n                <Button onClick={handleCopyPGN} size=\"sm\">\n                  Copy PGN\n                </Button>\n                <Button onClick={handleExportPGN} size=\"sm\" variant=\"outline\">\n                  Download PGN\n                </Button>\n              </div>\n            </div>\n          </div>\n        </DialogContent>\n      </Dialog>\n\n      {/* Settings */}\n      <Dialog open={settingsOpen} onOpenChange={setSettingsOpen}>\n        <DialogTrigger asChild>\n          <Button variant=\"outline\" size=\"icon\" title=\"Settings\">\n            <Settings className=\"h-4 w-4\" />\n          </Button>\n        </DialogTrigger>\n        <DialogContent>\n          <DialogHeader>\n            <DialogTitle>Settings</DialogTitle>\n            <DialogDescription>Customize your chess board</DialogDescription>\n          </DialogHeader>\n          <div className=\"space-y-4\">\n            <div>\n              <Label>Board Theme</Label>\n              <div className=\"mt-2 grid grid-cols-2 gap-2\">\n                {THEMES.map((t) => (\n                  <Button\n                    key={t}\n                    variant={theme === t ? \"default\" : \"outline\"}\n                    onClick={() => onThemeChange(t)}\n                    className=\"capitalize\"\n                  >\n                    {t}\n                  </Button>\n                ))}\n              </div>\n            </div>\n          </div>\n        </DialogContent>\n      </Dialog>\n    </motion.div>\n  );\n};\n\nexport { Controls };\n","import type { VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva } from \"class-variance-authority\";\n\nimport { cn } from \"~/lib/utils\";\n\nconst buttonVariants = cva(\n  \"focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n        destructive:\n          \"bg-destructive hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60 text-white\",\n        outline:\n          \"bg-background hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 border shadow-xs\",\n        secondary:\n          \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n        ghost:\n          \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\n        link: \"text-primary underline-offset-4 hover:underline\",\n      },\n      size: {\n        default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\n        sm: \"h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5\",\n        lg: \"h-10 rounded-md px-6 has-[>svg]:px-4\",\n        icon: \"size-9\",\n        \"icon-sm\": \"size-8\",\n        \"icon-lg\": \"size-10\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  },\n);\n\nfunction Button({\n  className,\n  variant,\n  size,\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"button\"> &\n  VariantProps<typeof buttonVariants> & {\n    asChild?: boolean;\n  }) {\n  const Comp = asChild ? Slot : \"button\";\n\n  return (\n    <Comp\n      data-slot=\"button\"\n      className={cn(buttonVariants({ variant, size, className }))}\n      {...props}\n    />\n  );\n}\n\nexport { Button, buttonVariants };\n","\"use client\";\n\nimport * as React from \"react\";\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { XIcon } from \"lucide-react\";\n\nimport { cn } from \"~/lib/utils\";\n\nfunction Dialog({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Root>) {\n  return <DialogPrimitive.Root data-slot=\"dialog\" {...props} />;\n}\n\nfunction DialogTrigger({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {\n  return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />;\n}\n\nfunction DialogPortal({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Portal>) {\n  return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />;\n}\n\nfunction DialogClose({\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Close>) {\n  return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />;\n}\n\nfunction DialogOverlay({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n  return (\n    <DialogPrimitive.Overlay\n      data-slot=\"dialog-overlay\"\n      className={cn(\n        \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction DialogContent({\n  className,\n  children,\n  showCloseButton = true,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Content> & {\n  showCloseButton?: boolean;\n}) {\n  return (\n    <DialogPortal data-slot=\"dialog-portal\">\n      <DialogOverlay />\n      <DialogPrimitive.Content\n        data-slot=\"dialog-content\"\n        className={cn(\n          \"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg\",\n          className,\n        )}\n        {...props}\n      >\n        {children}\n        {showCloseButton && (\n          <DialogPrimitive.Close\n            data-slot=\"dialog-close\"\n            className=\"ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\"\n          >\n            <XIcon />\n            <span className=\"sr-only\">Close</span>\n          </DialogPrimitive.Close>\n        )}\n      </DialogPrimitive.Content>\n    </DialogPortal>\n  );\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"dialog-header\"\n      className={cn(\"flex flex-col gap-2 text-center sm:text-left\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction DialogFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"dialog-footer\"\n      className={cn(\n        \"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction DialogTitle({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Title>) {\n  return (\n    <DialogPrimitive.Title\n      data-slot=\"dialog-title\"\n      className={cn(\"text-lg leading-none font-semibold\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction DialogDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n  return (\n    <DialogPrimitive.Description\n      data-slot=\"dialog-description\"\n      className={cn(\"text-muted-foreground text-sm\", className)}\n      {...props}\n    />\n  );\n}\n\nexport {\n  Dialog,\n  DialogClose,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogOverlay,\n  DialogPortal,\n  DialogTitle,\n  DialogTrigger,\n};\n","\"use client\";\n\nimport * as React from \"react\";\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\n\nimport { cn } from \"~/lib/utils\";\n\nfunction Label({\n  className,\n  ...props\n}: React.ComponentProps<typeof LabelPrimitive.Root>) {\n  return (\n    <LabelPrimitive.Root\n      data-slot=\"label\"\n      className={cn(\n        \"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport { Label };\n","import * as React from \"react\";\n\nimport { cn } from \"~/lib/utils\";\n\nfunction Textarea({ className, ...props }: React.ComponentProps<\"textarea\">) {\n  return (\n    <textarea\n      data-slot=\"textarea\"\n      className={cn(\n        \"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport { Textarea };\n","import { Chess } from \"chess.js\";\n\n/**\n * PGN (Portable Game Notation) utilities for game import/export\n */\n\nexport interface PGNMetadata {\n  Event?: string;\n  Site?: string;\n  Date?: string;\n  Round?: string;\n  White?: string;\n  Black?: string;\n  Result?: string;\n  WhiteElo?: string;\n  BlackElo?: string;\n  TimeControl?: string;\n  ECO?: string;\n  Opening?: string;\n  Annotator?: string;\n}\n\nexport interface ParsedPGN {\n  metadata: PGNMetadata;\n  moves: string[];\n  result: string;\n  pgn: string;\n}\n\n/**\n * Export game to PGN format\n */\nexport function exportPGN(\n  chess: Chess,\n  metadata: Partial<PGNMetadata> = {},\n): string {\n  const defaultMetadata: PGNMetadata = {\n    Event: \"Casual Game\",\n    Site: \"Chess Board\",\n    Date: new Date().toISOString().split(\"T\")[0].replace(/-/g, \".\"),\n    Round: \"?\",\n    White: \"Player 1\",\n    Black: \"Player 2\",\n    Result: getGameResult(chess),\n    ...metadata,\n  };\n\n  // Build PGN header\n  const headers = Object.entries(defaultMetadata)\n    .map(([key, value]) => `[${key} \"${value}\"]`)\n    .join(\"\\n\");\n\n  // Get move text\n  const moveText = chess.pgn({\n    maxWidth: 80,\n    newline: \"\\n\",\n  });\n\n  return `${headers}\\n\\n${moveText}`;\n}\n\n/**\n * Import PGN and load into chess instance\n */\nexport function importPGN(chess: Chess, pgn: string): boolean {\n  try {\n    chess.loadPgn(pgn);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Parse PGN string into metadata and moves\n */\nexport function parsePGN(pgn: string): ParsedPGN | null {\n  try {\n    const chess = new Chess();\n    chess.loadPgn(pgn);\n\n    const metadata: PGNMetadata = {};\n    const headerRegex = /\\[(\\w+)\\s+\"([^\"]+)\"\\]/g;\n    let match;\n\n    while ((match = headerRegex.exec(pgn)) !== null) {\n      metadata[match[1] as keyof PGNMetadata] = match[2];\n    }\n\n    const history = chess.history();\n    const result = metadata.Result || \"*\";\n\n    return {\n      metadata,\n      moves: history,\n      result,\n      pgn,\n    };\n  } catch {\n    return null;\n  }\n}\n\n/**\n * Get game result string\n */\nexport function getGameResult(chess: Chess): string {\n  if (chess.isCheckmate()) {\n    return chess.turn() === \"w\" ? \"0-1\" : \"1-0\";\n  }\n  if (chess.isDraw() || chess.isStalemate() || chess.isThreefoldRepetition()) {\n    return \"1/2-1/2\";\n  }\n  return \"*\"; // Game in progress\n}\n\n/**\n * Format move history as numbered list\n */\nexport function formatMoveHistory(\n  moves: string[],\n  startMoveNumber: number = 1,\n): string {\n  let result = \"\";\n  let moveNumber = startMoveNumber;\n\n  for (let i = 0; i < moves.length; i += 2) {\n    result += `${moveNumber}. ${moves[i]}`;\n    if (i + 1 < moves.length) {\n      result += ` ${moves[i + 1]}`;\n    }\n    result += \"\\n\";\n    moveNumber++;\n  }\n\n  return result.trim();\n}\n\n/**\n * Export game to PGN with move list\n */\nexport function exportPGNWithMoves(\n  moves: string[],\n  metadata: Partial<PGNMetadata> = {},\n): string {\n  const chess = new Chess();\n\n  // Replay all moves\n  for (const move of moves) {\n    try {\n      chess.move(move);\n    } catch {\n      // Invalid move, stop here\n      break;\n    }\n  }\n\n  return exportPGN(chess, metadata);\n}\n\n/**\n * Validate PGN string\n */\nexport function isValidPGN(pgn: string): boolean {\n  try {\n    const chess = new Chess();\n    chess.loadPgn(pgn);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Extract moves from PGN\n */\nexport function extractMovesFromPGN(pgn: string): string[] {\n  const chess = new Chess();\n  try {\n    chess.loadPgn(pgn);\n    return chess.history();\n  } catch {\n    return [];\n  }\n}\n\n/**\n * Get current position as PGN comment\n */\nexport function addPositionComment(\n  pgn: string,\n  comment: string,\n): string | null {\n  try {\n    const chess = new Chess();\n    chess.loadPgn(pgn);\n\n    const history = chess.history({ verbose: true });\n    if (history.length === 0) return pgn;\n\n    // Add comment to last move\n    const pgnWithComment = pgn.replace(/\\*$/, `{${comment}} *`);\n    return pgnWithComment;\n  } catch {\n    return null;\n  }\n}\n\n/**\n * Download PGN as file\n */\nexport function downloadPGN(pgn: string, filename: string = \"game.pgn\"): void {\n  const blob = new Blob([pgn], { type: \"text/plain\" });\n  const url = URL.createObjectURL(blob);\n  const link = document.createElement(\"a\");\n  link.href = url;\n  link.download = filename;\n  document.body.appendChild(link);\n  link.click();\n  document.body.removeChild(link);\n  URL.revokeObjectURL(url);\n}\n\n/**\n * Create shareable game link with PGN data\n */\nexport function createShareableLink(pgn: string, baseUrl: string): string {\n  const encoded = encodeURIComponent(pgn);\n  return `${baseUrl}?pgn=${encoded}`;\n}\n\n/**\n * Load PGN from URL parameter\n */\nexport function loadPGNFromURL(): string | null {\n  if (typeof window === \"undefined\") return null;\n\n  const params = new URLSearchParams(window.location.search);\n  const pgnParam = params.get(\"pgn\");\n\n  if (!pgnParam) return null;\n\n  try {\n    return decodeURIComponent(pgnParam);\n  } catch {\n    return null;\n  }\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { motion } from \"motion/react\";\n\nimport { ScrollArea } from \"~/components/ui/scroll-area\";\nimport { cn } from \"~/lib/utils\";\n\ninterface MoveHistoryProps {\n  moves: string[];\n  currentMoveNumber: number;\n  className?: string;\n}\n\n/**\n * Move history display component\n */\nconst MoveHistory: React.FC<MoveHistoryProps> = ({ moves, className }) => {\n  const formatMoveHistory = () => {\n    const formatted: Array<{\n      moveNumber: number;\n      white: string;\n      black?: string;\n    }> = [];\n\n    for (let i = 0; i < moves.length; i += 2) {\n      formatted.push({\n        moveNumber: Math.floor(i / 2) + 1,\n        white: moves[i],\n        black: moves[i + 1],\n      });\n    }\n\n    return formatted;\n  };\n\n  const formattedMoves = formatMoveHistory();\n\n  if (moves.length === 0) {\n    return (\n      <div\n        className={cn(\n          \"border-border bg-muted/20 flex h-64 items-center justify-center rounded-lg border p-4\",\n          className,\n        )}\n      >\n        <p className=\"text-muted-foreground text-sm\">No moves yet</p>\n      </div>\n    );\n  }\n\n  return (\n    <motion.div\n      className={cn(\n        \"border-border bg-background rounded-lg border p-4\",\n        className,\n      )}\n      initial={{ opacity: 0, y: 20 }}\n      animate={{ opacity: 1, y: 0 }}\n      transition={{ delay: 0.3 }}\n    >\n      <h3 className=\"mb-3 text-sm font-semibold\">Move History</h3>\n      <ScrollArea className=\"h-64\">\n        <div className=\"space-y-1\">\n          {formattedMoves.map((move, index) => (\n            <div\n              key={index}\n              className={cn(\n                \"grid grid-cols-[auto_1fr_1fr] gap-3 rounded px-2 py-1 text-sm transition-colors\",\n                index === formattedMoves.length - 1 && \"bg-accent font-medium\",\n              )}\n            >\n              <span className=\"text-muted-foreground font-semibold\">\n                {move.moveNumber}.\n              </span>\n              <span className=\"font-mono\">{move.white}</span>\n              <span className=\"font-mono\">{move.black || \"\"}</span>\n            </div>\n          ))}\n        </div>\n      </ScrollArea>\n      <div className=\"border-border text-muted-foreground mt-3 border-t pt-3 text-xs\">\n        Total moves: {moves.length}\n      </div>\n    </motion.div>\n  );\n};\n\nexport { MoveHistory };\n","\"use client\"\n\nimport * as React from \"react\"\nimport * as ScrollAreaPrimitive from \"@radix-ui/react-scroll-area\"\n\nimport { cn } from \"~/lib/utils\"\n\nfunction ScrollArea({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {\n  return (\n    <ScrollAreaPrimitive.Root\n      data-slot=\"scroll-area\"\n      className={cn(\"relative\", className)}\n      {...props}\n    >\n      <ScrollAreaPrimitive.Viewport\n        data-slot=\"scroll-area-viewport\"\n        className=\"focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1\"\n      >\n        {children}\n      </ScrollAreaPrimitive.Viewport>\n      <ScrollBar />\n      <ScrollAreaPrimitive.Corner />\n    </ScrollAreaPrimitive.Root>\n  )\n}\n\nfunction ScrollBar({\n  className,\n  orientation = \"vertical\",\n  ...props\n}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {\n  return (\n    <ScrollAreaPrimitive.ScrollAreaScrollbar\n      data-slot=\"scroll-area-scrollbar\"\n      orientation={orientation}\n      className={cn(\n        \"flex touch-none p-px transition-colors select-none\",\n        orientation === \"vertical\" &&\n          \"h-full w-2.5 border-l border-l-transparent\",\n        orientation === \"horizontal\" &&\n          \"h-2.5 flex-col border-t border-t-transparent\",\n        className\n      )}\n      {...props}\n    >\n      <ScrollAreaPrimitive.ScrollAreaThumb\n        data-slot=\"scroll-area-thumb\"\n        className=\"bg-border relative flex-1 rounded-full\"\n      />\n    </ScrollAreaPrimitive.ScrollAreaScrollbar>\n  )\n}\n\nexport { ScrollArea, ScrollBar }\n","\"use client\";\n\nimport { useEffect } from \"react\";\nimport { Pause, Play } from \"lucide-react\";\nimport { motion } from \"motion/react\";\n\nimport { Button } from \"~/components/ui/button\";\nimport { cn } from \"~/lib/utils\";\n\ninterface TimersProps {\n  whiteTime: number; // in seconds\n  blackTime: number; // in seconds\n  currentTurn: \"w\" | \"b\";\n  running: boolean;\n  onTimeUpdate: (color: \"w\" | \"b\", time: number) => void;\n  onTimeExpired: (color: \"w\" | \"b\") => void;\n  onTogglePause: () => void;\n  className?: string;\n}\n\n/**\n * Chess clock component with countdown timers\n */\nconst Timers: React.FC<TimersProps> = ({\n  whiteTime,\n  blackTime,\n  currentTurn,\n  running,\n  onTimeUpdate,\n  onTimeExpired,\n  onTogglePause,\n  className,\n}) => {\n  useEffect(() => {\n    if (!running) return;\n\n    const interval = setInterval(() => {\n      if (currentTurn === \"w\") {\n        onTimeUpdate(\"w\", Math.max(0, whiteTime - 1));\n        if (whiteTime <= 1) {\n          onTimeExpired(\"w\");\n        }\n      } else {\n        onTimeUpdate(\"b\", Math.max(0, blackTime - 1));\n        if (blackTime <= 1) {\n          onTimeExpired(\"b\");\n        }\n      }\n    }, 1000);\n\n    return () => clearInterval(interval);\n  }, [running, currentTurn, onTimeUpdate, onTimeExpired, whiteTime, blackTime]);\n\n  const formatTime = (seconds: number): string => {\n    const mins = Math.floor(seconds / 60);\n    const secs = seconds % 60;\n    return `${mins}:${secs.toString().padStart(2, \"0\")}`;\n  };\n\n  const getTimeColor = (time: number, isActive: boolean): string => {\n    if (!isActive) return \"text-muted-foreground\";\n    if (time <= 10) return \"text-red-500\";\n    if (time <= 30) return \"text-orange-500\";\n    return \"text-foreground\";\n  };\n\n  return (\n    <div className={cn(\"space-y-2\", className)}>\n      {/* Black timer */}\n      <motion.div\n        className={cn(\n          \"flex items-center justify-between rounded-lg border-2 p-4 transition-all\",\n          currentTurn === \"b\" && running\n            ? \"border-primary bg-accent\"\n            : \"border-border bg-muted/20\",\n        )}\n        animate={{\n          scale: currentTurn === \"b\" && running ? 1.02 : 1,\n        }}\n      >\n        <div className=\"flex items-center gap-2\">\n          <div className=\"h-3 w-3 rounded-full bg-zinc-900\" />\n          <span className=\"font-semibold\">Black</span>\n        </div>\n        <motion.span\n          className={cn(\n            \"font-mono text-2xl font-bold tabular-nums\",\n            getTimeColor(blackTime, currentTurn === \"b\" && running),\n          )}\n          animate={{\n            scale:\n              currentTurn === \"b\" && running && blackTime <= 10\n                ? [1, 1.1, 1]\n                : 1,\n          }}\n          transition={{ repeat: Infinity, duration: 1 }}\n        >\n          {formatTime(blackTime)}\n        </motion.span>\n      </motion.div>\n\n      {/* Pause/Play button */}\n      <div className=\"flex justify-center\">\n        <Button\n          variant=\"outline\"\n          size=\"icon\"\n          onClick={onTogglePause}\n          className=\"h-8 w-8\"\n        >\n          {running ? (\n            <Pause className=\"h-4 w-4\" />\n          ) : (\n            <Play className=\"h-4 w-4\" />\n          )}\n        </Button>\n      </div>\n\n      {/* White timer */}\n      <motion.div\n        className={cn(\n          \"flex items-center justify-between rounded-lg border-2 p-4 transition-all\",\n          currentTurn === \"w\" && running\n            ? \"border-primary bg-accent\"\n            : \"border-border bg-muted/20\",\n        )}\n        animate={{\n          scale: currentTurn === \"w\" && running ? 1.02 : 1,\n        }}\n      >\n        <div className=\"flex items-center gap-2\">\n          <div className=\"h-3 w-3 rounded-full bg-zinc-100 ring-1 ring-zinc-400\" />\n          <span className=\"font-semibold\">White</span>\n        </div>\n        <motion.span\n          className={cn(\n            \"font-mono text-2xl font-bold tabular-nums\",\n            getTimeColor(whiteTime, currentTurn === \"w\" && running),\n          )}\n          animate={{\n            scale:\n              currentTurn === \"w\" && running && whiteTime <= 10\n                ? [1, 1.1, 1]\n                : 1,\n          }}\n          transition={{ repeat: Infinity, duration: 1 }}\n        >\n          {formatTime(whiteTime)}\n        </motion.span>\n      </motion.div>\n    </div>\n  );\n};\n\nexport { Timers };\n","\"use client\";\n\nimport React, { useState } from \"react\";\nimport { Bot, Play, X } from \"lucide-react\";\nimport { motion } from \"motion/react\";\n\nimport { Badge } from \"~/components/ui/badge\";\nimport { Button } from \"~/components/ui/button\";\nimport { Label } from \"~/components/ui/label\";\nimport { Slider } from \"~/components/ui/slider\";\nimport { cn } from \"~/lib/utils\";\n\ninterface EngineControlsProps {\n  enabled: boolean;\n  thinking: boolean;\n  evaluation?: number;\n  depth?: number;\n  bestMove?: string;\n  onToggle: () => void;\n  onRequestMove: () => void;\n  onDepthChange?: (depth: number) => void;\n  className?: string;\n}\n\n/**\n * Stockfish engine controls (placeholder for future integration)\n */\nconst EngineControls: React.FC<EngineControlsProps> = ({\n  enabled,\n  thinking,\n  evaluation = 0,\n  depth = 15,\n  bestMove,\n  onToggle,\n  onRequestMove,\n  onDepthChange,\n  className,\n}) => {\n  const [localDepth, setLocalDepth] = useState(depth);\n\n  const formatEvaluation = (evaluation: number): string => {\n    if (Math.abs(evaluation) > 100) {\n      return evaluation > 0 ? \"M+\" : \"M-\";\n    }\n    return (evaluation / 100).toFixed(2);\n  };\n\n  const getEvaluationColor = (evaluation: number): string => {\n    if (evaluation > 2) return \"text-green-600 dark:text-green-400\";\n    if (evaluation > 0.5) return \"text-green-500 dark:text-green-500\";\n    if (evaluation < -2) return \"text-red-600 dark:text-red-400\";\n    if (evaluation < -0.5) return \"text-red-500 dark:text-red-500\";\n    return \"text-muted-foreground\";\n  };\n\n  const handleDepthChange = (value: number[]) => {\n    setLocalDepth(value[0]);\n    if (onDepthChange) {\n      onDepthChange(value[0]);\n    }\n  };\n\n  return (\n    <motion.div\n      className={cn(\n        \"border-border bg-background rounded-lg border p-4\",\n        className,\n      )}\n      initial={{ opacity: 0, y: 20 }}\n      animate={{ opacity: 1, y: 0 }}\n      transition={{ delay: 0.4 }}\n    >\n      <div className=\"mb-4 flex items-center justify-between\">\n        <div className=\"flex items-center gap-2\">\n          <Bot className=\"h-5 w-5\" />\n          <h3 className=\"text-sm font-semibold\">Engine Analysis</h3>\n        </div>\n        <Button\n          variant={enabled ? \"default\" : \"outline\"}\n          size=\"sm\"\n          onClick={onToggle}\n        >\n          {enabled ? (\n            <>\n              <X className=\"mr-1 h-3 w-3\" />\n              Disable\n            </>\n          ) : (\n            \"Enable\"\n          )}\n        </Button>\n      </div>\n\n      {enabled && (\n        <div className=\"space-y-4\">\n          {/* Evaluation */}\n          <div>\n            <Label className=\"text-xs\">Position Evaluation</Label>\n            <div className=\"mt-2 flex items-center justify-between\">\n              <span className=\"text-muted-foreground text-xs\">Black</span>\n              <motion.span\n                className={cn(\n                  \"font-mono text-xl font-bold\",\n                  getEvaluationColor(evaluation),\n                )}\n                key={evaluation}\n                initial={{ scale: 1.2 }}\n                animate={{ scale: 1 }}\n              >\n                {formatEvaluation(evaluation)}\n              </motion.span>\n              <span className=\"text-muted-foreground text-xs\">White</span>\n            </div>\n          </div>\n\n          {/* Depth control */}\n          <div>\n            <Label className=\"text-xs\">Search Depth: {localDepth}</Label>\n            <Slider\n              value={[localDepth]}\n              onValueChange={handleDepthChange}\n              min={5}\n              max={25}\n              step={1}\n              className=\"mt-2\"\n            />\n          </div>\n\n          {/* Best move */}\n          {bestMove && (\n            <div>\n              <Label className=\"text-xs\">Best Move</Label>\n              <div className=\"mt-2 flex items-center justify-between\">\n                <Badge variant=\"secondary\" className=\"font-mono\">\n                  {bestMove}\n                </Badge>\n                <Button\n                  size=\"sm\"\n                  variant=\"outline\"\n                  onClick={onRequestMove}\n                  disabled={thinking}\n                >\n                  {thinking ? (\n                    <>\n                      <motion.div\n                        className=\"mr-2 h-3 w-3 rounded-full border-2 border-current border-t-transparent\"\n                        animate={{ rotate: 360 }}\n                        transition={{\n                          repeat: Infinity,\n                          duration: 1,\n                          ease: \"linear\",\n                        }}\n                      />\n                      Thinking...\n                    </>\n                  ) : (\n                    <>\n                      <Play className=\"mr-1 h-3 w-3\" />\n                      Play Move\n                    </>\n                  )}\n                </Button>\n              </div>\n            </div>\n          )}\n\n          {/* Note */}\n          <p className=\"text-muted-foreground text-xs\">\n            Note: Stockfish integration is a placeholder. Implement using\n            stockfish.js or WASM.\n          </p>\n        </div>\n      )}\n    </motion.div>\n  );\n};\n\nexport { EngineControls };\n","import type { VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva } from \"class-variance-authority\";\n\nimport { cn } from \"~/lib/utils\";\n\nconst badgeVariants = cva(\n  \"focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] [&>svg]:pointer-events-none [&>svg]:size-3\",\n  {\n    variants: {\n      variant: {\n        default:\n          \"bg-primary text-primary-foreground [a&]:hover:bg-primary/90 border-transparent\",\n        secondary:\n          \"bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90 border-transparent\",\n        destructive:\n          \"bg-destructive [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60 border-transparent text-white\",\n        outline:\n          \"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n    },\n  },\n);\n\nfunction Badge({\n  className,\n  variant,\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"span\"> &\n  VariantProps<typeof badgeVariants> & { asChild?: boolean }) {\n  const Comp = asChild ? Slot : \"span\";\n\n  return (\n    <Comp\n      data-slot=\"badge\"\n      className={cn(badgeVariants({ variant }), className)}\n      {...props}\n    />\n  );\n}\n\nexport { Badge, badgeVariants };\n","\"use client\"\n\nimport * as React from \"react\"\nimport * as SliderPrimitive from \"@radix-ui/react-slider\"\n\nimport { cn } from \"~/lib/utils\"\n\nfunction Slider({\n  className,\n  defaultValue,\n  value,\n  min = 0,\n  max = 100,\n  ...props\n}: React.ComponentProps<typeof SliderPrimitive.Root>) {\n  const _values = React.useMemo(\n    () =>\n      Array.isArray(value)\n        ? value\n        : Array.isArray(defaultValue)\n          ? defaultValue\n          : [min, max],\n    [value, defaultValue, min, max]\n  )\n\n  return (\n    <SliderPrimitive.Root\n      data-slot=\"slider\"\n      defaultValue={defaultValue}\n      value={value}\n      min={min}\n      max={max}\n      className={cn(\n        \"relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col\",\n        className\n      )}\n      {...props}\n    >\n      <SliderPrimitive.Track\n        data-slot=\"slider-track\"\n        className={cn(\n          \"bg-muted relative grow overflow-hidden rounded-full data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5\"\n        )}\n      >\n        <SliderPrimitive.Range\n          data-slot=\"slider-range\"\n          className={cn(\n            \"bg-primary absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full\"\n          )}\n        />\n      </SliderPrimitive.Track>\n      {Array.from({ length: _values.length }, (_, index) => (\n        <SliderPrimitive.Thumb\n          data-slot=\"slider-thumb\"\n          key={index}\n          className=\"border-primary ring-ring/50 block size-4 shrink-0 rounded-full border bg-white shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50\"\n        />\n      ))}\n    </SliderPrimitive.Root>\n  )\n}\n\nexport { Slider }\n","\"use client\";\n\nimport React from \"react\";\nimport { Minus, RotateCcw, Trophy } from \"lucide-react\";\nimport { AnimatePresence, motion } from \"motion/react\";\n\nimport { Button } from \"~/components/ui/button\";\nimport {\n  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle,\n} from \"~/components/ui/dialog\";\nimport { cn } from \"~/lib/utils\";\n\ninterface GameEndModalProps {\n  open: boolean;\n  winner: \"white\" | \"black\" | \"draw\" | null;\n  reason?: string;\n  whitePlayer?: string;\n  blackPlayer?: string;\n  onRematch: () => void;\n  onClose: () => void;\n}\n\n/**\n * Game end modal with animations\n */\nconst GameEndModal: React.FC<GameEndModalProps> = ({\n  open,\n  winner,\n  reason = \"Checkmate\",\n  whitePlayer = \"White\",\n  blackPlayer = \"Black\",\n  onRematch,\n  onClose,\n}) => {\n  const getTitle = () => {\n    if (winner === \"draw\") return \"Game Draw\";\n    if (winner === \"white\") return `${whitePlayer} Wins!`;\n    if (winner === \"black\") return `${blackPlayer} Wins!`;\n    return \"Game Over\";\n  };\n\n  const getIcon = () => {\n    if (winner === \"draw\") {\n      return (\n        <motion.div\n          initial={{ scale: 0, rotate: -180 }}\n          animate={{ scale: 1, rotate: 0 }}\n          transition={{ type: \"spring\", stiffness: 200, damping: 15 }}\n        >\n          <Minus className=\"text-muted-foreground h-16 w-16\" />\n        </motion.div>\n      );\n    }\n\n    return (\n      <motion.div\n        initial={{ scale: 0, y: 50 }}\n        animate={{ scale: 1, y: 0 }}\n        transition={{ type: \"spring\", stiffness: 200, damping: 15 }}\n      >\n        <Trophy\n          className={cn(\n            \"h-16 w-16\",\n            winner === \"white\"\n              ? \"text-yellow-500\"\n              : winner === \"black\"\n                ? \"text-yellow-600\"\n                : \"text-muted-foreground\",\n          )}\n        />\n      </motion.div>\n    );\n  };\n\n  return (\n    <Dialog open={open} onOpenChange={onClose}>\n      <DialogContent className=\"sm:max-w-md\">\n        <DialogHeader>\n          <div className=\"flex justify-center py-4\">{getIcon()}</div>\n          <DialogTitle className=\"text-center text-2xl\">\n            {getTitle()}\n          </DialogTitle>\n          <DialogDescription className=\"text-center\">\n            {reason}\n          </DialogDescription>\n        </DialogHeader>\n\n        <AnimatePresence>\n          {winner && (\n            <motion.div\n              initial={{ opacity: 0, height: 0 }}\n              animate={{ opacity: 1, height: \"auto\" }}\n              exit={{ opacity: 0, height: 0 }}\n              className=\"border-border bg-muted/50 space-y-2 rounded-lg border p-4\"\n            >\n              <div className=\"flex justify-between text-sm\">\n                <span className=\"font-medium\">Winner:</span>\n                <span className=\"capitalize\">\n                  {winner === \"draw\" ? \"Draw\" : winner}\n                </span>\n              </div>\n              <div className=\"flex justify-between text-sm\">\n                <span className=\"font-medium\">Result:</span>\n                <span className=\"font-mono\">\n                  {winner === \"white\"\n                    ? \"1-0\"\n                    : winner === \"black\"\n                      ? \"0-1\"\n                      : \"½-½\"}\n                </span>\n              </div>\n            </motion.div>\n          )}\n        </AnimatePresence>\n\n        <DialogFooter className=\"flex-col gap-2 sm:flex-row\">\n          <Button variant=\"outline\" onClick={onClose} className=\"w-full\">\n            Close\n          </Button>\n          <Button onClick={onRematch} className=\"w-full\">\n            <RotateCcw className=\"mr-2 h-4 w-4\" />\n            Rematch\n          </Button>\n        </DialogFooter>\n      </DialogContent>\n    </Dialog>\n  );\n};\n\nexport { GameEndModal };\n","\"use client\";\n\nimport type { Move, PieceSymbol, Square } from \"chess.js\";\nimport { useCallback, useState } from \"react\";\nimport { Chess } from \"chess.js\";\n\nimport {\n  getGameStatus,\n  getValidMoves,\n  isCapture,\n  tryMakeMove,\n} from \"~/utils/chess-helpers\";\nimport { getFEN, loadFEN, STARTING_FEN } from \"~/utils/fen-utils\";\nimport { exportPGN, getGameResult } from \"~/utils/pgn-utils\";\n\nexport type Orientation = \"white\" | \"black\";\n\nexport interface MoveResult {\n  success: boolean;\n  move?: Move;\n  isCapture?: boolean;\n  isCheck?: boolean;\n  isCheckmate?: boolean;\n  isGameOver?: boolean;\n}\n\nexport interface HighlightSquares {\n  selected?: Square;\n  validMoves: Square[];\n  lastMove: Square[];\n  check?: Square;\n}\n\ninterface UseChessGameOptions {\n  initialFen?: string;\n  orientation?: Orientation;\n  onMove?: (move: Move) => void;\n  onGameOver?: (result: string) => void;\n}\n\nexport interface UseChessGameReturn {\n  // Game state\n  chess: Chess;\n  fen: string;\n  turn: \"w\" | \"b\";\n  gameOver: boolean;\n  winner: \"white\" | \"black\" | \"draw\" | null;\n  status: string;\n  moveHistory: string[];\n  currentMoveNumber: number;\n\n  // Board state\n  orientation: Orientation;\n  highlights: HighlightSquares;\n  inCheck: boolean;\n\n  // Actions\n  makeMove: (from: Square, to: Square, promotion?: PieceSymbol) => MoveResult;\n  selectSquare: (square: Square) => void;\n  clearSelection: () => void;\n  undoMove: () => boolean;\n  resetGame: () => void;\n  flipBoard: () => void;\n\n  // Import/Export\n  loadFEN: (fen: string) => boolean;\n  loadPGN: (pgn: string) => boolean;\n  exportPGN: (metadata?: Record<string, string>) => string;\n  exportFEN: () => string;\n\n  // Utility\n  isValidMove: (from: Square, to: Square) => boolean;\n  getValidMovesForSquare: (square: Square) => Square[];\n  getPieceAt: (\n    square: Square,\n  ) => { type: PieceSymbol; color: \"w\" | \"b\" } | null;\n}\n\n/**\n * Main chess game hook - encapsulates all game logic\n */\nexport function useChessGame(\n  options: UseChessGameOptions = {},\n): UseChessGameReturn {\n  const {\n    initialFen = STARTING_FEN,\n    orientation: initialOrientation = \"white\",\n    onMove,\n    onGameOver,\n  } = options;\n\n  // Core game state\n  const [chess] = useState(() => new Chess(initialFen));\n  const [fen, setFen] = useState(initialFen);\n  const [orientation, setOrientation] =\n    useState<Orientation>(initialOrientation);\n  const [gameOver, setGameOver] = useState(false);\n  const [winner, setWinner] = useState<\"white\" | \"black\" | \"draw\" | null>(null);\n\n  // Selection and highlighting\n  const [selectedSquare, setSelectedSquare] = useState<Square | undefined>();\n  const [validMoves, setValidMoves] = useState<Square[]>([]);\n  const [lastMove, setLastMove] = useState<Square[]>([]);\n\n  // Sync FEN state\n  const updateGameState = useCallback(() => {\n    const newFen = getFEN(chess);\n    setFen(newFen);\n\n    // Check game over conditions\n    if (chess.isGameOver()) {\n      setGameOver(true);\n\n      if (chess.isCheckmate()) {\n        setWinner(chess.turn() === \"w\" ? \"black\" : \"white\");\n      } else {\n        setWinner(\"draw\");\n      }\n\n      if (onGameOver) {\n        onGameOver(getGameResult(chess));\n      }\n    }\n  }, [chess, onGameOver]);\n\n  // Make a move\n  const makeMove = useCallback(\n    (from: Square, to: Square, promotion?: PieceSymbol): MoveResult => {\n      const move = tryMakeMove(chess, from, to, promotion);\n\n      if (!move) {\n        return { success: false };\n      }\n\n      const isCaptureMove = isCapture(chess, move);\n\n      setLastMove([from, to]);\n      setSelectedSquare(undefined);\n      setValidMoves([]);\n      updateGameState();\n\n      if (onMove) {\n        onMove(move);\n      }\n\n      return {\n        success: true,\n        move,\n        isCapture: isCaptureMove,\n        isCheck: chess.isCheck(),\n        isCheckmate: chess.isCheckmate(),\n        isGameOver: chess.isGameOver(),\n      };\n    },\n    [chess, onMove, updateGameState],\n  );\n\n  // Select a square\n  const selectSquare = useCallback(\n    (square: Square) => {\n      const piece = chess.get(square);\n\n      // If no piece or wrong color, try to move to this square\n      if (!piece || piece.color !== chess.turn()) {\n        if (selectedSquare) {\n          makeMove(selectedSquare, square);\n        }\n        return;\n      }\n\n      // Select piece and show valid moves\n      setSelectedSquare(square);\n      const moves = getValidMoves(chess, square);\n      setValidMoves(moves);\n    },\n    [chess, selectedSquare, makeMove],\n  );\n\n  // Clear selection\n  const clearSelection = useCallback(() => {\n    setSelectedSquare(undefined);\n    setValidMoves([]);\n  }, []);\n\n  // Undo last move\n  const undoMove = useCallback((): boolean => {\n    const move = chess.undo();\n    if (move) {\n      setLastMove([]);\n      setSelectedSquare(undefined);\n      setValidMoves([]);\n      setGameOver(false);\n      setWinner(null);\n      updateGameState();\n      return true;\n    }\n    return false;\n  }, [chess, updateGameState]);\n\n  // Reset game\n  const resetGame = useCallback(() => {\n    chess.reset();\n    setLastMove([]);\n    setSelectedSquare(undefined);\n    setValidMoves([]);\n    setGameOver(false);\n    setWinner(null);\n    updateGameState();\n  }, [chess, updateGameState]);\n\n  // Flip board\n  const flipBoard = useCallback(() => {\n    setOrientation((prev) => (prev === \"white\" ? \"black\" : \"white\"));\n  }, []);\n\n  // Load FEN\n  const loadFENHandler = useCallback(\n    (newFen: string): boolean => {\n      const success = loadFEN(chess, newFen);\n      if (success) {\n        setLastMove([]);\n        setSelectedSquare(undefined);\n        setValidMoves([]);\n        setGameOver(false);\n        setWinner(null);\n        updateGameState();\n      }\n      return success;\n    },\n    [chess, updateGameState],\n  );\n\n  // Load PGN\n  const loadPGNHandler = useCallback(\n    (pgn: string): boolean => {\n      try {\n        chess.loadPgn(pgn);\n        setLastMove([]);\n        setSelectedSquare(undefined);\n        setValidMoves([]);\n        updateGameState();\n        return true;\n      } catch {\n        return false;\n      }\n    },\n    [chess, updateGameState],\n  );\n\n  // Export PGN\n  const exportPGNHandler = useCallback(\n    (metadata?: Record<string, string>): string => {\n      return exportPGN(chess, metadata);\n    },\n    [chess],\n  );\n\n  // Export FEN\n  const exportFEN = useCallback((): string => {\n    return getFEN(chess);\n  }, [chess]);\n\n  // Check if move is valid\n  const isValidMove = useCallback(\n    (from: Square, to: Square): boolean => {\n      const moves = chess.moves({ square: from, verbose: true }) as Move[];\n      return moves.some((move) => move.to === to);\n    },\n    [chess],\n  );\n\n  // Get valid moves for square\n  const getValidMovesForSquare = useCallback(\n    (square: Square): Square[] => {\n      return getValidMoves(chess, square);\n    },\n    [chess],\n  );\n\n  // Get piece at square\n  const getPieceAt = useCallback(\n    (square: Square) => {\n      const piece = chess.get(square);\n      return piece || null;\n    },\n    [chess],\n  );\n\n  // Get check square\n  const checkSquare = chess.isCheck()\n    ? (chess\n        .board()\n        .flat()\n        .find((sq) => sq && sq.type === \"k\" && sq.color === chess.turn())\n        ?.square as Square | undefined)\n    : undefined;\n\n  return {\n    // Game state\n    chess,\n    fen,\n    turn: chess.turn(),\n    gameOver,\n    winner,\n    status: getGameStatus(chess),\n    moveHistory: chess.history(),\n    currentMoveNumber: chess.moveNumber(),\n\n    // Board state\n    orientation,\n    highlights: {\n      selected: selectedSquare,\n      validMoves,\n      lastMove,\n      check: checkSquare,\n    },\n    inCheck: chess.isCheck(),\n\n    // Actions\n    makeMove,\n    selectSquare,\n    clearSelection,\n    undoMove,\n    resetGame,\n    flipBoard,\n\n    // Import/Export\n    loadFEN: loadFENHandler,\n    loadPGN: loadPGNHandler,\n    exportPGN: exportPGNHandler,\n    exportFEN,\n\n    // Utility\n    isValidMove,\n    getValidMovesForSquare,\n    getPieceAt,\n  };\n}\n","import { Chess } from \"chess.js\";\n\n/**\n * FEN (Forsyth-Edwards Notation) utilities for board state serialization\n */\n\nexport const STARTING_FEN =\n  \"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1\";\n\nexport const EMPTY_BOARD_FEN = \"8/8/8/8/8/8/8/8 w - - 0 1\";\n\n/**\n * Common chess positions for testing and examples\n */\nexport const FAMOUS_POSITIONS = {\n  starting: STARTING_FEN,\n  empty: EMPTY_BOARD_FEN,\n  // Sicilian Defense\n  sicilian: \"rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq c6 0 2\",\n  // Scholar's Mate position (before mate)\n  scholarsMate:\n    \"r1bqkb1r/pppp1ppp/2n2n2/4p2Q/2B1P3/8/PPPP1PPP/RNB1K1NR w KQkq - 4 4\",\n  // Endgame: King and Pawn vs King\n  kingPawnEndgame: \"8/8/8/4k3/4P3/4K3/8/8 w - - 0 1\",\n  // Back rank mate threat\n  backRankMate: \"6k1/5ppp/8/8/8/8/5PPP/R5K1 w - - 0 1\",\n  // Lucena Position (winning endgame)\n  lucena: \"1K1k4/1P6/8/8/8/8/r7/2R5 w - - 0 1\",\n  // Philidor Position (drawing endgame)\n  philidor: \"3k4/R7/8/8/8/8/r2KP3/8 b - - 0 1\",\n} as const;\n\n/**\n * Validate a FEN string\n */\nexport function isValidFEN(fen: string): boolean {\n  try {\n    const chess = new Chess();\n    chess.load(fen);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Parse FEN and return board details\n */\nexport function parseFEN(fen: string): {\n  valid: boolean;\n  turn: \"w\" | \"b\";\n  castling: string;\n  enPassant: string;\n  halfmove: number;\n  fullmove: number;\n} {\n  const defaultResult = {\n    valid: false,\n    turn: \"w\" as const,\n    castling: \"-\",\n    enPassant: \"-\",\n    halfmove: 0,\n    fullmove: 1,\n  };\n\n  if (!isValidFEN(fen)) {\n    return defaultResult;\n  }\n\n  const parts = fen.split(\" \");\n  if (parts.length !== 6) {\n    return defaultResult;\n  }\n\n  return {\n    valid: true,\n    turn: parts[1] as \"w\" | \"b\",\n    castling: parts[2],\n    enPassant: parts[3],\n    halfmove: parseInt(parts[4]) || 0,\n    fullmove: parseInt(parts[5]) || 1,\n  };\n}\n\n/**\n * Get simplified board representation from FEN\n */\nexport function getFENPiecePlacement(fen: string): string {\n  return fen.split(\" \")[0];\n}\n\n/**\n * Create FEN from parts\n */\nexport function createFEN(\n  piecePlacement: string,\n  turn: \"w\" | \"b\" = \"w\",\n  castling: string = \"KQkq\",\n  enPassant: string = \"-\",\n  halfmove: number = 0,\n  fullmove: number = 1,\n): string {\n  return `${piecePlacement} ${turn} ${castling} ${enPassant} ${halfmove} ${fullmove}`;\n}\n\n/**\n * Load FEN into a chess instance safely\n */\nexport function loadFEN(chess: Chess, fen: string): boolean {\n  try {\n    chess.load(fen);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Get FEN from chess instance\n */\nexport function getFEN(chess: Chess): string {\n  return chess.fen();\n}\n\n/**\n * Compare two FEN strings (position only, ignoring move counters)\n */\nexport function compareFENPositions(fen1: string, fen2: string): boolean {\n  const parts1 = fen1.split(\" \");\n  const parts2 = fen2.split(\" \");\n\n  // Compare first 4 parts (board, turn, castling, en passant)\n  return (\n    parts1[0] === parts2[0] &&\n    parts1[1] === parts2[1] &&\n    parts1[2] === parts2[2] &&\n    parts1[3] === parts2[3]\n  );\n}\n\n/**\n * Get position key for threefold repetition checking\n */\nexport function getPositionKey(fen: string): string {\n  const parts = fen.split(\" \");\n  // Include board, turn, castling, and en passant for position key\n  return parts.slice(0, 4).join(\" \");\n}\n\n/**\n * Reset board to starting position\n */\nexport function resetToStartingPosition(chess: Chess): void {\n  chess.reset();\n}\n\n/**\n * Clear board completely\n */\nexport function clearBoard(chess: Chess): void {\n  chess.clear();\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\n/**\n * Sound types for chess events\n */\nexport type ChessSoundType = \"move\" | \"capture\" | \"notify\" | \"gameEnd\";\n\ninterface UseSoundOptions {\n  enabled?: boolean;\n  volume?: number;\n  /**\n   * Custom sound file paths or URLs to override default sounds.\n   * You can provide paths for any or all sound types.\n   * @example { gameEnd: \"/custom/game-end.mp3\" }\n   * @example { move: \"https://example.com/move.mp3\", capture: \"/custom/capture.mp3\" }\n   */\n  sounds?: Partial<Record<ChessSoundType, string>>;\n}\n\ninterface UseSoundReturn {\n  play: (sound: ChessSoundType) => void;\n  enabled: boolean;\n  setEnabled: (enabled: boolean) => void;\n  volume: number;\n  setVolume: (volume: number) => void;\n}\n\nconst SOUND_PATHS: Record<ChessSoundType, string> = {\n  move: \"/audio/move-self.mp3\",\n  capture: \"/audio/capture.mp3\",\n  notify: \"/audio/notify.mp3\",\n  gameEnd: \"/audio/game-end.webm\",\n};\n\n/**\n * Hook for playing chess sound effects\n */\nexport function useSound(options: UseSoundOptions = {}): UseSoundReturn {\n  const [enabled, setEnabled] = useState(options.enabled ?? true);\n  const [volume, setVolume] = useState(options.volume ?? 0.5);\n  const audioRefs = useRef<Map<ChessSoundType, HTMLAudioElement>>(new Map());\n\n  // Merge custom sounds with defaults\n  const soundPaths = useMemo(\n    () => ({ ...SOUND_PATHS, ...options.sounds }),\n    [options.sounds],\n  );\n\n  // Initialize audio elements\n  useEffect(() => {\n    const map = new Map<ChessSoundType, HTMLAudioElement>();\n\n    Object.entries(soundPaths).forEach(([type, path]) => {\n      const audio = new Audio(path);\n      audio.volume = volume;\n      audio.preload = \"auto\";\n      map.set(type as ChessSoundType, audio);\n    });\n\n    audioRefs.current = map;\n\n    // Cleanup\n    return () => {\n      map.forEach((audio) => {\n        audio.pause();\n        audio.src = \"\";\n      });\n      map.clear();\n    };\n  }, [volume, soundPaths]);\n\n  // Update volume for all audio elements when volume changes\n  useEffect(() => {\n    audioRefs.current.forEach((audio) => {\n      audio.volume = volume;\n    });\n  }, [volume]);\n\n  const play = useCallback(\n    (sound: ChessSoundType) => {\n      if (!enabled) return;\n\n      const audio = audioRefs.current.get(sound);\n      if (audio) {\n        // Reset audio to start if already playing\n        audio.currentTime = 0;\n        audio.play().catch((error) => {\n          console.warn(`Failed to play sound ${sound}:`, error);\n        });\n      }\n    },\n    [enabled],\n  );\n\n  return {\n    play,\n    enabled,\n    setEnabled,\n    volume,\n    setVolume,\n  };\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\n/**\n * Socket message types for chess multiplayer\n */\nexport type SocketMessageType =\n  | \"move\"\n  | \"chat\"\n  | \"join\"\n  | \"leave\"\n  | \"gameState\"\n  | \"playerReady\"\n  | \"rematch\"\n  | \"draw\"\n  | \"resign\";\n\nexport interface SocketMessage<T = unknown> {\n  type: SocketMessageType;\n  payload: T;\n  timestamp: number;\n  playerId?: string;\n}\n\nexport interface MovePayload {\n  from: string;\n  to: string;\n  promotion?: string;\n  fen?: string;\n}\n\nexport interface GameStatePayload {\n  fen: string;\n  pgn?: string;\n  turn: \"w\" | \"b\";\n  isGameOver: boolean;\n  result?: string;\n}\n\ninterface UseSocketOptions {\n  url?: string;\n  roomId?: string;\n  playerId?: string;\n  autoConnect?: boolean;\n  reconnectAttempts?: number;\n  reconnectDelay?: number;\n}\n\ninterface UseSocketReturn {\n  connected: boolean;\n  send: <T>(type: SocketMessageType, payload: T) => void;\n  subscribe: <T>(\n    type: SocketMessageType,\n    handler: (payload: T) => void,\n  ) => () => void;\n  connect: () => void;\n  disconnect: () => void;\n  error: string | null;\n}\n\n/**\n * Hook for WebSocket communication in multiplayer chess\n * Note: This is a client-side implementation ready for WebSocket integration\n */\nexport function useSocket(options: UseSocketOptions = {}): UseSocketReturn {\n  const {\n    url,\n    roomId,\n    playerId,\n    autoConnect = false,\n    reconnectAttempts = 3,\n    reconnectDelay = 2000,\n  } = options;\n\n  const [connected, setConnected] = useState(false);\n  const [error, setError] = useState<string | null>(null);\n\n  const socketRef = useRef<WebSocket | null>(null);\n  const subscribersRef = useRef<\n    Map<SocketMessageType, Set<(payload: unknown) => void>>\n  >(new Map());\n  const reconnectCountRef = useRef(0);\n  const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n  const connectRef = useRef<(() => void) | null>(null);\n\n  const connect = useCallback(() => {\n    if (!url) {\n      setError(\"WebSocket URL not provided\");\n      return;\n    }\n\n    if (socketRef.current?.readyState === WebSocket.OPEN) {\n      return; // Already connected\n    }\n\n    try {\n      const wsUrl = roomId ? `${url}?room=${roomId}` : url;\n      const socket = new WebSocket(wsUrl);\n\n      socket.onopen = () => {\n        console.log(\"WebSocket connected\");\n        setConnected(true);\n        setError(null);\n        reconnectCountRef.current = 0;\n\n        // Send join message\n        if (roomId && playerId) {\n          socket.send(\n            JSON.stringify({\n              type: \"join\",\n              payload: { roomId, playerId },\n              timestamp: Date.now(),\n            }),\n          );\n        }\n      };\n\n      socket.onmessage = (event) => {\n        try {\n          const message: SocketMessage = JSON.parse(event.data);\n          const subscribers = subscribersRef.current.get(message.type);\n\n          if (subscribers) {\n            subscribers.forEach((handler) => {\n              handler(message.payload);\n            });\n          }\n        } catch (err) {\n          console.error(\"Failed to parse socket message:\", err);\n        }\n      };\n\n      socket.onerror = (event) => {\n        console.error(\"WebSocket error:\", event);\n        setError(\"WebSocket connection error\");\n      };\n\n      socket.onclose = () => {\n        console.log(\"WebSocket disconnected\");\n        setConnected(false);\n        socketRef.current = null;\n\n        // Attempt reconnection\n        if (reconnectCountRef.current < reconnectAttempts) {\n          reconnectCountRef.current++;\n          reconnectTimeoutRef.current = setTimeout(() => {\n            console.log(`Reconnecting... Attempt ${reconnectCountRef.current}`);\n            connectRef.current?.();\n            // connect();\n          }, reconnectDelay);\n        }\n      };\n\n      socketRef.current = socket;\n    } catch (err) {\n      console.error(\"Failed to create WebSocket:\", err);\n      setError(\"Failed to establish connection\");\n    }\n  }, [url, roomId, playerId, reconnectAttempts, reconnectDelay]);\n\n  // Store connect function in ref\n  useEffect(() => {\n    connectRef.current = connect;\n  }, [connect]);\n\n  const disconnect = useCallback(() => {\n    if (reconnectTimeoutRef.current) {\n      clearTimeout(reconnectTimeoutRef.current);\n      reconnectTimeoutRef.current = null;\n    }\n\n    if (socketRef.current) {\n      socketRef.current.close();\n      socketRef.current = null;\n    }\n\n    setConnected(false);\n  }, []);\n\n  const send = useCallback(\n    <T>(type: SocketMessageType, payload: T) => {\n      if (\n        !socketRef.current ||\n        socketRef.current.readyState !== WebSocket.OPEN\n      ) {\n        console.warn(\"Cannot send message: WebSocket not connected\");\n        return;\n      }\n\n      const message: SocketMessage<T> = {\n        type,\n        payload,\n        timestamp: Date.now(),\n        playerId,\n      };\n\n      socketRef.current.send(JSON.stringify(message));\n    },\n    [playerId],\n  );\n\n  const subscribe = useCallback(\n    <T>(type: SocketMessageType, handler: (payload: T) => void) => {\n      if (!subscribersRef.current.has(type)) {\n        subscribersRef.current.set(type, new Set());\n      }\n\n      const subscribers = subscribersRef.current.get(type)!;\n      subscribers.add(handler as (payload: unknown) => void);\n\n      // Return unsubscribe function\n      return () => {\n        subscribers.delete(handler as (payload: unknown) => void);\n        if (subscribers.size === 0) {\n          subscribersRef.current.delete(type);\n        }\n      };\n    },\n    [],\n  );\n\n  // Auto-connect on mount if enabled\n  useEffect(() => {\n    if (autoConnect) {\n      // connect();\n      connectRef.current?.();\n    }\n\n    return () => {\n      disconnect();\n    };\n  }, [autoConnect, disconnect]);\n\n  return {\n    connected,\n    send,\n    subscribe,\n    connect,\n    disconnect,\n    error,\n  };\n}\n"]}