专栏文章

3D Dice Roll

休闲·娱乐参与者 2已保存评论 4

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
4 条
当前快照
1 份
快照标识符
@min8gfb4
此快照首次捕获于
2025/12/01 22:16
3 个月前
此快照最后确认于
2025/12/01 22:16
3 个月前
查看原文
访问次数 :。由于我极其可能会咕咕咕所以你们也可以直接把代码扔给 AI 进行修改。
食用方法:建一个文本文档,后缀名 .html,用记事本编辑,把代码复制进去,双击运行。
Update
  • v.1.0:初版;
  • v.1.1:将 Lucky Streak Card 的效果改为了:接下来的 3 次投掷中,扔到 1,2 不会计入总共投掷次数。
  • v.1.2:修复 Lucky Streak Card 的 bug;通过修改投掷结果的出现方式,解决页面元素上下移动的问题;骰子被投掷时,原则上不能做别的动作(升级、使用技能卡);优化 Roll History,冻结表头,修改奇怪 bug。
  • v.1.2.1:修改了 Roll history 中升级后积分变化错误的问题。
To do list
  • 增加一种新的技能卡。
  • 增加历史获胜所需次数并记录最好成绩(前提是修改 Play Again 的逻辑,这个类似多测清空,bug 极其的多)。
Code
v.1.0HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>3D Dice Roll Animation</title>
  <!-- Tailwind CSS v3 -->
  <script src="https://cdn.tailwindcss.com"></script>
  <!-- Font Awesome -->
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            primary: '#3b82f6',
            secondary: '#f97316',
            dark: '#1e293b',
            light: '#f8fafc'
          },
          fontFamily: {
            sans: ['Inter', 'system-ui', 'sans-serif'],
          },
          animation: {
            'shake': 'shake 0.5s ease-in-out',
          },
          keyframes: {
            shake: {
              '0%, 100%': { transform: 'translateX(0)' },
              '25%': { transform: 'translateX(-5px)' },
              '50%': { transform: 'translateX(5px)' },
              '75%': { transform: 'translateX(-5px)' },
            }
          }
        }
      }
    }
  </script>
  
  <style type="text/tailwindcss">
    @layer utilities {
      .preserve-3d {
        transform-style: preserve-3d;
      }
      .perspective {
        perspective: 1000px;
      }
      .backface-hidden {
        backface-visibility: hidden;
      }
      .dice-shadow {
        box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
      }
      .glass-effect {
        background: rgba(255, 255, 255, 0.7);
        backdrop-filter: blur(10px);
        -webkit-backdrop-filter: blur(10px);
      }
      .modal-backdrop {
        background-color: rgba(0, 0, 0, 0.5);
        backdrop-filter: blur(4px);
        -webkit-backdrop-filter: blur(4px);
      }
      .modal-content {
        transform: translateY(-20px);
        opacity: 0;
        transition: all 0.3s ease-out;
      }
      .modal-open .modal-content {
        transform: translateY(0);
        opacity: 1;
      }
      .modal-open .modal-backdrop {
        opacity: 1;
        visibility: visible;
      }
    }
    
    /* Custom styles for 3D dice */
    .dice-scene {
      perspective: 1500px;
      width: 120px;
      height: 120px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .dice-container {
      position: relative;
      width: 100px;
      height: 100px;
      transform-style: preserve-3d;
      transition: transform 1s ease-out;
      transform: rotateX(20deg) rotateY(20deg);
    }
    
    .dice-face {
      position: absolute;
      width: 100px;
      height: 100px;
      border-radius: 8px;
      background-color: white;
      border: 2px solid #f0f0f0;
      display: flex;
      align-items: center;
      justify-content: center;
      box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
    }
    
    /* Dice face positions */
    .face-1 { transform: translateZ(50px); }
    .face-2 { transform: rotateY(90deg) translateZ(50px); }
    .face-3 { transform: rotateY(180deg) translateZ(50px); }
    .face-4 { transform: rotateY(-90deg) translateZ(50px); }
    .face-5 { transform: rotateX(90deg) translateZ(50px); }
    .face-6 { transform: rotateX(-90deg) translateZ(50px); }
    
    /* Dots on dice faces */
    .dot {
      position: absolute;
      width: 20px;
      height: 20px;
      border-radius: 50%;
      background-color: black;
    }
    
    /* Dot positions for each face */
    .face-1 .dot { top: 40px; left: 40px; }
    
    .face-2 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-2 .dot:nth-child(2) { top: 60px; left: 60px; }
    
    .face-3 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-3 .dot:nth-child(2) { top: 40px; left: 40px; }
    .face-3 .dot:nth-child(3) { top: 60px; left: 60px; }
    
    .face-4 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-4 .dot:nth-child(2) { top: 20px; left: 60px; }
    .face-4 .dot:nth-child(3) { top: 60px; left: 20px; }
    .face-4 .dot:nth-child(4) { top: 60px; left: 60px; }
    
    .face-5 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-5 .dot:nth-child(2) { top: 20px; left: 60px; }
    .face-5 .dot:nth-child(3) { top: 40px; left: 40px; }
    .face-5 .dot:nth-child(4) { top: 60px; left: 20px; }
    .face-5 .dot:nth-child(5) { top: 60px; left: 60px; }
    
    .face-6 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-6 .dot:nth-child(2) { top: 20px; left: 60px; }
    .face-6 .dot:nth-child(3) { top: 40px; left: 20px; }
    .face-6 .dot:nth-child(4) { top: 40px; left: 60px; }
    .face-6 .dot:nth-child(5) { top: 60px; left: 20px; }
    .face-6 .dot:nth-child(6) { top: 60px; left: 60px; }
    
    .dice-result {
      transition: all 0.5s ease-out;
    }
    
    .result-shine {
      animation: shine 0.5s ease-out;
    }
    
    .score-increase {
      color: #10b981;
      animation: scorePopup 1s ease-out;
    }
    
    .score-decrease {
      color: #ef4444;
      animation: scorePopup 1s ease-out;
    }
    
    .score-neutral {
      color: #6b7280;
      animation: scorePopup 1s ease-out;
    }
    
    /* Locked color option styles */
    .color-option.locked {
      position: relative;
      opacity: 0.5;
      cursor: not-allowed;
    }
    
    .color-option.locked::after {
      content: '\f023'; /* Lock icon from Font Awesome */
      font-family: 'FontAwesome';
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      color: rgba(0, 0, 0, 0.5);
      font-size: 16px;
    }
    
    @keyframes shine {
      0% {
        box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4);
      }
      70% {
        box-shadow: 0 0 0 10px rgba(59, 130, 246, 0);
      }
      100% {
        box-shadow: 0 0 0 0 rgba(59, 130, 246, 0);
      }
    }
    
    @keyframes scorePopup {
      0% {
        transform: translateY(0);
        opacity: 0;
      }
      50% {
        transform: translateY(-10px);
        opacity: 1;
      }
      100% {
        transform: translateY(-20px);
        opacity: 0;
      }
    }
    
    .confetti {
      position: absolute;
      width: 10px;
      height: 10px;
      background-color: #f97316;
      animation: confetti-fall 3s ease-in-out infinite;
    }
    
    @keyframes confetti-fall {
      0% {
        transform: translateY(-100vh) rotate(0deg);
        opacity: 1;
      }
      100% {
        transform: translateY(100vh) rotate(720deg);
        opacity: 0;
      }
    }
    
    @keyframes lock-particle {
      0% {
        transform: translate(0, 0);
        opacity: 1;
      }
      100% {
        transform: translate(var(--tx), var(--ty));
        opacity: 0;
      }
    }
    
    /* Game Rules Modal Styles */
    .game-rules-modal {
      position: fixed;
      top: 0;
      left: 0;
      width: 100vw;
      height: 100vh;
      z-index: 50;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 1rem;
      visibility: hidden;
      box-sizing: border-box;
    }
    
    .game-rules-modal .modal-backdrop {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      opacity: 0;
      visibility: hidden;
      transition: all 0.3s ease-out;
    }
    
    .game-rules-modal .modal-content {
      position: relative;
      background-color: white;
      border-radius: 1rem;
      max-width: 90%;
      max-height: 80vh;
      width: 500px;
      overflow-y: auto;
      box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
    }
    
    .game-rules-modal .modal-header {
      padding: 1.5rem;
      border-bottom: 1px solid #e5e7eb;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
    
    .game-rules-modal .modal-title {
      font-size: 1.25rem;
      font-weight: 600;
      color: #1e293b;
    }
    
    .game-rules-modal .close-button {
      background: none;
      border: none;
      font-size: 1.5rem;
      cursor: pointer;
      color: #6b7280;
      transition: color 0.2s ease-in-out;
    }
    
    .game-rules-modal .close-button:hover {
      color: #1e293b;
    }
    
    .game-rules-modal .modal-body {
      padding: 1.5rem;
      line-height: 1.6;
      color: #374151;
    }
    
    .game-rules-modal .modal-body h3 {
      font-size: 1.1rem;
      font-weight: 600;
      margin-top: 1.5rem;
      margin-bottom: 0.75rem;
      color: #1e293b;
    }
    
    .game-rules-modal .modal-body p {
      margin-bottom: 1rem;
    }
    
    .game-rules-modal .modal-body ul {
      margin-bottom: 1rem;
      padding-left: 1.5rem;
      list-style-type: disc;
    }
    
    .game-rules-modal .modal-body li {
      margin-bottom: 0.5rem;
    }
    
    .game-rules-modal .modal-body strong {
      font-weight: 600;
      color: #1e293b;
    }
    
    .game-rules-modal .modal-footer {
      padding: 1rem 1.5rem;
      border-top: 1px solid #e5e7eb;
      display: flex;
      justify-content: flex-end;
    }
    
    .game-rules-modal .modal-footer button {
      padding: 0.5rem 1rem;
      border-radius: 0.5rem;
      background-color: #3b82f6;
      color: white;
      font-weight: 500;
      transition: background-color 0.2s ease-in-out;
    }
    
    .game-rules-modal .modal-footer button:hover {
      background-color: #2563eb;
    }
    
    /* Game Rules Button Styles */
    .game-rules-button {
      position: fixed;
      top: 1rem;
      right: 1rem;
      z-index: 40;
      padding: 0.5rem 1rem;
      border-radius: 0.5rem;
      background-color: #3b82f6;
      color: white;
      font-weight: 500;
      display: flex;
      align-items: center;
      gap: 0.5rem;
      transition: all 0.2s ease-in-out;
      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
    }
    
    .game-rules-button:hover {
      background-color: #2563eb;
      transform: translateY(-2px);
    }
    
    .game-rules-button i {
      font-size: 1.1rem;
    }
  </style>
</head>
<body class="bg-gradient-to-br from-light to-gray-200 min-h-screen flex flex-col items-center justify-center p-4 m-0">
  <!-- Game Rules Button -->
  <button id="game-rules-button" class="game-rules-button">
    <i class="fa fa-book"></i>
    <span>Game Rules</span>
  </button>
  
  <!-- Game Rules Modal -->
  <div id="game-rules-modal" class="game-rules-modal">
    <div class="modal-backdrop"></div>
    <div class="modal-content">
      <div class="modal-header">
        <h2 class="modal-title">3D Dice Game Rules</h2>
        <button class="close-button">&times;</button>
      </div>
      <div class="modal-body">
        <p>Welcome to the 3D Dice Game! This is an exciting game that combines luck, strategy, and upgrading mechanics. Below is the complete game rules explanation:</p>
        
        <h3>Basic Gameplay</h3>
        <ul>
          <li>Click the "Roll Dice" button to roll the dice</li>
          <li>The dice will randomly show a number between 1-6</li>
          <li>Gain or lose points based on the number rolled</li>
          <li>The goal is to obtain the highest tier "Unique" dice</li>
        </ul>
        
        <h3>Score System</h3>
        <ul>
          <li>Rolling 1 or 2: Lose 1 point (multiplier not applied)</li>
          <li>Rolling 3: No points gained or lost</li>
          <li>Rolling 4: Gain 1 point</li>
          <li>Rolling 5: Gain 2 points</li>
          <li>Rolling 6: Gain 3 points</li>
        </ul>
        
        <h3>Dice Upgrade System</h3>
        <p>There are 10 different tiers of dice in the game, from common to rare:</p>
        <ul>
          <li><strong>Empty</strong> (Initial) - Score Multiplier ×1.0</li>
          <li><strong>Common</strong> - Score Multiplier ×1.1</li>
          <li><strong>Unusual</strong> - Score Multiplier ×1.2</li>
          <li><strong>Rare</strong> - Score Multiplier ×1.3</li>
          <li><strong>Epic</strong> - Score Multiplier ×1.4</li>
          <li><strong>Legendary</strong> - Score Multiplier ×1.5</li>
          <li><strong>Mythic</strong> - Score Multiplier ×1.6</li>
          <li><strong>Ultra</strong> - Score Multiplier ×1.7</li>
          <li><strong>Super</strong> - Score Multiplier ×1.8</li>
          <li><strong>Unique</strong> - Score Multiplier ×1.9</li>
        </ul>
        <p>Each upgrade costs 5 points. After upgrading, you can choose to use the new dice or continue using the old one.</p>
        
        <h3>Item System</h3>
        <p>When upgrading, you have a chance to obtain item cards that can be used at critical moments:</p>
        <ul>
          <li><strong>Double Points Card</strong>: Doubles the points from one roll</li>
          <li><strong>No Penalty Card</strong>: Prevents point loss when rolling 1 or 2</li>
          <li><strong>Lucky Streak Card</strong>: Gives you 3 free dice rolls that don't count towards your total</li>
        </ul>
        <p>Items can be stockpiled and each card can only be used once. Double Points Cards and No Penalty Cards can be used simultaneously. Lucky Streak Cards give you 3 free rolls that don't count towards your total roll count.</p>
        
        <h3>Game Rules</h3>
        <ul>
          <li>Initial score is 10 points</li>
          <li>Score multiplier changes based on the current dice tier being used</li>
          <li>Game over when score is less than 0</li>
          <li>Game victory when obtaining the Unique dice</li>
          <li>Unlocked dice colors can be switched at any time</li>
        </ul>
        
        <h3>Operation Tips</h3>
        <ul>
          <li>Click on dice color options to switch the dice being used</li>
          <li>Click the "Upgrade Dice" button to upgrade your dice (requires 5 points)</li>
          <li>Click the "Use" button next to item cards to use them</li>
          <li>Press the ESC key to close the rules window</li>
        </ul>
        
        <p>Good luck, and may you successfully obtain the highest tier Unique dice!</p>
      </div>
      <div class="modal-footer">
        <button class="close-button">Got it</button>
      </div>
    </div>
  </div>
  
  <div class="w-full max-w-md mx-auto glass-effect rounded-2xl p-6 dice-shadow relative z-10">
    <h1 class="text-3xl font-bold text-center text-dark mb-8">3D Dice Roll</h1>
    
    <div class="flex flex-col items-center justify-center mb-8">
      <!-- Dice display area -->
      <div id="dice-display" class="w-48 h-48 flex items-center justify-center mb-4 bg-gray-100 rounded-lg">
        <!-- Dice scene for 3D perspective -->
        <div class="dice-scene">
          <div id="dice" class="dice-container">
            <!-- Dice faces will be inserted here by JavaScript -->
          </div>
        </div>
      </div>
      
      <!-- Result display -->
      <div id="result-display" class="text-2xl font-bold text-center mb-4 hidden">
        Result: <span id="result-value" class="text-primary">0</span>
      </div>
      
      <!-- Score display -->
      <div id="score-display" class="text-xl font-bold text-center mb-2">
        Score: <span id="score-value" class="text-secondary">10</span>
        <span id="score-change" class="ml-2 text-sm font-normal"></span>
      </div>
      
      <!-- Roll count display -->
      <div id="roll-count-display" class="text-lg font-medium text-center mb-4">
        Rolls: <span id="roll-count-value" class="text-gray-700">0</span>
      </div>
      
      <!-- Roll button -->
      <button id="roll-button" class="bg-primary hover:bg-blue-600 text-white font-bold py-3 px-6 rounded-full transition-all duration-300 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-blue-300 focus:ring-opacity-50">
        <i class="fa fa-random mr-2"></i> Roll Dice
      </button>
      
      <!-- Upgrade button and current tier display -->
      <div class="flex flex-col items-center mt-4">
        <div id="current-tier" class="text-sm text-gray-600 mb-2">
          Current Dice: <span class="font-semibold text-primary">Empty</span>
        </div>
        <div id="tier-multiplier-display" class="text-sm text-gray-600 mb-2">
          Tier Multiplier: <span class="font-semibold text-purple-500">×1.0</span>
        </div>
        <button id="upgrade-button" class="bg-secondary hover:bg-orange-600 text-white font-bold py-2 px-4 rounded-full transition-all duration-300 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-orange-300 focus:ring-opacity-50">
          <i class="fa fa-arrow-up mr-1"></i> Upgrade Dice <span id="upgrade-cost">(Cost: 5)</span>
        </button>
      </div>
      
      <!-- Game message display -->
      <div id="game-message" class="mt-4 text-center font-semibold hidden"></div>
      
      <!-- Items display -->
      <div id="items-display" class="mt-6 grid grid-cols-2 gap-4">
        <div class="bg-white rounded-lg p-3 dice-shadow">
          <div class="flex items-center justify-between">
            <div class="flex items-center">
              <i class="fa fa-plus-circle text-green-500 text-xl mr-2"></i>
              <span class="font-medium">Double Points Card</span>
            </div>
            <div class="flex items-center">
              <span id="double-points-count" class="bg-green-100 text-green-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">0</span>
              <button id="use-double-points" class="bg-green-500 hover:bg-green-600 text-white text-xs py-1 px-2 rounded disabled:opacity-50 disabled:cursor-not-allowed" disabled>
                Use
              </button>
            </div>
          </div>
          <p class="text-xs text-gray-500 mt-1">Doubles your score change for one roll</p>
        </div>
        
        <div class="bg-white rounded-lg p-3 dice-shadow">
          <div class="flex items-center justify-between">
            <div class="flex items-center">
              <i class="fa fa-shield text-blue-500 text-xl mr-2"></i>
              <span class="font-medium">No Penalty Card</span>
            </div>
            <div class="flex items-center">
              <span id="no-penalty-count" class="bg-blue-100 text-blue-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">0</span>
              <button id="use-no-penalty" class="bg-blue-500 hover:bg-blue-600 text-white text-xs py-1 px-2 rounded disabled:opacity-50 disabled:cursor-not-allowed" disabled>
                Use
              </button>
            </div>
          </div>
          <p class="text-xs text-gray-500 mt-1">Prevents score loss when rolling 1 or 2</p>
        </div>
        
        <div class="bg-white rounded-lg p-3 dice-shadow">
          <div class="flex items-center justify-between">
            <div class="flex items-center">
              <i class="fa fa-star text-yellow-500 text-xl mr-2"></i>
              <span class="font-medium">Lucky Streak Card</span>
            </div>
            <div class="flex items-center">
              <span id="lucky-streak-count" class="bg-yellow-100 text-yellow-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">0</span>
              <button id="use-lucky-streak" class="bg-yellow-500 hover:bg-yellow-600 text-white text-xs py-1 px-2 rounded disabled:opacity-50 disabled:cursor-not-allowed" disabled>
                Use
              </button>
            </div>
          </div>
          <p class="text-xs text-gray-500 mt-1">Get 3 free dice rolls (not counted in total)</p>
        </div>
      </div>
      
      <!-- Free rolls indicator -->
      <div id="free-rolls-indicator" class="mt-3 text-center hidden">
        <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
          <i class="fa fa-star mr-1" style="color: #f59e0b;"></i>
          <span>Free Rolls: <span id="free-rolls-count">0</span></span>
        </span>
      </div>
      
      <!-- Active item indicator -->
      <div id="active-item-indicator" class="mt-3 text-center hidden">
        <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium">
          <i id="active-item-icon" class="mr-1"></i>
          <span id="active-item-text">Active Item: None</span>
        </span>
      </div>
    </div>
    
    <!-- Dice color selection -->
    <div class="mb-8">
      <label class="block text-sm font-medium text-gray-700 mb-2">Dice Rarity</label>
      <div class="grid grid-cols-5 gap-4">
        <!-- Empty -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #FFFFFF; border: 1px solid #dddddd;" data-color="#FFFFFF"></button>
          <span class="text-xs text-center text-gray-600">Empty</span>
        </div>
        <!-- Common -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #7EEF6D;" data-color="#7EEF6D"></button>
          <span class="text-xs text-center text-gray-600">Common</span>
        </div>
        <!-- Unusual -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #FFE65D;" data-color="#FFE65D"></button>
          <span class="text-xs text-center text-gray-600">Unusual</span>
        </div>
        <!-- Rare -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #4d52e3;" data-color="#4d52e3"></button>
          <span class="text-xs text-center text-gray-600">Rare</span>
        </div>
        <!-- Epic -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #861FDE;" data-color="#861FDE"></button>
          <span class="text-xs text-center text-gray-600">Epic</span>
        </div>
        <!-- Legendary -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #DE1F1F;" data-color="#DE1F1F"></button>
          <span class="text-xs text-center text-gray-600">Legendary</span>
        </div>
        <!-- Mythic -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #1fdbde;" data-color="#1fdbde"></button>
          <span class="text-xs text-center text-gray-600">Mythic</span>
        </div>
        <!-- Ultra -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #ff2b75;" data-color="#ff2b75"></button>
          <span class="text-xs text-center text-gray-600">Ultra</span>
        </div>
        <!-- Super -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #2bffa3;" data-color="#2bffa3"></button>
          <span class="text-xs text-center text-gray-600">Super</span>
        </div>
        <!-- Unique -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #555555;" data-color="#555555"></button>
          <span class="text-xs text-center text-gray-600">Unique</span>
        </div>
      </div>
    </div>
    
    <!-- History log -->
    <div class="bg-white rounded-lg p-4 h-32 overflow-y-auto">
      <h2 class="text-lg font-semibold text-center mb-2">Roll History</h2>
      <ul id="history-list" class="text-sm">
        <!-- History items will be inserted here by JavaScript -->
      </ul>
    </div>
  </div>
  
  <footer class="mt-8 text-center text-gray-600 text-sm">
    <p>Click the button to roll the dice and see the result!</p>
  </footer>

  <script>
    // Set up global error handler
    window.addEventListener('error', function(event) {
      console.error('Global error caught:', event.error);
      
      // Try to get roll button element
      const rollButton = document.getElementById('roll-button');
      if (rollButton && rollButton.disabled) {
        console.warn('Error during dice roll, re-enabling button');
        rollButton.disabled = false;
        rollButton.classList.remove('opacity-70', 'cursor-not-allowed');
        
        // Try to show error message
        const gameMessage = document.getElementById('game-message');
        if (gameMessage) {
          gameMessage.textContent = 'An error occurred. Please try again.';
          gameMessage.className = 'mt-4 text-center font-semibold text-red-500';
          gameMessage.classList.remove('hidden');
        }
      }
    });
    
    // DOM elements
    const diceElement = document.getElementById('dice');
    const rollButton = document.getElementById('roll-button');
    const resultDisplay = document.getElementById('result-display');
    const resultValue = document.getElementById('result-value');
    const historyList = document.getElementById('history-list');
    const colorOptions = document.querySelectorAll('.color-option');
    const scoreDisplay = document.getElementById('score-display');
    const scoreValue = document.getElementById('score-value');
    const scoreChange = document.getElementById('score-change');
    const upgradeButton = document.getElementById('upgrade-button');
    const currentTierDisplay = document.getElementById('current-tier');
    const gameMessageDisplay = document.getElementById('game-message');
    const rollCountDisplay = document.getElementById('roll-count-display');
    const rollCountValue = document.getElementById('roll-count-value');
    const upgradeCost = document.getElementById('upgrade-cost');
    
    // Item related DOM elements
    const doublePointsCount = document.getElementById('double-points-count');
    const noPenaltyCount = document.getElementById('no-penalty-count');
    const luckyStreakCount = document.getElementById('lucky-streak-count');
    const useDoublePointsButton = document.getElementById('use-double-points');
    const useNoPenaltyButton = document.getElementById('use-no-penalty');
    const useLuckyStreakButton = document.getElementById('use-lucky-streak');
    const activeItemIndicator = document.getElementById('active-item-indicator');
    const freeRollsIndicator = document.getElementById('free-rolls-indicator');
    const freeRollsCountElement = document.getElementById('free-rolls-count');
    
    // Game state
    let currentScore = 10; // Initial score
    let currentTier = 0; // Initial dice tier (0 = Empty)
    let gameOver = false; // Game over flag
    let rollCount = 0; // Number of dice rolls
    
    // Item system
    let doublePointsCards = 0; // Number of double points cards
    let noPenaltyCards = 0; // Number of no penalty cards
    let luckyStreakCards = 0; // Number of lucky streak cards
    let freeRolls = 0; // Number of free rolls available
    let activeItems = { // Currently active items
      double: 0, // Number of active double points cards
      noPenalty: false // Whether no penalty card is active
    };
    
    // Dice tiers configuration
    const diceTiers = [
      { name: 'Empty', color: '#FFFFFF' },
      { name: 'Common', color: '#7EEF6D' },
      { name: 'Unusual', color: '#FFE65D' },
      { name: 'Rare', color: '#4d52e3' },
      { name: 'Epic', color: '#861FDE' },
      { name: 'Legendary', color: '#DE1F1F' },
      { name: 'Mythic', color: '#1fdbde' },
      { name: 'Ultra', color: '#ff2b75' },
      { name: 'Super', color: '#2bffa3' },
      { name: 'Unique', color: '#555555' }
    ];
    
    // Initialize 3D dice
    function initializeDice() {
      console.log('Initializing dice...');
      // Create 6 faces for the dice
      const faces = [1, 2, 3, 4, 5, 6];
      
      faces.forEach(faceNumber => {
        const face = document.createElement('div');
        face.className = `dice-face face-${faceNumber}`;
        
        // Add dots to the face based on the number
        for (let i = 0; i < faceNumber; i++) {
          const dot = document.createElement('div');
          dot.className = 'dot';
          face.appendChild(dot);
        }
        
        diceElement.appendChild(face);
        console.log(`Added face ${faceNumber}`);
      });
      
      console.log('Dice initialized with faces:', diceElement.children.length);
      
      // Set initial position to show face 1 clearly
      diceElement.style.transform = 'rotateX(0deg) rotateY(0deg)';
    }
    
    // Get random rotation values for the dice
    function getRandomRotation() {
      // Determine which face we want to show
      const targetFace = Math.floor(Math.random() * 6) + 1;
      
      // Get current rotation from dice element
      const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
      const matrix = new DOMMatrix(currentTransform);
      
      // Extract current rotation angles
      let currentX = 0, currentY = 0;
      
      // If transform is not identity matrix, extract rotation
      if (currentTransform !== 'none') {
        // Calculate rotation from matrix
        currentX = Math.atan2(matrix.b, matrix.a) * (180 / Math.PI);
        currentY = Math.atan2(-matrix.c, matrix.f) * (180 / Math.PI);
      }
      
      // Set target rotation based on target face
      // These values are precisely calibrated to show the correct face
      let targetX = 0, targetY = 0;
      switch(targetFace) {
        case 1: // Front face (Z+) - visible when no rotation
          targetX = 0;
          targetY = 0;
          break;
        case 2: // Left face (X-) - visible when Y rotated 270 degrees
          targetX = 0;
          targetY = 270;
          break;
        case 3: // Back face (Z-) - visible when Y rotated 180 degrees
          targetX = 0;
          targetY = 180;
          break;
        case 4: // Right face (X+) - visible when Y rotated 90 degrees
          targetX = 0;
          targetY = 90;
          break;
        case 5: // Top face (Y-) - visible when X rotated -90 degrees
          targetX = -90;
          targetY = 0;
          break;
        case 6: // Bottom face (Y+) - visible when X rotated 90 degrees
          targetX = 90;
          targetY = 0;
          break;
      }
      
      // Calculate the shortest path to the target rotation
      // This prevents large rotation values from accumulating
      let diffX = targetX - currentX;
      let diffY = targetY - currentY;
      
      // Normalize the difference to the range [-180, 180] to find the shortest path
      diffX = ((diffX + 180) % 360) - 180;
      diffY = ((diffY + 180) % 360) - 180;
      
      // Add multiple full rotations for spinning effect (2-4 full rotations)
      const fullRotations = 2 + Math.floor(Math.random() * 3);
      
      // Calculate final rotation with full spins
      // We add full rotations in the direction of the shortest path
      const spinDirectionX = diffX >= 0 ? 1 : -1;
      const spinDirectionY = diffY >= 0 ? 1 : -1;
      
      const finalX = currentX + diffX + spinDirectionX * fullRotations * 360;
      const finalY = currentY + diffY + spinDirectionY * fullRotations * 360;
      
      // Add a tiny bit of randomness to make it look more natural
      // But not enough to change which face is visible
      const randomX = (Math.random() - 0.5) * 2;
      const randomY = (Math.random() - 0.5) * 2;
      
      return {
        x: finalX + randomX,
        y: finalY + randomY,
        targetFace: targetFace // Return the target face so we don't have to recalculate it
      };
    }
    
    // Roll the dice function
    function rollDice() {
      // Check if game is over
      if (gameOver) {
        showGameMessage('Game over! Click "Play Again" to restart.', 'text-red-500');
        return;
      }
      
      // Check if there are free rolls available
      const isFreeRoll = freeRolls > 0;
      
      // Increment roll count only if not a free roll
      if (!isFreeRoll) {
        rollCount++;
        console.log(`Roll count: ${rollCount}`);
      } else {
        // Decrement free rolls count
        freeRolls--;
        updateFreeRollsDisplay();
        console.log(`Free roll used. Remaining free rolls: ${freeRolls}`);
      }
      
      // Update roll count display
      if (rollCountValue) {
        rollCountValue.textContent = rollCount;
      }
      
      console.log('Rolling dice...');
      console.log('Button state before disable:', rollButton.disabled);
      
      // Disable button during animation
      rollButton.disabled = true;
      rollButton.classList.add('opacity-70', 'cursor-not-allowed');
      
      console.log('Button state after disable:', rollButton.disabled);
      
      // Hide result display
      resultDisplay.classList.add('hidden');
      
      try {
        // Set animation duration
        const duration = 2000; // Fixed duration for consistent experience
        
        // Get random rotation values for the final position
        const rotationData = getRandomRotation();
        console.log('Rotation data:', rotationData);
        console.log('Target face:', rotationData.targetFace);
        
        // Animate the dice using JavaScript for more control
        animateDice(duration, rotationData);
        
        // Set a safety timeout to ensure button is re-enabled even if something goes wrong
        setTimeout(() => {
          if (rollButton.disabled) {
            console.warn('Safety timeout: Re-enabling roll button');
            enableRollButton();
            showGameMessage('The dice roll took longer than expected. Please try again.', 'text-orange-500');
          }
        }, duration + 1000); // Add 1 second buffer
      } catch (error) {
        console.error('Error during dice roll:', error);
        // Re-enable button if there's an error
        enableRollButton();
        showGameMessage('An error occurred during the dice roll. Please try again.', 'text-red-500');
      }
    }
    
    // Animate the dice with spin animation
    function animateDice(duration, rotationData) {
      console.log('Animate dice called with rotationData:', rotationData);
      const startTime = performance.now();
      const finalRotation = rotationData;
      
      // Get current rotation from dice element
      const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
      const matrix = new DOMMatrix(currentTransform);
      
      // Extract current rotation angles
      let startX = 0, startY = 0;
      
      // If transform is not identity matrix, extract rotation
      if (currentTransform !== 'none') {
        // Calculate rotation from matrix
        startX = Math.atan2(matrix.b, matrix.a) * (180 / Math.PI);
        startY = Math.atan2(-matrix.c, matrix.f) * (180 / Math.PI);
      }
      
      // Function to handle each animation frame
      function animate(currentTime) {
        const elapsedTime = currentTime - startTime;
        const progress = Math.min(elapsedTime / duration, 1);
        
        // Apply easing function for smooth, natural animation
        const easedProgress = easeOutCubic(progress);
        
        // Calculate current rotation - smooth continuous rotation
        const currentX = startX + (finalRotation.x - startX) * easedProgress;
        const currentY = startY + (finalRotation.y - startY) * easedProgress;
        
        // Spin animation: rotate in place
        diceElement.style.transform = `rotateX(${currentX}deg) rotateY(${currentY}deg)`;
        
        // Continue animation if not complete
        if (progress < 1) {
          requestAnimationFrame(animate);
        } else {
          // Animation complete - ensure we're at the exact target rotation
          diceElement.style.transform = `rotateX(${finalRotation.x}deg) rotateY(${finalRotation.y}deg)`;
          
          // Show result after a short delay to ensure rotation is complete
          console.log('Animation complete, calling finalizeAnimation...');
          setTimeout(() => {
            finalizeAnimation(finalRotation);
          }, 50);
        }
      }
      
      // Start the animation
      requestAnimationFrame(animate);
    }
    
    // Helper function to normalize angles to the range [-180, 180]
    function normalizeAngle(angle) {
      angle = angle % 360;
      if (angle > 180) angle -= 360;
      if (angle < -180) angle += 360;
      return angle;
    }
    
    // Easing function for smooth, natural animation with gentle acceleration and deceleration
    // Uses a cubic easing function that starts slow, accelerates, then slows down at the end
    function easeOutCubic(t) {
      return 1 - Math.pow(1 - t, 3);
    }
    
    // Calculate score change based on dice roll result
    function calculateScoreChange(result) {
      let baseChange = 0;
      
      switch(result) {
        case 1:
        case 2:
          baseChange = -1;
          break;
        case 3:
          baseChange = 0;
          break;
        case 4:
          baseChange = 1;
          break;
        case 5:
          baseChange = 2;
          break;
        case 6:
          baseChange = 3;
          break;
        default:
          baseChange = 0;
      }
      
      // Apply current tier multiplier
      // If losing points (baseChange < 0), use multiplier of 1 instead of tier multiplier
      const tierMultiplier = 1 + currentTier / 10;
      let finalChange;
      
      if (baseChange < 0) {
        // For point loss, use multiplier of 1 regardless of tier
        finalChange = baseChange * 1;
      } else {
        // For point gain or neutral, use tier multiplier
        finalChange = baseChange * tierMultiplier;
      }
      
      // Apply active item effects
      const itemsUsed = {
        double: activeItems.double,
        noPenalty: activeItems.noPenalty
      };
      
      // Apply no penalty card first
      if (activeItems.noPenalty && baseChange < 0) {
        finalChange = 0;
      }
      
      // Apply double points cards
      if (activeItems.double > 0) {
        finalChange = finalChange * Math.pow(2, activeItems.double);
      }
      
      // Round to 2 decimal places to avoid floating point precision issues
      finalChange = Math.round(finalChange * 100) / 100;
      
      return {
        baseChange: baseChange,
        finalChange: finalChange,
        itemsUsed: itemsUsed,
        tierMultiplier: tierMultiplier
      };
    }
    
    // Enable roll button
    function enableRollButton() {
      console.log('Button state before enable:', rollButton.disabled);
      
      // Directly enable the button
      rollButton.disabled = false;
      rollButton.classList.remove('opacity-70', 'cursor-not-allowed');
      
      console.log('Button state after enable:', rollButton.disabled);
      
      // Double-check and force enable if needed
      if (rollButton.disabled) {
        console.warn('Forcing button enable');
        setTimeout(() => {
          rollButton.disabled = false;
          rollButton.classList.remove('opacity-70', 'cursor-not-allowed');
          console.log('Button state after forced enable:', rollButton.disabled);
        }, 100);
      }
    }
    
    // Finalize the animation and show result
    function finalizeAnimation(rotationData) {
      console.log('=== Finalize animation called ===');
      console.log('Rotation data:', rotationData);
      const finalRotation = rotationData;
      
      // Use the target face directly instead of recalculating
      const result = finalRotation.targetFace;
      console.log(`Final result: ${result} (should show face ${result})`);
      
      // Show result display
      resultValue.textContent = result;
      resultDisplay.classList.remove('hidden');
      
      // Add shine effect to result
      resultDisplay.classList.add('result-shine');
      setTimeout(() => {
        resultDisplay.classList.remove('result-shine');
      }, 500);
      
      // Calculate and update score
      console.log('Calculating score change...');
      const scoreChangeData = calculateScoreChange(result);
      console.log('Score change data:', scoreChangeData);
      
      currentScore += scoreChangeData.finalChange;
      console.log('Updated score:', currentScore);
      
      // Update score display with animation
      console.log('Updating score display...');
      updateScoreDisplay(scoreChangeData);
      
      // Enable button
      console.log('Enabling roll button...');
      enableRollButton();
      
      // Add to history - include whether it was a free roll
      addToHistory(result, scoreChangeData, isFreeRoll);
      
      // Check if reached the Unique dice
      if (currentTier === diceTiers.length - 1) {
        showGameMessage('Congratulations! You obtained the Unique dice!', 'text-green-500');
        gameOver = true;
        createConfetti();
      }
      
      // Create confetti effect if result is 6
      if (result === 6) {
        createConfetti();
      }
      
      // Debug: log final state
      console.log(`Final precise rotation: X=${finalRotation.x}°, Y=${finalRotation.y}°`);
      console.log(`Displayed result: ${result}`);
      console.log(`Score change: ${scoreChangeData.finalChange}, Current score: ${currentScore}`);
      console.log('=== finalizeAnimation completed ===');
    }
    
    // Update score display with animation
    function updateScoreDisplay(scoreChangeData) {
      console.log('=== updateScoreDisplay called ===');
      console.log('Score change data:', scoreChangeData);
      
      const change = scoreChangeData.finalChange;
      const baseChange = scoreChangeData.baseChange;
      const itemsUsed = scoreChangeData.itemsUsed;
      const tierMultiplier = scoreChangeData.tierMultiplier;
      
      console.log('Change:', change, 'Base change:', baseChange, 'Items used:', itemsUsed);
      
      // Update the score value - round to 2 decimal places
      currentScore = Math.round(currentScore * 100) / 100;
      scoreValue.textContent = currentScore;
      console.log('Score value updated to:', currentScore);
      
      // Clear previous score change display
      scoreChange.textContent = '';
      scoreChange.className = 'ml-2 text-sm font-normal';
      console.log('Cleared previous score change display');
      
      // Show score change with appropriate styling
      if (change > 0) {
        scoreChange.textContent = `+${change}`;
        scoreChange.classList.add('score-increase');
        console.log('Score increase:', change);
      } else if (change < 0) {
        scoreChange.textContent = `${change}`;
        scoreChange.classList.add('score-decrease');
        console.log('Score decrease:', change);
      } else {
        scoreChange.textContent = `±0`;
        scoreChange.classList.add('score-neutral');
        console.log('Score neutral');
      }
      
      // Show item effect message if items were used
      if (itemsUsed && (itemsUsed.double > 0 || itemsUsed.noPenalty)) {
        // Create container for item effects
        const itemEffectsContainer = document.createElement('div');
        itemEffectsContainer.className = 'flex flex-wrap gap-2 mt-1';
        
        // Add tier multiplier effect if applicable
        if (tierMultiplier !== 1) {
          const tierEffect = document.createElement('div');
          tierEffect.className = 'text-xs text-purple-500';
          tierEffect.textContent = `Tier Multiplier ×${tierMultiplier.toFixed(1)}!`;
          itemEffectsContainer.appendChild(tierEffect);
        }
        
        // Add no penalty effect
        if (itemsUsed.noPenalty) {
          const noPenaltyEffect = document.createElement('div');
          noPenaltyEffect.className = 'text-xs text-blue-500';
          noPenaltyEffect.textContent = `No Penalty! (Score protected from ${baseChange < 0 ? baseChange : 0} loss)`;
          itemEffectsContainer.appendChild(noPenaltyEffect);
        }
        
        // Add double points effect
        if (itemsUsed.double > 0) {
          const doublePointsEffect = document.createElement('div');
          doublePointsEffect.className = 'text-xs text-green-500';
          
          // Calculate multiplier
          const multiplier = Math.pow(2, itemsUsed.double);
          let calculationText = `${baseChange}`;
          
          // Apply tier multiplier for display
          let displayChange = baseChange * tierMultiplier;
          
          // Apply no penalty first for display
          if (itemsUsed.noPenalty && baseChange < 0) {
            displayChange = 0;
            calculationText = `(${baseChange} × ${tierMultiplier.toFixed(1)} → 0)`;
          } else if (tierMultiplier !== 1) {
            calculationText = `(${baseChange} × ${tierMultiplier.toFixed(1)} = ${displayChange.toFixed(2)})`;
          }
          
          // Show multiplication steps if multiple double cards used
          if (itemsUsed.double > 1) {
            for (let i = 0; i < itemsUsed.double; i++) {
              calculationText += ` × 2`;
            }
            calculationText += ` = ${(displayChange * multiplier).toFixed(2)}`;
          } else {
            calculationText += ` × 2 = ${(displayChange * multiplier).toFixed(2)}`;
          }
          
          doublePointsEffect.textContent = `Double Points ×${itemsUsed.double}! (${calculationText})`;
          itemEffectsContainer.appendChild(doublePointsEffect);
        }
        
        // Add to score display
        scoreDisplay.appendChild(itemEffectsContainer);
        
        // Remove after animation
        setTimeout(() => {
          scoreDisplay.removeChild(itemEffectsContainer);
        }, 1000);
      }
      
      // Reset score change display after animation completes
      setTimeout(() => {
        scoreChange.textContent = '';
      }, 1000);
      
      // Clear active items after score update
      console.log('Checking if items need to be cleared...');
      if (itemsUsed && (itemsUsed.double > 0 || itemsUsed.noPenalty)) {
        console.log('Clearing active items...');
        clearActiveItems();
        console.log('Updating items display...');
        updateItemsDisplay();
      }
      
      // Check game state after score update
      console.log('Checking game state...');
      checkGameState();
      console.log('=== updateScoreDisplay completed ===');
    }
    
    // Handle dice upgrade
    function upgradeDice() {
      // Check if game is already over
      if (gameOver) {
        showGameMessage('Game over! Click "Play Again" to restart.', 'text-red-500');
        return;
      }
      
      // Check if already at maximum tier
      if (currentTier >= diceTiers.length - 1) {
        // If not already game over, end the game with win condition
        if (!gameOver) {
          gameOver = true;
          endGame(true);
        } else {
          showGameMessage('Congratulations! You already have the Unique dice!', 'text-green-500');
        }
        return;
      }
      
      // Calculate required score for upgrade (5 + currentTier)
      const requiredScore = 5 + currentTier;
      
      // Check if enough score to upgrade
      if (currentScore < requiredScore) {
        showGameMessage(`Not enough score to upgrade! Need ${requiredScore} points.`, 'text-orange-500');
        // Add shake animation to score display
        scoreDisplay.classList.add('animate-shake');
        setTimeout(() => {
          scoreDisplay.classList.remove('animate-shake');
        }, 500);
        return;
      }
      
      // Deduct score for upgrade
      currentScore -= requiredScore;
      // Round to 2 decimal places
      currentScore = Math.round(currentScore * 100) / 100;
      
      // Update score display
      scoreValue.textContent = currentScore;
      showScoreChange(-5);
      
      // Increase tier
      currentTier++;
      
      // Update current tier display
      currentTierDisplay.innerHTML = `Current Dice: <span class="font-semibold text-primary">${diceTiers[currentTier].name}</span>`;
      
      // Update tier multiplier display
      updateTierMultiplierDisplay();
      
      // Unlock the new dice color
      unlockDiceColor(currentTier);
      
      // Update color selection UI
      updateColorSelection(currentTier);
      
      // Update upgrade cost display
      updateUpgradeCostDisplay();
      
      // Change to the new dice color
      console.log(`Changing dice color to ${diceTiers[currentTier].color} (${diceTiers[currentTier].name})`);
      changeDiceColor(diceTiers[currentTier].color);
      
      // Check if this upgrade reached the maximum tier
      checkGameState();
      
      // Randomly get an item
      const itemChance = Math.random();
      if (itemChance < 0.32) { // 32% chance to get double points card
        doublePointsCards++;
      } else if (itemChance < 0.64) { // 32% chance to get no penalty card
        noPenaltyCards++;
      } else if (itemChance < 0.98) { // 34% chance to get nothing
        // Do nothing
      } else { // 2% chance to get lucky streak card
        luckyStreakCards++;
      }
      
      // Update items display to show new counts
      updateItemsDisplay();
      
      // Update items display
      updateItemsDisplay();
      
      // Check if reached the Unique dice
      if (currentTier === diceTiers.length - 1) {
        showGameMessage('Congratulations! You obtained the Unique dice!', 'text-green-500');
        gameOver = true;
        createConfetti();
      }
      
      // Add to history
      addToHistory('UPGRADE', -5);
      
      // Add item to history if obtained
      if (itemChance < 0.32) {
        addToHistory('ITEM', 'Double Points Card');
      } else if (itemChance < 0.64) {
        addToHistory('ITEM', 'No Penalty Card');
      } else if (itemChance >= 0.98) {
        addToHistory('ITEM', 'Lucky Streak Card');
      }
      
      // Check game state after upgrade
      checkGameState();
    }
    
    // Show score change temporarily
    function showScoreChange(change) {
      scoreChange.textContent = change > 0 ? `+${change}` : change;
      scoreChange.className = `ml-2 text-sm font-normal ${change > 0 ? 'score-increase' : 'score-decrease'}`;
      
      setTimeout(() => {
        scoreChange.textContent = '';
      }, 1000);
    }
    
    // Unlock a dice color option
    function unlockDiceColor(tierIndex) {
      if (tierIndex >= 0 && tierIndex < colorOptions.length) {
        const option = colorOptions[tierIndex];
        // Show particle effect on the lock before unlocking
        createLockParticles(option);
        // Add a small delay to show the particles before unlocking
        setTimeout(() => {
          option.disabled = false;
          option.classList.remove('locked');
        }, 300);
      }
    }
    
    // Show game message
    function showGameMessage(message, className) {
      gameMessageDisplay.textContent = message;
      gameMessageDisplay.className = `mt-4 text-center font-semibold ${className}`;
      gameMessageDisplay.classList.remove('hidden');
      
      // Hide message after 3 seconds
      setTimeout(() => {
        if (!gameOver) {
          gameMessageDisplay.classList.add('hidden');
        }
      }, 3000);
    }
    
    // Check game state (win/lose conditions)
    function checkGameState() {
      console.log('=== checkGameState called ===');
      console.log('Current score:', currentScore, 'Game over:', gameOver);
      
      // Check if score is negative (lose condition)
      if (currentScore < 0 && !gameOver) {
        console.log('Score is negative, ending game...');
        gameOver = true;
        endGame(false);
      }
      
      // Check if reached Unique dice (win condition)
      if (currentTier === diceTiers.length - 1 && !gameOver) {
        console.log('Reached Unique dice, ending game...');
        gameOver = true;
        endGame(true);
      }
      
      // Check if score is low (warning)
      if (currentScore >= 0 && currentScore <= 5 && !gameOver) {
        showLowScoreWarning();
      }
      
      console.log('=== checkGameState completed ===');
    }
    
    // Update items display
    function updateItemsDisplay() {
      // Update counts
      doublePointsCount.textContent = doublePointsCards;
      noPenaltyCount.textContent = noPenaltyCards;
      luckyStreakCount.textContent = luckyStreakCards;
      
      // Enable/disable buttons based on available items
      useDoublePointsButton.disabled = doublePointsCards <= 0 || gameOver;
      useNoPenaltyButton.disabled = noPenaltyCards <= 0 || activeItems.noPenalty || gameOver;
      useLuckyStreakButton.disabled = luckyStreakCards <= 0 || gameOver;
      
      // Update free rolls display
      updateFreeRollsDisplay();
    }
    
    // Update free rolls display
    function updateFreeRollsDisplay() {
      if (freeRolls > 0) {
        freeRollsCountElement.textContent = freeRolls;
        freeRollsIndicator.classList.remove('hidden');
      } else {
        freeRollsIndicator.classList.add('hidden');
      }
    }
    
    // Update upgrade cost display
    function updateUpgradeCostDisplay() {
      if (currentTier >= diceTiers.length - 1) {
        // Already at maximum tier
        upgradeCost.textContent = '(Max Tier)';
      } else {
        const requiredScore = 5 + currentTier;
        upgradeCost.textContent = `(Cost: ${requiredScore})`;
      }
    }
    
    // Use double points card
    function useDoublePointsCard() {
      if (doublePointsCards > 0 && !gameOver) {
        activeItems.double++;
        doublePointsCards--;
        
        // Update UI
        updateItemsDisplay();
        showActiveItemIndicator();
        
        // Show message
        showGameMessage('Double Points Card activated! Next roll will double your score change.', 'text-green-500');
      }
    }
    
    // Use no penalty card
    function useNoPenaltyCard() {
      if (noPenaltyCards > 0 && !activeItems.noPenalty && !gameOver) {
        activeItems.noPenalty = true;
        noPenaltyCards--;
        
        // Update UI
        updateItemsDisplay();
        showActiveItemIndicator();
        
        // Show message
        showGameMessage('No Penalty Card activated! Next roll won\'t lose points.', 'text-blue-500');
      }
    }
    
    // Use lucky streak card
    function useLuckyStreakCard() {
      if (luckyStreakCards > 0 && !gameOver) {
        freeRolls += 3;
        luckyStreakCards--;
        
        // Update UI
        updateItemsDisplay();
        
        // Show message
        showGameMessage('Lucky Streak Card activated! You have 3 free rolls!', 'text-yellow-500');
        
        // Add to history
        addToHistory('ITEM USE', 'Lucky Streak Card');
      }
    }
    
    // Show active item indicator
    function showActiveItemIndicator() {
      // Clear previous content
      activeItemIndicator.innerHTML = '';
      
      // Check if any items are active
      if (activeItems.double === 0 && !activeItems.noPenalty) {
        activeItemIndicator.className = 'mt-3 text-center hidden';
        return;
      }
      
      // Create container for active items
      const itemsContainer = document.createElement('div');
      itemsContainer.className = 'flex flex-wrap justify-center gap-2';
      
      // Add double points cards indicator
      if (activeItems.double > 0) {
        const doublePointsIndicator = document.createElement('span');
        doublePointsIndicator.className = 'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800';
        doublePointsIndicator.innerHTML = `
          <i class="fa fa-plus-circle mr-1" style="color: #10b981;"></i>
          <span>Double Points ×${activeItems.double}</span>
        `;
        itemsContainer.appendChild(doublePointsIndicator);
      }
      
      // Add no penalty card indicator
      if (activeItems.noPenalty) {
        const noPenaltyIndicator = document.createElement('span');
        noPenaltyIndicator.className = 'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800';
        noPenaltyIndicator.innerHTML = `
          <i class="fa fa-shield mr-1" style="color: #3b82f6;"></i>
          <span>No Penalty</span>
        `;
        itemsContainer.appendChild(noPenaltyIndicator);
      }
      
      // Add indicators to container
      activeItemIndicator.appendChild(itemsContainer);
      activeItemIndicator.className = 'mt-3 text-center';
    }
    
    // Clear active items
    function clearActiveItems() {
      activeItems = {
        double: 0,
        noPenalty: false
      };
      showActiveItemIndicator();
    }
    
    // End the game and display appropriate message
    function endGame(isWin) {
      console.log('=== endGame called ===');
      console.log('Is win:', isWin, 'Current score:', currentScore);
      
      // Disable all interactive elements
      rollButton.disabled = true;
      upgradeButton.disabled = true;
      rollButton.classList.add('opacity-70', 'cursor-not-allowed');
      upgradeButton.classList.add('opacity-70', 'cursor-not-allowed');
      
      // Disable all interactive elements
      colorOptions.forEach(option => {
        option.disabled = true;
        option.classList.add('opacity-50', 'cursor-not-allowed');
      });
      
      // Disable item buttons
      useDoublePointsButton.disabled = true;
      useNoPenaltyButton.disabled = true;
      
      // Hide active item indicator
      activeItemIndicator.classList.add('hidden');
      
      // Create game over message element
      const gameOverMessage = document.createElement('div');
      gameOverMessage.className = `mt-4 p-4 rounded-lg text-center font-bold ${isWin ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}`;
      
      // Format final score to 2 decimal places
      const formattedScore = currentScore.toFixed(2);
      
      if (isWin) {
        gameOverMessage.innerHTML = `
          <div class="text-2xl mb-2">Congratulations!</div>
          <p>You won the game!</p>
          <p>You obtained the Unique dice!</p>
          <p class="mt-2 text-sm">Final Score: ${formattedScore}</p>
          <p class="mt-1 text-sm">Total Rolls: ${rollCount}</p>
          <p class="mt-1 text-sm">Double Points Cards: ${doublePointsCards}</p>
          <p class="mt-1 text-sm">No Penalty Cards: ${noPenaltyCards}</p>
          <p class="mt-1 text-sm">Lucky Streak Cards: ${luckyStreakCards}</p>
          <p class="mt-1 text-sm">Final Tier Multiplier: ×${(1 + currentTier / 10).toFixed(1)}</p>
          <button id="play-again" class="mt-4 bg-primary hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-full transition-all duration-300 transform hover:scale-105">
            <i class="fa fa-refresh mr-1"></i> Play Again
          </button>
        `;
        createConfetti();
      } else {
        gameOverMessage.innerHTML = `
          <div class="text-2xl mb-2">Game Over!</div>
          <p>Your score went negative.</p>
          <p>Better luck next time!</p>
          <p class="mt-2 text-sm">Final Score: ${formattedScore}</p>
          <p class="mt-1 text-sm">Total Rolls: ${rollCount}</p>
          <p class="mt-1 text-sm">Double Points Cards: ${doublePointsCards}</p>
          <p class="mt-1 text-sm">No Penalty Cards: ${noPenaltyCards}</p>
          <p class="mt-1 text-sm">Lucky Streak Cards: ${luckyStreakCards}</p>
          <p class="mt-1 text-sm">Final Tier Multiplier: ×${(1 + currentTier / 10).toFixed(1)}</p>
          <button id="play-again" class="mt-4 bg-primary hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-full transition-all duration-300 transform hover:scale-105">
            <i class="fa fa-refresh mr-1"></i> Play Again
          </button>
        `;
      }
      
      // Add restart button event listener
      gameOverMessage.querySelector('#play-again').addEventListener('click', () => {
        window.location.reload();
      });
      
      // Replace game message display with game over message
      const gameMessageContainer = gameMessageDisplay.parentElement;
      gameMessageContainer.replaceChild(gameOverMessage, gameMessageDisplay);
      gameMessageDisplay = gameOverMessage;
      
      // Add game end to history
      addToHistory(isWin ? 'GAME WIN' : 'GAME OVER', 0);
      
      console.log('=== endGame completed ===');
    }
    
    // Show warning when score is low
    function showLowScoreWarning() {
      // Only show warning if not already showing
      if (gameMessageDisplay.classList.contains('hidden')) {
        showGameMessage('Warning: Low score! Risk of game over.', 'text-orange-500');
      }
    }
    
    // Update color selection UI to show the currently selected color
    function updateColorSelection(selectedIndex) {
      // Remove active state from all color options
      colorOptions.forEach(opt => opt.classList.remove('ring-2', 'ring-offset-2', 'ring-primary'));
      
      // Add active state to the selected color option
      if (selectedIndex >= 0 && selectedIndex < colorOptions.length) {
        colorOptions[selectedIndex].classList.add('ring-2', 'ring-offset-2', 'ring-primary');
      }
    }
    
    // Add result to history
    function addToHistory(result, scoreChangeData, isFreeRoll = false) {
      const now = new Date();
      const timeString = now.toLocaleTimeString();
      
      // Determine score change display and color
      let scoreChangeText = '';
      let scoreChangeClass = '';
      let actionText = '';
      
      if (result === 'UPGRADE') {
        actionText = 'Upgraded dice';
        scoreChangeText = `${scoreChangeData}`;
        scoreChangeClass = 'text-red-500';
      } else if (result === 'ITEM') {
        actionText = `Received <span class="font-bold text-purple-500">${scoreChangeData}</span>`;
        scoreChangeText = '+1';
        scoreChangeClass = 'text-purple-500';
      } else if (result === 'GAME WIN' || result === 'GAME OVER') {
        actionText = result;
        scoreChangeText = '';
        scoreChangeClass = '';
      } else {
        const scoreChange = scoreChangeData.finalChange;
        const baseChange = scoreChangeData.baseChange;
        const itemsUsed = scoreChangeData.itemsUsed;
        
        actionText = `Rolled a <span class="font-bold text-primary">${result}</span>`;
        
        // Add free roll indicator if applicable
        if (isFreeRoll) {
          actionText += ` <span class="text-yellow-500">(Free Roll)</span>`;
        }
        
        // Add item effect indicators if applicable
        const activeItemsText = [];
        if (itemsUsed && itemsUsed.double > 0) {
          activeItemsText.push(`<span class="text-green-500">(Double Points ×${itemsUsed.double})</span>`);
        }
        if (itemsUsed && itemsUsed.noPenalty) {
          activeItemsText.push(`<span class="text-blue-500">(No Penalty)</span>`);
        }
        
        if (activeItemsText.length > 0) {
          actionText += ` ${activeItemsText.join(' ')}`;
        }
        
        if (scoreChange > 0) {
          scoreChangeText = `+${scoreChange}`;
          scoreChangeClass = 'text-green-500';
        } else if (scoreChange < 0) {
          scoreChangeText = `${scoreChange}`;
          scoreChangeClass = 'text-red-500';
        } else {
          scoreChangeText = '±0';
          scoreChangeClass = 'text-gray-500';
        }
        
        // Show base change if different from final change (items were used)
        if ((itemsUsed && (itemsUsed.double > 0 || itemsUsed.noPenalty)) && baseChange !== scoreChange) {
          scoreChangeText += ` <span class="text-xs">(Base: ${baseChange > 0 ? '+' : ''}${baseChange})</span>`;
        }
      }
      
      const listItem = document.createElement('li');
      listItem.className = 'py-1 border-b border-gray-100 flex justify-between items-center';
      listItem.innerHTML = `
        <span><span class="text-gray-500">${timeString}</span>: ${actionText}</span>
        <span class="font-medium ${scoreChangeClass}">${scoreChangeText}</span>
      `;
      
      historyList.prepend(listItem);
      
      // Keep only last 5 history items
      if (historyList.children.length > 5) {
        historyList.removeChild(historyList.lastChild);
      }
    }
    
    // Create confetti effect
    function createConfetti() {
      const confettiContainer = document.createElement('div');
      confettiContainer.className = 'fixed inset-0 pointer-events-none overflow-hidden';
      document.body.appendChild(confettiContainer);
      
      // Create 50 confetti pieces
      for (let i = 0; i < 50; i++) {
        const confetti = document.createElement('div');
        confetti.className = 'confetti';
        
        // Random position
        const posX = Math.random() * 100;
        const delay = Math.random() * 3;
        const duration = 3 + Math.random() * 2;
        
        // Random colors
        const colors = ['#3b82f6', '#f97316', '#10b981', '#ef4444', '#8b5cf6'];
        const color = colors[Math.floor(Math.random() * colors.length)];
        
        confetti.style.left = `${posX}%`;
        confetti.style.backgroundColor = color;
        confetti.style.animationDelay = `${delay}s`;
        confetti.style.animationDuration = `${duration}s`;
        
        confettiContainer.appendChild(confetti);
      }
      
      // Remove confetti container after animation completes
      setTimeout(() => {
        document.body.removeChild(confettiContainer);
      }, 5000);
    }
    
    // Create particle effect on lock
    function createLockParticles(lockElement) {
      // Get lock element position
      const rect = lockElement.getBoundingClientRect();
      const centerX = rect.left + rect.width / 2;
      const centerY = rect.top + rect.height / 2;
      
      // Create particle container
      const particleContainer = document.createElement('div');
      particleContainer.className = 'absolute pointer-events-none';
      particleContainer.style.left = `${centerX}px`;
      particleContainer.style.top = `${centerY}px`;
      particleContainer.style.transform = 'translate(-50%, -50%)';
      document.body.appendChild(particleContainer);
      
      // Create 15 particles
      for (let i = 0; i < 15; i++) {
        const particle = document.createElement('div');
        particle.className = 'lock-particle';
        
        // Random direction and distance
        const angle = Math.random() * Math.PI * 2;
        const distance = 10 + Math.random() * 20;
        const tx = Math.cos(angle) * distance;
        const ty = Math.sin(angle) * distance;
        
        // Random color (use the color of the unlocked dice)
        const color = lockElement.style.backgroundColor;
        
        // Random animation duration
        const duration = 0.5 + Math.random() * 0.5;
        
        // Set particle styles
        particle.style.backgroundColor = color;
        particle.style.setProperty('--tx', `${tx}px`);
        particle.style.setProperty('--ty', `${ty}px`);
        particle.style.animation = `lock-particle ${duration}s ease-out forwards`;
        
        particleContainer.appendChild(particle);
      }
      
      // Remove particle container after animation completes
      setTimeout(() => {
        document.body.removeChild(particleContainer);
      }, 1000);
    }
    
    // Function to darken a color by a certain percentage
    function darkenColor(color, percent) {
      const hex = color.replace('#', '');
      let r = parseInt(hex.substr(0, 2), 16);
      let g = parseInt(hex.substr(2, 2), 16);
      let b = parseInt(hex.substr(4, 2), 16);
      
      // Darken each channel by the percentage
      r = Math.max(0, Math.floor(r * (1 - percent / 100)));
      g = Math.max(0, Math.floor(g * (1 - percent / 100)));
      b = Math.max(0, Math.floor(b * (1 - percent / 100)));
      
      // Convert back to hex
      const darkenedHex = '#' + 
        r.toString(16).padStart(2, '0') + 
        g.toString(16).padStart(2, '0') + 
        b.toString(16).padStart(2, '0');
      
      return darkenedHex;
    }
    
    // Change dice color function
    function changeDiceColor(color) {
      console.log(`changeDiceColor called with color: ${color}`);
      const faces = document.querySelectorAll('.dice-face');
      console.log(`Found ${faces.length} dice faces`);
      let dotColor, borderColor;
      
      // Special cases for high contrast
      if (color.toUpperCase() === '#FFFFFF') {
        // White dice - use black dots and light gray borders
        dotColor = '#000000';
        borderColor = '#CCCCCC';
      } else if (color.toUpperCase() === '#555555') {
        // Dark gray dice - use white dots and slightly lighter gray borders
        dotColor = '#FFFFFF';
        borderColor = '#777777';
      } else {
        // Calculate darker color for dots and borders (40% darker for more contrast)
        dotColor = darkenColor(color, 40);
        borderColor = darkenColor(color, 30); // Slightly lighter border than dots
      }
      
      faces.forEach(face => {
        // Set face background color
        face.style.backgroundColor = color;
        
        // Set face border color
        face.style.border = `3px solid ${borderColor}`;
        
        // Set dots color
        const dots = face.querySelectorAll('.dot');
        dots.forEach(dot => {
          dot.style.backgroundColor = dotColor;
          // Add slight border to dots for better definition
          dot.style.border = color.toUpperCase() === '#FFFFFF' ? '1px solid rgba(0, 0, 0, 0.2)' : '1px solid rgba(0, 0, 0, 0.1)';
        });
      });
    }
    
    // Update tier multiplier display
    function updateTierMultiplierDisplay() {
      const display = document.getElementById('tier-multiplier-display');
      if (display) {
        display.innerHTML = `Tier Multiplier: <span class="font-semibold text-purple-500">×${(1 + currentTier / 10).toFixed(1)}</span>`;
      }
    }
    
    // Event listener for roll button
    rollButton.addEventListener('click', rollDice);
    
    // Event listener for upgrade button
    upgradeButton.addEventListener('click', upgradeDice);
    
    // Event listeners for item buttons
    useDoublePointsButton.addEventListener('click', useDoublePointsCard);
    useNoPenaltyButton.addEventListener('click', useNoPenaltyCard);
    useLuckyStreakButton.addEventListener('click', useLuckyStreakCard);
    
    // Event listeners for color options
    colorOptions.forEach((option, index) => {
      // Disable all color options except the first one initially
      if (index !== 0) {
        option.disabled = true;
        option.classList.add('locked');
      }
      
      option.addEventListener('click', () => {
        // Check if game is over
        if (gameOver) {
          showGameMessage('Game over! Click "Play Again" to restart.', 'text-red-500');
          return;
        }
        
        // Check if color is unlocked
        if (option.disabled) {
          showGameMessage('You need to upgrade to unlock this dice color!', 'text-orange-500');
          return;
        }
        
        const color = option.getAttribute('data-color');
        changeDiceColor(color);
        
        // Add active state to selected color
        colorOptions.forEach(opt => opt.classList.remove('ring-2', 'ring-offset-2', 'ring-primary'));
        option.classList.add('ring-2', 'ring-offset-2', 'ring-primary');
        
        // Update current tier to the selected color's tier
        currentTier = index;
        currentTierDisplay.innerHTML = `Current Dice: <span class="font-semibold text-primary">${diceTiers[currentTier].name}</span>`;
        updateTierMultiplierDisplay();
      });
    });
    
    // Initialize dice on page load
    window.addEventListener('DOMContentLoaded', () => {
      console.log('DOM fully loaded');
      initializeDice();
      
      // Set default color (first option)
      if (colorOptions.length > 0) {
        const defaultColor = colorOptions[0].getAttribute('data-color');
        changeDiceColor(defaultColor);
        colorOptions[0].classList.add('ring-2', 'ring-offset-2', 'ring-primary');
      }
      
      // Initialize current tier display
      currentTierDisplay.innerHTML = `Current Dice: <span class="font-semibold text-primary">${diceTiers[currentTier].name}</span>`;
      
      // Initialize tier multiplier display
      updateTierMultiplierDisplay();
      
      // Initialize items display
      updateItemsDisplay();
      
      // Initialize upgrade cost display
      updateUpgradeCostDisplay();
      
      // Show welcome message
      setTimeout(() => {
        showGameMessage('Welcome! Roll the dice to earn points and upgrade your dice!', 'text-blue-500');
      }, 1000);
    });
    
    // Also try initializing on window load
    window.addEventListener('load', () => {
      console.log('Window loaded');
      // If dice not already initialized, try again
      if (diceElement.children.length === 0) {
        console.log('Dice not initialized, trying again...');
        initializeDice();
      }
    });
    
    // Game Rules Modal Functionality
    (function() {
      // Get elements
      const rulesButton = document.getElementById('game-rules-button');
      const rulesModal = document.getElementById('game-rules-modal');
      const closeButtons = rulesModal.querySelectorAll('.close-button');
      const modalBackdrop = rulesModal.querySelector('.modal-backdrop');
      const modalContent = rulesModal.querySelector('.modal-content');
      
      // Function to prevent background scrolling
      function preventBackgroundScroll(event) {
        // Allow scrolling inside the modal content
        if (modalContent.contains(event.target)) {
          // Check if we're at the top or bottom of the modal content
          const isAtTop = modalContent.scrollTop === 0;
          const isAtBottom = modalContent.scrollTop + modalContent.clientHeight >= modalContent.scrollHeight;
          
          // Prevent scrolling if at the top and scrolling up, or at the bottom and scrolling down
          if ((isAtTop && event.deltaY < 0) || (isAtBottom && event.deltaY > 0)) {
            event.preventDefault();
          }
        } else {
          // Prevent scrolling outside the modal content
          event.preventDefault();
        }
      }
      
      // Function to open modal
      function openModal() {
        // Add event listeners to prevent background scrolling
        document.addEventListener('wheel', preventBackgroundScroll, { passive: false });
        document.addEventListener('touchmove', preventBackgroundScroll, { passive: false });
        
        // Add open class to trigger animations
        rulesModal.classList.add('modal-open');
        
        // Show the modal
        rulesModal.style.visibility = 'visible';
      }
      
      // Function to close modal
      function closeModal() {
        // Remove open class to trigger animations
        rulesModal.classList.remove('modal-open');
        
        // Remove event listeners that prevent background scrolling
        document.removeEventListener('wheel', preventBackgroundScroll);
        document.removeEventListener('touchmove', preventBackgroundScroll);
        
        // Hide the modal after animation completes
        setTimeout(() => {
          rulesModal.style.visibility = 'hidden';
        }, 300);
      }
      
      // Add event listeners
      if (rulesButton) {
        rulesButton.addEventListener('click', openModal);
      }
      
      // Close buttons
      closeButtons.forEach(button => {
        button.addEventListener('click', closeModal);
      });
      
      // Close when clicking outside the modal content
      modalBackdrop.addEventListener('click', closeModal);
      
      // Close when pressing Escape key
      document.addEventListener('keydown', (event) => {
        if (event.key === 'Escape' && rulesModal.classList.contains('modal-open')) {
          closeModal();
        }
      });
      
      // Add hover effect to rules button
      if (rulesButton) {
        rulesButton.addEventListener('mouseenter', () => {
          rulesButton.classList.add('scale-105');
        });
        
        rulesButton.addEventListener('mouseleave', () => {
          rulesButton.classList.remove('scale-105');
        });
      }
      
      // Add click effect to close buttons
      closeButtons.forEach(button => {
        button.addEventListener('mousedown', () => {
          button.classList.add('scale-95');
        });
        
        button.addEventListener('mouseup', () => {
          button.classList.remove('scale-95');
        });
        
        button.addEventListener('mouseleave', () => {
          button.classList.remove('scale-95');
        });
      });
    })();
  </script>
</body>
</html>

v.1.1HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>3D Dice Roll Animation</title>
  <!-- Tailwind CSS v3 -->
  <script src="https://cdn.tailwindcss.com"></script>
  <!-- Font Awesome -->
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            primary: '#3b82f6',
            secondary: '#f97316',
            dark: '#1e293b',
            light: '#f8fafc'
          },
          fontFamily: {
            sans: ['Inter', 'system-ui', 'sans-serif'],
          },
          animation: {
            'shake': 'shake 0.5s ease-in-out',
          },
          keyframes: {
            shake: {
              '0%, 100%': { transform: 'translateX(0)' },
              '25%': { transform: 'translateX(-5px)' },
              '50%': { transform: 'translateX(5px)' },
              '75%': { transform: 'translateX(-5px)' },
            }
          }
        }
      }
    }
  </script>
  
  <style type="text/tailwindcss">
    @layer utilities {
      .preserve-3d {
        transform-style: preserve-3d;
      }
      .perspective {
        perspective: 1000px;
      }
      .backface-hidden {
        backface-visibility: hidden;
      }
      .dice-shadow {
        box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
      }
      .glass-effect {
        background: rgba(255, 255, 255, 0.7);
        backdrop-filter: blur(10px);
        -webkit-backdrop-filter: blur(10px);
      }
      .modal-backdrop {
        background-color: rgba(0, 0, 0, 0.5);
        backdrop-filter: blur(4px);
        -webkit-backdrop-filter: blur(4px);
      }
      .modal-content {
        transform: translateY(-20px);
        opacity: 0;
        transition: all 0.3s ease-out;
      }
      .modal-open .modal-content {
        transform: translateY(0);
        opacity: 1;
      }
      .modal-open .modal-backdrop {
        opacity: 1;
        visibility: visible;
      }
      .trophy-animation {
        animation: trophy-pulse 2s ease-in-out infinite;
      }
      .record-animation {
        animation: record-shine 2s ease-in-out;
      }
    }
    
    @keyframes trophy-pulse {
      0% { transform: scale(1); }
      50% { transform: scale(1.1); }
      100% { transform: scale(1); }
    }
    
    @keyframes record-shine {
      0% { box-shadow: 0 0 0 0 rgba(251, 191, 36, 0.7); }
      70% { box-shadow: 0 0 0 15px rgba(251, 191, 36, 0); }
      100% { box-shadow: 0 0 0 0 rgba(251, 191, 36, 0); }
    }
    
    /* Custom styles for 3D dice */
    .dice-scene {
      perspective: 1500px;
      width: 120px;
      height: 120px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .dice-container {
      position: relative;
      width: 100px;
      height: 100px;
      transform-style: preserve-3d;
      transition: transform 1s ease-out;
      transform: rotateX(20deg) rotateY(20deg);
    }
    
    .dice-face {
      position: absolute;
      width: 100px;
      height: 100px;
      border-radius: 8px;
      background-color: white;
      border: 2px solid #f0f0f0;
      display: flex;
      align-items: center;
      justify-content: center;
      box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
    }
    
    /* Dice face positions */
    .face-1 { transform: translateZ(50px); }
    .face-2 { transform: rotateY(90deg) translateZ(50px); }
    .face-3 { transform: rotateY(180deg) translateZ(50px); }
    .face-4 { transform: rotateY(-90deg) translateZ(50px); }
    .face-5 { transform: rotateX(90deg) translateZ(50px); }
    .face-6 { transform: rotateX(-90deg) translateZ(50px); }
    
    /* Dots on dice faces */
    .dot {
      position: absolute;
      width: 20px;
      height: 20px;
      border-radius: 50%;
      background-color: black;
    }
    
    /* Dot positions for each face */
    .face-1 .dot { top: 40px; left: 40px; }
    
    .face-2 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-2 .dot:nth-child(2) { top: 60px; left: 60px; }
    
    .face-3 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-3 .dot:nth-child(2) { top: 40px; left: 40px; }
    .face-3 .dot:nth-child(3) { top: 60px; left: 60px; }
    
    .face-4 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-4 .dot:nth-child(2) { top: 20px; left: 60px; }
    .face-4 .dot:nth-child(3) { top: 60px; left: 20px; }
    .face-4 .dot:nth-child(4) { top: 60px; left: 60px; }
    
    .face-5 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-5 .dot:nth-child(2) { top: 20px; left: 60px; }
    .face-5 .dot:nth-child(3) { top: 40px; left: 40px; }
    .face-5 .dot:nth-child(4) { top: 60px; left: 20px; }
    .face-5 .dot:nth-child(5) { top: 60px; left: 60px; }
    
    .face-6 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-6 .dot:nth-child(2) { top: 20px; left: 60px; }
    .face-6 .dot:nth-child(3) { top: 40px; left: 20px; }
    .face-6 .dot:nth-child(4) { top: 40px; left: 60px; }
    .face-6 .dot:nth-child(5) { top: 60px; left: 20px; }
    .face-6 .dot:nth-child(6) { top: 60px; left: 60px; }
    
    .dice-result {
      transition: all 0.5s ease-out;
    }
    
    .result-shine {
      animation: shine 0.5s ease-out;
    }
    
    .score-increase {
      color: #10b981;
      animation: scorePopup 1s ease-out;
    }
    
    .score-decrease {
      color: #ef4444;
      animation: scorePopup 1s ease-out;
    }
    
    .score-neutral {
      color: #6b7280;
      animation: scorePopup 1s ease-out;
    }
    
    /* Locked color option styles */
    .color-option.locked {
      position: relative;
      opacity: 0.5;
      cursor: not-allowed;
    }
    
    .color-option.locked::after {
      content: '\f023'; /* Lock icon from Font Awesome */
      font-family: 'FontAwesome';
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      color: rgba(0, 0, 0, 0.5);
      font-size: 16px;
    }
    
    @keyframes shine {
      0% {
        box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4);
      }
      70% {
        box-shadow: 0 0 0 10px rgba(59, 130, 246, 0);
      }
      100% {
        box-shadow: 0 0 0 0 rgba(59, 130, 246, 0);
      }
    }
    
    @keyframes scorePopup {
      0% {
        transform: translateY(0);
        opacity: 0;
      }
      50% {
        transform: translateY(-10px);
        opacity: 1;
      }
      100% {
        transform: translateY(-20px);
        opacity: 0;
      }
    }
    
    .confetti {
      position: absolute;
      width: 10px;
      height: 10px;
      background-color: #f97316;
      animation: confetti-fall 3s ease-in-out infinite;
    }
    
    @keyframes confetti-fall {
      0% {
        transform: translateY(-100vh) rotate(0deg);
        opacity: 1;
      }
      100% {
        transform: translateY(100vh) rotate(720deg);
        opacity: 0;
      }
    }
    
    @keyframes lock-particle {
      0% {
        transform: translate(0, 0);
        opacity: 1;
      }
      100% {
        transform: translate(var(--tx), var(--ty));
        opacity: 0;
      }
    }
    
    /* Game Rules Modal Styles */
    .game-rules-modal {
      position: fixed;
      top: 0;
      left: 0;
      width: 100vw;
      height: 100vh;
      z-index: 50;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 1rem;
      visibility: hidden;
      box-sizing: border-box;
    }
    
    .game-rules-modal .modal-backdrop {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      opacity: 0;
      visibility: hidden;
      transition: all 0.3s ease-out;
    }
    
    .game-rules-modal .modal-content {
      position: relative;
      background-color: white;
      border-radius: 1rem;
      max-width: 90%;
      max-height: 80vh;
      width: 500px;
      overflow-y: auto;
      box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
    }
    
    .game-rules-modal .modal-header {
      padding: 1.5rem;
      border-bottom: 1px solid #e5e7eb;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
    
    .game-rules-modal .modal-title {
      font-size: 1.25rem;
      font-weight: 600;
      color: #1e293b;
    }
    
    .game-rules-modal .close-button {
      background: none;
      border: none;
      font-size: 1.5rem;
      cursor: pointer;
      color: #6b7280;
      transition: color 0.2s ease-in-out;
    }
    
    .game-rules-modal .close-button:hover {
      color: #1e293b;
    }
    
    .game-rules-modal .modal-body {
      padding: 1.5rem;
      line-height: 1.6;
      color: #374151;
    }
    
    .game-rules-modal .modal-body h3 {
      font-size: 1.1rem;
      font-weight: 600;
      margin-top: 1.5rem;
      margin-bottom: 0.75rem;
      color: #1e293b;
    }
    
    .game-rules-modal .modal-body p {
      margin-bottom: 1rem;
    }
    
    .game-rules-modal .modal-body ul {
      margin-bottom: 1rem;
      padding-left: 1.5rem;
      list-style-type: disc;
    }
    
    .game-rules-modal .modal-body li {
      margin-bottom: 0.5rem;
    }
    
    .game-rules-modal .modal-body strong {
      font-weight: 600;
      color: #1e293b;
    }
    
    .game-rules-modal .modal-footer {
      padding: 1rem 1.5rem;
      border-top: 1px solid #e5e7eb;
      display: flex;
      justify-content: flex-end;
    }
    
    .game-rules-modal .modal-footer button {
      padding: 0.5rem 1rem;
      border-radius: 0.5rem;
      background-color: #3b82f6;
      color: white;
      font-size: 1.25rem;
      font-weight: 500;
      transition: background-color 0.2s ease-in-out;
    }
    
    .game-rules-modal .modal-footer button:hover {
      background-color: #2563eb;
    }
    
    /* Game Rules Button Styles */
    .game-rules-button {
      position: fixed;
      top: 1rem;
      right: 1rem;
      z-index: 40;
      padding: 0.5rem 1rem;
      border-radius: 0.5rem;
      background-color: #3b82f6;
      color: white;
      font-weight: 500;
      display: flex;
      align-items: center;
      gap: 0.5rem;
      transition: all 0.2s ease-in-out;
      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
    }
    
    .game-rules-button:hover {
      background-color: #2563eb;
      transform: translateY(-2px);
    }
    
    .game-rules-button i {
      font-size: 1.1rem;
    }
  </style>
</head>
<body class="bg-gradient-to-br from-light to-gray-200 min-h-screen flex flex-col items-center justify-center p-4 m-0">
  <!-- Game Rules Button -->
  <button id="game-rules-button" class="game-rules-button">
    <i class="fa fa-book"></i>
    <span>Game Rules</span>
  </button>
  
  <!-- Game Rules Modal -->
  <div id="game-rules-modal" class="game-rules-modal">
    <div class="modal-backdrop"></div>
    <div class="modal-content">
      <div class="modal-header">
        <h2 class="modal-title">3D Dice Game Rules</h2>
        <button class="close-button">&times;</button>
      </div>
      <div class="modal-body">
        <p>Welcome to the 3D Dice Game! This is an exciting game that combines luck, strategy, and upgrading mechanics. Below is the complete game rules explanation:</p>
        
        <h3>Basic Gameplay</h3>
        <ul>
          <li>Click the "Roll Dice" button to roll the dice</li>
          <li>The dice will randomly show a number between 1-6</li>
          <li>Gain or lose points based on the number rolled</li>
          <li>The goal is to obtain the highest tier "Unique" dice</li>
        </ul>
        
        <h3>Score System</h3>
        <ul>
          <li>Rolling 1 or 2: Lose 1 point (multiplier not applied)</li>
          <li>Rolling 3: No points gained or lost</li>
          <li>Rolling 4: Gain 1 point</li>
          <li>Rolling 5: Gain 2 points</li>
          <li>Rolling 6: Gain 3 points</li>
        </ul>
        
        <h3>Dice Upgrade System</h3>
        <p>There are 10 different tiers of dice in the game, from common to rare:</p>
        <ul>
          <li><strong>Empty</strong> (Initial) - Score Multiplier ×1.0</li>
          <li><strong>Common</strong> - Score Multiplier ×1.1</li>
          <li><strong>Unusual</strong> - Score Multiplier ×1.2</li>
          <li><strong>Rare</strong> - Score Multiplier ×1.3</li>
          <li><strong>Epic</strong> - Score Multiplier ×1.4</li>
          <li><strong>Legendary</strong> - Score Multiplier ×1.5</li>
          <li><strong>Mythic</strong> - Score Multiplier ×1.6</li>
          <li><strong>Ultra</strong> - Score Multiplier ×1.7</li>
          <li><strong>Super</strong> - Score Multiplier ×1.8</li>
          <li><strong>Unique</strong> - Score Multiplier ×1.9</li>
        </ul>
        <p>Each upgrade costs (5 + current tier) points. For example, upgrading from Empty (tier 0) costs 5 points, upgrading from Common (tier 1) costs 6 points, and so on. After upgrading, you can choose to use the new dice or continue using the old one.</p>
        
        <h3>Item System</h3>
        <p>When upgrading, you have a chance to obtain item cards that can be used at critical moments:</p>
        <ul>
          <li><strong>Double Points Card</strong>: Doubles the points from one roll</li>
          <li><strong>No Penalty Card</strong>: Prevents point loss when rolling 1 or 2</li>
          <li><strong>Lucky Streak Card</strong>: Next 3 rolls of 1 or 2 won't count towards your total roll count</li>
        </ul>
        <p>Items can be stockpiled and each card can only be used once. Double Points Cards and No Penalty Cards can be used simultaneously. Lucky Streak Cards make your next 3 rolls of 1 or 2 not count towards your total roll count, giving you a chance to recover from bad luck.</p>
        
        <h3>Game Rules</h3>
        <ul>
          <li>Initial score is 10 points</li>
          <li>Score multiplier changes based on the current dice tier being used</li>
          <li>Game over when score is less than 0</li>
          <li>Game victory when obtaining the Unique dice</li>
          <li>Unlocked dice colors can be switched at any time</li>
        </ul>
        
        <h3>Operation Tips</h3>
        <ul>
          <li>Click on dice color options to switch the dice being used</li>
          <li>Click the "Upgrade Dice" button to upgrade your dice (requires 5 points)</li>
          <li>Click the "Use" button next to item cards to use them</li>
          <li>Press the ESC key to close the rules window</li>
        </ul>
        
        <p>Good luck, and may you successfully obtain the highest tier Unique dice!</p>
      </div>
      <div class="modal-footer">
        <button class="close-button">Got it</button>
      </div>
    </div>
  </div>
  
  <div class="w-full max-w-md mx-auto glass-effect rounded-2xl p-6 dice-shadow relative z-10">
    <h1 class="text-3xl font-bold text-center text-dark mb-8">3D Dice Roll</h1>
    
    <div class="flex flex-col items-center justify-center mb-8">
      <!-- Dice display area -->
      <div id="dice-display" class="w-48 h-48 flex items-center justify-center mb-4 bg-gray-100 rounded-lg">
        <!-- Dice scene for 3D perspective -->
        <div class="dice-scene">
          <div id="dice" class="dice-container">
            <!-- Dice faces will be inserted here by JavaScript -->
          </div>
        </div>
      </div>
      
      <!-- Result display -->
      <div id="result-display" class="text-2xl font-bold text-center mb-4 hidden">
        Result: <span id="result-value" class="text-primary">0</span>
      </div>
      
      <!-- Score display -->
      <div id="score-display" class="text-xl font-bold text-center mb-2">
        Score: <span id="score-value" class="text-secondary">10</span>
        <span id="score-change" class="ml-2 text-sm font-normal"></span>
      </div>
      
      <!-- Roll count display -->
      <div id="roll-count-display" class="text-lg font-medium text-center mb-4">
        Rolls: <span id="roll-count-value" class="text-gray-700">0</span>
      </div>
      
      <!-- Roll button -->
      <button id="roll-button" class="bg-primary hover:bg-blue-600 text-white font-bold py-3 px-6 rounded-full transition-all duration-300 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-blue-300 focus:ring-opacity-50">
        <i class="fa fa-random mr-2"></i> Roll Dice
      </button>
      
      <!-- Upgrade button and current tier display -->
      <div class="flex flex-col items-center mt-4">
        <div id="current-tier" class="text-sm text-gray-600 mb-2">
          Current Dice: <span class="font-semibold text-primary">Empty</span>
        </div>
        <div id="tier-multiplier-display" class="text-sm text-gray-600 mb-2">
          Tier Multiplier: <span class="font-semibold text-purple-500">×1.0</span>
        </div>
        <button id="upgrade-button" class="bg-secondary hover:bg-orange-600 text-white font-bold py-2 px-4 rounded-full transition-all duration-300 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-orange-300 focus:ring-opacity-50">
          <i class="fa fa-arrow-up mr-1"></i> Upgrade Dice <span id="upgrade-cost">(Cost: 5)</span>
        </button>
      </div>
      
      <!-- Game message display -->
      <div id="game-message" class="mt-4 text-center font-semibold hidden"></div>
      
      <!-- Items display -->
      <div id="items-display" class="mt-6 grid grid-cols-2 gap-4">
        <div class="bg-white rounded-lg p-3 dice-shadow">
          <div class="flex items-center justify-between">
            <div class="flex items-center">
              <i class="fa fa-plus-circle text-green-500 text-xl mr-2"></i>
              <span class="font-medium">Double Points Card</span>
            </div>
            <div class="flex items-center">
              <span id="double-points-count" class="bg-green-100 text-green-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">0</span>
              <button id="use-double-points" class="bg-green-500 hover:bg-green-600 text-white text-xs py-1 px-2 rounded disabled:opacity-50 disabled:cursor-not-allowed" disabled>
                Use
              </button>
            </div>
          </div>
          <p class="text-xs text-gray-500 mt-1">Doubles your score change for one roll</p>
        </div>
        
        <div class="bg-white rounded-lg p-3 dice-shadow">
          <div class="flex items-center justify-between">
            <div class="flex items-center">
              <i class="fa fa-shield text-blue-500 text-xl mr-2"></i>
              <span class="font-medium">No Penalty Card</span>
            </div>
            <div class="flex items-center">
              <span id="no-penalty-count" class="bg-blue-100 text-blue-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">0</span>
              <button id="use-no-penalty" class="bg-blue-500 hover:bg-blue-600 text-white text-xs py-1 px-2 rounded disabled:opacity-50 disabled:cursor-not-allowed" disabled>
                Use
              </button>
            </div>
          </div>
          <p class="text-xs text-gray-500 mt-1">Prevents score loss when rolling 1 or 2</p>
        </div>
        
        <div class="bg-white rounded-lg p-3 dice-shadow">
          <div class="flex items-center justify-between">
            <div class="flex items-center">
              <i class="fa fa-star text-yellow-500 text-xl mr-2"></i>
              <span class="font-medium">Lucky Streak Card</span>
            </div>
            <div class="flex items-center">
              <span id="lucky-streak-count" class="bg-yellow-100 text-yellow-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">0</span>
              <button id="use-lucky-streak" class="bg-yellow-500 hover:bg-yellow-600 text-white text-xs py-1 px-2 rounded disabled:opacity-50 disabled:cursor-not-allowed" disabled>
                Use
              </button>
            </div>
          </div>
          <p class="text-xs text-gray-500 mt-1">Next 3 rolls of 1 or 2 won't count towards your total roll count</p>
        </div>
      </div>
      
      <!-- Free rolls indicator -->
      <div id="free-rolls-indicator" class="mt-3 text-center hidden">
        <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
          <i class="fa fa-star mr-1" style="color: #f59e0b;"></i>
          <span>Free Rolls: <span id="free-rolls-count">0</span></span>
        </span>
      </div>
      
      <!-- Active item indicator -->
      <div id="active-item-indicator" class="mt-3 text-center hidden">
        <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium">
          <i id="active-item-icon" class="mr-1"></i>
          <span id="active-item-text">Active Item: None</span>
        </span>
      </div>
    </div>
    
    <!-- Dice color selection -->
    <div class="mb-8">
      <label class="block text-sm font-medium text-gray-700 mb-2">Dice Rarity</label>
      <div class="grid grid-cols-5 gap-4">
        <!-- Empty -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #FFFFFF; border: 1px solid #dddddd;" data-color="#FFFFFF"></button>
          <span class="text-xs text-center text-gray-600">Empty</span>
        </div>
        <!-- Common -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #7EEF6D;" data-color="#7EEF6D"></button>
          <span class="text-xs text-center text-gray-600">Common</span>
        </div>
        <!-- Unusual -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #FFE65D;" data-color="#FFE65D"></button>
          <span class="text-xs text-center text-gray-600">Unusual</span>
        </div>
        <!-- Rare -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #4d52e3;" data-color="#4d52e3"></button>
          <span class="text-xs text-center text-gray-600">Rare</span>
        </div>
        <!-- Epic -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #861FDE;" data-color="#861FDE"></button>
          <span class="text-xs text-center text-gray-600">Epic</span>
        </div>
        <!-- Legendary -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #DE1F1F;" data-color="#DE1F1F"></button>
          <span class="text-xs text-center text-gray-600">Legendary</span>
        </div>
        <!-- Mythic -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #1fdbde;" data-color="#1fdbde"></button>
          <span class="text-xs text-center text-gray-600">Mythic</span>
        </div>
        <!-- Ultra -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #ff2b75;" data-color="#ff2b75"></button>
          <span class="text-xs text-center text-gray-600">Ultra</span>
        </div>
        <!-- Super -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #2bffa3;" data-color="#2bffa3"></button>
          <span class="text-xs text-center text-gray-600">Super</span>
        </div>
        <!-- Unique -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #555555;" data-color="#555555"></button>
          <span class="text-xs text-center text-gray-600">Unique</span>
        </div>
      </div>
    </div>
    
    <!-- History log -->
    <div class="bg-white rounded-lg p-4 h-32 overflow-y-auto">
      <h2 class="text-lg font-semibold text-center mb-2">Roll History</h2>
      <ul id="history-list" class="text-sm">
        <!-- History items will be inserted here by JavaScript -->
      </ul>
    </div>
  </div>
  
  <footer class="mt-8 text-center text-gray-600 text-sm">
    <p>Click the button to roll the dice and see the result!</p>
  </footer>

  <script>
    // Set up global error handler
    window.addEventListener('error', function(event) {
      console.error('Global error caught:', event.error);
      
      // Try to get roll button element
      const rollButton = document.getElementById('roll-button');
      if (rollButton && rollButton.disabled) {
        console.warn('Error during dice roll, re-enabling button');
        rollButton.disabled = false;
        rollButton.classList.remove('opacity-70', 'cursor-not-allowed');
        
        // Try to show error message
        const gameMessage = document.getElementById('game-message');
        if (gameMessage) {
          gameMessage.textContent = 'An error occurred. Please try again.';
          gameMessage.className = 'mt-4 text-center font-semibold text-red-500';
          gameMessage.classList.remove('hidden');
        }
      }
    });
    
    // DOM elements
    const diceElement = document.getElementById('dice');
    const rollButton = document.getElementById('roll-button');
    const resultDisplay = document.getElementById('result-display');
    const resultValue = document.getElementById('result-value');
    const historyList = document.getElementById('history-list');
    const colorOptions = document.querySelectorAll('.color-option');
    const scoreDisplay = document.getElementById('score-display');
    const scoreValue = document.getElementById('score-value');
    const scoreChange = document.getElementById('score-change');
    const upgradeButton = document.getElementById('upgrade-button');
    const currentTierDisplay = document.getElementById('current-tier');
    const gameMessageDisplay = document.getElementById('game-message');
    const rollCountDisplay = document.getElementById('roll-count-display');
    const rollCountValue = document.getElementById('roll-count-value');
    const upgradeCost = document.getElementById('upgrade-cost');
    
    // Item related DOM elements
    const doublePointsCount = document.getElementById('double-points-count');
    const noPenaltyCount = document.getElementById('no-penalty-count');
    const luckyStreakCount = document.getElementById('lucky-streak-count');
    const useDoublePointsButton = document.getElementById('use-double-points');
    const useNoPenaltyButton = document.getElementById('use-no-penalty');
    const useLuckyStreakButton = document.getElementById('use-lucky-streak');
    const activeItemIndicator = document.getElementById('active-item-indicator');
    const freeRollsIndicator = document.getElementById('free-rolls-indicator');
    const freeRollsCountElement = document.getElementById('free-rolls-count');
    
    // Game state
    let currentScore = 10; // Initial score
    let currentTier = 0; // Initial dice tier (0 = Empty)
    let gameOver = false; // Game over flag
    let rollCount = 0; // Number of dice rolls
    let luckyRollsRemaining = 0; // Number of lucky rolls remaining
    
    // Item system
    let doublePointsCards = 0; // Number of double points cards
    let noPenaltyCards = 0; // Number of no penalty cards
    let luckyStreakCards = 0; // Number of lucky streak cards
    let freeRolls = 0; // Number of free rolls available
    let activeItems = { // Currently active items
      double: 0, // Number of active double points cards
      noPenalty: false // Whether no penalty card is active
    };
    
    // Dice tiers configuration
    const diceTiers = [
      { name: 'Empty', color: '#FFFFFF' },
      { name: 'Common', color: '#7EEF6D' },
      { name: 'Unusual', color: '#FFE65D' },
      { name: 'Rare', color: '#4d52e3' },
      { name: 'Epic', color: '#861FDE' },
      { name: 'Legendary', color: '#DE1F1F' },
      { name: 'Mythic', color: '#1fdbde' },
      { name: 'Ultra', color: '#ff2b75' },
      { name: 'Super', color: '#2bffa3' },
      { name: 'Unique', color: '#555555' }
    ];
    
    // Initialize 3D dice
    function initializeDice() {
      console.log('Initializing dice...');
      // Create 6 faces for the dice
      const faces = [1, 2, 3, 4, 5, 6];
      
      faces.forEach(faceNumber => {
        const face = document.createElement('div');
        face.className = `dice-face face-${faceNumber}`;
        
        // Add dots to the face based on the number
        for (let i = 0; i < faceNumber; i++) {
          const dot = document.createElement('div');
          dot.className = 'dot';
          face.appendChild(dot);
        }
        
        diceElement.appendChild(face);
        console.log(`Added face ${faceNumber}`);
      });
      
      console.log('Dice initialized with faces:', diceElement.children.length);
      
      // Set initial position to show face 1 clearly
      diceElement.style.transform = 'rotateX(0deg) rotateY(0deg)';
    }
    
    // Get random rotation values for the dice
    function getRandomRotation() {
      // Determine which face we want to show
      const targetFace = Math.floor(Math.random() * 6) + 1;
      
      // Get current rotation from dice element
      const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
      const matrix = new DOMMatrix(currentTransform);
      
      // Extract current rotation angles
      let currentX = 0, currentY = 0;
      
      // If transform is not identity matrix, extract rotation
      if (currentTransform !== 'none') {
        // Calculate rotation from matrix
        currentX = Math.atan2(matrix.b, matrix.a) * (180 / Math.PI);
        currentY = Math.atan2(-matrix.c, matrix.f) * (180 / Math.PI);
      }
      
      // Set target rotation based on target face
      // These values are precisely calibrated to show the correct face
      let targetX = 0, targetY = 0;
      switch(targetFace) {
        case 1: // Front face (Z+) - visible when no rotation
          targetX = 0;
          targetY = 0;
          break;
        case 2: // Left face (X-) - visible when Y rotated 270 degrees
          targetX = 0;
          targetY = 270;
          break;
        case 3: // Back face (Z-) - visible when Y rotated 180 degrees
          targetX = 0;
          targetY = 180;
          break;
        case 4: // Right face (X+) - visible when Y rotated 90 degrees
          targetX = 0;
          targetY = 90;
          break;
        case 5: // Top face (Y-) - visible when X rotated -90 degrees
          targetX = -90;
          targetY = 0;
          break;
        case 6: // Bottom face (Y+) - visible when X rotated 90 degrees
          targetX = 90;
          targetY = 0;
          break;
      }
      
      // Calculate the shortest path to the target rotation
      // This prevents large rotation values from accumulating
      let diffX = targetX - currentX;
      let diffY = targetY - currentY;
      
      // Normalize the difference to the range [-180, 180] to find the shortest path
      diffX = ((diffX + 180) % 360) - 180;
      diffY = ((diffY + 180) % 360) - 180;
      
      // Add multiple full rotations for spinning effect (2-4 full rotations)
      const fullRotations = 2 + Math.floor(Math.random() * 3);
      
      // Calculate final rotation with full spins
      // We add full rotations in the direction of the shortest path
      const spinDirectionX = diffX >= 0 ? 1 : -1;
      const spinDirectionY = diffY >= 0 ? 1 : -1;
      
      const finalX = currentX + diffX + spinDirectionX * fullRotations * 360;
      const finalY = currentY + diffY + spinDirectionY * fullRotations * 360;
      
      // Add a tiny bit of randomness to make it look more natural
      // But not enough to change which face is visible
      const randomX = (Math.random() - 0.5) * 2;
      const randomY = (Math.random() - 0.5) * 2;
      
      return {
        x: finalX + randomX,
        y: finalY + randomY,
        targetFace: targetFace // Return the target face so we don't have to recalculate it
      };
    }
    
    // Roll the dice function
    function rollDice() {
      // Check if game is over
      if (gameOver) {
        showGameMessage('Game over! Click "Play Again" to restart.', 'text-red-500');
        return;
      }
      
      // Check if there are free rolls available
      const isFreeRoll = freeRolls > 0;
      
      // Check if in lucky streak mode
      const isLuckyRoll = luckyRollsRemaining > 0;
      
      // Increment roll count only if not a free roll and not a lucky roll that will be reverted
      if (!isFreeRoll && !isLuckyRoll) {
        rollCount++;
        console.log(`Roll count: ${rollCount}`);
      } else if (isFreeRoll) {
        // Decrement free rolls count
        freeRolls--;
        updateFreeRollsDisplay();
        console.log(`Free roll used. Remaining free rolls: ${freeRolls}`);
      }
      
      // Update roll count display
      if (rollCountValue) {
        rollCountValue.textContent = rollCount;
      }
      
      console.log('Rolling dice...');
      console.log('Button state before disable:', rollButton.disabled);
      
      // Disable button during animation
      rollButton.disabled = true;
      rollButton.classList.add('opacity-70', 'cursor-not-allowed');
      
      console.log('Button state after disable:', rollButton.disabled);
      
      // Hide result display
      resultDisplay.classList.add('hidden');
      
      try {
        // Set animation duration
        const duration = 2000; // Fixed duration for consistent experience
        
        // Get random rotation values for the final position
        const rotationData = getRandomRotation();
        console.log('Rotation data:', rotationData);
        console.log('Target face:', rotationData.targetFace);
        
        // Animate the dice using JavaScript for more control
        animateDice(duration, rotationData);
        
        // Set a safety timeout to ensure button is re-enabled even if something goes wrong
        setTimeout(() => {
          if (rollButton.disabled) {
            console.warn('Safety timeout: Re-enabling roll button');
            enableRollButton();
          }
        }, duration + 1000); // Add 1 second buffer
      } catch (error) {
        console.error('Error during dice roll:', error);
        // Re-enable button if there's an error
        enableRollButton();
        showGameMessage('An error occurred during the dice roll. Please try again.', 'text-red-500');
      }
    }
    
    // Animate the dice with spin animation
    function animateDice(duration, rotationData) {
      console.log('Animate dice called with rotationData:', rotationData);
      const startTime = performance.now();
      const finalRotation = rotationData;
      
      // Get current rotation from dice element
      const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
      const matrix = new DOMMatrix(currentTransform);
      
      // Extract current rotation angles
      let startX = 0, startY = 0;
      
      // If transform is not identity matrix, extract rotation
      if (currentTransform !== 'none') {
        // Calculate rotation from matrix
        startX = Math.atan2(matrix.b, matrix.a) * (180 / Math.PI);
        startY = Math.atan2(-matrix.c, matrix.f) * (180 / Math.PI);
      }
      
      // Function to handle each animation frame
      function animate(currentTime) {
        const elapsedTime = currentTime - startTime;
        const progress = Math.min(elapsedTime / duration, 1);
        
        // Apply easing function for smooth, natural animation
        const easedProgress = easeOutCubic(progress);
        
        // Calculate current rotation - smooth continuous rotation
        const currentX = startX + (finalRotation.x - startX) * easedProgress;
        const currentY = startY + (finalRotation.y - startY) * easedProgress;
        
        // Spin animation: rotate in place
        diceElement.style.transform = `rotateX(${currentX}deg) rotateY(${currentY}deg)`;
        
        // Continue animation if not complete
        if (progress < 1) {
          requestAnimationFrame(animate);
        } else {
          // Animation complete - ensure we're at the exact target rotation
          diceElement.style.transform = `rotateX(${finalRotation.x}deg) rotateY(${finalRotation.y}deg)`;
          
          // Show result after a delay to ensure rotation is complete and CSS has applied
          console.log('Animation complete, waiting before finalizing...');
          setTimeout(() => {
            // Double-check that the transform has been applied
            const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
            console.log('Current transform after animation:', currentTransform);
            console.log('Calling finalizeAnimation...');
            finalizeAnimation(finalRotation);
          }, 600);
        }
      }
      
      // Start the animation
      requestAnimationFrame(animate);
    }
    
    // Helper function to normalize angles to the range [-180, 180]
    function normalizeAngle(angle) {
      angle = angle % 360;
      if (angle > 180) angle -= 360;
      if (angle < -180) angle += 360;
      return angle;
    }
    
    // Easing function for smooth, natural animation with gentle acceleration and deceleration
    // Uses a cubic easing function that starts slow, accelerates, then slows down at the end
    function easeOutCubic(t) {
      return 1 - Math.pow(1 - t, 3);
    }
    
    // Calculate score change based on dice roll result
    function calculateScoreChange(result) {
      let baseChange = 0;
      
      switch(result) {
        case 1:
        case 2:
          baseChange = -1;
          break;
        case 3:
          baseChange = 0;
          break;
        case 4:
          baseChange = 1;
          break;
        case 5:
          baseChange = 2;
          break;
        case 6:
          baseChange = 3;
          break;
        default:
          baseChange = 0;
      }
      
      // Apply current tier multiplier
      // If losing points (baseChange < 0), use multiplier of 1 instead of tier multiplier
      const tierMultiplier = 1 + currentTier / 10;
      let finalChange;
      
      if (baseChange < 0) {
        // For point loss, use multiplier of 1 regardless of tier
        finalChange = baseChange * 1;
      } else {
        // For point gain or neutral, use tier multiplier
        finalChange = baseChange * tierMultiplier;
      }
      
      // Apply active item effects
      const itemsUsed = {
        double: activeItems.double,
        noPenalty: activeItems.noPenalty
      };
      
      // Apply no penalty card first
      if (activeItems.noPenalty && baseChange < 0) {
        finalChange = 0;
      }
      
      // Apply double points cards
      if (activeItems.double > 0) {
        finalChange = finalChange * Math.pow(2, activeItems.double);
      }
      
      // Round to 2 decimal places to avoid floating point precision issues
      finalChange = Math.round(finalChange * 100) / 100;
      
      return {
        baseChange: baseChange,
        finalChange: finalChange,
        itemsUsed: itemsUsed,
        tierMultiplier: tierMultiplier
      };
    }
    
    // Enable roll button
    function enableRollButton() {
      console.log('Button state before enable:', rollButton.disabled);
      
      // Directly enable the button
      rollButton.disabled = false;
      rollButton.classList.remove('opacity-70', 'cursor-not-allowed');
      
      console.log('Button state after enable:', rollButton.disabled);
      
      // Double-check and force enable if needed
      if (rollButton.disabled) {
        console.warn('Forcing button enable');
        setTimeout(() => {
          rollButton.disabled = false;
          rollButton.classList.remove('opacity-70', 'cursor-not-allowed');
          console.log('Button state after forced enable:', rollButton.disabled);
        }, 100);
      }
    }
    
    // Finalize the animation and show result
    function finalizeAnimation(rotationData) {
      console.log('=== Finalize animation called ===');
      console.log('Current time:', new Date().toISOString().split('T')[1]);
      console.log('Rotation data:', rotationData);
      const finalRotation = rotationData;
      
      // Use the target face directly instead of recalculating
      const result = finalRotation.targetFace;
      console.log(`Final result: ${result} (should show face ${result})`);
      
      // Verify dice is in the correct position
      const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
      console.log('Current dice transform:', currentTransform);
      
      // Show result display
      console.log('Showing result display...');
      resultValue.textContent = result;
      resultDisplay.classList.remove('hidden');
      
      // Add shine effect to result
      resultDisplay.classList.add('result-shine');
      setTimeout(() => {
        resultDisplay.classList.remove('result-shine');
      }, 500);
      
      // Calculate and update score
      console.log('Calculating score change...');
      const scoreChangeData = calculateScoreChange(result);
      console.log('Score change data:', scoreChangeData);
      
      currentScore += scoreChangeData.finalChange;
      console.log('Updated score:', currentScore);
      
      // Update score display with animation
      console.log('Updating score display...');
      updateScoreDisplay(scoreChangeData);
      
      // Enable button
      console.log('Enabling roll button...');
      enableRollButton();
      
      // Add to history - include whether it was a free roll or lucky roll
      addToHistory(result, scoreChangeData, isFreeRoll, isLuckyRoll);
      
      // Check if reached the Unique dice
      if (currentTier === diceTiers.length - 1) {
        showGameMessage('Congratulations! You obtained the Unique dice!', 'text-green-500');
        gameOver = true;
        createConfetti();
      }
      
      // Handle lucky roll logic
      if (luckyRollsRemaining > 0) {
        // Decrement remaining lucky rolls
        luckyRollsRemaining--;
        
        // If rolled 1 or 2, decrement roll count
        if (result === 1 || result === 2) {
          rollCount--;
          console.log(`Lucky roll: Reverted roll count to ${rollCount}`);
          
          // Update roll count display
          if (rollCountValue) {
            rollCountValue.textContent = rollCount;
          }
          
          // Show message
          showGameMessage('Lucky! This 1/2 roll doesn\'t count!', 'text-yellow-500');
        }
        
        // Update lucky rolls display
        updateLuckyRollsDisplay();
        
        // If no more lucky rolls, show message
        if (luckyRollsRemaining === 0) {
          setTimeout(() => {
            showGameMessage('Lucky Streak ended!', 'text-yellow-500');
          }, 1000);
        }
      }
      
      // Create confetti effect if result is 6
      if (result === 6) {
        createConfetti();
      }
      
      // Debug: log final state
      console.log(`Final precise rotation: X=${finalRotation.x}°, Y=${finalRotation.y}°`);
      console.log(`Displayed result: ${result}`);
      console.log(`Score change: ${scoreChangeData.finalChange}, Current score: ${currentScore}`);
      console.log('=== finalizeAnimation completed ===');
    }
    
    // Update score display with animation
    function updateScoreDisplay(scoreChangeData) {
      console.log('=== updateScoreDisplay called ===');
      console.log('Score change data:', scoreChangeData);
      
      const change = scoreChangeData.finalChange;
      const baseChange = scoreChangeData.baseChange;
      const itemsUsed = scoreChangeData.itemsUsed;
      const tierMultiplier = scoreChangeData.tierMultiplier;
      
      console.log('Change:', change, 'Base change:', baseChange, 'Items used:', itemsUsed);
      
      // Update the score value - round to 2 decimal places
      currentScore = Math.round(currentScore * 100) / 100;
      scoreValue.textContent = currentScore;
      console.log('Score value updated to:', currentScore);
      
      // Clear previous score change display
      scoreChange.textContent = '';
      scoreChange.className = 'ml-2 text-sm font-normal';
      console.log('Cleared previous score change display');
      
      // Show score change with appropriate styling
      if (change > 0) {
        scoreChange.textContent = `+${change}`;
        scoreChange.classList.add('score-increase');
        console.log('Score increase:', change);
      } else if (change < 0) {
        scoreChange.textContent = `${change}`;
        scoreChange.classList.add('score-decrease');
        console.log('Score decrease:', change);
      } else {
        scoreChange.textContent = `±0`;
        scoreChange.classList.add('score-neutral');
        console.log('Score neutral');
      }
      
      // Show item effect message if items were used
      if (itemsUsed && (itemsUsed.double > 0 || itemsUsed.noPenalty)) {
        // Create container for item effects
        const itemEffectsContainer = document.createElement('div');
        itemEffectsContainer.className = 'flex flex-wrap gap-2 mt-1';
        
        // Add tier multiplier effect if applicable
        if (tierMultiplier !== 1) {
          const tierEffect = document.createElement('div');
          tierEffect.className = 'text-xs text-purple-500';
          tierEffect.textContent = `Tier Multiplier ×${tierMultiplier.toFixed(1)}!`;
          itemEffectsContainer.appendChild(tierEffect);
        }
        
        // Add no penalty effect
        if (itemsUsed.noPenalty) {
          const noPenaltyEffect = document.createElement('div');
          noPenaltyEffect.className = 'text-xs text-blue-500';
          noPenaltyEffect.textContent = `No Penalty! (Score protected from ${baseChange < 0 ? baseChange : 0} loss)`;
          itemEffectsContainer.appendChild(noPenaltyEffect);
        }
        
        // Add double points effect
        if (itemsUsed.double > 0) {
          const doublePointsEffect = document.createElement('div');
          doublePointsEffect.className = 'text-xs text-green-500';
          
          // Calculate multiplier
          const multiplier = Math.pow(2, itemsUsed.double);
          let calculationText = `${baseChange}`;
          
          // Apply tier multiplier for display
          let displayChange = baseChange * tierMultiplier;
          
          // Apply no penalty first for display
          if (itemsUsed.noPenalty && baseChange < 0) {
            displayChange = 0;
            calculationText = `(${baseChange} × ${tierMultiplier.toFixed(1)} → 0)`;
          } else if (tierMultiplier !== 1) {
            calculationText = `(${baseChange} × ${tierMultiplier.toFixed(1)} = ${displayChange.toFixed(2)})`;
          }
          
          // Show multiplication steps if multiple double cards used
          if (itemsUsed.double > 1) {
            for (let i = 0; i < itemsUsed.double; i++) {
              calculationText += ` × 2`;
            }
            calculationText += ` = ${(displayChange * multiplier).toFixed(2)}`;
          } else {
            calculationText += ` × 2 = ${(displayChange * multiplier).toFixed(2)}`;
          }
          
          doublePointsEffect.textContent = `Double Points ×${itemsUsed.double}! (${calculationText})`;
          itemEffectsContainer.appendChild(doublePointsEffect);
        }
        
        // Add to score display
        scoreDisplay.appendChild(itemEffectsContainer);
        
        // Remove after animation
        setTimeout(() => {
          scoreDisplay.removeChild(itemEffectsContainer);
        }, 1000);
      }
      
      // Reset score change display after animation completes
      setTimeout(() => {
        scoreChange.textContent = '';
      }, 1000);
      
      // Clear active items after score update
      console.log('Checking if items need to be cleared...');
      if (itemsUsed && (itemsUsed.double > 0 || itemsUsed.noPenalty)) {
        console.log('Clearing active items...');
        clearActiveItems();
        console.log('Updating items display...');
        updateItemsDisplay();
      }
      
      // Check game state after score update
      console.log('Checking game state...');
      checkGameState();
      
      // Update upgrade button state
      updateUpgradeCostDisplay();
      
      console.log('=== updateScoreDisplay completed ===');
    }
    
    // Handle dice upgrade
    function upgradeDice() {
      // Check if game is already over
      if (gameOver) {
        showGameMessage('Game over! Click "Play Again" to restart.', 'text-red-500');
        return;
      }
      
      // Check if already at maximum tier
      if (currentTier >= diceTiers.length - 1) {
        // If not already game over, end the game with win condition
        if (!gameOver) {
          gameOver = true;
          endGame(true);
        } else {
          showGameMessage('Congratulations! You already have the Unique dice!', 'text-green-500');
        }
        return;
      }
      
      // Calculate required score for upgrade (5 + currentTier)
      const requiredScore = 5 + currentTier;
      
      // Check if enough score to upgrade
      if (currentScore < requiredScore) {
        showGameMessage(`Not enough score to upgrade! Need ${requiredScore} points.`, 'text-orange-500');
        // Add shake animation to score display
        scoreDisplay.classList.add('animate-shake');
        setTimeout(() => {
          scoreDisplay.classList.remove('animate-shake');
        }, 500);
        return;
      }
      
      // Deduct score for upgrade
      currentScore -= requiredScore;
      // Round to 2 decimal places
      currentScore = Math.round(currentScore * 100) / 100;
      
      // Update score display
      scoreValue.textContent = currentScore;
      showScoreChange(-requiredScore);
      
      // Increase tier
      currentTier++;
      
      // Update current tier display
      currentTierDisplay.innerHTML = `Current Dice: <span class="font-semibold text-primary">${diceTiers[currentTier].name}</span>`;
      
      // Update tier multiplier display
      updateTierMultiplierDisplay();
      
      // Unlock the new dice color
      unlockDiceColor(currentTier);
      
      // Update color selection UI
      updateColorSelection(currentTier);
      
      // Update upgrade cost display
      updateUpgradeCostDisplay();
      
      // Change to the new dice color
      console.log(`Changing dice color to ${diceTiers[currentTier].color} (${diceTiers[currentTier].name})`);
      changeDiceColor(diceTiers[currentTier].color);
      
      // Check if this upgrade reached the maximum tier
      checkGameState();
      
      // Randomly get an item
      const itemChance = Math.random();
      if (itemChance < 0.30) { // 30% chance to get double points card
        doublePointsCards++;
      } else if (itemChance < 0.60) { // 30% chance to get no penalty card
        noPenaltyCards++;
      } else if (itemChance < 0.70) { // 10% chance to get lucky streak card
        luckyStreakCards++;
      } else { // 30% chance to get nothing
        // Do nothing
      }
      
      // Update items display to show new counts
      updateItemsDisplay();
      
      // Update items display
      updateItemsDisplay();
      
      // Check if reached the Unique dice
      if (currentTier === diceTiers.length - 1) {
        showGameMessage('Congratulations! You obtained the Unique dice!', 'text-green-500');
        gameOver = true;
        createConfetti();
      }
      
      // Handle lucky roll logic
      if (luckyRollsRemaining > 0) {
        // Decrement remaining lucky rolls
        luckyRollsRemaining--;
        
        // If rolled 1 or 2, decrement roll count
        if (result === 1 || result === 2) {
          rollCount--;
          console.log(`Lucky roll: Reverted roll count to ${rollCount}`);
          
          // Update roll count display
          if (rollCountValue) {
            rollCountValue.textContent = rollCount;
          }
          
          // Show message
          showGameMessage('Lucky! This 1/2 roll doesn\'t count!', 'text-yellow-500');
        }
        
        // Update lucky rolls display
        updateLuckyRollsDisplay();
        
        // If no more lucky rolls, show message
        if (luckyRollsRemaining === 0) {
          setTimeout(() => {
            showGameMessage('Lucky Streak ended!', 'text-yellow-500');
          }, 1000);
        }
      }
      
      // Add to history
      addToHistory('UPGRADE', -5);
      
      // Add item to history if obtained
      if (itemChance < 0.30) {
        addToHistory('ITEM', 'Double Points Card');
      } else if (itemChance < 0.60) {
        addToHistory('ITEM', 'No Penalty Card');
      } else if (itemChance < 0.70) {
        addToHistory('ITEM', 'Lucky Streak Card');
      }
      
      // Check game state after upgrade
      checkGameState();
    }
    
    // Show score change temporarily
    function showScoreChange(change) {
      scoreChange.textContent = change > 0 ? `+${change}` : change;
      scoreChange.className = `ml-2 text-sm font-normal ${change > 0 ? 'score-increase' : 'score-decrease'}`;
      
      setTimeout(() => {
        scoreChange.textContent = '';
      }, 1000);
    }
    
    // Unlock a dice color option
    function unlockDiceColor(tierIndex) {
      if (tierIndex >= 0 && tierIndex < colorOptions.length) {
        const option = colorOptions[tierIndex];
        // Show particle effect on the lock before unlocking
        createLockParticles(option);
        // Add a small delay to show the particles before unlocking
        setTimeout(() => {
          option.disabled = false;
          option.classList.remove('locked');
        }, 300);
      }
    }
    
    // Show game message
    function showGameMessage(message, className) {
      gameMessageDisplay.textContent = message;
      gameMessageDisplay.className = `mt-4 text-center font-semibold ${className}`;
      gameMessageDisplay.classList.remove('hidden');
      
      // Hide message after 3 seconds
      setTimeout(() => {
        if (!gameOver) {
          gameMessageDisplay.classList.add('hidden');
        }
      }, 3000);
    }
    
    // Check game state (win/lose conditions)
    function checkGameState() {
      console.log('=== checkGameState called ===');
      console.log('Current score:', currentScore, 'Game over:', gameOver);
      
      // Check if score is negative (lose condition)
      if (currentScore < 0 && !gameOver) {
        console.log('Score is negative, ending game...');
        gameOver = true;
        endGame(false);
      }
      
      // Check if reached Unique dice (win condition)
      if (currentTier === diceTiers.length - 1 && !gameOver) {
        console.log('Reached Unique dice, ending game...');
        gameOver = true;
        endGame(true);
        
        // Check if this is a new record
        setTimeout(() => {
          checkWinRecord();
        }, 1000);
      }
      
      // Check if score is low (warning)
      if (currentScore >= 0 && currentScore <= 5 && !gameOver) {
        showLowScoreWarning();
      }
      
      console.log('=== checkGameState completed ===');
    }
    
    // Update items display
    function updateItemsDisplay() {
      // Update counts
      doublePointsCount.textContent = doublePointsCards;
      noPenaltyCount.textContent = noPenaltyCards;
      luckyStreakCount.textContent = luckyStreakCards;
      
      // Enable/disable buttons based on available items
      useDoublePointsButton.disabled = doublePointsCards <= 0 || gameOver;
      useNoPenaltyButton.disabled = noPenaltyCards <= 0 || activeItems.noPenalty || gameOver;
      useLuckyStreakButton.disabled = luckyStreakCards <= 0 || gameOver;
      
      // Update free rolls display
      updateFreeRollsDisplay();
      
      // Update lucky rolls display
      updateLuckyRollsDisplay();
    }
    
    // Update free rolls display
    function updateFreeRollsDisplay() {
      if (freeRolls > 0) {
        freeRollsCountElement.textContent = freeRolls;
        freeRollsIndicator.classList.remove('hidden');
      } else {
        freeRollsIndicator.classList.add('hidden');
      }
    }
    
    // Update upgrade cost display and button state
    function updateUpgradeCostDisplay() {
      if (currentTier >= diceTiers.length - 1) {
        // Already at maximum tier
        upgradeCost.textContent = '(Max Tier)';
        upgradeButton.disabled = true;
        upgradeButton.classList.add('opacity-70', 'cursor-not-allowed');
      } else {
        const requiredScore = 5 + currentTier;
        upgradeCost.textContent = `(Cost: ${requiredScore})`;
        
        // Update button state based on available score
        if (currentScore >= requiredScore && !gameOver) {
          upgradeButton.disabled = false;
          upgradeButton.classList.remove('opacity-70', 'cursor-not-allowed');
        } else {
          upgradeButton.disabled = true;
          upgradeButton.classList.add('opacity-70', 'cursor-not-allowed');
        }
      }
    }
    
    // Use double points card
    function useDoublePointsCard() {
      if (doublePointsCards > 0 && !gameOver) {
        activeItems.double++;
        doublePointsCards--;
        
        // Update UI
        updateItemsDisplay();
        showActiveItemIndicator();
        
        // Show message
        showGameMessage('Double Points Card activated! Next roll will double your score change.', 'text-green-500');
      }
    }
    
    // Use no penalty card
    function useNoPenaltyCard() {
      if (noPenaltyCards > 0 && !activeItems.noPenalty && !gameOver) {
        activeItems.noPenalty = true;
        noPenaltyCards--;
        
        // Update UI
        updateItemsDisplay();
        showActiveItemIndicator();
        
        // Show message
        showGameMessage('No Penalty Card activated! Next roll won\'t lose points.', 'text-blue-500');
      }
    }
    
    // Use lucky streak card
    function useLuckyStreakCard() {
      if (luckyStreakCards > 0 && !gameOver) {
        luckyRollsRemaining = 3;
        luckyStreakCards--;
        
        // Update UI
        updateItemsDisplay();
        updateLuckyRollsDisplay();
        
        // Show message
        showGameMessage('Lucky Streak Card activated! Next 3 rolls of 1 or 2 won\'t count!', 'text-yellow-500');
        
        // Add to history
        addToHistory('ITEM USE', 'Lucky Streak Card');
      }
    }
    
    // Update lucky rolls display
    function updateLuckyRollsDisplay() {
      if (luckyRollsRemaining > 0) {
        // Check if indicator exists, if not create it
        let luckyRollsIndicator = document.getElementById('lucky-rolls-indicator');
        if (!luckyRollsIndicator) {
          luckyRollsIndicator = document.createElement('div');
          luckyRollsIndicator.id = 'lucky-rolls-indicator';
          luckyRollsIndicator.className = 'mt-3 text-center';
          
          // Insert after free rolls indicator
          const freeRollsIndicator = document.getElementById('free-rolls-indicator');
          if (freeRollsIndicator) {
            freeRollsIndicator.parentNode.insertBefore(luckyRollsIndicator, freeRollsIndicator.nextSibling);
          } else {
            // Fallback: insert after active item indicator
            const activeItemIndicator = document.getElementById('active-item-indicator');
            if (activeItemIndicator) {
              activeItemIndicator.parentNode.insertBefore(luckyRollsIndicator, activeItemIndicator.nextSibling);
            } else {
              // Fallback: insert after items display
              const itemsDisplay = document.getElementById('items-display');
              if (itemsDisplay) {
                itemsDisplay.parentNode.insertBefore(luckyRollsIndicator, itemsDisplay.nextSibling);
              }
            }
          }
        }
        
        // Update content
        luckyRollsIndicator.innerHTML = `
          <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
            <i class="fa fa-star mr-1" style="color: #f59e0b;"></i>
            <span>Lucky Rolls: <span id="lucky-rolls-count">${luckyRollsRemaining}</span> (1-2 won't count)</span>
          </span>
        `;
        
        // Show indicator
        luckyRollsIndicator.classList.remove('hidden');
      } else {
        // Remove indicator if exists
        const luckyRollsIndicator = document.getElementById('lucky-rolls-indicator');
        if (luckyRollsIndicator) {
          luckyRollsIndicator.classList.add('hidden');
        }
      }
    }
    
    // Show active item indicator
    function showActiveItemIndicator() {
      // Clear previous content
      activeItemIndicator.innerHTML = '';
      
      // Check if any items are active
      if (activeItems.double === 0 && !activeItems.noPenalty) {
        activeItemIndicator.className = 'mt-3 text-center hidden';
        return;
      }
      
      // Create container for active items
      const itemsContainer = document.createElement('div');
      itemsContainer.className = 'flex flex-wrap justify-center gap-2';
      
      // Add double points cards indicator
      if (activeItems.double > 0) {
        const doublePointsIndicator = document.createElement('span');
        doublePointsIndicator.className = 'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800';
        doublePointsIndicator.innerHTML = `
          <i class="fa fa-plus-circle mr-1" style="color: #10b981;"></i>
          <span>Double Points ×${activeItems.double}</span>
        `;
        itemsContainer.appendChild(doublePointsIndicator);
      }
      
      // Add no penalty card indicator
      if (activeItems.noPenalty) {
        const noPenaltyIndicator = document.createElement('span');
        noPenaltyIndicator.className = 'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800';
        noPenaltyIndicator.innerHTML = `
          <i class="fa fa-shield mr-1" style="color: #3b82f6;"></i>
          <span>No Penalty</span>
        `;
        itemsContainer.appendChild(noPenaltyIndicator);
      }
      
      // Add indicators to container
      activeItemIndicator.appendChild(itemsContainer);
      activeItemIndicator.className = 'mt-3 text-center';
    }
    
    // Clear active items
    function clearActiveItems() {
      activeItems = {
        double: 0,
        noPenalty: false
      };
      showActiveItemIndicator();
    }
    
    // End the game and display appropriate message
    function endGame(isWin) {
      console.log('=== endGame called ===');
      console.log('Is win:', isWin, 'Current score:', currentScore);
      
      // Disable all interactive elements
      rollButton.disabled = true;
      upgradeButton.disabled = true;
      rollButton.classList.add('opacity-70', 'cursor-not-allowed');
      upgradeButton.classList.add('opacity-70', 'cursor-not-allowed');
      
      // Disable all interactive elements
      colorOptions.forEach(option => {
        option.disabled = true;
        option.classList.add('opacity-50', 'cursor-not-allowed');
      });
      
      // Disable item buttons
      useDoublePointsButton.disabled = true;
      useNoPenaltyButton.disabled = true;
      useLuckyStreakButton.disabled = true;
      
      // Hide active indicators
      activeItemIndicator.classList.add('hidden');
      const luckyRollsIndicator = document.getElementById('lucky-rolls-indicator');
      if (luckyRollsIndicator) {
        luckyRollsIndicator.classList.add('hidden');
      }
      
      // Create game over message element
      const gameOverMessage = document.createElement('div');
      gameOverMessage.className = `mt-4 p-4 rounded-lg text-center font-bold ${isWin ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}`;
      
      // Format final score to 2 decimal places
      const formattedScore = currentScore.toFixed(2);
      
      if (isWin) {
        gameOverMessage.innerHTML = `
          <div class="text-2xl mb-2">Congratulations!</div>
          <p>You won the game!</p>
          <p>You obtained the Unique dice!</p>
          <p class="mt-2 text-sm">Final Score: ${formattedScore}</p>
          <p class="mt-1 text-sm">Total Rolls: ${rollCount}</p>
          <p class="mt-1 text-sm">Double Points Cards: ${doublePointsCards}</p>
          <p class="mt-1 text-sm">No Penalty Cards: ${noPenaltyCards}</p>
          <p class="mt-1 text-sm">Lucky Streak Cards: ${luckyStreakCards}</p>
          <p class="mt-1 text-sm">Final Tier Multiplier: ×${(1 + currentTier / 10).toFixed(1)}</p>
          <button id="play-again" class="mt-4 bg-primary hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-full transition-all duration-300 transform hover:scale-105">
            <i class="fa fa-refresh mr-1"></i> Play Again
          </button>
        `;
        createConfetti();
      } else {
        gameOverMessage.innerHTML = `
          <div class="text-2xl mb-2">Game Over!</div>
          <p>Your score went negative.</p>
          <p>Better luck next time!</p>
          <p class="mt-2 text-sm">Final Score: ${formattedScore}</p>
          <p class="mt-1 text-sm">Total Rolls: ${rollCount}</p>
          <p class="mt-1 text-sm">Double Points Cards: ${doublePointsCards}</p>
          <p class="mt-1 text-sm">No Penalty Cards: ${noPenaltyCards}</p>
          <p class="mt-1 text-sm">Lucky Streak Cards: ${luckyStreakCards}</p>
          <p class="mt-1 text-sm">Final Tier Multiplier: ×${(1 + currentTier / 10).toFixed(1)}</p>
          <button id="play-again" class="mt-4 bg-primary hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-full transition-all duration-300 transform hover:scale-105">
            <i class="fa fa-refresh mr-1"></i> Play Again
          </button>
        `;
      }
      
      // Add restart button event listener
      gameOverMessage.querySelector('#play-again').addEventListener('click', () => {
        window.location.reload();
      });
      
      // Replace game message display with game over message
      const gameMessageContainer = gameMessageDisplay.parentElement;
      gameMessageContainer.replaceChild(gameOverMessage, gameMessageDisplay);
      gameMessageDisplay = gameOverMessage;
      
      // Add game end to history
      addToHistory(isWin ? 'GAME WIN' : 'GAME OVER', 0);
      
      console.log('=== endGame completed ===');
    }
    
    // Show warning when score is low
    function showLowScoreWarning() {
      // Only show warning if not already showing
      if (gameMessageDisplay.classList.contains('hidden')) {
        showGameMessage('Warning: Low score! Risk of game over.', 'text-orange-500');
      }
    }
    
    // Update color selection UI to show the currently selected color
    function updateColorSelection(selectedIndex) {
      // Remove active state from all color options
      colorOptions.forEach(opt => opt.classList.remove('ring-2', 'ring-offset-2', 'ring-primary'));
      
      // Add active state to the selected color option
      if (selectedIndex >= 0 && selectedIndex < colorOptions.length) {
        colorOptions[selectedIndex].classList.add('ring-2', 'ring-offset-2', 'ring-primary');
      }
    }
    
    // Add result to history
    function addToHistory(result, scoreChangeData, isFreeRoll = false, isLuckyRoll = false) {
      const now = new Date();
      const timeString = now.toLocaleTimeString();
      
      // Determine score change display and color
      let scoreChangeText = '';
      let scoreChangeClass = '';
      let actionText = '';
      
      if (result === 'UPGRADE') {
        actionText = 'Upgraded dice';
        scoreChangeText = `${scoreChangeData}`;
        scoreChangeClass = 'text-red-500';
      } else if (result === 'ITEM') {
        actionText = `Received <span class="font-bold text-purple-500">${scoreChangeData}</span>`;
        scoreChangeText = '+1';
        scoreChangeClass = 'text-purple-500';
      } else if (result === 'GAME WIN' || result === 'GAME OVER') {
        actionText = result;
        scoreChangeText = '';
        scoreChangeClass = '';
      } else {
        const scoreChange = scoreChangeData.finalChange;
        const baseChange = scoreChangeData.baseChange;
        const itemsUsed = scoreChangeData.itemsUsed;
        
        actionText = `Rolled a <span class="font-bold text-primary">${result}</span>`;
        
        // Add free roll indicator if applicable
        if (isFreeRoll) {
          actionText += ` <span class="text-yellow-500">(Free Roll)</span>`;
        }
        
        // Add lucky roll indicator if applicable
        if (isLuckyRoll) {
          actionText += ` <span class="text-yellow-500">(Lucky Roll)</span>`;
        }
        
        // Add item effect indicators if applicable
        const activeItemsText = [];
        if (itemsUsed && itemsUsed.double > 0) {
          activeItemsText.push(`<span class="text-green-500">(Double Points ×${itemsUsed.double})</span>`);
        }
        if (itemsUsed && itemsUsed.noPenalty) {
          activeItemsText.push(`<span class="text-blue-500">(No Penalty)</span>`);
        }
        
        if (activeItemsText.length > 0) {
          actionText += ` ${activeItemsText.join(' ')}`;
        }
        
        if (scoreChange > 0) {
          scoreChangeText = `+${scoreChange}`;
          scoreChangeClass = 'text-green-500';
        } else if (scoreChange < 0) {
          scoreChangeText = `${scoreChange}`;
          scoreChangeClass = 'text-red-500';
        } else {
          scoreChangeText = '±0';
          scoreChangeClass = 'text-gray-500';
        }
        
        // Show base change if different from final change (items were used)
        if ((itemsUsed && (itemsUsed.double > 0 || itemsUsed.noPenalty)) && baseChange !== scoreChange) {
          scoreChangeText += ` <span class="text-xs">(Base: ${baseChange > 0 ? '+' : ''}${baseChange})</span>`;
        }
      }
      
      const listItem = document.createElement('li');
      listItem.className = 'py-1 border-b border-gray-100 flex justify-between items-center';
      listItem.innerHTML = `
        <span><span class="text-gray-500">${timeString}</span>: ${actionText}</span>
        <span class="font-medium ${scoreChangeClass}">${scoreChangeText}</span>
      `;
      
      historyList.prepend(listItem);
      
      // Keep only last 5 history items
      if (historyList.children.length > 5) {
        historyList.removeChild(historyList.lastChild);
      }
    }
    
    // Create confetti effect
    function createConfetti() {
      const confettiContainer = document.createElement('div');
      confettiContainer.className = 'fixed inset-0 pointer-events-none overflow-hidden';
      document.body.appendChild(confettiContainer);
      
      // Create 50 confetti pieces
      for (let i = 0; i < 50; i++) {
        const confetti = document.createElement('div');
        confetti.className = 'confetti';
        
        // Random position
        const posX = Math.random() * 100;
        const delay = Math.random() * 3;
        const duration = 3 + Math.random() * 2;
        
        // Random colors
        const colors = ['#3b82f6', '#f97316', '#10b981', '#ef4444', '#8b5cf6'];
        const color = colors[Math.floor(Math.random() * colors.length)];
        
        confetti.style.left = `${posX}%`;
        confetti.style.backgroundColor = color;
        confetti.style.animationDelay = `${delay}s`;
        confetti.style.animationDuration = `${duration}s`;
        
        confettiContainer.appendChild(confetti);
      }
      
      // Remove confetti container after animation completes
      setTimeout(() => {
        document.body.removeChild(confettiContainer);
      }, 5000);
    }
    
    
    
    // Create particle effect on lock
    function createLockParticles(lockElement) {
      // Get lock element position
      const rect = lockElement.getBoundingClientRect();
      const centerX = rect.left + rect.width / 2;
      const centerY = rect.top + rect.height / 2;
      
      // Create particle container
      const particleContainer = document.createElement('div');
      particleContainer.className = 'absolute pointer-events-none';
      particleContainer.style.left = `${centerX}px`;
      particleContainer.style.top = `${centerY}px`;
      particleContainer.style.transform = 'translate(-50%, -50%)';
      document.body.appendChild(particleContainer);
      
      // Create 15 particles
      for (let i = 0; i < 15; i++) {
        const particle = document.createElement('div');
        particle.className = 'lock-particle';
        
        // Random direction and distance
        const angle = Math.random() * Math.PI * 2;
        const distance = 10 + Math.random() * 20;
        const tx = Math.cos(angle) * distance;
        const ty = Math.sin(angle) * distance;
        
        // Random color (use the color of the unlocked dice)
        const color = lockElement.style.backgroundColor;
        
        // Random animation duration
        const duration = 0.5 + Math.random() * 0.5;
        
        // Set particle styles
        particle.style.backgroundColor = color;
        particle.style.setProperty('--tx', `${tx}px`);
        particle.style.setProperty('--ty', `${ty}px`);
        particle.style.animation = `lock-particle ${duration}s ease-out forwards`;
        
        particleContainer.appendChild(particle);
      }
      
      // Remove particle container after animation completes
      setTimeout(() => {
        document.body.removeChild(particleContainer);
      }, 1000);
    }
    
    // Function to darken a color by a certain percentage
    function darkenColor(color, percent) {
      const hex = color.replace('#', '');
      let r = parseInt(hex.substr(0, 2), 16);
      let g = parseInt(hex.substr(2, 2), 16);
      let b = parseInt(hex.substr(4, 2), 16);
      
      // Darken each channel by the percentage
      r = Math.max(0, Math.floor(r * (1 - percent / 100)));
      g = Math.max(0, Math.floor(g * (1 - percent / 100)));
      b = Math.max(0, Math.floor(b * (1 - percent / 100)));
      
      // Convert back to hex
      const darkenedHex = '#' + 
        r.toString(16).padStart(2, '0') + 
        g.toString(16).padStart(2, '0') + 
        b.toString(16).padStart(2, '0');
      
      return darkenedHex;
    }
    
    // Change dice color function
    function changeDiceColor(color) {
      console.log(`changeDiceColor called with color: ${color}`);
      const faces = document.querySelectorAll('.dice-face');
      console.log(`Found ${faces.length} dice faces`);
      let dotColor, borderColor;
      
      // Special cases for high contrast
      if (color.toUpperCase() === '#FFFFFF') {
        // White dice - use black dots and light gray borders
        dotColor = '#000000';
        borderColor = '#CCCCCC';
      } else if (color.toUpperCase() === '#555555') {
        // Dark gray dice - use white dots and slightly lighter gray borders
        dotColor = '#FFFFFF';
        borderColor = '#777777';
      } else {
        // Calculate darker color for dots and borders (40% darker for more contrast)
        dotColor = darkenColor(color, 40);
        borderColor = darkenColor(color, 30); // Slightly lighter border than dots
      }
      
      faces.forEach(face => {
        // Set face background color
        face.style.backgroundColor = color;
        
        // Set face border color
        face.style.border = `3px solid ${borderColor}`;
        
        // Set dots color
        const dots = face.querySelectorAll('.dot');
        dots.forEach(dot => {
          dot.style.backgroundColor = dotColor;
          // Add slight border to dots for better definition
          dot.style.border = color.toUpperCase() === '#FFFFFF' ? '1px solid rgba(0, 0, 0, 0.2)' : '1px solid rgba(0, 0, 0, 0.1)';
        });
      });
    }
    
    // Update tier multiplier display
    function updateTierMultiplierDisplay() {
      const display = document.getElementById('tier-multiplier-display');
      if (display) {
        display.innerHTML = `Tier Multiplier: <span class="font-semibold text-purple-500">×${(1 + currentTier / 10).toFixed(1)}</span>`;
      }
    }
    
    // Event listener for roll button
    rollButton.addEventListener('click', rollDice);
    
    // Event listener for upgrade button
    upgradeButton.addEventListener('click', upgradeDice);
    
    // Event listeners for item buttons
    useDoublePointsButton.addEventListener('click', useDoublePointsCard);
    useNoPenaltyButton.addEventListener('click', useNoPenaltyCard);
    useLuckyStreakButton.addEventListener('click', useLuckyStreakCard);
    
    // Event listeners for color options
    colorOptions.forEach((option, index) => {
      // Disable all color options except the first one initially
      if (index !== 0) {
        option.disabled = true;
        option.classList.add('locked');
      }
      
      option.addEventListener('click', () => {
        // Check if game is over
        if (gameOver) {
          showGameMessage('Game over! Click "Play Again" to restart.', 'text-red-500');
          return;
        }
        
        // Check if color is unlocked
        if (option.disabled) {
          showGameMessage('You need to upgrade to unlock this dice color!', 'text-orange-500');
          return;
        }
        
        const color = option.getAttribute('data-color');
        changeDiceColor(color);
        
        // Add active state to selected color
        colorOptions.forEach(opt => opt.classList.remove('ring-2', 'ring-offset-2', 'ring-primary'));
        option.classList.add('ring-2', 'ring-offset-2', 'ring-primary');
        
        // Update current tier to the selected color's tier
        currentTier = index;
        currentTierDisplay.innerHTML = `Current Dice: <span class="font-semibold text-primary">${diceTiers[currentTier].name}</span>`;
        updateTierMultiplierDisplay();
      });
    });
    
    // Initialize dice on page load
    window.addEventListener('DOMContentLoaded', () => {
      console.log('=== DOMContentLoaded event fired ===');
      
      // Check if elements exist
      console.log('Checking if elements exist before initialization:');
      console.log('best-record-display exists:', !!document.getElementById('best-record-display'));
      console.log('best-record-value exists:', !!document.getElementById('best-record-value'));
      
      console.log('DOM fully loaded');
      initializeDice();
      
      // Set default color (first option)
      if (colorOptions.length > 0) {
        const defaultColor = colorOptions[0].getAttribute('data-color');
        changeDiceColor(defaultColor);
        colorOptions[0].classList.add('ring-2', 'ring-offset-2', 'ring-primary');
      }
      
      // Initialize current tier display
      currentTierDisplay.innerHTML = `Current Dice: <span class="font-semibold text-primary">${diceTiers[currentTier].name}</span>`;
      
      // Initialize tier multiplier display
      updateTierMultiplierDisplay();
      
      // Initialize items display
      updateItemsDisplay();
      
      // Initialize upgrade cost display
      updateUpgradeCostDisplay();
      
      // Show welcome message
      setTimeout(() => {
        showGameMessage('Welcome! Roll the dice to earn points and upgrade your dice!', 'text-blue-500');
      }, 1000);
    });
    
    // Also try initializing on window load
    window.addEventListener('load', () => {
      console.log('Window loaded');
      // If dice not already initialized, try again
      if (diceElement.children.length === 0) {
        console.log('Dice not initialized, trying again...');
        initializeDice();
      }
    });
    
    // Game Rules Modal Functionality
    (function() {
      // Get elements
      const rulesButton = document.getElementById('game-rules-button');
      const rulesModal = document.getElementById('game-rules-modal');
      const closeButtons = rulesModal.querySelectorAll('.close-button');
      const modalBackdrop = rulesModal.querySelector('.modal-backdrop');
      const modalContent = rulesModal.querySelector('.modal-content');
      
      // Function to prevent background scrolling
      function preventBackgroundScroll(event) {
        // Allow scrolling inside the modal content
        if (modalContent.contains(event.target)) {
          // Check if we're at the top or bottom of the modal content
          const isAtTop = modalContent.scrollTop === 0;
          const isAtBottom = modalContent.scrollTop + modalContent.clientHeight >= modalContent.scrollHeight;
          
          // Prevent scrolling if at the top and scrolling up, or at the bottom and scrolling down
          if ((isAtTop && event.deltaY < 0) || (isAtBottom && event.deltaY > 0)) {
            event.preventDefault();
          }
        } else {
          // Prevent scrolling outside the modal content
          event.preventDefault();
        }
      }
      
      // Function to open modal
      function openModal() {
        // Add event listeners to prevent background scrolling
        document.addEventListener('wheel', preventBackgroundScroll, { passive: false });
        document.addEventListener('touchmove', preventBackgroundScroll, { passive: false });
        
        // Add open class to trigger animations
        rulesModal.classList.add('modal-open');
        
        // Show the modal
        rulesModal.style.visibility = 'visible';
      }
      
      // Function to close modal
      function closeModal() {
        // Remove open class to trigger animations
        rulesModal.classList.remove('modal-open');
        
        // Remove event listeners that prevent background scrolling
        document.removeEventListener('wheel', preventBackgroundScroll);
        document.removeEventListener('touchmove', preventBackgroundScroll);
        
        // Hide the modal after animation completes
        setTimeout(() => {
          rulesModal.style.visibility = 'hidden';
        }, 300);
      }
      
      // Add event listeners
      if (rulesButton) {
        rulesButton.addEventListener('click', openModal);
      }
      
      // Close buttons
      closeButtons.forEach(button => {
        button.addEventListener('click', closeModal);
      });
      
      // Close when clicking outside the modal content
      modalBackdrop.addEventListener('click', closeModal);
      
      // Close when pressing Escape key
      document.addEventListener('keydown', (event) => {
        if (event.key === 'Escape' && rulesModal.classList.contains('modal-open')) {
          closeModal();
        }
      });
      
      // Add hover effect to rules button
      if (rulesButton) {
        rulesButton.addEventListener('mouseenter', () => {
          rulesButton.classList.add('scale-105');
        });
        
        rulesButton.addEventListener('mouseleave', () => {
          rulesButton.classList.remove('scale-105');
        });
      }
      
      // Add click effect to close buttons
      closeButtons.forEach(button => {
        button.addEventListener('mousedown', () => {
          button.classList.add('scale-95');
        });
        
        button.addEventListener('mouseup', () => {
          button.classList.remove('scale-95');
        });
        
        button.addEventListener('mouseleave', () => {
          button.classList.remove('scale-95');
        });
      });
    })();
  </script>
</body>
</html>
v.1.2HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>3D Dice Roll Animation</title>
  <!-- Tailwind CSS v3 -->
  <script src="https://cdn.tailwindcss.com"></script>
  <!-- Font Awesome -->
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            primary: '#3b82f6',
            secondary: '#f97316',
            dark: '#1e293b',
            light: '#f8fafc'
          },
          fontFamily: {
            sans: ['Inter', 'system-ui', 'sans-serif'],
          },
          animation: {
            'shake': 'shake 0.5s ease-in-out',
          },
          keyframes: {
            shake: {
              '0%, 100%': { transform: 'translateX(0)' },
              '25%': { transform: 'translateX(-5px)' },
              '50%': { transform: 'translateX(5px)' },
              '75%': { transform: 'translateX(-5px)' },
            }
          }
        }
      }
    }
  </script>
  
  <style type="text/tailwindcss">
    @layer utilities {
      .preserve-3d {
        transform-style: preserve-3d;
      }
      .perspective {
        perspective: 1000px;
      }
      .backface-hidden {
        backface-visibility: hidden;
      }
      .dice-shadow {
        box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
      }
      .glass-effect {
        background: rgba(255, 255, 255, 0.7);
        backdrop-filter: blur(10px);
        -webkit-backdrop-filter: blur(10px);
      }
      .modal-backdrop {
        background-color: rgba(0, 0, 0, 0.5);
        backdrop-filter: blur(4px);
        -webkit-backdrop-filter: blur(4px);
      }
      .modal-content {
        transform: translateY(-20px);
        opacity: 0;
        transition: all 0.3s ease-out;
      }
      .modal-open .modal-content {
        transform: translateY(0);
        opacity: 1;
      }
      .modal-open .modal-backdrop {
        opacity: 1;
        visibility: visible;
      }
      .trophy-animation {
        animation: trophy-pulse 2s ease-in-out infinite;
      }
      .record-animation {
        animation: record-shine 2s ease-in-out;
      }
    }
    
    @keyframes trophy-pulse {
      0% { transform: scale(1); }
      50% { transform: scale(1.1); }
      100% { transform: scale(1); }
    }
    
    @keyframes record-shine {
      0% { box-shadow: 0 0 0 0 rgba(251, 191, 36, 0.7); }
      70% { box-shadow: 0 0 0 15px rgba(251, 191, 36, 0); }
      100% { box-shadow: 0 0 0 0 rgba(251, 191, 36, 0); }
    }
    
    /* Custom styles for 3D dice */
    .dice-scene {
      perspective: 1500px;
      width: 120px;
      height: 120px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .dice-container {
      position: relative;
      width: 100px;
      height: 100px;
      transform-style: preserve-3d;
      transition: transform 1s ease-out;
      transform: rotateX(20deg) rotateY(20deg);
    }
    
    .dice-face {
      position: absolute;
      width: 100px;
      height: 100px;
      border-radius: 8px;
      background-color: white;
      border: 2px solid #f0f0f0;
      display: flex;
      align-items: center;
      justify-content: center;
      box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
    }
    
    /* Dice face positions */
    .face-1 { transform: translateZ(50px); }
    .face-2 { transform: rotateY(90deg) translateZ(50px); }
    .face-3 { transform: rotateY(180deg) translateZ(50px); }
    .face-4 { transform: rotateY(-90deg) translateZ(50px); }
    .face-5 { transform: rotateX(90deg) translateZ(50px); }
    .face-6 { transform: rotateX(-90deg) translateZ(50px); }
    
    /* Dots on dice faces */
    .dot {
      position: absolute;
      width: 20px;
      height: 20px;
      border-radius: 50%;
      background-color: black;
    }
    
    /* Dot positions for each face */
    .face-1 .dot { top: 40px; left: 40px; }
    
    .face-2 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-2 .dot:nth-child(2) { top: 60px; left: 60px; }
    
    .face-3 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-3 .dot:nth-child(2) { top: 40px; left: 40px; }
    .face-3 .dot:nth-child(3) { top: 60px; left: 60px; }
    
    .face-4 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-4 .dot:nth-child(2) { top: 20px; left: 60px; }
    .face-4 .dot:nth-child(3) { top: 60px; left: 20px; }
    .face-4 .dot:nth-child(4) { top: 60px; left: 60px; }
    
    .face-5 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-5 .dot:nth-child(2) { top: 20px; left: 60px; }
    .face-5 .dot:nth-child(3) { top: 40px; left: 40px; }
    .face-5 .dot:nth-child(4) { top: 60px; left: 20px; }
    .face-5 .dot:nth-child(5) { top: 60px; left: 60px; }
    
    .face-6 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-6 .dot:nth-child(2) { top: 20px; left: 60px; }
    .face-6 .dot:nth-child(3) { top: 40px; left: 20px; }
    .face-6 .dot:nth-child(4) { top: 40px; left: 60px; }
    .face-6 .dot:nth-child(5) { top: 60px; left: 20px; }
    .face-6 .dot:nth-child(6) { top: 60px; left: 60px; }
    
    .dice-result {
      transition: all 0.5s ease-out;
    }
    
    /* Fixed height for result display to prevent page jumping */
    #result-display {
      height: 40px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .result-shine {
      animation: shine 0.5s ease-out;
    }
    
    .score-increase {
      color: #10b981;
      animation: scorePopup 1s ease-out;
    }
    
    .score-decrease {
      color: #ef4444;
      animation: scorePopup 1s ease-out;
    }
    
    .score-neutral {
      color: #6b7280;
      animation: scorePopup 1s ease-out;
    }
    
    /* Locked color option styles */
    .color-option.locked {
      position: relative;
      opacity: 0.5;
      cursor: not-allowed;
    }
    
    .color-option.locked::after {
      content: '\f023'; /* Lock icon from Font Awesome */
      font-family: 'FontAwesome';
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      color: rgba(0, 0, 0, 0.5);
      font-size: 16px;
    }
    
    @keyframes shine {
      0% {
        box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4);
      }
      70% {
        box-shadow: 0 0 0 10px rgba(59, 130, 246, 0);
      }
      100% {
        box-shadow: 0 0 0 0 rgba(59, 130, 246, 0);
      }
    }
    
    @keyframes scorePopup {
      0% {
        transform: translateY(0);
        opacity: 0;
      }
      50% {
        transform: translateY(-10px);
        opacity: 1;
      }
      100% {
        transform: translateY(-20px);
        opacity: 0;
      }
    }
    
    .confetti {
      position: absolute;
      width: 10px;
      height: 10px;
      background-color: #f97316;
      animation: confetti-fall 3s ease-in-out infinite;
    }
    
    @keyframes confetti-fall {
      0% {
        transform: translateY(-100vh) rotate(0deg);
        opacity: 1;
      }
      100% {
        transform: translateY(100vh) rotate(720deg);
        opacity: 0;
      }
    }
    
    @keyframes lock-particle {
      0% {
        transform: translate(0, 0);
        opacity: 1;
      }
      100% {
        transform: translate(var(--tx), var(--ty));
        opacity: 0;
      }
    }
    
    /* Game Rules Modal Styles */
    .game-rules-modal {
      position: fixed;
      top: 0;
      left: 0;
      width: 100vw;
      height: 100vh;
      z-index: 50;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 1rem;
      visibility: hidden;
      box-sizing: border-box;
    }
    
    .game-rules-modal .modal-backdrop {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      opacity: 0;
      visibility: hidden;
      transition: all 0.3s ease-out;
    }
    
    .game-rules-modal .modal-content {
      position: relative;
      background-color: white;
      border-radius: 1rem;
      max-width: 90%;
      max-height: 80vh;
      width: 500px;
      overflow-y: auto;
      box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
    }
    
    .game-rules-modal .modal-header {
      padding: 1.5rem;
      border-bottom: 1px solid #e5e7eb;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
    
    .game-rules-modal .modal-title {
      font-size: 1.25rem;
      font-weight: 600;
      color: #1e293b;
    }
    
    .game-rules-modal .close-button {
      background: none;
      border: none;
      font-size: 1.5rem;
      cursor: pointer;
      color: #6b7280;
      transition: color 0.2s ease-in-out;
    }
    
    .game-rules-modal .close-button:hover {
      color: #1e293b;
    }
    
    .game-rules-modal .modal-body {
      padding: 1.5rem;
      line-height: 1.6;
      color: #374151;
    }
    
    .game-rules-modal .modal-body h3 {
      font-size: 1.1rem;
      font-weight: 600;
      margin-top: 1.5rem;
      margin-bottom: 0.75rem;
      color: #1e293b;
    }
    
    .game-rules-modal .modal-body p {
      margin-bottom: 1rem;
    }
    
    .game-rules-modal .modal-body ul {
      margin-bottom: 1rem;
      padding-left: 1.5rem;
      list-style-type: disc;
    }
    
    .game-rules-modal .modal-body li {
      margin-bottom: 0.5rem;
    }
    
    .game-rules-modal .modal-body strong {
      font-weight: 600;
      color: #1e293b;
    }
    
    .game-rules-modal .modal-footer {
      padding: 1rem 1.5rem;
      border-top: 1px solid #e5e7eb;
      display: flex;
      justify-content: flex-end;
    }
    
    .game-rules-modal .modal-footer button {
      padding: 0.5rem 1rem;
      border-radius: 0.5rem;
      background-color: #3b82f6;
      color: white;
      font-size: 1.25rem;
      font-weight: 500;
      transition: background-color 0.2s ease-in-out;
    }
    
    .game-rules-modal .modal-footer button:hover {
      background-color: #2563eb;
    }
    
    /* Game Rules Button Styles */
    .game-rules-button {
      position: fixed;
      top: 1rem;
      right: 1rem;
      z-index: 40;
      padding: 0.5rem 1rem;
      border-radius: 0.5rem;
      background-color: #3b82f6;
      color: white;
      font-weight: 500;
      display: flex;
      align-items: center;
      gap: 0.5rem;
      transition: all 0.2s ease-in-out;
      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
    }
    
    .game-rules-button:hover {
      background-color: #2563eb;
      transform: translateY(-2px);
    }
    
    .game-rules-button i {
      font-size: 1.1rem;
    }
  </style>
</head>
<body class="bg-gradient-to-br from-light to-gray-200 min-h-screen flex flex-col items-center justify-center p-4 m-0">
  <!-- Game Rules Button -->
  <button id="game-rules-button" class="game-rules-button">
    <i class="fa fa-book"></i>
    <span>Game Rules</span>
  </button>
  
  <!-- Game Rules Modal -->
  <div id="game-rules-modal" class="game-rules-modal">
    <div class="modal-backdrop"></div>
    <div class="modal-content">
      <div class="modal-header">
        <h2 class="modal-title">3D Dice Game Rules</h2>
        <button class="close-button">&times;</button>
      </div>
      <div class="modal-body">
        <p>Welcome to the 3D Dice Game! This is an exciting game that combines luck, strategy, and upgrading mechanics. Below is the complete game rules explanation:</p>
        
        <h3>Basic Gameplay</h3>
        <ul>
          <li>Click the "Roll Dice" button to roll the dice</li>
          <li>The dice will randomly show a number between 1-6</li>
          <li>Gain or lose points based on the number rolled</li>
          <li>The goal is to obtain the highest tier "Unique" dice</li>
        </ul>
        
        <h3>Score System</h3>
        <ul>
          <li>Rolling 1 or 2: Lose 1 point (multiplier not applied)</li>
          <li>Rolling 3: No points gained or lost</li>
          <li>Rolling 4: Gain 1 point</li>
          <li>Rolling 5: Gain 2 points</li>
          <li>Rolling 6: Gain 3 points</li>
        </ul>
        
        <h3>Dice Upgrade System</h3>
        <p>There are 10 different tiers of dice in the game, from common to rare:</p>
        <ul>
          <li><strong>Empty</strong> (Initial) - Score Multiplier ×1.0</li>
          <li><strong>Common</strong> - Score Multiplier ×1.1</li>
          <li><strong>Unusual</strong> - Score Multiplier ×1.2</li>
          <li><strong>Rare</strong> - Score Multiplier ×1.3</li>
          <li><strong>Epic</strong> - Score Multiplier ×1.4</li>
          <li><strong>Legendary</strong> - Score Multiplier ×1.5</li>
          <li><strong>Mythic</strong> - Score Multiplier ×1.6</li>
          <li><strong>Ultra</strong> - Score Multiplier ×1.7</li>
          <li><strong>Super</strong> - Score Multiplier ×1.8</li>
          <li><strong>Unique</strong> - Score Multiplier ×1.9</li>
        </ul>
        <p>Each upgrade costs (5 + current tier) points. For example, upgrading from Empty (tier 0) costs 5 points, upgrading from Common (tier 1) costs 6 points, and so on. After upgrading, you can choose to use the new dice or continue using the old one.</p>
        
        <h3>Item System</h3>
        <p>When upgrading, you have a chance to obtain item cards that can be used at critical moments:</p>
        <ul>
          <li><strong>Double Points Card</strong>: Doubles the points from one roll</li>
          <li><strong>No Penalty Card</strong>: Prevents point loss when rolling 1 or 2</li>
          <li><strong>Lucky Streak Card</strong>: Next 3 rolls of 1 or 2 won't count towards your total roll count</li>
        </ul>
        <p>Items can be stockpiled and each card can only be used once. Double Points Cards and No Penalty Cards can be used simultaneously. Lucky Streak Cards make your next 3 rolls of 1 or 2 not count towards your total roll count, giving you a chance to recover from bad luck.</p>
        
        <h3>Game Rules</h3>
        <ul>
          <li>Initial score is 10 points</li>
          <li>Score multiplier changes based on the current dice tier being used</li>
          <li>Game over when score is less than 0</li>
          <li>Game victory when obtaining the Unique dice</li>
          <li>Unlocked dice colors can be switched at any time</li>
        </ul>
        
        <h3>Operation Tips</h3>
        <ul>
          <li>Click on dice color options to switch the dice being used</li>
          <li>Click the "Upgrade Dice" button to upgrade your dice (requires 5 points)</li>
          <li>Click the "Use" button next to item cards to use them</li>
          <li>Press the ESC key to close the rules window</li>
        </ul>
        
        <p>Good luck, and may you successfully obtain the highest tier Unique dice!</p>
      </div>
      <div class="modal-footer">
        <button class="close-button">Got it</button>
      </div>
    </div>
  </div>
  
  <div class="w-full max-w-md mx-auto glass-effect rounded-2xl p-6 dice-shadow relative z-10">
    <h1 class="text-3xl font-bold text-center text-dark mb-8">3D Dice Roll</h1>
    
    <div class="flex flex-col items-center justify-center mb-8">
      <!-- Dice display area -->
      <div id="dice-display" class="w-48 h-48 flex items-center justify-center mb-4 bg-gray-100 rounded-lg">
        <!-- Dice scene for 3D perspective -->
        <div class="dice-scene">
          <div id="dice" class="dice-container">
            <!-- Dice faces will be inserted here by JavaScript -->
          </div>
        </div>
      </div>
      
      <!-- Result display -->
      <div id="result-display" class="text-2xl font-bold text-center mb-4 hidden">
        Result: <span id="result-value" class="text-primary">0</span>
      </div>
      
      <!-- Score display -->
      <div id="score-display" class="text-xl font-bold text-center mb-2">
        Score: <span id="score-value" class="text-secondary">10</span>
        <span id="score-change" class="ml-2 text-sm font-normal"></span>
      </div>
      
      <!-- Roll count display -->
      <div id="roll-count-display" class="text-lg font-medium text-center mb-4">
        Rolls: <span id="roll-count-value" class="text-gray-700">0</span>
      </div>
      
      <!-- Roll button -->
      <button id="roll-button" class="bg-primary hover:bg-blue-600 text-white font-bold py-3 px-6 rounded-full transition-all duration-300 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-blue-300 focus:ring-opacity-50">
        <i class="fa fa-random mr-2"></i> Roll Dice
      </button>
      
      <!-- Upgrade button and current tier display -->
      <div class="flex flex-col items-center mt-4">
        <div id="current-tier" class="text-sm text-gray-600 mb-2">
          Current Dice: <span class="font-semibold text-primary">Empty</span>
        </div>
        <div id="tier-multiplier-display" class="text-sm text-gray-600 mb-2">
          Tier Multiplier: <span class="font-semibold text-purple-500">×1.0</span>
        </div>
        <button id="upgrade-button" class="bg-secondary hover:bg-orange-600 text-white font-bold py-2 px-4 rounded-full transition-all duration-300 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-orange-300 focus:ring-opacity-50">
          <i class="fa fa-arrow-up mr-1"></i> Upgrade Dice <span id="upgrade-cost">(Cost: 5)</span>
        </button>
      </div>
      
      <!-- Game message display -->
      <div id="game-message" class="mt-4 text-center font-semibold hidden"></div>
      
      <!-- Items display -->
      <div id="items-display" class="mt-6 grid grid-cols-2 gap-4">
        <div class="bg-white rounded-lg p-3 dice-shadow">
          <div class="flex items-center justify-between">
            <div class="flex items-center">
              <i class="fa fa-plus-circle text-green-500 text-xl mr-2"></i>
              <span class="font-medium">Double Points Card</span>
            </div>
            <div class="flex items-center">
              <span id="double-points-count" class="bg-green-100 text-green-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">0</span>
              <button id="use-double-points" class="bg-green-500 hover:bg-green-600 text-white text-xs py-1 px-2 rounded disabled:opacity-50 disabled:cursor-not-allowed" disabled>
                Use
              </button>
            </div>
          </div>
          <p class="text-xs text-gray-500 mt-1">Doubles your score change for one roll</p>
        </div>
        
        <div class="bg-white rounded-lg p-3 dice-shadow">
          <div class="flex items-center justify-between">
            <div class="flex items-center">
              <i class="fa fa-shield text-blue-500 text-xl mr-2"></i>
              <span class="font-medium">No Penalty Card</span>
            </div>
            <div class="flex items-center">
              <span id="no-penalty-count" class="bg-blue-100 text-blue-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">0</span>
              <button id="use-no-penalty" class="bg-blue-500 hover:bg-blue-600 text-white text-xs py-1 px-2 rounded disabled:opacity-50 disabled:cursor-not-allowed" disabled>
                Use
              </button>
            </div>
          </div>
          <p class="text-xs text-gray-500 mt-1">Prevents score loss when rolling 1 or 2</p>
        </div>
        
        <div class="bg-white rounded-lg p-3 dice-shadow">
          <div class="flex items-center justify-between">
            <div class="flex items-center">
              <i class="fa fa-star text-yellow-500 text-xl mr-2"></i>
              <span class="font-medium">Lucky Streak Card</span>
            </div>
            <div class="flex items-center">
              <span id="lucky-streak-count" class="bg-yellow-100 text-yellow-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">0</span>
              <button id="use-lucky-streak" class="bg-yellow-500 hover:bg-yellow-600 text-white text-xs py-1 px-2 rounded disabled:opacity-50 disabled:cursor-not-allowed" disabled>
                Use
              </button>
            </div>
          </div>
          <p class="text-xs text-gray-500 mt-1">Next 3 rolls of 1 or 2 won't count towards your total roll count</p>
        </div>
      </div>
      
      <!-- Free rolls indicator -->
      <div id="free-rolls-indicator" class="mt-3 text-center hidden">
        <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
          <i class="fa fa-star mr-1" style="color: #f59e0b;"></i>
          <span>Free Rolls: <span id="free-rolls-count">0</span></span>
        </span>
      </div>
      
      <!-- Active item indicator -->
      <div id="active-item-indicator" class="mt-3 text-center hidden">
        <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium">
          <i id="active-item-icon" class="mr-1"></i>
          <span id="active-item-text">Active Item: None</span>
        </span>
      </div>
    </div>
    
    <!-- Dice color selection -->
    <div class="mb-8">
      <label class="block text-sm font-medium text-gray-700 mb-2">Dice Rarity</label>
      <div class="grid grid-cols-5 gap-4">
        <!-- Empty -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #FFFFFF; border: 1px solid #dddddd;" data-color="#FFFFFF"></button>
          <span class="text-xs text-center text-gray-600">Empty</span>
        </div>
        <!-- Common -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #7EEF6D;" data-color="#7EEF6D"></button>
          <span class="text-xs text-center text-gray-600">Common</span>
        </div>
        <!-- Unusual -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #FFE65D;" data-color="#FFE65D"></button>
          <span class="text-xs text-center text-gray-600">Unusual</span>
        </div>
        <!-- Rare -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #4d52e3;" data-color="#4d52e3"></button>
          <span class="text-xs text-center text-gray-600">Rare</span>
        </div>
        <!-- Epic -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #861FDE;" data-color="#861FDE"></button>
          <span class="text-xs text-center text-gray-600">Epic</span>
        </div>
        <!-- Legendary -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #DE1F1F;" data-color="#DE1F1F"></button>
          <span class="text-xs text-center text-gray-600">Legendary</span>
        </div>
        <!-- Mythic -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #1fdbde;" data-color="#1fdbde"></button>
          <span class="text-xs text-center text-gray-600">Mythic</span>
        </div>
        <!-- Ultra -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #ff2b75;" data-color="#ff2b75"></button>
          <span class="text-xs text-center text-gray-600">Ultra</span>
        </div>
        <!-- Super -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #2bffa3;" data-color="#2bffa3"></button>
          <span class="text-xs text-center text-gray-600">Super</span>
        </div>
        <!-- Unique -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #555555;" data-color="#555555"></button>
          <span class="text-xs text-center text-gray-600">Unique</span>
        </div>
      </div>
    </div>
    
    <!-- History log -->
    <div class="bg-white rounded-lg p-4">
      <h2 class="text-lg font-semibold text-center mb-2">Roll History</h2>
      <div id="history-container" class="h-64 overflow-y-auto">
        <div class="grid grid-cols-3 gap-2 text-xs font-medium text-gray-500 border-b border-gray-200 sticky top-0 bg-white z-10">
          <div>Time</div>
          <div>Action</div>
          <div class="text-right">Score</div>
        </div>
        <ul id="history-list" class="text-sm">
          <!-- History items will be inserted here by JavaScript -->
        </ul>
      </div>
    </div>
  </div>
  
  <footer class="mt-8 text-center text-gray-600 text-sm">
    <p>Click the button to roll the dice and see the result!</p>
  </footer>

  <script>
    // Set up global error handler
    window.addEventListener('error', function(event) {
      console.error('Global error caught:', event.error);
      
      // Try to get roll button element
      const rollButton = document.getElementById('roll-button');
      if (rollButton && rollButton.disabled) {
        console.warn('Error during dice roll, re-enabling button');
        rollButton.disabled = false;
        rollButton.classList.remove('opacity-70', 'cursor-not-allowed');
        
        // Try to show error message
        const gameMessage = document.getElementById('game-message');
        if (gameMessage) {
          gameMessage.textContent = 'An error occurred. Please try again.';
          gameMessage.className = 'mt-4 text-center font-semibold text-red-500';
          gameMessage.classList.remove('hidden');
        }
      }
    });
    
    // DOM elements
    const diceElement = document.getElementById('dice');
    const rollButton = document.getElementById('roll-button');
    const resultDisplay = document.getElementById('result-display');
    const resultValue = document.getElementById('result-value');
    const historyList = document.getElementById('history-list');
    const colorOptions = document.querySelectorAll('.color-option');
    const scoreDisplay = document.getElementById('score-display');
    const scoreValue = document.getElementById('score-value');
    const scoreChange = document.getElementById('score-change');
    const upgradeButton = document.getElementById('upgrade-button');
    const currentTierDisplay = document.getElementById('current-tier');
    const gameMessageDisplay = document.getElementById('game-message');
    const rollCountDisplay = document.getElementById('roll-count-display');
    const rollCountValue = document.getElementById('roll-count-value');
    const upgradeCost = document.getElementById('upgrade-cost');
    
    // Item related DOM elements
    const doublePointsCount = document.getElementById('double-points-count');
    const noPenaltyCount = document.getElementById('no-penalty-count');
    const luckyStreakCount = document.getElementById('lucky-streak-count');
    const useDoublePointsButton = document.getElementById('use-double-points');
    const useNoPenaltyButton = document.getElementById('use-no-penalty');
    const useLuckyStreakButton = document.getElementById('use-lucky-streak');
    const activeItemIndicator = document.getElementById('active-item-indicator');
    const freeRollsIndicator = document.getElementById('free-rolls-indicator');
    const freeRollsCountElement = document.getElementById('free-rolls-count');
    
    // Game state
    let currentScore = 10; // Initial score
    let currentTier = 0; // Initial dice tier (0 = Empty)
    let gameOver = false; // Game over flag
    let rollCount = 0; // Number of dice rolls
    let luckyRollsRemaining = 0; // Number of lucky rolls remaining
    let isRolling = false; // Whether dice is currently rolling
    
    // Item system
    let doublePointsCards = 0; // Number of double points cards
    let noPenaltyCards = 0; // Number of no penalty cards
    let luckyStreakCards = 0; // Number of lucky streak cards
    let freeRolls = 0; // Number of free rolls available
    let activeItems = { // Currently active items
      double: 0, // Number of active double points cards
      noPenalty: false // Whether no penalty card is active
    };
    
    // Dice tiers configuration
    const diceTiers = [
      { name: 'Empty', color: '#FFFFFF' },
      { name: 'Common', color: '#7EEF6D' },
      { name: 'Unusual', color: '#FFE65D' },
      { name: 'Rare', color: '#4d52e3' },
      { name: 'Epic', color: '#861FDE' },
      { name: 'Legendary', color: '#DE1F1F' },
      { name: 'Mythic', color: '#1fdbde' },
      { name: 'Ultra', color: '#ff2b75' },
      { name: 'Super', color: '#2bffa3' },
      { name: 'Unique', color: '#555555' }
    ];
    
    // Initialize 3D dice
    function initializeDice() {
      console.log('Initializing dice...');
      // Create 6 faces for the dice
      const faces = [1, 2, 3, 4, 5, 6];
      
      faces.forEach(faceNumber => {
        const face = document.createElement('div');
        face.className = `dice-face face-${faceNumber}`;
        
        // Add dots to the face based on the number
        for (let i = 0; i < faceNumber; i++) {
          const dot = document.createElement('div');
          dot.className = 'dot';
          face.appendChild(dot);
        }
        
        diceElement.appendChild(face);
        console.log(`Added face ${faceNumber}`);
      });
      
      console.log('Dice initialized with faces:', diceElement.children.length);
      
      // Set initial position to show face 1 clearly
      diceElement.style.transform = 'rotateX(0deg) rotateY(0deg)';
    }
    
    // Get random rotation values for the dice
    function getRandomRotation() {
      // Determine which face we want to show
      const targetFace = Math.floor(Math.random() * 6) + 1;
      
      // Get current rotation from dice element
      const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
      const matrix = new DOMMatrix(currentTransform);
      
      // Extract current rotation angles
      let currentX = 0, currentY = 0;
      
      // If transform is not identity matrix, extract rotation
      if (currentTransform !== 'none') {
        // Calculate rotation from matrix
        currentX = Math.atan2(matrix.b, matrix.a) * (180 / Math.PI);
        currentY = Math.atan2(-matrix.c, matrix.f) * (180 / Math.PI);
      }
      
      // Set target rotation based on target face
      // These values are precisely calibrated to show the correct face
      let targetX = 0, targetY = 0;
      switch(targetFace) {
        case 1: // Front face (Z+) - visible when no rotation
          targetX = 0;
          targetY = 0;
          break;
        case 2: // Left face (X-) - visible when Y rotated 270 degrees
          targetX = 0;
          targetY = 270;
          break;
        case 3: // Back face (Z-) - visible when Y rotated 180 degrees
          targetX = 0;
          targetY = 180;
          break;
        case 4: // Right face (X+) - visible when Y rotated 90 degrees
          targetX = 0;
          targetY = 90;
          break;
        case 5: // Top face (Y-) - visible when X rotated -90 degrees
          targetX = -90;
          targetY = 0;
          break;
        case 6: // Bottom face (Y+) - visible when X rotated 90 degrees
          targetX = 90;
          targetY = 0;
          break;
      }
      
      // Calculate the shortest path to the target rotation
      // This prevents large rotation values from accumulating
      let diffX = targetX - currentX;
      let diffY = targetY - currentY;
      
      // Normalize the difference to the range [-180, 180] to find the shortest path
      diffX = ((diffX + 180) % 360) - 180;
      diffY = ((diffY + 180) % 360) - 180;
      
      // Add multiple full rotations for spinning effect (2-4 full rotations)
      const fullRotations = 2 + Math.floor(Math.random() * 3);
      
      // Calculate final rotation with full spins
      // We add full rotations in the direction of the shortest path
      const spinDirectionX = diffX >= 0 ? 1 : -1;
      const spinDirectionY = diffY >= 0 ? 1 : -1;
      
      const finalX = currentX + diffX + spinDirectionX * fullRotations * 360;
      const finalY = currentY + diffY + spinDirectionY * fullRotations * 360;
      
      // Add a tiny bit of randomness to make it look more natural
      // But not enough to change which face is visible
      const randomX = (Math.random() - 0.5) * 2;
      const randomY = (Math.random() - 0.5) * 2;
      
      return {
        x: finalX + randomX,
        y: finalY + randomY,
        targetFace: targetFace // Return the target face so we don't have to recalculate it
      };
    }
    
    // Roll the dice function
    function rollDice() {
      // Check if game is over
      if (gameOver) {
        showGameMessage('Game over! Click "Play Again" to restart.', 'text-red-500');
        return;
      }
      
      // Check if there are free rolls available
      const isFreeRoll = freeRolls > 0;
      
      // Check if in lucky streak mode
      const isLuckyRoll = luckyRollsRemaining > 0;
      
      // Increment roll count only if not a free roll (lucky rolls will be handled based on result)
      if (!isFreeRoll) {
        rollCount++;
        console.log(`Roll count: ${rollCount}`);
      } else {
        // Decrement free rolls count
        freeRolls--;
        updateFreeRollsDisplay();
        console.log(`Free roll used. Remaining free rolls: ${freeRolls}`);
      }
      
      // Update roll count display
      if (rollCountValue) {
        rollCountValue.textContent = rollCount;
      }
      
      console.log('Rolling dice...');
      console.log('Button state before disable:', rollButton.disabled);
      
      // Set rolling state and disable button during animation
      isRolling = true;
      rollButton.disabled = true;
      rollButton.classList.add('opacity-70', 'cursor-not-allowed');
      
      // Disable other interactive elements during roll
      upgradeButton.disabled = true;
      upgradeButton.classList.add('opacity-70', 'cursor-not-allowed');
      useDoublePointsButton.disabled = true;
      useNoPenaltyButton.disabled = true;
      useLuckyStreakButton.disabled = true;
      
      // Disable color options during roll
      colorOptions.forEach(option => {
        option.disabled = true;
      });
      
      console.log('Button state after disable:', rollButton.disabled);
      
      // Hide result display
      resultDisplay.classList.add('hidden');
      
      // Reset dice display height - use Tailwind class instead of inline style
      const diceDisplay = document.getElementById('dice-display');
      if (diceDisplay) {
        // Ensure the height class is applied to prevent layout shifts during animation
        diceDisplay.classList.add('h-48');
      }
      
      try {
        // Set animation duration
        const duration = 2000; // Fixed duration for consistent experience
        
        // Get random rotation values for the final position
        const rotationData = getRandomRotation();
        console.log('Rotation data:', rotationData);
        console.log('Target face:', rotationData.targetFace);
        
        // Animate the dice using JavaScript for more control
        animateDice(duration, rotationData, { isFreeRoll, isLuckyRoll });
        
        // Set a safety timeout to ensure button is re-enabled even if something goes wrong
        setTimeout(() => {
          if (rollButton.disabled) {
            console.warn('Safety timeout: Re-enabling roll button');
            enableRollButton();
          }
        }, duration + 1000); // Add 1 second buffer
      } catch (error) {
        console.error('Error during dice roll:', error);
        // Re-enable button if there's an error
        enableRollButton();
        showGameMessage('An error occurred during the dice roll. Please try again.', 'text-red-500');
      }
    }
    
    // Animate the dice with spin animation
    function animateDice(duration, rotationData, rollContext) {
      console.log('Animate dice called with rotationData:', rotationData);
      console.log('Roll context:', rollContext);
      const startTime = performance.now();
      const finalRotation = rotationData;
      
      // Get current rotation from dice element
      const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
      const matrix = new DOMMatrix(currentTransform);
      
      // Extract current rotation angles
      let startX = 0, startY = 0;
      
      // If transform is not identity matrix, extract rotation
      if (currentTransform !== 'none') {
        // Calculate rotation from matrix
        startX = Math.atan2(matrix.b, matrix.a) * (180 / Math.PI);
        startY = Math.atan2(-matrix.c, matrix.f) * (180 / Math.PI);
      }
      
      // Function to handle each animation frame
      function animate(currentTime) {
        const elapsedTime = currentTime - startTime;
        const progress = Math.min(elapsedTime / duration, 1);
        
        // Apply easing function for smooth, natural animation
        const easedProgress = easeOutCubic(progress);
        
        // Calculate current rotation - smooth continuous rotation
        const currentX = startX + (finalRotation.x - startX) * easedProgress;
        const currentY = startY + (finalRotation.y - startY) * easedProgress;
        
        // Spin animation: rotate in place
        diceElement.style.transform = `rotateX(${currentX}deg) rotateY(${currentY}deg)`;
        
        // Continue animation if not complete
        if (progress < 1) {
          requestAnimationFrame(animate);
        } else {
          // Animation complete - ensure we're at the exact target rotation
          diceElement.style.transform = `rotateX(${finalRotation.x}deg) rotateY(${finalRotation.y}deg)`;
          
          // Show result after a delay to ensure rotation is complete and CSS has applied
          console.log('Animation complete, waiting before finalizing...');
          setTimeout(() => {
            // Double-check that the transform has been applied
            const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
            console.log('Current transform after animation:', currentTransform);
            console.log('Calling finalizeAnimation...');
            finalizeAnimation(finalRotation, rollContext);
          }, 600);
        }
      }
      
      // Start the animation
      requestAnimationFrame(animate);
    }
    
    // Helper function to normalize angles to the range [-180, 180]
    function normalizeAngle(angle) {
      angle = angle % 360;
      if (angle > 180) angle -= 360;
      if (angle < -180) angle += 360;
      return angle;
    }
    
    // Easing function for smooth, natural animation with gentle acceleration and deceleration
    // Uses a cubic easing function that starts slow, accelerates, then slows down at the end
    function easeOutCubic(t) {
      return 1 - Math.pow(1 - t, 3);
    }
    
    // Calculate score change based on dice roll result
    function calculateScoreChange(result) {
      let baseChange = 0;
      
      switch(result) {
        case 1:
        case 2:
          baseChange = -1;
          break;
        case 3:
          baseChange = 0;
          break;
        case 4:
          baseChange = 1;
          break;
        case 5:
          baseChange = 2;
          break;
        case 6:
          baseChange = 3;
          break;
        default:
          baseChange = 0;
      }
      
      // Apply current tier multiplier
      // If losing points (baseChange < 0), use multiplier of 1 instead of tier multiplier
      const tierMultiplier = 1 + currentTier / 10;
      let finalChange;
      
      if (baseChange < 0) {
        // For point loss, use multiplier of 1 regardless of tier
        finalChange = baseChange * 1;
      } else {
        // For point gain or neutral, use tier multiplier
        finalChange = baseChange * tierMultiplier;
      }
      
      // Apply active item effects
      const itemsUsed = {
        double: activeItems.double,
        noPenalty: activeItems.noPenalty
      };
      
      // Apply no penalty card first
      if (activeItems.noPenalty && baseChange < 0) {
        finalChange = 0;
      }
      
      // Apply double points cards
      if (activeItems.double > 0) {
        finalChange = finalChange * Math.pow(2, activeItems.double);
      }
      
      // Round to 2 decimal places to avoid floating point precision issues
      finalChange = Math.round(finalChange * 100) / 100;
      
      return {
        baseChange: baseChange,
        finalChange: finalChange,
        itemsUsed: itemsUsed,
        tierMultiplier: tierMultiplier
      };
    }
    
    // Enable roll button
    function enableRollButton() {
      console.log('Button state before enable:', rollButton.disabled);
      
      // Directly enable the button
      rollButton.disabled = false;
      rollButton.classList.remove('opacity-70', 'cursor-not-allowed');
      
      // Re-enable other interactive buttons based on their conditions
      updateUpgradeCostDisplay(); // This will enable/disable upgrade button based on score
      updateItemsDisplay(); // This will enable/disable item buttons based on availability
      
      console.log('Button state after enable:', rollButton.disabled);
      
      // Double-check and force enable if needed
      if (rollButton.disabled) {
        console.warn('Forcing button enable');
        setTimeout(() => {
          rollButton.disabled = false;
          rollButton.classList.remove('opacity-70', 'cursor-not-allowed');
          console.log('Button state after forced enable:', rollButton.disabled);
        }, 100);
      }
    }
    
    // Finalize the animation and show result
    function finalizeAnimation(rotationData, rollContext) {
      console.log('=== Finalize animation called ===');
      console.log('Current time:', new Date().toISOString().split('T')[1]);
      console.log('Rotation data:', rotationData);
      console.log('Roll context:', rollContext);
      
      const finalRotation = rotationData;
      const isFreeRoll = rollContext && rollContext.isFreeRoll || false;
      const isLuckyRoll = rollContext && rollContext.isLuckyRoll || false;
      
      // Use the target face directly instead of recalculating
      const result = finalRotation.targetFace;
      console.log(`Final result: ${result} (should show face ${result})`);
      
      // Verify dice is in the correct position
      const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
      console.log('Current dice transform:', currentTransform);
      
      // Show result display
      console.log('Showing result display...');
      resultValue.textContent = result;
      resultDisplay.classList.remove('hidden');
      
      // Add shine effect to result
      resultDisplay.classList.add('result-shine');
      setTimeout(() => {
        resultDisplay.classList.remove('result-shine');
      }, 500);
      
      // Calculate and update score
      console.log('Calculating score change...');
      const scoreChangeData = calculateScoreChange(result);
      console.log('Score change data:', scoreChangeData);
      
      currentScore += scoreChangeData.finalChange;
      console.log('Updated score:', currentScore);
      
      // Update score display with animation
      console.log('Updating score display...');
      updateScoreDisplay(scoreChangeData);
      
      // Enable button
      console.log('Enabling roll button...');
      enableRollButton();
      
      // Add to history - include whether it was a free roll or lucky roll
      addToHistory(result, scoreChangeData, isFreeRoll, isLuckyRoll);
      
      // Check if reached the Unique dice
      if (currentTier === diceTiers.length - 1) {
        showGameMessage('Congratulations! You obtained the Unique dice!', 'text-green-500');
        gameOver = true;
        createConfetti();
      }
      
      // Handle lucky roll logic
      if (luckyRollsRemaining > 0) {
        // Decrement remaining lucky rolls
        luckyRollsRemaining--;
        
        // If rolled 1 or 2, decrement roll count
        if (result === 1 || result === 2) {
          rollCount--;
          console.log(`Lucky roll: Reverted roll count to ${rollCount}`);
          
          // Update roll count display
          if (rollCountValue) {
            rollCountValue.textContent = rollCount;
          }
          
          // Show message
          showGameMessage('Lucky! This 1/2 roll doesn\'t count!', 'text-yellow-500');
        }
        
        // Update lucky rolls display
        updateLuckyRollsDisplay();
        
        // If no more lucky rolls, show message
        if (luckyRollsRemaining === 0) {
          setTimeout(() => {
            showGameMessage('Lucky Streak ended!', 'text-yellow-500');
          }, 1000);
        }
      }
      
      // Create confetti effect if result is 6
      if (result === 6) {
        createConfetti();
      }
      
      // Debug: log final state
      console.log(`Final precise rotation: X=${finalRotation.x}°, Y=${finalRotation.y}°`);
      console.log(`Displayed result: ${result}`);
      console.log(`Score change: ${scoreChangeData.finalChange}, Current score: ${currentScore}`);
      console.log('=== finalizeAnimation completed ===');
    }
    
    // Update score display with animation
    function updateScoreDisplay(scoreChangeData) {
      console.log('=== updateScoreDisplay called ===');
      console.log('Score change data:', scoreChangeData);
      
      const change = scoreChangeData.finalChange;
      const baseChange = scoreChangeData.baseChange;
      const itemsUsed = scoreChangeData.itemsUsed;
      const tierMultiplier = scoreChangeData.tierMultiplier;
      
      console.log('Change:', change, 'Base change:', baseChange, 'Items used:', itemsUsed);
      
      // Update the score value - round to 2 decimal places
      currentScore = Math.round(currentScore * 100) / 100;
      scoreValue.textContent = currentScore;
      console.log('Score value updated to:', currentScore);
      
      // Clear previous score change display
      scoreChange.textContent = '';
      scoreChange.className = 'ml-2 text-sm font-normal';
      console.log('Cleared previous score change display');
      
      // Show score change with appropriate styling
      if (change > 0) {
        scoreChange.textContent = `+${change}`;
        scoreChange.classList.add('score-increase');
        console.log('Score increase:', change);
      } else if (change < 0) {
        scoreChange.textContent = `${change}`;
        scoreChange.classList.add('score-decrease');
        console.log('Score decrease:', change);
      } else {
        scoreChange.textContent = `±0`;
        scoreChange.classList.add('score-neutral');
        console.log('Score neutral');
      }
      
      // Show item effect message if items were used
      if (itemsUsed && (itemsUsed.double > 0 || itemsUsed.noPenalty)) {
        // Create container for item effects
        const itemEffectsContainer = document.createElement('div');
        itemEffectsContainer.className = 'flex flex-wrap gap-2 mt-1';
        
        // Add tier multiplier effect if applicable
        if (tierMultiplier !== 1) {
          const tierEffect = document.createElement('div');
          tierEffect.className = 'text-xs text-purple-500';
          tierEffect.textContent = `Tier Multiplier ×${tierMultiplier.toFixed(1)}!`;
          itemEffectsContainer.appendChild(tierEffect);
        }
        
        // Add no penalty effect
        if (itemsUsed.noPenalty) {
          const noPenaltyEffect = document.createElement('div');
          noPenaltyEffect.className = 'text-xs text-blue-500';
          noPenaltyEffect.textContent = `No Penalty! (Score protected from ${baseChange < 0 ? baseChange : 0} loss)`;
          itemEffectsContainer.appendChild(noPenaltyEffect);
        }
        
        // Add double points effect
        if (itemsUsed.double > 0) {
          const doublePointsEffect = document.createElement('div');
          doublePointsEffect.className = 'text-xs text-green-500';
          
          // Calculate multiplier
          const multiplier = Math.pow(2, itemsUsed.double);
          let calculationText = `${baseChange}`;
          
          // Apply tier multiplier for display
          let displayChange = baseChange * tierMultiplier;
          
          // Apply no penalty first for display
          if (itemsUsed.noPenalty && baseChange < 0) {
            displayChange = 0;
            calculationText = `(${baseChange} × ${tierMultiplier.toFixed(1)} → 0)`;
          } else if (tierMultiplier !== 1) {
            calculationText = `(${baseChange} × ${tierMultiplier.toFixed(1)} = ${displayChange.toFixed(2)})`;
          }
          
          // Show multiplication steps if multiple double cards used
          if (itemsUsed.double > 1) {
            for (let i = 0; i < itemsUsed.double; i++) {
              calculationText += ` × 2`;
            }
            calculationText += ` = ${(displayChange * multiplier).toFixed(2)}`;
          } else {
            calculationText += ` × 2 = ${(displayChange * multiplier).toFixed(2)}`;
          }
          
          doublePointsEffect.textContent = `Double Points ×${itemsUsed.double}! (${calculationText})`;
          itemEffectsContainer.appendChild(doublePointsEffect);
        }
        
        // Add to score display
        scoreDisplay.appendChild(itemEffectsContainer);
        
        // Remove after animation
        setTimeout(() => {
          scoreDisplay.removeChild(itemEffectsContainer);
        }, 1000);
      }
      
      // Reset score change display after animation completes
      setTimeout(() => {
        scoreChange.textContent = '';
      }, 1000);
      
      // Clear active items after score update
      console.log('Checking if items need to be cleared...');
      if (itemsUsed && (itemsUsed.double > 0 || itemsUsed.noPenalty)) {
        console.log('Clearing active items...');
        clearActiveItems();
        console.log('Updating items display...');
        updateItemsDisplay();
      }
      
      // Check game state after score update
      console.log('Checking game state...');
      checkGameState();
      
      // Update upgrade button state
      updateUpgradeCostDisplay();
      
      console.log('=== updateScoreDisplay completed ===');
    }
    
    // Handle dice upgrade
    function upgradeDice() {
      // Check if game is already over
      if (gameOver) {
        showGameMessage('Game over! Click "Play Again" to restart.', 'text-red-500');
        return;
      }
      
      // Check if already at maximum tier
      if (currentTier >= diceTiers.length - 1) {
        // If not already game over, end the game with win condition
        if (!gameOver) {
          gameOver = true;
          endGame(true);
        } else {
          showGameMessage('Congratulations! You already have the Unique dice!', 'text-green-500');
        }
        return;
      }
      
      // Calculate required score for upgrade (5 + currentTier)
      const requiredScore = 5 + currentTier;
      
      // Check if enough score to upgrade
      if (currentScore < requiredScore) {
        showGameMessage(`Not enough score to upgrade! Need ${requiredScore} points.`, 'text-orange-500');
        // Add shake animation to score display
        scoreDisplay.classList.add('animate-shake');
        setTimeout(() => {
          scoreDisplay.classList.remove('animate-shake');
        }, 500);
        return;
      }
      
      // Deduct score for upgrade
      currentScore -= requiredScore;
      // Round to 2 decimal places
      currentScore = Math.round(currentScore * 100) / 100;
      
      // Update score display
      scoreValue.textContent = currentScore;
      showScoreChange(-requiredScore);
      
      // Increase tier
      currentTier++;
      
      // Update current tier display
      currentTierDisplay.innerHTML = `Current Dice: <span class="font-semibold text-primary">${diceTiers[currentTier].name}</span>`;
      
      // Update tier multiplier display
      updateTierMultiplierDisplay();
      
      // Unlock the new dice color
      unlockDiceColor(currentTier);
      
      // Update color selection UI
      updateColorSelection(currentTier);
      
      // Update upgrade cost display
      updateUpgradeCostDisplay();
      
      // Change to the new dice color
      console.log(`Changing dice color to ${diceTiers[currentTier].color} (${diceTiers[currentTier].name})`);
      changeDiceColor(diceTiers[currentTier].color);
      
      // Check if this upgrade reached the maximum tier
      checkGameState();
      
      // Randomly get an item
      const itemChance = Math.random();
      if (itemChance < 0.30) { // 30% chance to get double points card
        doublePointsCards++;
      } else if (itemChance < 0.60) { // 30% chance to get no penalty card
        noPenaltyCards++;
      } else if (itemChance < 0.70) { // 10% chance to get lucky streak card
        luckyStreakCards++;
      } else { // 30% chance to get nothing
        // Do nothing
      }
      
      // Update items display to show new counts
      updateItemsDisplay();
      
      // Update items display
      updateItemsDisplay();
      
      // Check if reached the Unique dice
      if (currentTier === diceTiers.length - 1) {
        showGameMessage('Congratulations! You obtained the Unique dice!', 'text-green-500');
        gameOver = true;
        createConfetti();
      }
      
      // Handle lucky roll logic
      if (luckyRollsRemaining > 0) {
        // Decrement remaining lucky rolls
        luckyRollsRemaining--;
        
        // If rolled 1 or 2, decrement roll count
        if (result === 1 || result === 2) {
          rollCount--;
          console.log(`Lucky roll: Reverted roll count to ${rollCount}`);
          
          // Update roll count display
          if (rollCountValue) {
            rollCountValue.textContent = rollCount;
          }
          
          // Show message
          showGameMessage('Lucky! This 1/2 roll doesn\'t count!', 'text-yellow-500');
        }
        
        // Update lucky rolls display
        updateLuckyRollsDisplay();
        
        // If no more lucky rolls, show message
        if (luckyRollsRemaining === 0) {
          setTimeout(() => {
            showGameMessage('Lucky Streak ended!', 'text-yellow-500');
          }, 1000);
        }
      }
      
      // Add to history
      addToHistory('UPGRADE', -5);
      
      // Add item to history if obtained
      if (itemChance < 0.30) {
        addToHistory('ITEM', 'Double Points Card');
      } else if (itemChance < 0.60) {
        addToHistory('ITEM', 'No Penalty Card');
      } else if (itemChance < 0.70) {
        addToHistory('ITEM', 'Lucky Streak Card');
      }
      
      // Check game state after upgrade
      checkGameState();
    }
    
    // Show score change temporarily
    function showScoreChange(change) {
      scoreChange.textContent = change > 0 ? `+${change}` : change;
      scoreChange.className = `ml-2 text-sm font-normal ${change > 0 ? 'score-increase' : 'score-decrease'}`;
      
      setTimeout(() => {
        scoreChange.textContent = '';
      }, 1000);
    }
    
    // Unlock a dice color option
    function unlockDiceColor(tierIndex) {
      if (tierIndex >= 0 && tierIndex < colorOptions.length) {
        const option = colorOptions[tierIndex];
        // Show particle effect on the lock before unlocking
        createLockParticles(option);
        // Add a small delay to show the particles before unlocking
        setTimeout(() => {
          option.disabled = false;
          option.classList.remove('locked');
        }, 300);
      }
    }
    
    // Show game message
    function showGameMessage(message, className) {
      gameMessageDisplay.textContent = message;
      gameMessageDisplay.className = `mt-4 text-center font-semibold ${className}`;
      gameMessageDisplay.classList.remove('hidden');
      
      // Hide message after 3 seconds
      setTimeout(() => {
        if (!gameOver) {
          gameMessageDisplay.classList.add('hidden');
        }
      }, 3000);
    }
    
    // Check game state (win/lose conditions)
    function checkGameState() {
      console.log('=== checkGameState called ===');
      console.log('Current score:', currentScore, 'Game over:', gameOver);
      
      // Check if score is negative (lose condition)
      if (currentScore < 0 && !gameOver) {
        console.log('Score is negative, ending game...');
        gameOver = true;
        endGame(false);
      }
      
      // Check if reached Unique dice (win condition)
      if (currentTier === diceTiers.length - 1 && !gameOver) {
        console.log('Reached Unique dice, ending game...');
        gameOver = true;
        endGame(true);
        
        // Check if this is a new record
        setTimeout(() => {
          checkWinRecord();
        }, 1000);
      }
      
      // Check if score is low (warning)
      if (currentScore >= 0 && currentScore <= 5 && !gameOver) {
        showLowScoreWarning();
      }
      
      console.log('=== checkGameState completed ===');
    }
    
    // Update items display
    function updateItemsDisplay() {
      // Update counts
      doublePointsCount.textContent = doublePointsCards;
      noPenaltyCount.textContent = noPenaltyCards;
      luckyStreakCount.textContent = luckyStreakCards;
      
      // Enable/disable buttons based on available items
      useDoublePointsButton.disabled = doublePointsCards <= 0 || gameOver;
      useNoPenaltyButton.disabled = noPenaltyCards <= 0 || activeItems.noPenalty || gameOver;
      useLuckyStreakButton.disabled = luckyStreakCards <= 0 || gameOver;
      
      // Update free rolls display
      updateFreeRollsDisplay();
      
      // Update lucky rolls display
      updateLuckyRollsDisplay();
    }
    
    // Update free rolls display
    function updateFreeRollsDisplay() {
      if (freeRolls > 0) {
        freeRollsCountElement.textContent = freeRolls;
        freeRollsIndicator.classList.remove('hidden');
      } else {
        freeRollsIndicator.classList.add('hidden');
      }
    }
    
    // Update upgrade cost display and button state
    function updateUpgradeCostDisplay() {
      if (currentTier >= diceTiers.length - 1) {
        // Already at maximum tier
        upgradeCost.textContent = '(Max Tier)';
        upgradeButton.disabled = true;
        upgradeButton.classList.add('opacity-70', 'cursor-not-allowed');
      } else {
        const requiredScore = 5 + currentTier;
        upgradeCost.textContent = `(Cost: ${requiredScore})`;
        
        // Update button state based on available score
        if (currentScore >= requiredScore && !gameOver) {
          upgradeButton.disabled = false;
          upgradeButton.classList.remove('opacity-70', 'cursor-not-allowed');
        } else {
          upgradeButton.disabled = true;
          upgradeButton.classList.add('opacity-70', 'cursor-not-allowed');
        }
      }
    }
    
    // Use double points card
    function useDoublePointsCard() {
      if (doublePointsCards > 0 && !gameOver) {
        activeItems.double++;
        doublePointsCards--;
        
        // Update UI
        updateItemsDisplay();
        showActiveItemIndicator();
        
        // Show message
        showGameMessage('Double Points Card activated! Next roll will double your score change.', 'text-green-500');
      }
    }
    
    // Use no penalty card
    function useNoPenaltyCard() {
      if (noPenaltyCards > 0 && !activeItems.noPenalty && !gameOver) {
        activeItems.noPenalty = true;
        noPenaltyCards--;
        
        // Update UI
        updateItemsDisplay();
        showActiveItemIndicator();
        
        // Show message
        showGameMessage('No Penalty Card activated! Next roll won\'t lose points.', 'text-blue-500');
      }
    }
    
    // Use lucky streak card
    function useLuckyStreakCard() {
      if (luckyStreakCards > 0 && !gameOver) {
        luckyRollsRemaining = 3;
        luckyStreakCards--;
        
        // Update UI
        updateItemsDisplay();
        updateLuckyRollsDisplay();
        
        // Show message
        showGameMessage('Lucky Streak Card activated! Next 3 rolls of 1 or 2 won\'t count!', 'text-yellow-500');
        
        // Add to history
        addToHistory('ITEM USE', 'Lucky Streak Card');
      }
    }
    
    // Update lucky rolls display
    function updateLuckyRollsDisplay() {
      if (luckyRollsRemaining > 0) {
        // Check if indicator exists, if not create it
        let luckyRollsIndicator = document.getElementById('lucky-rolls-indicator');
        if (!luckyRollsIndicator) {
          luckyRollsIndicator = document.createElement('div');
          luckyRollsIndicator.id = 'lucky-rolls-indicator';
          luckyRollsIndicator.className = 'mt-3 text-center';
          
          // Insert after free rolls indicator
          const freeRollsIndicator = document.getElementById('free-rolls-indicator');
          if (freeRollsIndicator) {
            freeRollsIndicator.parentNode.insertBefore(luckyRollsIndicator, freeRollsIndicator.nextSibling);
          } else {
            // Fallback: insert after active item indicator
            const activeItemIndicator = document.getElementById('active-item-indicator');
            if (activeItemIndicator) {
              activeItemIndicator.parentNode.insertBefore(luckyRollsIndicator, activeItemIndicator.nextSibling);
            } else {
              // Fallback: insert after items display
              const itemsDisplay = document.getElementById('items-display');
              if (itemsDisplay) {
                itemsDisplay.parentNode.insertBefore(luckyRollsIndicator, itemsDisplay.nextSibling);
              }
            }
          }
        }
        
        // Update content
        luckyRollsIndicator.innerHTML = `
          <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
            <i class="fa fa-star mr-1" style="color: #f59e0b;"></i>
            <span>Lucky Rolls: <span id="lucky-rolls-count">${luckyRollsRemaining}</span> (1-2 won't count)</span>
          </span>
        `;
        
        // Show indicator
        luckyRollsIndicator.classList.remove('hidden');
      } else {
        // Remove indicator if exists
        const luckyRollsIndicator = document.getElementById('lucky-rolls-indicator');
        if (luckyRollsIndicator) {
          luckyRollsIndicator.classList.add('hidden');
        }
      }
    }
    
    // Show active item indicator
    function showActiveItemIndicator() {
      // Clear previous content
      activeItemIndicator.innerHTML = '';
      
      // Check if any items are active
      if (activeItems.double === 0 && !activeItems.noPenalty) {
        activeItemIndicator.className = 'mt-3 text-center hidden';
        return;
      }
      
      // Create container for active items
      const itemsContainer = document.createElement('div');
      itemsContainer.className = 'flex flex-wrap justify-center gap-2';
      
      // Add double points cards indicator
      if (activeItems.double > 0) {
        const doublePointsIndicator = document.createElement('span');
        doublePointsIndicator.className = 'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800';
        doublePointsIndicator.innerHTML = `
          <i class="fa fa-plus-circle mr-1" style="color: #10b981;"></i>
          <span>Double Points ×${activeItems.double}</span>
        `;
        itemsContainer.appendChild(doublePointsIndicator);
      }
      
      // Add no penalty card indicator
      if (activeItems.noPenalty) {
        const noPenaltyIndicator = document.createElement('span');
        noPenaltyIndicator.className = 'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800';
        noPenaltyIndicator.innerHTML = `
          <i class="fa fa-shield mr-1" style="color: #3b82f6;"></i>
          <span>No Penalty</span>
        `;
        itemsContainer.appendChild(noPenaltyIndicator);
      }
      
      // Add indicators to container
      activeItemIndicator.appendChild(itemsContainer);
      activeItemIndicator.className = 'mt-3 text-center';
    }
    
    // Clear active items
    function clearActiveItems() {
      activeItems = {
        double: 0,
        noPenalty: false
      };
      showActiveItemIndicator();
    }
    
    // End the game and display appropriate message
    function endGame(isWin) {
      console.log('=== endGame called ===');
      console.log('Is win:', isWin, 'Current score:', currentScore);
      
      // Disable all interactive elements
      rollButton.disabled = true;
      upgradeButton.disabled = true;
      rollButton.classList.add('opacity-70', 'cursor-not-allowed');
      upgradeButton.classList.add('opacity-70', 'cursor-not-allowed');
      
      // Disable all interactive elements
      colorOptions.forEach(option => {
        option.disabled = true;
        option.classList.add('opacity-50', 'cursor-not-allowed');
      });
      
      // Disable item buttons
      useDoublePointsButton.disabled = true;
      useNoPenaltyButton.disabled = true;
      useLuckyStreakButton.disabled = true;
      
      // Hide active indicators
      activeItemIndicator.classList.add('hidden');
      const luckyRollsIndicator = document.getElementById('lucky-rolls-indicator');
      if (luckyRollsIndicator) {
        luckyRollsIndicator.classList.add('hidden');
      }
      
      // Create game over message element
      const gameOverMessage = document.createElement('div');
      gameOverMessage.className = `mt-4 p-4 rounded-lg text-center font-bold ${isWin ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}`;
      
      // Format final score to 2 decimal places
      const formattedScore = currentScore.toFixed(2);
      
      if (isWin) {
        gameOverMessage.innerHTML = `
          <div class="text-2xl mb-2">Congratulations!</div>
          <p>You won the game!</p>
          <p>You obtained the Unique dice!</p>
          <p class="mt-2 text-sm">Final Score: ${formattedScore}</p>
          <p class="mt-1 text-sm">Total Rolls: ${rollCount}</p>
          <p class="mt-1 text-sm">Double Points Cards: ${doublePointsCards}</p>
          <p class="mt-1 text-sm">No Penalty Cards: ${noPenaltyCards}</p>
          <p class="mt-1 text-sm">Lucky Streak Cards: ${luckyStreakCards}</p>
          <p class="mt-1 text-sm">Final Tier Multiplier: ×${(1 + currentTier / 10).toFixed(1)}</p>
          <button id="play-again" class="mt-4 bg-primary hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-full transition-all duration-300 transform hover:scale-105">
            <i class="fa fa-refresh mr-1"></i> Play Again
          </button>
        `;
        createConfetti();
      } else {
        gameOverMessage.innerHTML = `
          <div class="text-2xl mb-2">Game Over!</div>
          <p>Your score went negative.</p>
          <p>Better luck next time!</p>
          <p class="mt-2 text-sm">Final Score: ${formattedScore}</p>
          <p class="mt-1 text-sm">Total Rolls: ${rollCount}</p>
          <p class="mt-1 text-sm">Double Points Cards: ${doublePointsCards}</p>
          <p class="mt-1 text-sm">No Penalty Cards: ${noPenaltyCards}</p>
          <p class="mt-1 text-sm">Lucky Streak Cards: ${luckyStreakCards}</p>
          <p class="mt-1 text-sm">Final Tier Multiplier: ×${(1 + currentTier / 10).toFixed(1)}</p>
          <button id="play-again" class="mt-4 bg-primary hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-full transition-all duration-300 transform hover:scale-105">
            <i class="fa fa-refresh mr-1"></i> Play Again
          </button>
        `;
      }
      
      // Add restart button event listener
      gameOverMessage.querySelector('#play-again').addEventListener('click', () => {
        window.location.reload();
      });
      
      // Replace game message display with game over message
      const gameMessageContainer = gameMessageDisplay.parentElement;
      gameMessageContainer.replaceChild(gameOverMessage, gameMessageDisplay);
      gameMessageDisplay = gameOverMessage;
      
      // Add game end to history
      addToHistory(isWin ? 'GAME WIN' : 'GAME OVER', 0);
      
      console.log('=== endGame completed ===');
    }
    
    // Show warning when score is low
    function showLowScoreWarning() {
      // Only show warning if not already showing
      if (gameMessageDisplay.classList.contains('hidden')) {
        showGameMessage('Warning: Low score! Risk of game over.', 'text-orange-500');
      }
    }
    
    // Update color selection UI to show the currently selected color
    function updateColorSelection(selectedIndex) {
      // Remove active state from all color options
      colorOptions.forEach(opt => opt.classList.remove('ring-2', 'ring-offset-2', 'ring-primary'));
      
      // Add active state to the selected color option
      if (selectedIndex >= 0 && selectedIndex < colorOptions.length) {
        colorOptions[selectedIndex].classList.add('ring-2', 'ring-offset-2', 'ring-primary');
      }
    }
    
    // Add result to history
    function addToHistory(result, scoreChangeData, isFreeRoll = false, isLuckyRoll = false) {
      const now = new Date();
      const timeString = now.toLocaleTimeString();
      
      // Determine score change display and color
      let scoreChangeText = '';
      let scoreChangeClass = '';
      let actionText = '';
      
      if (result === 'UPGRADE') {
        actionText = 'Upgraded dice';
        scoreChangeText = `${scoreChangeData}`;
        scoreChangeClass = 'text-red-500';
      } else if (result === 'ITEM') {
        actionText = `Received <span class="font-bold text-purple-500">${scoreChangeData}</span>`;
        scoreChangeText = '+1';
        scoreChangeClass = 'text-purple-500';
      } else if (result === 'GAME WIN' || result === 'GAME OVER') {
        actionText = result;
        scoreChangeText = '';
        scoreChangeClass = '';
      } else {
        const scoreChange = scoreChangeData.finalChange;
        const baseChange = scoreChangeData.baseChange;
        const itemsUsed = scoreChangeData.itemsUsed;
        
        actionText = `Rolled a <span class="font-bold text-primary">${result}</span>`;
        
        // Add free roll indicator if applicable
        if (isFreeRoll) {
          actionText += ` <span class="text-yellow-500">(Free Roll)</span>`;
        }
        
        // Add lucky roll indicator if applicable
        if (isLuckyRoll) {
          actionText += ` <span class="text-yellow-500">(Lucky Roll)</span>`;
        }
        
        // Add item effect indicators if applicable
        const activeItemsText = [];
        if (itemsUsed && itemsUsed.double > 0) {
          activeItemsText.push(`<span class="text-green-500">(Double Points ×${itemsUsed.double})</span>`);
        }
        if (itemsUsed && itemsUsed.noPenalty) {
          activeItemsText.push(`<span class="text-blue-500">(No Penalty)</span>`);
        }
        
        if (activeItemsText.length > 0) {
          actionText += ` ${activeItemsText.join(' ')}`;
        }
        
        if (scoreChange > 0) {
          scoreChangeText = `+${scoreChange}`;
          scoreChangeClass = 'text-green-500';
        } else if (scoreChange < 0) {
          scoreChangeText = `${scoreChange}`;
          scoreChangeClass = 'text-red-500';
        } else {
          scoreChangeText = '±0';
          scoreChangeClass = 'text-gray-500';
        }
        
        // Show base change if different from final change (items were used)
        if ((itemsUsed && (itemsUsed.double > 0 || itemsUsed.noPenalty)) && baseChange !== scoreChange) {
          scoreChangeText += ` <span class="text-xs">(Base: ${baseChange > 0 ? '+' : ''}${baseChange})</span>`;
        }
      }
      
      const listItem = document.createElement('li');
      listItem.className = 'py-1 border-b border-gray-100 grid grid-cols-3 gap-2 items-center';
      listItem.innerHTML = `
        <span class="col-span-1 text-gray-500">${timeString}</span>
        <span class="col-span-1">${actionText}</span>
        <span class="col-span-1 text-right font-medium ${scoreChangeClass}">${scoreChangeText}</span>
      `;
      
      historyList.prepend(listItem);
      
      // Keep only last 10 history items
      if (historyList.children.length > 10) {
        historyList.removeChild(historyList.lastChild);
      }
      
      // Ensure scroll is at the bottom
      const historyContainer = document.getElementById('history-container');
      if (historyContainer) {
        historyContainer.scrollTop = historyContainer.scrollHeight;
      }
    }
    
    // Create confetti effect
    function createConfetti() {
      const confettiContainer = document.createElement('div');
      confettiContainer.className = 'fixed inset-0 pointer-events-none overflow-hidden';
      document.body.appendChild(confettiContainer);
      
      // Create 50 confetti pieces
      for (let i = 0; i < 50; i++) {
        const confetti = document.createElement('div');
        confetti.className = 'confetti';
        
        // Random position
        const posX = Math.random() * 100;
        const delay = Math.random() * 3;
        const duration = 3 + Math.random() * 2;
        
        // Random colors
        const colors = ['#3b82f6', '#f97316', '#10b981', '#ef4444', '#8b5cf6'];
        const color = colors[Math.floor(Math.random() * colors.length)];
        
        confetti.style.left = `${posX}%`;
        confetti.style.backgroundColor = color;
        confetti.style.animationDelay = `${delay}s`;
        confetti.style.animationDuration = `${duration}s`;
        
        confettiContainer.appendChild(confetti);
      }
      
      // Remove confetti container after animation completes
      setTimeout(() => {
        document.body.removeChild(confettiContainer);
      }, 5000);
    }
    
    
    
    // Create particle effect on lock
    function createLockParticles(lockElement) {
      // Get lock element position
      const rect = lockElement.getBoundingClientRect();
      const centerX = rect.left + rect.width / 2;
      const centerY = rect.top + rect.height / 2;
      
      // Create particle container
      const particleContainer = document.createElement('div');
      particleContainer.className = 'absolute pointer-events-none';
      particleContainer.style.left = `${centerX}px`;
      particleContainer.style.top = `${centerY}px`;
      particleContainer.style.transform = 'translate(-50%, -50%)';
      document.body.appendChild(particleContainer);
      
      // Create 15 particles
      for (let i = 0; i < 15; i++) {
        const particle = document.createElement('div');
        particle.className = 'lock-particle';
        
        // Random direction and distance
        const angle = Math.random() * Math.PI * 2;
        const distance = 10 + Math.random() * 20;
        const tx = Math.cos(angle) * distance;
        const ty = Math.sin(angle) * distance;
        
        // Random color (use the color of the unlocked dice)
        const color = lockElement.style.backgroundColor;
        
        // Random animation duration
        const duration = 0.5 + Math.random() * 0.5;
        
        // Set particle styles
        particle.style.backgroundColor = color;
        particle.style.setProperty('--tx', `${tx}px`);
        particle.style.setProperty('--ty', `${ty}px`);
        particle.style.animation = `lock-particle ${duration}s ease-out forwards`;
        
        particleContainer.appendChild(particle);
      }
      
      // Remove particle container after animation completes
      setTimeout(() => {
        document.body.removeChild(particleContainer);
      }, 1000);
    }
    
    // Function to darken a color by a certain percentage
    function darkenColor(color, percent) {
      const hex = color.replace('#', '');
      let r = parseInt(hex.substr(0, 2), 16);
      let g = parseInt(hex.substr(2, 2), 16);
      let b = parseInt(hex.substr(4, 2), 16);
      
      // Darken each channel by the percentage
      r = Math.max(0, Math.floor(r * (1 - percent / 100)));
      g = Math.max(0, Math.floor(g * (1 - percent / 100)));
      b = Math.max(0, Math.floor(b * (1 - percent / 100)));
      
      // Convert back to hex
      const darkenedHex = '#' + 
        r.toString(16).padStart(2, '0') + 
        g.toString(16).padStart(2, '0') + 
        b.toString(16).padStart(2, '0');
      
      return darkenedHex;
    }
    
    // Change dice color function
    function changeDiceColor(color) {
      console.log(`changeDiceColor called with color: ${color}`);
      const faces = document.querySelectorAll('.dice-face');
      console.log(`Found ${faces.length} dice faces`);
      let dotColor, borderColor;
      
      // Special cases for high contrast
      if (color.toUpperCase() === '#FFFFFF') {
        // White dice - use black dots and light gray borders
        dotColor = '#000000';
        borderColor = '#CCCCCC';
      } else if (color.toUpperCase() === '#555555') {
        // Dark gray dice - use white dots and slightly lighter gray borders
        dotColor = '#FFFFFF';
        borderColor = '#777777';
      } else {
        // Calculate darker color for dots and borders (40% darker for more contrast)
        dotColor = darkenColor(color, 40);
        borderColor = darkenColor(color, 30); // Slightly lighter border than dots
      }
      
      faces.forEach(face => {
        // Set face background color
        face.style.backgroundColor = color;
        
        // Set face border color
        face.style.border = `3px solid ${borderColor}`;
        
        // Set dots color
        const dots = face.querySelectorAll('.dot');
        dots.forEach(dot => {
          dot.style.backgroundColor = dotColor;
          // Add slight border to dots for better definition
          dot.style.border = color.toUpperCase() === '#FFFFFF' ? '1px solid rgba(0, 0, 0, 0.2)' : '1px solid rgba(0, 0, 0, 0.1)';
        });
      });
    }
    
    // Update tier multiplier display
    function updateTierMultiplierDisplay() {
      const display = document.getElementById('tier-multiplier-display');
      if (display) {
        display.innerHTML = `Tier Multiplier: <span class="font-semibold text-purple-500">×${(1 + currentTier / 10).toFixed(1)}</span>`;
      }
    }
    
    // Event listener for roll button
    rollButton.addEventListener('click', rollDice);
    
    // Event listener for upgrade button
    upgradeButton.addEventListener('click', upgradeDice);
    
    // Event listeners for item buttons
    useDoublePointsButton.addEventListener('click', useDoublePointsCard);
    useNoPenaltyButton.addEventListener('click', useNoPenaltyCard);
    useLuckyStreakButton.addEventListener('click', useLuckyStreakCard);
    
    // Event listeners for color options
    colorOptions.forEach((option, index) => {
      // Disable all color options except the first one initially
      if (index !== 0) {
        option.disabled = true;
        option.classList.add('locked');
      }
      
      option.addEventListener('click', () => {
        // Check if game is over
        if (gameOver) {
          showGameMessage('Game over! Click "Play Again" to restart.', 'text-red-500');
          return;
        }
        
        // Check if color is unlocked
        if (option.disabled) {
          showGameMessage('You need to upgrade to unlock this dice color!', 'text-orange-500');
          return;
        }
        
        const color = option.getAttribute('data-color');
        changeDiceColor(color);
        
        // Add active state to selected color
        colorOptions.forEach(opt => opt.classList.remove('ring-2', 'ring-offset-2', 'ring-primary'));
        option.classList.add('ring-2', 'ring-offset-2', 'ring-primary');
        
        // Update current tier to the selected color's tier
        currentTier = index;
        currentTierDisplay.innerHTML = `Current Dice: <span class="font-semibold text-primary">${diceTiers[currentTier].name}</span>`;
        updateTierMultiplierDisplay();
      });
    });
    
    // Initialize dice on page load
    window.addEventListener('DOMContentLoaded', () => {
      console.log('=== DOMContentLoaded event fired ===');
      
      // Check if elements exist
      console.log('Checking if elements exist before initialization:');
      console.log('best-record-display exists:', !!document.getElementById('best-record-display'));
      console.log('best-record-value exists:', !!document.getElementById('best-record-value'));
      
      console.log('DOM fully loaded');
      initializeDice();
      
      // Set default color (first option)
      if (colorOptions.length > 0) {
        const defaultColor = colorOptions[0].getAttribute('data-color');
        changeDiceColor(defaultColor);
        colorOptions[0].classList.add('ring-2', 'ring-offset-2', 'ring-primary');
      }
      
      // Initialize current tier display
      currentTierDisplay.innerHTML = `Current Dice: <span class="font-semibold text-primary">${diceTiers[currentTier].name}</span>`;
      
      // Initialize tier multiplier display
      updateTierMultiplierDisplay();
      
      // Initialize items display
      updateItemsDisplay();
      
      // Initialize upgrade cost display
      updateUpgradeCostDisplay();
      
      // Show welcome message
      setTimeout(() => {
        showGameMessage('Welcome! Roll the dice to earn points and upgrade your dice!', 'text-blue-500');
      }, 1000);
    });
    
    // Also try initializing on window load
    window.addEventListener('load', () => {
      console.log('Window loaded');
      // If dice not already initialized, try again
      if (diceElement.children.length === 0) {
        console.log('Dice not initialized, trying again...');
        initializeDice();
      }
    });
    
    // Game Rules Modal Functionality
    (function() {
      // Get elements
      const rulesButton = document.getElementById('game-rules-button');
      const rulesModal = document.getElementById('game-rules-modal');
      const closeButtons = rulesModal.querySelectorAll('.close-button');
      const modalBackdrop = rulesModal.querySelector('.modal-backdrop');
      const modalContent = rulesModal.querySelector('.modal-content');
      
      // Function to prevent background scrolling
      function preventBackgroundScroll(event) {
        // Allow scrolling inside the modal content
        if (modalContent.contains(event.target)) {
          // Check if we're at the top or bottom of the modal content
          const isAtTop = modalContent.scrollTop === 0;
          const isAtBottom = modalContent.scrollTop + modalContent.clientHeight >= modalContent.scrollHeight;
          
          // Prevent scrolling if at the top and scrolling up, or at the bottom and scrolling down
          if ((isAtTop && event.deltaY < 0) || (isAtBottom && event.deltaY > 0)) {
            event.preventDefault();
          }
        } else {
          // Prevent scrolling outside the modal content
          event.preventDefault();
        }
      }
      
      // Function to open modal
      function openModal() {
        // Add event listeners to prevent background scrolling
        document.addEventListener('wheel', preventBackgroundScroll, { passive: false });
        document.addEventListener('touchmove', preventBackgroundScroll, { passive: false });
        
        // Add open class to trigger animations
        rulesModal.classList.add('modal-open');
        
        // Show the modal
        rulesModal.style.visibility = 'visible';
      }
      
      // Function to close modal
      function closeModal() {
        // Remove open class to trigger animations
        rulesModal.classList.remove('modal-open');
        
        // Remove event listeners that prevent background scrolling
        document.removeEventListener('wheel', preventBackgroundScroll);
        document.removeEventListener('touchmove', preventBackgroundScroll);
        
        // Hide the modal after animation completes
        setTimeout(() => {
          rulesModal.style.visibility = 'hidden';
        }, 300);
      }
      
      // Add event listeners
      if (rulesButton) {
        rulesButton.addEventListener('click', openModal);
      }
      
      // Close buttons
      closeButtons.forEach(button => {
        button.addEventListener('click', closeModal);
      });
      
      // Close when clicking outside the modal content
      modalBackdrop.addEventListener('click', closeModal);
      
      // Close when pressing Escape key
      document.addEventListener('keydown', (event) => {
        if (event.key === 'Escape' && rulesModal.classList.contains('modal-open')) {
          closeModal();
        }
      });
      
      // Add hover effect to rules button
      if (rulesButton) {
        rulesButton.addEventListener('mouseenter', () => {
          rulesButton.classList.add('scale-105');
        });
        
        rulesButton.addEventListener('mouseleave', () => {
          rulesButton.classList.remove('scale-105');
        });
      }
      
      // Add click effect to close buttons
      closeButtons.forEach(button => {
        button.addEventListener('mousedown', () => {
          button.classList.add('scale-95');
        });
        
        button.addEventListener('mouseup', () => {
          button.classList.remove('scale-95');
        });
        
        button.addEventListener('mouseleave', () => {
          button.classList.remove('scale-95');
        });
      });
    })();
  </script>
</body>
</html>

v.1.2.1HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>3D Dice Roll Animation</title>
  <!-- Tailwind CSS v3 -->
  <script src="https://cdn.tailwindcss.com"></script>
  <!-- Font Awesome -->
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            primary: '#3b82f6',
            secondary: '#f97316',
            dark: '#1e293b',
            light: '#f8fafc'
          },
          fontFamily: {
            sans: ['Inter', 'system-ui', 'sans-serif'],
          },
          animation: {
            'shake': 'shake 0.5s ease-in-out',
          },
          keyframes: {
            shake: {
              '0%, 100%': { transform: 'translateX(0)' },
              '25%': { transform: 'translateX(-5px)' },
              '50%': { transform: 'translateX(5px)' },
              '75%': { transform: 'translateX(-5px)' },
            }
          }
        }
      }
    }
  </script>
  
  <style type="text/tailwindcss">
    @layer utilities {
      .preserve-3d {
        transform-style: preserve-3d;
      }
      .perspective {
        perspective: 1000px;
      }
      .backface-hidden {
        backface-visibility: hidden;
      }
      .dice-shadow {
        box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
      }
      .glass-effect {
        background: rgba(255, 255, 255, 0.7);
        backdrop-filter: blur(10px);
        -webkit-backdrop-filter: blur(10px);
      }
      .modal-backdrop {
        background-color: rgba(0, 0, 0, 0.5);
        backdrop-filter: blur(4px);
        -webkit-backdrop-filter: blur(4px);
      }
      .modal-content {
        transform: translateY(-20px);
        opacity: 0;
        transition: all 0.3s ease-out;
      }
      .modal-open .modal-content {
        transform: translateY(0);
        opacity: 1;
      }
      .modal-open .modal-backdrop {
        opacity: 1;
        visibility: visible;
      }
      .trophy-animation {
        animation: trophy-pulse 2s ease-in-out infinite;
      }
      .record-animation {
        animation: record-shine 2s ease-in-out;
      }
    }
    
    @keyframes trophy-pulse {
      0% { transform: scale(1); }
      50% { transform: scale(1.1); }
      100% { transform: scale(1); }
    }
    
    @keyframes record-shine {
      0% { box-shadow: 0 0 0 0 rgba(251, 191, 36, 0.7); }
      70% { box-shadow: 0 0 0 15px rgba(251, 191, 36, 0); }
      100% { box-shadow: 0 0 0 0 rgba(251, 191, 36, 0); }
    }
    
    /* Custom styles for 3D dice */
    .dice-scene {
      perspective: 1500px;
      width: 120px;
      height: 120px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .dice-container {
      position: relative;
      width: 100px;
      height: 100px;
      transform-style: preserve-3d;
      transition: transform 1s ease-out;
      transform: rotateX(20deg) rotateY(20deg);
    }
    
    .dice-face {
      position: absolute;
      width: 100px;
      height: 100px;
      border-radius: 8px;
      background-color: white;
      border: 2px solid #f0f0f0;
      display: flex;
      align-items: center;
      justify-content: center;
      box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
    }
    
    /* Dice face positions */
    .face-1 { transform: translateZ(50px); }
    .face-2 { transform: rotateY(90deg) translateZ(50px); }
    .face-3 { transform: rotateY(180deg) translateZ(50px); }
    .face-4 { transform: rotateY(-90deg) translateZ(50px); }
    .face-5 { transform: rotateX(90deg) translateZ(50px); }
    .face-6 { transform: rotateX(-90deg) translateZ(50px); }
    
    /* Dots on dice faces */
    .dot {
      position: absolute;
      width: 20px;
      height: 20px;
      border-radius: 50%;
      background-color: black;
    }
    
    /* Dot positions for each face */
    .face-1 .dot { top: 40px; left: 40px; }
    
    .face-2 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-2 .dot:nth-child(2) { top: 60px; left: 60px; }
    
    .face-3 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-3 .dot:nth-child(2) { top: 40px; left: 40px; }
    .face-3 .dot:nth-child(3) { top: 60px; left: 60px; }
    
    .face-4 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-4 .dot:nth-child(2) { top: 20px; left: 60px; }
    .face-4 .dot:nth-child(3) { top: 60px; left: 20px; }
    .face-4 .dot:nth-child(4) { top: 60px; left: 60px; }
    
    .face-5 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-5 .dot:nth-child(2) { top: 20px; left: 60px; }
    .face-5 .dot:nth-child(3) { top: 40px; left: 40px; }
    .face-5 .dot:nth-child(4) { top: 60px; left: 20px; }
    .face-5 .dot:nth-child(5) { top: 60px; left: 60px; }
    
    .face-6 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-6 .dot:nth-child(2) { top: 20px; left: 60px; }
    .face-6 .dot:nth-child(3) { top: 40px; left: 20px; }
    .face-6 .dot:nth-child(4) { top: 40px; left: 60px; }
    .face-6 .dot:nth-child(5) { top: 60px; left: 20px; }
    .face-6 .dot:nth-child(6) { top: 60px; left: 60px; }
    
    .dice-result {
      transition: all 0.5s ease-out;
    }
    
    /* Fixed height for result display to prevent page jumping */
    #result-display {
      height: 40px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .result-shine {
      animation: shine 0.5s ease-out;
    }
    
    .score-increase {
      color: #10b981;
      animation: scorePopup 1s ease-out;
    }
    
    .score-decrease {
      color: #ef4444;
      animation: scorePopup 1s ease-out;
    }
    
    .score-neutral {
      color: #6b7280;
      animation: scorePopup 1s ease-out;
    }
    
    /* Locked color option styles */
    .color-option.locked {
      position: relative;
      opacity: 0.5;
      cursor: not-allowed;
    }
    
    .color-option.locked::after {
      content: '\f023'; /* Lock icon from Font Awesome */
      font-family: 'FontAwesome';
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      color: rgba(0, 0, 0, 0.5);
      font-size: 16px;
    }
    
    @keyframes shine {
      0% {
        box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4);
      }
      70% {
        box-shadow: 0 0 0 10px rgba(59, 130, 246, 0);
      }
      100% {
        box-shadow: 0 0 0 0 rgba(59, 130, 246, 0);
      }
    }
    
    @keyframes scorePopup {
      0% {
        transform: translateY(0);
        opacity: 0;
      }
      50% {
        transform: translateY(-10px);
        opacity: 1;
      }
      100% {
        transform: translateY(-20px);
        opacity: 0;
      }
    }
    
    .confetti {
      position: absolute;
      width: 10px;
      height: 10px;
      background-color: #f97316;
      animation: confetti-fall 3s ease-in-out infinite;
    }
    
    @keyframes confetti-fall {
      0% {
        transform: translateY(-100vh) rotate(0deg);
        opacity: 1;
      }
      100% {
        transform: translateY(100vh) rotate(720deg);
        opacity: 0;
      }
    }
    
    @keyframes lock-particle {
      0% {
        transform: translate(0, 0);
        opacity: 1;
      }
      100% {
        transform: translate(var(--tx), var(--ty));
        opacity: 0;
      }
    }
    
    /* Game Rules Modal Styles */
    .game-rules-modal {
      position: fixed;
      top: 0;
      left: 0;
      width: 100vw;
      height: 100vh;
      z-index: 50;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 1rem;
      visibility: hidden;
      box-sizing: border-box;
    }
    
    .game-rules-modal .modal-backdrop {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      opacity: 0;
      visibility: hidden;
      transition: all 0.3s ease-out;
    }
    
    .game-rules-modal .modal-content {
      position: relative;
      background-color: white;
      border-radius: 1rem;
      max-width: 90%;
      max-height: 80vh;
      width: 500px;
      overflow-y: auto;
      box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
    }
    
    .game-rules-modal .modal-header {
      padding: 1.5rem;
      border-bottom: 1px solid #e5e7eb;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
    
    .game-rules-modal .modal-title {
      font-size: 1.25rem;
      font-weight: 600;
      color: #1e293b;
    }
    
    .game-rules-modal .close-button {
      background: none;
      border: none;
      font-size: 1.5rem;
      cursor: pointer;
      color: #6b7280;
      transition: color 0.2s ease-in-out;
    }
    
    .game-rules-modal .close-button:hover {
      color: #1e293b;
    }
    
    .game-rules-modal .modal-body {
      padding: 1.5rem;
      line-height: 1.6;
      color: #374151;
    }
    
    .game-rules-modal .modal-body h3 {
      font-size: 1.1rem;
      font-weight: 600;
      margin-top: 1.5rem;
      margin-bottom: 0.75rem;
      color: #1e293b;
    }
    
    .game-rules-modal .modal-body p {
      margin-bottom: 1rem;
    }
    
    .game-rules-modal .modal-body ul {
      margin-bottom: 1rem;
      padding-left: 1.5rem;
      list-style-type: disc;
    }
    
    .game-rules-modal .modal-body li {
      margin-bottom: 0.5rem;
    }
    
    .game-rules-modal .modal-body strong {
      font-weight: 600;
      color: #1e293b;
    }
    
    .game-rules-modal .modal-footer {
      padding: 1rem 1.5rem;
      border-top: 1px solid #e5e7eb;
      display: flex;
      justify-content: flex-end;
    }
    
    .game-rules-modal .modal-footer button {
      padding: 0.5rem 1rem;
      border-radius: 0.5rem;
      background-color: #3b82f6;
      color: white;
      font-size: 1.25rem;
      font-weight: 500;
      transition: background-color 0.2s ease-in-out;
    }
    
    .game-rules-modal .modal-footer button:hover {
      background-color: #2563eb;
    }
    
    /* Game Rules Button Styles */
    .game-rules-button {
      position: fixed;
      top: 1rem;
      right: 1rem;
      z-index: 40;
      padding: 0.5rem 1rem;
      border-radius: 0.5rem;
      background-color: #3b82f6;
      color: white;
      font-weight: 500;
      display: flex;
      align-items: center;
      gap: 0.5rem;
      transition: all 0.2s ease-in-out;
      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
    }
    
    .game-rules-button:hover {
      background-color: #2563eb;
      transform: translateY(-2px);
    }
    
    .game-rules-button i {
      font-size: 1.1rem;
    }
  </style>
</head>
<body class="bg-gradient-to-br from-light to-gray-200 min-h-screen flex flex-col items-center justify-center p-4 m-0">
  <!-- Game Rules Button -->
  <button id="game-rules-button" class="game-rules-button">
    <i class="fa fa-book"></i>
    <span>Game Rules</span>
  </button>
  
  <!-- Game Rules Modal -->
  <div id="game-rules-modal" class="game-rules-modal">
    <div class="modal-backdrop"></div>
    <div class="modal-content">
      <div class="modal-header">
        <h2 class="modal-title">3D Dice Game Rules</h2>
        <button class="close-button">&times;</button>
      </div>
      <div class="modal-body">
        <p>Welcome to the 3D Dice Game! This is an exciting game that combines luck, strategy, and upgrading mechanics. Below is the complete game rules explanation:</p>
        
        <h3>Basic Gameplay</h3>
        <ul>
          <li>Click the "Roll Dice" button to roll the dice</li>
          <li>The dice will randomly show a number between 1-6</li>
          <li>Gain or lose points based on the number rolled</li>
          <li>The goal is to obtain the highest tier "Unique" dice</li>
        </ul>
        
        <h3>Score System</h3>
        <ul>
          <li>Rolling 1 or 2: Lose 1 point (multiplier not applied)</li>
          <li>Rolling 3: No points gained or lost</li>
          <li>Rolling 4: Gain 1 point</li>
          <li>Rolling 5: Gain 2 points</li>
          <li>Rolling 6: Gain 3 points</li>
        </ul>
        
        <h3>Dice Upgrade System</h3>
        <p>There are 10 different tiers of dice in the game, from common to rare:</p>
        <ul>
          <li><strong>Empty</strong> (Initial) - Score Multiplier ×1.0</li>
          <li><strong>Common</strong> - Score Multiplier ×1.1</li>
          <li><strong>Unusual</strong> - Score Multiplier ×1.2</li>
          <li><strong>Rare</strong> - Score Multiplier ×1.3</li>
          <li><strong>Epic</strong> - Score Multiplier ×1.4</li>
          <li><strong>Legendary</strong> - Score Multiplier ×1.5</li>
          <li><strong>Mythic</strong> - Score Multiplier ×1.6</li>
          <li><strong>Ultra</strong> - Score Multiplier ×1.7</li>
          <li><strong>Super</strong> - Score Multiplier ×1.8</li>
          <li><strong>Unique</strong> - Score Multiplier ×1.9</li>
        </ul>
        <p>Each upgrade costs (5 + current tier) points. For example, upgrading from Empty (tier 0) costs 5 points, upgrading from Common (tier 1) costs 6 points, and so on. After upgrading, you can choose to use the new dice or continue using the old one.</p>
        
        <h3>Item System</h3>
        <p>When upgrading, you have a chance to obtain item cards that can be used at critical moments:</p>
        <ul>
          <li><strong>Double Points Card</strong>: Doubles the points from one roll</li>
          <li><strong>No Penalty Card</strong>: Prevents point loss when rolling 1 or 2</li>
          <li><strong>Lucky Streak Card</strong>: Next 3 rolls of 1 or 2 won't count towards your total roll count</li>
        </ul>
        <p>Items can be stockpiled and each card can only be used once. Double Points Cards and No Penalty Cards can be used simultaneously. Lucky Streak Cards make your next 3 rolls of 1 or 2 not count towards your total roll count, giving you a chance to recover from bad luck.</p>
        
        <h3>Game Rules</h3>
        <ul>
          <li>Initial score is 10 points</li>
          <li>Score multiplier changes based on the current dice tier being used</li>
          <li>Game over when score is less than 0</li>
          <li>Game victory when obtaining the Unique dice</li>
          <li>Unlocked dice colors can be switched at any time</li>
        </ul>
        
        <h3>Operation Tips</h3>
        <ul>
          <li>Click on dice color options to switch the dice being used</li>
          <li>Click the "Upgrade Dice" button to upgrade your dice (requires 5 points)</li>
          <li>Click the "Use" button next to item cards to use them</li>
          <li>Press the ESC key to close the rules window</li>
        </ul>
        
        <p>Good luck, and may you successfully obtain the highest tier Unique dice!</p>
      </div>
      <div class="modal-footer">
        <button class="close-button">Got it</button>
      </div>
    </div>
  </div>
  
  <div class="w-full max-w-md mx-auto glass-effect rounded-2xl p-6 dice-shadow relative z-10">
    <h1 class="text-3xl font-bold text-center text-dark mb-8">3D Dice Roll</h1>
    
    <div class="flex flex-col items-center justify-center mb-8">
      <!-- Dice display area -->
      <div id="dice-display" class="w-48 h-48 flex items-center justify-center mb-4 bg-gray-100 rounded-lg">
        <!-- Dice scene for 3D perspective -->
        <div class="dice-scene">
          <div id="dice" class="dice-container">
            <!-- Dice faces will be inserted here by JavaScript -->
          </div>
        </div>
      </div>
      
      <!-- Result display -->
      <div id="result-display" class="text-2xl font-bold text-center mb-4 hidden">
        Result: <span id="result-value" class="text-primary">0</span>
      </div>
      
      <!-- Score display -->
      <div id="score-display" class="text-xl font-bold text-center mb-2">
        Score: <span id="score-value" class="text-secondary">10</span>
        <span id="score-change" class="ml-2 text-sm font-normal"></span>
      </div>
      
      <!-- Roll count display -->
      <div id="roll-count-display" class="text-lg font-medium text-center mb-4">
        Rolls: <span id="roll-count-value" class="text-gray-700">0</span>
      </div>
      
      <!-- Roll button -->
      <button id="roll-button" class="bg-primary hover:bg-blue-600 text-white font-bold py-3 px-6 rounded-full transition-all duration-300 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-blue-300 focus:ring-opacity-50">
        <i class="fa fa-random mr-2"></i> Roll Dice
      </button>
      
      <!-- Upgrade button and current tier display -->
      <div class="flex flex-col items-center mt-4">
        <div id="current-tier" class="text-sm text-gray-600 mb-2">
          Current Dice: <span class="font-semibold text-primary">Empty</span>
        </div>
        <div id="tier-multiplier-display" class="text-sm text-gray-600 mb-2">
          Tier Multiplier: <span class="font-semibold text-purple-500">×1.0</span>
        </div>
        <button id="upgrade-button" class="bg-secondary hover:bg-orange-600 text-white font-bold py-2 px-4 rounded-full transition-all duration-300 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-orange-300 focus:ring-opacity-50">
          <i class="fa fa-arrow-up mr-1"></i> Upgrade Dice <span id="upgrade-cost">(Cost: 5)</span>
        </button>
      </div>
      
      <!-- Game message display -->
      <div id="game-message" class="mt-4 text-center font-semibold hidden"></div>
      
      <!-- Items display -->
      <div id="items-display" class="mt-6 grid grid-cols-2 gap-4">
        <div class="bg-white rounded-lg p-3 dice-shadow">
          <div class="flex items-center justify-between">
            <div class="flex items-center">
              <i class="fa fa-plus-circle text-green-500 text-xl mr-2"></i>
              <span class="font-medium">Double Points Card</span>
            </div>
            <div class="flex items-center">
              <span id="double-points-count" class="bg-green-100 text-green-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">0</span>
              <button id="use-double-points" class="bg-green-500 hover:bg-green-600 text-white text-xs py-1 px-2 rounded disabled:opacity-50 disabled:cursor-not-allowed" disabled>
                Use
              </button>
            </div>
          </div>
          <p class="text-xs text-gray-500 mt-1">Doubles your score change for one roll</p>
        </div>
        
        <div class="bg-white rounded-lg p-3 dice-shadow">
          <div class="flex items-center justify-between">
            <div class="flex items-center">
              <i class="fa fa-shield text-blue-500 text-xl mr-2"></i>
              <span class="font-medium">No Penalty Card</span>
            </div>
            <div class="flex items-center">
              <span id="no-penalty-count" class="bg-blue-100 text-blue-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">0</span>
              <button id="use-no-penalty" class="bg-blue-500 hover:bg-blue-600 text-white text-xs py-1 px-2 rounded disabled:opacity-50 disabled:cursor-not-allowed" disabled>
                Use
              </button>
            </div>
          </div>
          <p class="text-xs text-gray-500 mt-1">Prevents score loss when rolling 1 or 2</p>
        </div>
        
        <div class="bg-white rounded-lg p-3 dice-shadow">
          <div class="flex items-center justify-between">
            <div class="flex items-center">
              <i class="fa fa-star text-yellow-500 text-xl mr-2"></i>
              <span class="font-medium">Lucky Streak Card</span>
            </div>
            <div class="flex items-center">
              <span id="lucky-streak-count" class="bg-yellow-100 text-yellow-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">0</span>
              <button id="use-lucky-streak" class="bg-yellow-500 hover:bg-yellow-600 text-white text-xs py-1 px-2 rounded disabled:opacity-50 disabled:cursor-not-allowed" disabled>
                Use
              </button>
            </div>
          </div>
          <p class="text-xs text-gray-500 mt-1">Next 3 rolls of 1 or 2 won't count towards your total roll count</p>
        </div>
      </div>
      
      <!-- Free rolls indicator -->
      <div id="free-rolls-indicator" class="mt-3 text-center hidden">
        <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
          <i class="fa fa-star mr-1" style="color: #f59e0b;"></i>
          <span>Free Rolls: <span id="free-rolls-count">0</span></span>
        </span>
      </div>
      
      <!-- Active item indicator -->
      <div id="active-item-indicator" class="mt-3 text-center hidden">
        <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium">
          <i id="active-item-icon" class="mr-1"></i>
          <span id="active-item-text">Active Item: None</span>
        </span>
      </div>
    </div>
    
    <!-- Dice color selection -->
    <div class="mb-8">
      <label class="block text-sm font-medium text-gray-700 mb-2">Dice Rarity</label>
      <div class="grid grid-cols-5 gap-4">
        <!-- Empty -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #FFFFFF; border: 1px solid #dddddd;" data-color="#FFFFFF"></button>
          <span class="text-xs text-center text-gray-600">Empty</span>
        </div>
        <!-- Common -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #7EEF6D;" data-color="#7EEF6D"></button>
          <span class="text-xs text-center text-gray-600">Common</span>
        </div>
        <!-- Unusual -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #FFE65D;" data-color="#FFE65D"></button>
          <span class="text-xs text-center text-gray-600">Unusual</span>
        </div>
        <!-- Rare -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #4d52e3;" data-color="#4d52e3"></button>
          <span class="text-xs text-center text-gray-600">Rare</span>
        </div>
        <!-- Epic -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #861FDE;" data-color="#861FDE"></button>
          <span class="text-xs text-center text-gray-600">Epic</span>
        </div>
        <!-- Legendary -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #DE1F1F;" data-color="#DE1F1F"></button>
          <span class="text-xs text-center text-gray-600">Legendary</span>
        </div>
        <!-- Mythic -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #1fdbde;" data-color="#1fdbde"></button>
          <span class="text-xs text-center text-gray-600">Mythic</span>
        </div>
        <!-- Ultra -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #ff2b75;" data-color="#ff2b75"></button>
          <span class="text-xs text-center text-gray-600">Ultra</span>
        </div>
        <!-- Super -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #2bffa3;" data-color="#2bffa3"></button>
          <span class="text-xs text-center text-gray-600">Super</span>
        </div>
        <!-- Unique -->
        <div class="flex flex-col items-center">
          <button class="color-option w-full h-8 rounded-md mb-1" style="background-color: #555555;" data-color="#555555"></button>
          <span class="text-xs text-center text-gray-600">Unique</span>
        </div>
      </div>
    </div>
    
    <!-- History log -->
    <div class="bg-white rounded-lg p-4">
      <h2 class="text-lg font-semibold text-center mb-2">Roll History</h2>
      <div id="history-container" class="h-64 overflow-y-auto">
        <div class="grid grid-cols-3 gap-2 text-xs font-medium text-gray-500 border-b border-gray-200 sticky top-0 bg-white z-10">
          <div>Time</div>
          <div>Action</div>
          <div class="text-right">Score</div>
        </div>
        <ul id="history-list" class="text-sm">
          <!-- History items will be inserted here by JavaScript -->
        </ul>
      </div>
    </div>
  </div>
  
  <footer class="mt-8 text-center text-gray-600 text-sm">
    <p>Click the button to roll the dice and see the result!</p>
  </footer>

  <script>
    // Set up global error handler
    window.addEventListener('error', function(event) {
      console.error('Global error caught:', event.error);
      
      // Try to get roll button element
      const rollButton = document.getElementById('roll-button');
      if (rollButton && rollButton.disabled) {
        console.warn('Error during dice roll, re-enabling button');
        rollButton.disabled = false;
        rollButton.classList.remove('opacity-70', 'cursor-not-allowed');
        
        // Try to show error message
        const gameMessage = document.getElementById('game-message');
        if (gameMessage) {
          gameMessage.textContent = 'An error occurred. Please try again.';
          gameMessage.className = 'mt-4 text-center font-semibold text-red-500';
          gameMessage.classList.remove('hidden');
        }
      }
    });
    
    // DOM elements
    const diceElement = document.getElementById('dice');
    const rollButton = document.getElementById('roll-button');
    const resultDisplay = document.getElementById('result-display');
    const resultValue = document.getElementById('result-value');
    const historyList = document.getElementById('history-list');
    const colorOptions = document.querySelectorAll('.color-option');
    const scoreDisplay = document.getElementById('score-display');
    const scoreValue = document.getElementById('score-value');
    const scoreChange = document.getElementById('score-change');
    const upgradeButton = document.getElementById('upgrade-button');
    const currentTierDisplay = document.getElementById('current-tier');
    const gameMessageDisplay = document.getElementById('game-message');
    const rollCountDisplay = document.getElementById('roll-count-display');
    const rollCountValue = document.getElementById('roll-count-value');
    const upgradeCost = document.getElementById('upgrade-cost');
    
    // Item related DOM elements
    const doublePointsCount = document.getElementById('double-points-count');
    const noPenaltyCount = document.getElementById('no-penalty-count');
    const luckyStreakCount = document.getElementById('lucky-streak-count');
    const useDoublePointsButton = document.getElementById('use-double-points');
    const useNoPenaltyButton = document.getElementById('use-no-penalty');
    const useLuckyStreakButton = document.getElementById('use-lucky-streak');
    const activeItemIndicator = document.getElementById('active-item-indicator');
    const freeRollsIndicator = document.getElementById('free-rolls-indicator');
    const freeRollsCountElement = document.getElementById('free-rolls-count');
    
    // Game state
    let currentScore = 10; // Initial score
    let currentTier = 0; // Initial dice tier (0 = Empty)
    let gameOver = false; // Game over flag
    let rollCount = 0; // Number of dice rolls
    let luckyRollsRemaining = 0; // Number of lucky rolls remaining
    let isRolling = false; // Whether dice is currently rolling
    
    // Item system
    let doublePointsCards = 0; // Number of double points cards
    let noPenaltyCards = 0; // Number of no penalty cards
    let luckyStreakCards = 0; // Number of lucky streak cards
    let freeRolls = 0; // Number of free rolls available
    let activeItems = { // Currently active items
      double: 0, // Number of active double points cards
      noPenalty: false // Whether no penalty card is active
    };
    
    // Dice tiers configuration
    const diceTiers = [
      { name: 'Empty', color: '#FFFFFF' },
      { name: 'Common', color: '#7EEF6D' },
      { name: 'Unusual', color: '#FFE65D' },
      { name: 'Rare', color: '#4d52e3' },
      { name: 'Epic', color: '#861FDE' },
      { name: 'Legendary', color: '#DE1F1F' },
      { name: 'Mythic', color: '#1fdbde' },
      { name: 'Ultra', color: '#ff2b75' },
      { name: 'Super', color: '#2bffa3' },
      { name: 'Unique', color: '#555555' }
    ];
    
    // Initialize 3D dice
    function initializeDice() {
      console.log('Initializing dice...');
      // Create 6 faces for the dice
      const faces = [1, 2, 3, 4, 5, 6];
      
      faces.forEach(faceNumber => {
        const face = document.createElement('div');
        face.className = `dice-face face-${faceNumber}`;
        
        // Add dots to the face based on the number
        for (let i = 0; i < faceNumber; i++) {
          const dot = document.createElement('div');
          dot.className = 'dot';
          face.appendChild(dot);
        }
        
        diceElement.appendChild(face);
        console.log(`Added face ${faceNumber}`);
      });
      
      console.log('Dice initialized with faces:', diceElement.children.length);
      
      // Set initial position to show face 1 clearly
      diceElement.style.transform = 'rotateX(0deg) rotateY(0deg)';
    }
    
    // Get random rotation values for the dice
    function getRandomRotation() {
      // Determine which face we want to show
      const targetFace = Math.floor(Math.random() * 6) + 1;
      
      // Get current rotation from dice element
      const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
      const matrix = new DOMMatrix(currentTransform);
      
      // Extract current rotation angles
      let currentX = 0, currentY = 0;
      
      // If transform is not identity matrix, extract rotation
      if (currentTransform !== 'none') {
        // Calculate rotation from matrix
        currentX = Math.atan2(matrix.b, matrix.a) * (180 / Math.PI);
        currentY = Math.atan2(-matrix.c, matrix.f) * (180 / Math.PI);
      }
      
      // Set target rotation based on target face
      // These values are precisely calibrated to show the correct face
      let targetX = 0, targetY = 0;
      switch(targetFace) {
        case 1: // Front face (Z+) - visible when no rotation
          targetX = 0;
          targetY = 0;
          break;
        case 2: // Left face (X-) - visible when Y rotated 270 degrees
          targetX = 0;
          targetY = 270;
          break;
        case 3: // Back face (Z-) - visible when Y rotated 180 degrees
          targetX = 0;
          targetY = 180;
          break;
        case 4: // Right face (X+) - visible when Y rotated 90 degrees
          targetX = 0;
          targetY = 90;
          break;
        case 5: // Top face (Y-) - visible when X rotated -90 degrees
          targetX = -90;
          targetY = 0;
          break;
        case 6: // Bottom face (Y+) - visible when X rotated 90 degrees
          targetX = 90;
          targetY = 0;
          break;
      }
      
      // Calculate the shortest path to the target rotation
      // This prevents large rotation values from accumulating
      let diffX = targetX - currentX;
      let diffY = targetY - currentY;
      
      // Normalize the difference to the range [-180, 180] to find the shortest path
      diffX = ((diffX + 180) % 360) - 180;
      diffY = ((diffY + 180) % 360) - 180;
      
      // Add multiple full rotations for spinning effect (2-4 full rotations)
      const fullRotations = 2 + Math.floor(Math.random() * 3);
      
      // Calculate final rotation with full spins
      // We add full rotations in the direction of the shortest path
      const spinDirectionX = diffX >= 0 ? 1 : -1;
      const spinDirectionY = diffY >= 0 ? 1 : -1;
      
      const finalX = currentX + diffX + spinDirectionX * fullRotations * 360;
      const finalY = currentY + diffY + spinDirectionY * fullRotations * 360;
      
      // Add a tiny bit of randomness to make it look more natural
      // But not enough to change which face is visible
      const randomX = (Math.random() - 0.5) * 2;
      const randomY = (Math.random() - 0.5) * 2;
      
      return {
        x: finalX + randomX,
        y: finalY + randomY,
        targetFace: targetFace // Return the target face so we don't have to recalculate it
      };
    }
    
    // Roll the dice function
    function rollDice() {
      // Check if game is over
      if (gameOver) {
        showGameMessage('Game over! Click "Play Again" to restart.', 'text-red-500');
        return;
      }
      
      // Check if there are free rolls available
      const isFreeRoll = freeRolls > 0;
      
      // Check if in lucky streak mode
      const isLuckyRoll = luckyRollsRemaining > 0;
      
      // Increment roll count only if not a free roll (lucky rolls will be handled based on result)
      if (!isFreeRoll) {
        rollCount++;
        console.log(`Roll count: ${rollCount}`);
      } else {
        // Decrement free rolls count
        freeRolls--;
        updateFreeRollsDisplay();
        console.log(`Free roll used. Remaining free rolls: ${freeRolls}`);
      }
      
      // Update roll count display
      if (rollCountValue) {
        rollCountValue.textContent = rollCount;
      }
      
      console.log('Rolling dice...');
      console.log('Button state before disable:', rollButton.disabled);
      
      // Set rolling state and disable button during animation
      isRolling = true;
      rollButton.disabled = true;
      rollButton.classList.add('opacity-70', 'cursor-not-allowed');
      
      // Disable other interactive elements during roll
      upgradeButton.disabled = true;
      upgradeButton.classList.add('opacity-70', 'cursor-not-allowed');
      useDoublePointsButton.disabled = true;
      useNoPenaltyButton.disabled = true;
      useLuckyStreakButton.disabled = true;
      
      // Disable color options during roll
      colorOptions.forEach(option => {
        option.disabled = true;
      });
      
      console.log('Button state after disable:', rollButton.disabled);
      
      // Hide result display
      resultDisplay.classList.add('hidden');
      
      // Reset dice display height - use Tailwind class instead of inline style
      const diceDisplay = document.getElementById('dice-display');
      if (diceDisplay) {
        // Ensure the height class is applied to prevent layout shifts during animation
        diceDisplay.classList.add('h-48');
      }
      
      try {
        // Set animation duration
        const duration = 2000; // Fixed duration for consistent experience
        
        // Get random rotation values for the final position
        const rotationData = getRandomRotation();
        console.log('Rotation data:', rotationData);
        console.log('Target face:', rotationData.targetFace);
        
        // Animate the dice using JavaScript for more control
        animateDice(duration, rotationData, { isFreeRoll, isLuckyRoll });
        
        // Set a safety timeout to ensure button is re-enabled even if something goes wrong
        setTimeout(() => {
          if (rollButton.disabled) {
            console.warn('Safety timeout: Re-enabling roll button');
            enableRollButton();
          }
        }, duration + 1000); // Add 1 second buffer
      } catch (error) {
        console.error('Error during dice roll:', error);
        // Re-enable button if there's an error
        enableRollButton();
        showGameMessage('An error occurred during the dice roll. Please try again.', 'text-red-500');
      }
    }
    
    // Animate the dice with spin animation
    function animateDice(duration, rotationData, rollContext) {
      console.log('Animate dice called with rotationData:', rotationData);
      console.log('Roll context:', rollContext);
      const startTime = performance.now();
      const finalRotation = rotationData;
      
      // Get current rotation from dice element
      const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
      const matrix = new DOMMatrix(currentTransform);
      
      // Extract current rotation angles
      let startX = 0, startY = 0;
      
      // If transform is not identity matrix, extract rotation
      if (currentTransform !== 'none') {
        // Calculate rotation from matrix
        startX = Math.atan2(matrix.b, matrix.a) * (180 / Math.PI);
        startY = Math.atan2(-matrix.c, matrix.f) * (180 / Math.PI);
      }
      
      // Function to handle each animation frame
      function animate(currentTime) {
        const elapsedTime = currentTime - startTime;
        const progress = Math.min(elapsedTime / duration, 1);
        
        // Apply easing function for smooth, natural animation
        const easedProgress = easeOutCubic(progress);
        
        // Calculate current rotation - smooth continuous rotation
        const currentX = startX + (finalRotation.x - startX) * easedProgress;
        const currentY = startY + (finalRotation.y - startY) * easedProgress;
        
        // Spin animation: rotate in place
        diceElement.style.transform = `rotateX(${currentX}deg) rotateY(${currentY}deg)`;
        
        // Continue animation if not complete
        if (progress < 1) {
          requestAnimationFrame(animate);
        } else {
          // Animation complete - ensure we're at the exact target rotation
          diceElement.style.transform = `rotateX(${finalRotation.x}deg) rotateY(${finalRotation.y}deg)`;
          
          // Show result after a delay to ensure rotation is complete and CSS has applied
          console.log('Animation complete, waiting before finalizing...');
          setTimeout(() => {
            // Double-check that the transform has been applied
            const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
            console.log('Current transform after animation:', currentTransform);
            console.log('Calling finalizeAnimation...');
            finalizeAnimation(finalRotation, rollContext);
          }, 600);
        }
      }
      
      // Start the animation
      requestAnimationFrame(animate);
    }
    
    // Helper function to normalize angles to the range [-180, 180]
    function normalizeAngle(angle) {
      angle = angle % 360;
      if (angle > 180) angle -= 360;
      if (angle < -180) angle += 360;
      return angle;
    }
    
    // Easing function for smooth, natural animation with gentle acceleration and deceleration
    // Uses a cubic easing function that starts slow, accelerates, then slows down at the end
    function easeOutCubic(t) {
      return 1 - Math.pow(1 - t, 3);
    }
    
    // Calculate score change based on dice roll result
    function calculateScoreChange(result) {
      let baseChange = 0;
      
      switch(result) {
        case 1:
        case 2:
          baseChange = -1;
          break;
        case 3:
          baseChange = 0;
          break;
        case 4:
          baseChange = 1;
          break;
        case 5:
          baseChange = 2;
          break;
        case 6:
          baseChange = 3;
          break;
        default:
          baseChange = 0;
      }
      
      // Apply current tier multiplier
      // If losing points (baseChange < 0), use multiplier of 1 instead of tier multiplier
      const tierMultiplier = 1 + currentTier / 10;
      let finalChange;
      
      if (baseChange < 0) {
        // For point loss, use multiplier of 1 regardless of tier
        finalChange = baseChange * 1;
      } else {
        // For point gain or neutral, use tier multiplier
        finalChange = baseChange * tierMultiplier;
      }
      
      // Apply active item effects
      const itemsUsed = {
        double: activeItems.double,
        noPenalty: activeItems.noPenalty
      };
      
      // Apply no penalty card first
      if (activeItems.noPenalty && baseChange < 0) {
        finalChange = 0;
      }
      
      // Apply double points cards
      if (activeItems.double > 0) {
        finalChange = finalChange * Math.pow(2, activeItems.double);
      }
      
      // Round to 2 decimal places to avoid floating point precision issues
      finalChange = Math.round(finalChange * 100) / 100;
      
      return {
        baseChange: baseChange,
        finalChange: finalChange,
        itemsUsed: itemsUsed,
        tierMultiplier: tierMultiplier
      };
    }
    
    // Enable roll button
    function enableRollButton() {
      console.log('Button state before enable:', rollButton.disabled);
      
      // Directly enable the button
      rollButton.disabled = false;
      rollButton.classList.remove('opacity-70', 'cursor-not-allowed');
      
      // Re-enable other interactive buttons based on their conditions
      updateUpgradeCostDisplay(); // This will enable/disable upgrade button based on score
      updateItemsDisplay(); // This will enable/disable item buttons based on availability
      
      console.log('Button state after enable:', rollButton.disabled);
      
      // Double-check and force enable if needed
      if (rollButton.disabled) {
        console.warn('Forcing button enable');
        setTimeout(() => {
          rollButton.disabled = false;
          rollButton.classList.remove('opacity-70', 'cursor-not-allowed');
          console.log('Button state after forced enable:', rollButton.disabled);
        }, 100);
      }
    }
    
    // Finalize the animation and show result
    function finalizeAnimation(rotationData, rollContext) {
      console.log('=== Finalize animation called ===');
      console.log('Current time:', new Date().toISOString().split('T')[1]);
      console.log('Rotation data:', rotationData);
      console.log('Roll context:', rollContext);
      
      const finalRotation = rotationData;
      const isFreeRoll = rollContext && rollContext.isFreeRoll || false;
      const isLuckyRoll = rollContext && rollContext.isLuckyRoll || false;
      
      // Use the target face directly instead of recalculating
      const result = finalRotation.targetFace;
      console.log(`Final result: ${result} (should show face ${result})`);
      
      // Verify dice is in the correct position
      const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
      console.log('Current dice transform:', currentTransform);
      
      // Show result display
      console.log('Showing result display...');
      resultValue.textContent = result;
      resultDisplay.classList.remove('hidden');
      
      // Add shine effect to result
      resultDisplay.classList.add('result-shine');
      setTimeout(() => {
        resultDisplay.classList.remove('result-shine');
      }, 500);
      
      // Calculate and update score
      console.log('Calculating score change...');
      const scoreChangeData = calculateScoreChange(result);
      console.log('Score change data:', scoreChangeData);
      
      currentScore += scoreChangeData.finalChange;
      console.log('Updated score:', currentScore);
      
      // Update score display with animation
      console.log('Updating score display...');
      updateScoreDisplay(scoreChangeData);
      
      // Enable button
      console.log('Enabling roll button...');
      enableRollButton();
      
      // Add to history - include whether it was a free roll or lucky roll
      addToHistory(result, scoreChangeData, isFreeRoll, isLuckyRoll);
      
      // Check if reached the Unique dice
      if (currentTier === diceTiers.length - 1) {
        showGameMessage('Congratulations! You obtained the Unique dice!', 'text-green-500');
        gameOver = true;
        createConfetti();
      }
      
      // Handle lucky roll logic
      if (luckyRollsRemaining > 0) {
        // Decrement remaining lucky rolls
        luckyRollsRemaining--;
        
        // If rolled 1 or 2, decrement roll count
        if (result === 1 || result === 2) {
          rollCount--;
          console.log(`Lucky roll: Reverted roll count to ${rollCount}`);
          
          // Update roll count display
          if (rollCountValue) {
            rollCountValue.textContent = rollCount;
          }
          
          // Show message
          showGameMessage('Lucky! This 1/2 roll doesn\'t count!', 'text-yellow-500');
        }
        
        // Update lucky rolls display
        updateLuckyRollsDisplay();
        
        // If no more lucky rolls, show message
        if (luckyRollsRemaining === 0) {
          setTimeout(() => {
            showGameMessage('Lucky Streak ended!', 'text-yellow-500');
          }, 1000);
        }
      }
      
      // Create confetti effect if result is 6
      if (result === 6) {
        createConfetti();
      }
      
      // Debug: log final state
      console.log(`Final precise rotation: X=${finalRotation.x}°, Y=${finalRotation.y}°`);
      console.log(`Displayed result: ${result}`);
      console.log(`Score change: ${scoreChangeData.finalChange}, Current score: ${currentScore}`);
      console.log('=== finalizeAnimation completed ===');
    }
    
    // Update score display with animation
    function updateScoreDisplay(scoreChangeData) {
      console.log('=== updateScoreDisplay called ===');
      console.log('Score change data:', scoreChangeData);
      
      const change = scoreChangeData.finalChange;
      const baseChange = scoreChangeData.baseChange;
      const itemsUsed = scoreChangeData.itemsUsed;
      const tierMultiplier = scoreChangeData.tierMultiplier;
      
      console.log('Change:', change, 'Base change:', baseChange, 'Items used:', itemsUsed);
      
      // Update the score value - round to 2 decimal places
      currentScore = Math.round(currentScore * 100) / 100;
      scoreValue.textContent = currentScore;
      console.log('Score value updated to:', currentScore);
      
      // Clear previous score change display
      scoreChange.textContent = '';
      scoreChange.className = 'ml-2 text-sm font-normal';
      console.log('Cleared previous score change display');
      
      // Show score change with appropriate styling
      if (change > 0) {
        scoreChange.textContent = `+${change}`;
        scoreChange.classList.add('score-increase');
        console.log('Score increase:', change);
      } else if (change < 0) {
        scoreChange.textContent = `${change}`;
        scoreChange.classList.add('score-decrease');
        console.log('Score decrease:', change);
      } else {
        scoreChange.textContent = `±0`;
        scoreChange.classList.add('score-neutral');
        console.log('Score neutral');
      }
      
      // Show item effect message if items were used
      if (itemsUsed && (itemsUsed.double > 0 || itemsUsed.noPenalty)) {
        // Create container for item effects
        const itemEffectsContainer = document.createElement('div');
        itemEffectsContainer.className = 'flex flex-wrap gap-2 mt-1';
        
        // Add tier multiplier effect if applicable
        if (tierMultiplier !== 1) {
          const tierEffect = document.createElement('div');
          tierEffect.className = 'text-xs text-purple-500';
          tierEffect.textContent = `Tier Multiplier ×${tierMultiplier.toFixed(1)}!`;
          itemEffectsContainer.appendChild(tierEffect);
        }
        
        // Add no penalty effect
        if (itemsUsed.noPenalty) {
          const noPenaltyEffect = document.createElement('div');
          noPenaltyEffect.className = 'text-xs text-blue-500';
          noPenaltyEffect.textContent = `No Penalty! (Score protected from ${baseChange < 0 ? baseChange : 0} loss)`;
          itemEffectsContainer.appendChild(noPenaltyEffect);
        }
        
        // Add double points effect
        if (itemsUsed.double > 0) {
          const doublePointsEffect = document.createElement('div');
          doublePointsEffect.className = 'text-xs text-green-500';
          
          // Calculate multiplier
          const multiplier = Math.pow(2, itemsUsed.double);
          let calculationText = `${baseChange}`;
          
          // Apply tier multiplier for display
          let displayChange = baseChange * tierMultiplier;
          
          // Apply no penalty first for display
          if (itemsUsed.noPenalty && baseChange < 0) {
            displayChange = 0;
            calculationText = `(${baseChange} × ${tierMultiplier.toFixed(1)} → 0)`;
          } else if (tierMultiplier !== 1) {
            calculationText = `(${baseChange} × ${tierMultiplier.toFixed(1)} = ${displayChange.toFixed(2)})`;
          }
          
          // Show multiplication steps if multiple double cards used
          if (itemsUsed.double > 1) {
            for (let i = 0; i < itemsUsed.double; i++) {
              calculationText += ` × 2`;
            }
            calculationText += ` = ${(displayChange * multiplier).toFixed(2)}`;
          } else {
            calculationText += ` × 2 = ${(displayChange * multiplier).toFixed(2)}`;
          }
          
          doublePointsEffect.textContent = `Double Points ×${itemsUsed.double}! (${calculationText})`;
          itemEffectsContainer.appendChild(doublePointsEffect);
        }
        
        // Add to score display
        scoreDisplay.appendChild(itemEffectsContainer);
        
        // Remove after animation
        setTimeout(() => {
          scoreDisplay.removeChild(itemEffectsContainer);
        }, 1000);
      }
      
      // Reset score change display after animation completes
      setTimeout(() => {
        scoreChange.textContent = '';
      }, 1000);
      
      // Clear active items after score update
      console.log('Checking if items need to be cleared...');
      if (itemsUsed && (itemsUsed.double > 0 || itemsUsed.noPenalty)) {
        console.log('Clearing active items...');
        clearActiveItems();
        console.log('Updating items display...');
        updateItemsDisplay();
      }
      
      // Check game state after score update
      console.log('Checking game state...');
      checkGameState();
      
      // Update upgrade button state
      updateUpgradeCostDisplay();
      
      console.log('=== updateScoreDisplay completed ===');
    }
    
    // Handle dice upgrade
    function upgradeDice() {
      // Check if game is already over
      if (gameOver) {
        showGameMessage('Game over! Click "Play Again" to restart.', 'text-red-500');
        return;
      }
      
      // Check if already at maximum tier
      if (currentTier >= diceTiers.length - 1) {
        // If not already game over, end the game with win condition
        if (!gameOver) {
          gameOver = true;
          endGame(true);
        } else {
          showGameMessage('Congratulations! You already have the Unique dice!', 'text-green-500');
        }
        return;
      }
      
      // Calculate required score for upgrade (5 + currentTier)
      const requiredScore = 5 + currentTier;
      
      // Check if enough score to upgrade
      if (currentScore < requiredScore) {
        showGameMessage(`Not enough score to upgrade! Need ${requiredScore} points.`, 'text-orange-500');
        // Add shake animation to score display
        scoreDisplay.classList.add('animate-shake');
        setTimeout(() => {
          scoreDisplay.classList.remove('animate-shake');
        }, 500);
        return;
      }
      
      // Deduct score for upgrade
      currentScore -= requiredScore;
      // Round to 2 decimal places
      currentScore = Math.round(currentScore * 100) / 100;
      
      // Update score display
      scoreValue.textContent = currentScore;
      showScoreChange(-requiredScore);
      
      // Increase tier
      currentTier++;
      
      // Update current tier display
      currentTierDisplay.innerHTML = `Current Dice: <span class="font-semibold text-primary">${diceTiers[currentTier].name}</span>`;
      
      // Update tier multiplier display
      updateTierMultiplierDisplay();
      
      // Unlock the new dice color
      unlockDiceColor(currentTier);
      
      // Update color selection UI
      updateColorSelection(currentTier);
      
      // Update upgrade cost display
      updateUpgradeCostDisplay();
      
      // Change to the new dice color
      console.log(`Changing dice color to ${diceTiers[currentTier].color} (${diceTiers[currentTier].name})`);
      changeDiceColor(diceTiers[currentTier].color);
      
      // Check if this upgrade reached the maximum tier
      checkGameState();
      
      // Randomly get an item
      const itemChance = Math.random();
      if (itemChance < 0.30) { // 30% chance to get double points card
        doublePointsCards++;
      } else if (itemChance < 0.60) { // 30% chance to get no penalty card
        noPenaltyCards++;
      } else if (itemChance < 0.70) { // 10% chance to get lucky streak card
        luckyStreakCards++;
      } else { // 30% chance to get nothing
        // Do nothing
      }
      
      // Update items display to show new counts
      updateItemsDisplay();
      
      // Update items display
      updateItemsDisplay();
      
      // Check if reached the Unique dice
      if (currentTier === diceTiers.length - 1) {
        showGameMessage('Congratulations! You obtained the Unique dice!', 'text-green-500');
        gameOver = true;
        createConfetti();
      }
      
      // Handle lucky roll logic
      if (luckyRollsRemaining > 0) {
        // Decrement remaining lucky rolls
        luckyRollsRemaining--;
        
        // If rolled 1 or 2, decrement roll count
        if (result === 1 || result === 2) {
          rollCount--;
          console.log(`Lucky roll: Reverted roll count to ${rollCount}`);
          
          // Update roll count display
          if (rollCountValue) {
            rollCountValue.textContent = rollCount;
          }
          
          // Show message
          showGameMessage('Lucky! This 1/2 roll doesn\'t count!', 'text-yellow-500');
        }
        
        // Update lucky rolls display
        updateLuckyRollsDisplay();
        
        // If no more lucky rolls, show message
        if (luckyRollsRemaining === 0) {
          setTimeout(() => {
            showGameMessage('Lucky Streak ended!', 'text-yellow-500');
          }, 1000);
        }
      }
      
      // Add to history
      addToHistory('UPGRADE', -requiredScore);
      
      // Add item to history if obtained
      if (itemChance < 0.30) {
        addToHistory('ITEM', 'Double Points Card');
      } else if (itemChance < 0.60) {
        addToHistory('ITEM', 'No Penalty Card');
      } else if (itemChance < 0.70) {
        addToHistory('ITEM', 'Lucky Streak Card');
      }
      
      // Check game state after upgrade
      checkGameState();
    }
    
    // Show score change temporarily
    function showScoreChange(change) {
      scoreChange.textContent = change > 0 ? `+${change}` : change;
      scoreChange.className = `ml-2 text-sm font-normal ${change > 0 ? 'score-increase' : 'score-decrease'}`;
      
      setTimeout(() => {
        scoreChange.textContent = '';
      }, 1000);
    }
    
    // Unlock a dice color option
    function unlockDiceColor(tierIndex) {
      if (tierIndex >= 0 && tierIndex < colorOptions.length) {
        const option = colorOptions[tierIndex];
        // Show particle effect on the lock before unlocking
        createLockParticles(option);
        // Add a small delay to show the particles before unlocking
        setTimeout(() => {
          option.disabled = false;
          option.classList.remove('locked');
        }, 300);
      }
    }
    
    // Show game message
    function showGameMessage(message, className) {
      gameMessageDisplay.textContent = message;
      gameMessageDisplay.className = `mt-4 text-center font-semibold ${className}`;
      gameMessageDisplay.classList.remove('hidden');
      
      // Hide message after 3 seconds
      setTimeout(() => {
        if (!gameOver) {
          gameMessageDisplay.classList.add('hidden');
        }
      }, 3000);
    }
    
    // Check game state (win/lose conditions)
    function checkGameState() {
      console.log('=== checkGameState called ===');
      console.log('Current score:', currentScore, 'Game over:', gameOver);
      
      // Check if score is negative (lose condition)
      if (currentScore < 0 && !gameOver) {
        console.log('Score is negative, ending game...');
        gameOver = true;
        endGame(false);
      }
      
      // Check if reached Unique dice (win condition)
      if (currentTier === diceTiers.length - 1 && !gameOver) {
        console.log('Reached Unique dice, ending game...');
        gameOver = true;
        endGame(true);
        
        // Check if this is a new record
        setTimeout(() => {
          checkWinRecord();
        }, 1000);
      }
      
      // Check if score is low (warning)
      if (currentScore >= 0 && currentScore <= 5 && !gameOver) {
        showLowScoreWarning();
      }
      
      console.log('=== checkGameState completed ===');
    }
    
    // Update items display
    function updateItemsDisplay() {
      // Update counts
      doublePointsCount.textContent = doublePointsCards;
      noPenaltyCount.textContent = noPenaltyCards;
      luckyStreakCount.textContent = luckyStreakCards;
      
      // Enable/disable buttons based on available items
      useDoublePointsButton.disabled = doublePointsCards <= 0 || gameOver;
      useNoPenaltyButton.disabled = noPenaltyCards <= 0 || activeItems.noPenalty || gameOver;
      useLuckyStreakButton.disabled = luckyStreakCards <= 0 || gameOver;
      
      // Update free rolls display
      updateFreeRollsDisplay();
      
      // Update lucky rolls display
      updateLuckyRollsDisplay();
    }
    
    // Update free rolls display
    function updateFreeRollsDisplay() {
      if (freeRolls > 0) {
        freeRollsCountElement.textContent = freeRolls;
        freeRollsIndicator.classList.remove('hidden');
      } else {
        freeRollsIndicator.classList.add('hidden');
      }
    }
    
    // Update upgrade cost display and button state
    function updateUpgradeCostDisplay() {
      if (currentTier >= diceTiers.length - 1) {
        // Already at maximum tier
        upgradeCost.textContent = '(Max Tier)';
        upgradeButton.disabled = true;
        upgradeButton.classList.add('opacity-70', 'cursor-not-allowed');
      } else {
        const requiredScore = 5 + currentTier;
        upgradeCost.textContent = `(Cost: ${requiredScore})`;
        
        // Update button state based on available score
        if (currentScore >= requiredScore && !gameOver) {
          upgradeButton.disabled = false;
          upgradeButton.classList.remove('opacity-70', 'cursor-not-allowed');
        } else {
          upgradeButton.disabled = true;
          upgradeButton.classList.add('opacity-70', 'cursor-not-allowed');
        }
      }
    }
    
    // Use double points card
    function useDoublePointsCard() {
      if (doublePointsCards > 0 && !gameOver) {
        activeItems.double++;
        doublePointsCards--;
        
        // Update UI
        updateItemsDisplay();
        showActiveItemIndicator();
        
        // Show message
        showGameMessage('Double Points Card activated! Next roll will double your score change.', 'text-green-500');
      }
    }
    
    // Use no penalty card
    function useNoPenaltyCard() {
      if (noPenaltyCards > 0 && !activeItems.noPenalty && !gameOver) {
        activeItems.noPenalty = true;
        noPenaltyCards--;
        
        // Update UI
        updateItemsDisplay();
        showActiveItemIndicator();
        
        // Show message
        showGameMessage('No Penalty Card activated! Next roll won\'t lose points.', 'text-blue-500');
      }
    }
    
    // Use lucky streak card
    function useLuckyStreakCard() {
      if (luckyStreakCards > 0 && !gameOver) {
        luckyRollsRemaining = 3;
        luckyStreakCards--;
        
        // Update UI
        updateItemsDisplay();
        updateLuckyRollsDisplay();
        
        // Show message
        showGameMessage('Lucky Streak Card activated! Next 3 rolls of 1 or 2 won\'t count!', 'text-yellow-500');
        
        // Add to history
        addToHistory('ITEM USE', 'Lucky Streak Card');
      }
    }
    
    // Update lucky rolls display
    function updateLuckyRollsDisplay() {
      if (luckyRollsRemaining > 0) {
        // Check if indicator exists, if not create it
        let luckyRollsIndicator = document.getElementById('lucky-rolls-indicator');
        if (!luckyRollsIndicator) {
          luckyRollsIndicator = document.createElement('div');
          luckyRollsIndicator.id = 'lucky-rolls-indicator';
          luckyRollsIndicator.className = 'mt-3 text-center';
          
          // Insert after free rolls indicator
          const freeRollsIndicator = document.getElementById('free-rolls-indicator');
          if (freeRollsIndicator) {
            freeRollsIndicator.parentNode.insertBefore(luckyRollsIndicator, freeRollsIndicator.nextSibling);
          } else {
            // Fallback: insert after active item indicator
            const activeItemIndicator = document.getElementById('active-item-indicator');
            if (activeItemIndicator) {
              activeItemIndicator.parentNode.insertBefore(luckyRollsIndicator, activeItemIndicator.nextSibling);
            } else {
              // Fallback: insert after items display
              const itemsDisplay = document.getElementById('items-display');
              if (itemsDisplay) {
                itemsDisplay.parentNode.insertBefore(luckyRollsIndicator, itemsDisplay.nextSibling);
              }
            }
          }
        }
        
        // Update content
        luckyRollsIndicator.innerHTML = `
          <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
            <i class="fa fa-star mr-1" style="color: #f59e0b;"></i>
            <span>Lucky Rolls: <span id="lucky-rolls-count">${luckyRollsRemaining}</span> (1-2 won't count)</span>
          </span>
        `;
        
        // Show indicator
        luckyRollsIndicator.classList.remove('hidden');
      } else {
        // Remove indicator if exists
        const luckyRollsIndicator = document.getElementById('lucky-rolls-indicator');
        if (luckyRollsIndicator) {
          luckyRollsIndicator.classList.add('hidden');
        }
      }
    }
    
    // Show active item indicator
    function showActiveItemIndicator() {
      // Clear previous content
      activeItemIndicator.innerHTML = '';
      
      // Check if any items are active
      if (activeItems.double === 0 && !activeItems.noPenalty) {
        activeItemIndicator.className = 'mt-3 text-center hidden';
        return;
      }
      
      // Create container for active items
      const itemsContainer = document.createElement('div');
      itemsContainer.className = 'flex flex-wrap justify-center gap-2';
      
      // Add double points cards indicator
      if (activeItems.double > 0) {
        const doublePointsIndicator = document.createElement('span');
        doublePointsIndicator.className = 'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800';
        doublePointsIndicator.innerHTML = `
          <i class="fa fa-plus-circle mr-1" style="color: #10b981;"></i>
          <span>Double Points ×${activeItems.double}</span>
        `;
        itemsContainer.appendChild(doublePointsIndicator);
      }
      
      // Add no penalty card indicator
      if (activeItems.noPenalty) {
        const noPenaltyIndicator = document.createElement('span');
        noPenaltyIndicator.className = 'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800';
        noPenaltyIndicator.innerHTML = `
          <i class="fa fa-shield mr-1" style="color: #3b82f6;"></i>
          <span>No Penalty</span>
        `;
        itemsContainer.appendChild(noPenaltyIndicator);
      }
      
      // Add indicators to container
      activeItemIndicator.appendChild(itemsContainer);
      activeItemIndicator.className = 'mt-3 text-center';
    }
    
    // Clear active items
    function clearActiveItems() {
      activeItems = {
        double: 0,
        noPenalty: false
      };
      showActiveItemIndicator();
    }
    
    // End the game and display appropriate message
    function endGame(isWin) {
      console.log('=== endGame called ===');
      console.log('Is win:', isWin, 'Current score:', currentScore);
      
      // Disable all interactive elements
      rollButton.disabled = true;
      upgradeButton.disabled = true;
      rollButton.classList.add('opacity-70', 'cursor-not-allowed');
      upgradeButton.classList.add('opacity-70', 'cursor-not-allowed');
      
      // Disable all interactive elements
      colorOptions.forEach(option => {
        option.disabled = true;
        option.classList.add('opacity-50', 'cursor-not-allowed');
      });
      
      // Disable item buttons
      useDoublePointsButton.disabled = true;
      useNoPenaltyButton.disabled = true;
      useLuckyStreakButton.disabled = true;
      
      // Hide active indicators
      activeItemIndicator.classList.add('hidden');
      const luckyRollsIndicator = document.getElementById('lucky-rolls-indicator');
      if (luckyRollsIndicator) {
        luckyRollsIndicator.classList.add('hidden');
      }
      
      // Create game over message element
      const gameOverMessage = document.createElement('div');
      gameOverMessage.className = `mt-4 p-4 rounded-lg text-center font-bold ${isWin ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}`;
      
      // Format final score to 2 decimal places
      const formattedScore = currentScore.toFixed(2);
      
      if (isWin) {
        gameOverMessage.innerHTML = `
          <div class="text-2xl mb-2">Congratulations!</div>
          <p>You won the game!</p>
          <p>You obtained the Unique dice!</p>
          <p class="mt-2 text-sm">Final Score: ${formattedScore}</p>
          <p class="mt-1 text-sm">Total Rolls: ${rollCount}</p>
          <p class="mt-1 text-sm">Double Points Cards: ${doublePointsCards}</p>
          <p class="mt-1 text-sm">No Penalty Cards: ${noPenaltyCards}</p>
          <p class="mt-1 text-sm">Lucky Streak Cards: ${luckyStreakCards}</p>
          <p class="mt-1 text-sm">Final Tier Multiplier: ×${(1 + currentTier / 10).toFixed(1)}</p>
          <button id="play-again" class="mt-4 bg-primary hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-full transition-all duration-300 transform hover:scale-105">
            <i class="fa fa-refresh mr-1"></i> Play Again
          </button>
        `;
        createConfetti();
      } else {
        gameOverMessage.innerHTML = `
          <div class="text-2xl mb-2">Game Over!</div>
          <p>Your score went negative.</p>
          <p>Better luck next time!</p>
          <p class="mt-2 text-sm">Final Score: ${formattedScore}</p>
          <p class="mt-1 text-sm">Total Rolls: ${rollCount}</p>
          <p class="mt-1 text-sm">Double Points Cards: ${doublePointsCards}</p>
          <p class="mt-1 text-sm">No Penalty Cards: ${noPenaltyCards}</p>
          <p class="mt-1 text-sm">Lucky Streak Cards: ${luckyStreakCards}</p>
          <p class="mt-1 text-sm">Final Tier Multiplier: ×${(1 + currentTier / 10).toFixed(1)}</p>
          <button id="play-again" class="mt-4 bg-primary hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-full transition-all duration-300 transform hover:scale-105">
            <i class="fa fa-refresh mr-1"></i> Play Again
          </button>
        `;
      }
      
      // Add restart button event listener
      gameOverMessage.querySelector('#play-again').addEventListener('click', () => {
        window.location.reload();
      });
      
      // Replace game message display with game over message
      const gameMessageContainer = gameMessageDisplay.parentElement;
      gameMessageContainer.replaceChild(gameOverMessage, gameMessageDisplay);
      gameMessageDisplay = gameOverMessage;
      
      // Add game end to history
      addToHistory(isWin ? 'GAME WIN' : 'GAME OVER', 0);
      
      console.log('=== endGame completed ===');
    }
    
    // Show warning when score is low
    function showLowScoreWarning() {
      // Only show warning if not already showing
      if (gameMessageDisplay.classList.contains('hidden')) {
        showGameMessage('Warning: Low score! Risk of game over.', 'text-orange-500');
      }
    }
    
    // Update color selection UI to show the currently selected color
    function updateColorSelection(selectedIndex) {
      // Remove active state from all color options
      colorOptions.forEach(opt => opt.classList.remove('ring-2', 'ring-offset-2', 'ring-primary'));
      
      // Add active state to the selected color option
      if (selectedIndex >= 0 && selectedIndex < colorOptions.length) {
        colorOptions[selectedIndex].classList.add('ring-2', 'ring-offset-2', 'ring-primary');
      }
    }
    
    // Add result to history
    function addToHistory(result, scoreChangeData, isFreeRoll = false, isLuckyRoll = false) {
      const now = new Date();
      const timeString = now.toLocaleTimeString();
      
      // Determine score change display and color
      let scoreChangeText = '';
      let scoreChangeClass = '';
      let actionText = '';
      
      if (result === 'UPGRADE') {
        actionText = 'Upgraded dice';
        scoreChangeText = `${scoreChangeData}`;
        scoreChangeClass = 'text-red-500';
      } else if (result === 'ITEM') {
        actionText = `Received <span class="font-bold text-purple-500">${scoreChangeData}</span>`;
        scoreChangeText = '+1';
        scoreChangeClass = 'text-purple-500';
      } else if (result === 'GAME WIN' || result === 'GAME OVER') {
        actionText = result;
        scoreChangeText = '';
        scoreChangeClass = '';
      } else {
        const scoreChange = scoreChangeData.finalChange;
        const baseChange = scoreChangeData.baseChange;
        const itemsUsed = scoreChangeData.itemsUsed;
        
        actionText = `Rolled a <span class="font-bold text-primary">${result}</span>`;
        
        // Add free roll indicator if applicable
        if (isFreeRoll) {
          actionText += ` <span class="text-yellow-500">(Free Roll)</span>`;
        }
        
        // Add lucky roll indicator if applicable
        if (isLuckyRoll) {
          actionText += ` <span class="text-yellow-500">(Lucky Roll)</span>`;
        }
        
        // Add item effect indicators if applicable
        const activeItemsText = [];
        if (itemsUsed && itemsUsed.double > 0) {
          activeItemsText.push(`<span class="text-green-500">(Double Points ×${itemsUsed.double})</span>`);
        }
        if (itemsUsed && itemsUsed.noPenalty) {
          activeItemsText.push(`<span class="text-blue-500">(No Penalty)</span>`);
        }
        
        if (activeItemsText.length > 0) {
          actionText += ` ${activeItemsText.join(' ')}`;
        }
        
        if (scoreChange > 0) {
          scoreChangeText = `+${scoreChange}`;
          scoreChangeClass = 'text-green-500';
        } else if (scoreChange < 0) {
          scoreChangeText = `${scoreChange}`;
          scoreChangeClass = 'text-red-500';
        } else {
          scoreChangeText = '±0';
          scoreChangeClass = 'text-gray-500';
        }
        
        // Show base change if different from final change (items were used)
        if ((itemsUsed && (itemsUsed.double > 0 || itemsUsed.noPenalty)) && baseChange !== scoreChange) {
          scoreChangeText += ` <span class="text-xs">(Base: ${baseChange > 0 ? '+' : ''}${baseChange})</span>`;
        }
      }
      
      const listItem = document.createElement('li');
      listItem.className = 'py-1 border-b border-gray-100 grid grid-cols-3 gap-2 items-center';
      listItem.innerHTML = `
        <span class="col-span-1 text-gray-500">${timeString}</span>
        <span class="col-span-1">${actionText}</span>
        <span class="col-span-1 text-right font-medium ${scoreChangeClass}">${scoreChangeText}</span>
      `;
      
      historyList.prepend(listItem);
      
      // Keep only last 10 history items
      if (historyList.children.length > 10) {
        historyList.removeChild(historyList.lastChild);
      }
      
      // Ensure scroll is at the bottom
      const historyContainer = document.getElementById('history-container');
      if (historyContainer) {
        historyContainer.scrollTop = historyContainer.scrollHeight;
      }
    }
    
    // Create confetti effect
    function createConfetti() {
      const confettiContainer = document.createElement('div');
      confettiContainer.className = 'fixed inset-0 pointer-events-none overflow-hidden';
      document.body.appendChild(confettiContainer);
      
      // Create 50 confetti pieces
      for (let i = 0; i < 50; i++) {
        const confetti = document.createElement('div');
        confetti.className = 'confetti';
        
        // Random position
        const posX = Math.random() * 100;
        const delay = Math.random() * 3;
        const duration = 3 + Math.random() * 2;
        
        // Random colors
        const colors = ['#3b82f6', '#f97316', '#10b981', '#ef4444', '#8b5cf6'];
        const color = colors[Math.floor(Math.random() * colors.length)];
        
        confetti.style.left = `${posX}%`;
        confetti.style.backgroundColor = color;
        confetti.style.animationDelay = `${delay}s`;
        confetti.style.animationDuration = `${duration}s`;
        
        confettiContainer.appendChild(confetti);
      }
      
      // Remove confetti container after animation completes
      setTimeout(() => {
        document.body.removeChild(confettiContainer);
      }, 5000);
    }
    
    
    
    // Create particle effect on lock
    function createLockParticles(lockElement) {
      // Get lock element position
      const rect = lockElement.getBoundingClientRect();
      const centerX = rect.left + rect.width / 2;
      const centerY = rect.top + rect.height / 2;
      
      // Create particle container
      const particleContainer = document.createElement('div');
      particleContainer.className = 'absolute pointer-events-none';
      particleContainer.style.left = `${centerX}px`;
      particleContainer.style.top = `${centerY}px`;
      particleContainer.style.transform = 'translate(-50%, -50%)';
      document.body.appendChild(particleContainer);
      
      // Create 15 particles
      for (let i = 0; i < 15; i++) {
        const particle = document.createElement('div');
        particle.className = 'lock-particle';
        
        // Random direction and distance
        const angle = Math.random() * Math.PI * 2;
        const distance = 10 + Math.random() * 20;
        const tx = Math.cos(angle) * distance;
        const ty = Math.sin(angle) * distance;
        
        // Random color (use the color of the unlocked dice)
        const color = lockElement.style.backgroundColor;
        
        // Random animation duration
        const duration = 0.5 + Math.random() * 0.5;
        
        // Set particle styles
        particle.style.backgroundColor = color;
        particle.style.setProperty('--tx', `${tx}px`);
        particle.style.setProperty('--ty', `${ty}px`);
        particle.style.animation = `lock-particle ${duration}s ease-out forwards`;
        
        particleContainer.appendChild(particle);
      }
      
      // Remove particle container after animation completes
      setTimeout(() => {
        document.body.removeChild(particleContainer);
      }, 1000);
    }
    
    // Function to darken a color by a certain percentage
    function darkenColor(color, percent) {
      const hex = color.replace('#', '');
      let r = parseInt(hex.substr(0, 2), 16);
      let g = parseInt(hex.substr(2, 2), 16);
      let b = parseInt(hex.substr(4, 2), 16);
      
      // Darken each channel by the percentage
      r = Math.max(0, Math.floor(r * (1 - percent / 100)));
      g = Math.max(0, Math.floor(g * (1 - percent / 100)));
      b = Math.max(0, Math.floor(b * (1 - percent / 100)));
      
      // Convert back to hex
      const darkenedHex = '#' + 
        r.toString(16).padStart(2, '0') + 
        g.toString(16).padStart(2, '0') + 
        b.toString(16).padStart(2, '0');
      
      return darkenedHex;
    }
    
    // Change dice color function
    function changeDiceColor(color) {
      console.log(`changeDiceColor called with color: ${color}`);
      const faces = document.querySelectorAll('.dice-face');
      console.log(`Found ${faces.length} dice faces`);
      let dotColor, borderColor;
      
      // Special cases for high contrast
      if (color.toUpperCase() === '#FFFFFF') {
        // White dice - use black dots and light gray borders
        dotColor = '#000000';
        borderColor = '#CCCCCC';
      } else if (color.toUpperCase() === '#555555') {
        // Dark gray dice - use white dots and slightly lighter gray borders
        dotColor = '#FFFFFF';
        borderColor = '#777777';
      } else {
        // Calculate darker color for dots and borders (40% darker for more contrast)
        dotColor = darkenColor(color, 40);
        borderColor = darkenColor(color, 30); // Slightly lighter border than dots
      }
      
      faces.forEach(face => {
        // Set face background color
        face.style.backgroundColor = color;
        
        // Set face border color
        face.style.border = `3px solid ${borderColor}`;
        
        // Set dots color
        const dots = face.querySelectorAll('.dot');
        dots.forEach(dot => {
          dot.style.backgroundColor = dotColor;
          // Add slight border to dots for better definition
          dot.style.border = color.toUpperCase() === '#FFFFFF' ? '1px solid rgba(0, 0, 0, 0.2)' : '1px solid rgba(0, 0, 0, 0.1)';
        });
      });
    }
    
    // Update tier multiplier display
    function updateTierMultiplierDisplay() {
      const display = document.getElementById('tier-multiplier-display');
      if (display) {
        display.innerHTML = `Tier Multiplier: <span class="font-semibold text-purple-500">×${(1 + currentTier / 10).toFixed(1)}</span>`;
      }
    }
    
    // Event listener for roll button
    rollButton.addEventListener('click', rollDice);
    
    // Event listener for upgrade button
    upgradeButton.addEventListener('click', upgradeDice);
    
    // Event listeners for item buttons
    useDoublePointsButton.addEventListener('click', useDoublePointsCard);
    useNoPenaltyButton.addEventListener('click', useNoPenaltyCard);
    useLuckyStreakButton.addEventListener('click', useLuckyStreakCard);
    
    // Event listeners for color options
    colorOptions.forEach((option, index) => {
      // Disable all color options except the first one initially
      if (index !== 0) {
        option.disabled = true;
        option.classList.add('locked');
      }
      
      option.addEventListener('click', () => {
        // Check if game is over
        if (gameOver) {
          showGameMessage('Game over! Click "Play Again" to restart.', 'text-red-500');
          return;
        }
        
        // Check if color is unlocked
        if (option.disabled) {
          showGameMessage('You need to upgrade to unlock this dice color!', 'text-orange-500');
          return;
        }
        
        const color = option.getAttribute('data-color');
        changeDiceColor(color);
        
        // Add active state to selected color
        colorOptions.forEach(opt => opt.classList.remove('ring-2', 'ring-offset-2', 'ring-primary'));
        option.classList.add('ring-2', 'ring-offset-2', 'ring-primary');
        
        // Update current tier to the selected color's tier
        currentTier = index;
        currentTierDisplay.innerHTML = `Current Dice: <span class="font-semibold text-primary">${diceTiers[currentTier].name}</span>`;
        updateTierMultiplierDisplay();
      });
    });
    
    // Initialize dice on page load
    window.addEventListener('DOMContentLoaded', () => {
      console.log('=== DOMContentLoaded event fired ===');
      
      // Check if elements exist
      console.log('Checking if elements exist before initialization:');
      console.log('best-record-display exists:', !!document.getElementById('best-record-display'));
      console.log('best-record-value exists:', !!document.getElementById('best-record-value'));
      
      console.log('DOM fully loaded');
      initializeDice();
      
      // Set default color (first option)
      if (colorOptions.length > 0) {
        const defaultColor = colorOptions[0].getAttribute('data-color');
        changeDiceColor(defaultColor);
        colorOptions[0].classList.add('ring-2', 'ring-offset-2', 'ring-primary');
      }
      
      // Initialize current tier display
      currentTierDisplay.innerHTML = `Current Dice: <span class="font-semibold text-primary">${diceTiers[currentTier].name}</span>`;
      
      // Initialize tier multiplier display
      updateTierMultiplierDisplay();
      
      // Initialize items display
      updateItemsDisplay();
      
      // Initialize upgrade cost display
      updateUpgradeCostDisplay();
      
      // Show welcome message
      setTimeout(() => {
        showGameMessage('Welcome! Roll the dice to earn points and upgrade your dice!', 'text-blue-500');
      }, 1000);
    });
    
    // Also try initializing on window load
    window.addEventListener('load', () => {
      console.log('Window loaded');
      // If dice not already initialized, try again
      if (diceElement.children.length === 0) {
        console.log('Dice not initialized, trying again...');
        initializeDice();
      }
    });
    
    // Game Rules Modal Functionality
    (function() {
      // Get elements
      const rulesButton = document.getElementById('game-rules-button');
      const rulesModal = document.getElementById('game-rules-modal');
      const closeButtons = rulesModal.querySelectorAll('.close-button');
      const modalBackdrop = rulesModal.querySelector('.modal-backdrop');
      const modalContent = rulesModal.querySelector('.modal-content');
      
      // Function to prevent background scrolling
      function preventBackgroundScroll(event) {
        // Allow scrolling inside the modal content
        if (modalContent.contains(event.target)) {
          // Check if we're at the top or bottom of the modal content
          const isAtTop = modalContent.scrollTop === 0;
          const isAtBottom = modalContent.scrollTop + modalContent.clientHeight >= modalContent.scrollHeight;
          
          // Prevent scrolling if at the top and scrolling up, or at the bottom and scrolling down
          if ((isAtTop && event.deltaY < 0) || (isAtBottom && event.deltaY > 0)) {
            event.preventDefault();
          }
        } else {
          // Prevent scrolling outside the modal content
          event.preventDefault();
        }
      }
      
      // Function to open modal
      function openModal() {
        // Add event listeners to prevent background scrolling
        document.addEventListener('wheel', preventBackgroundScroll, { passive: false });
        document.addEventListener('touchmove', preventBackgroundScroll, { passive: false });
        
        // Add open class to trigger animations
        rulesModal.classList.add('modal-open');
        
        // Show the modal
        rulesModal.style.visibility = 'visible';
      }
      
      // Function to close modal
      function closeModal() {
        // Remove open class to trigger animations
        rulesModal.classList.remove('modal-open');
        
        // Remove event listeners that prevent background scrolling
        document.removeEventListener('wheel', preventBackgroundScroll);
        document.removeEventListener('touchmove', preventBackgroundScroll);
        
        // Hide the modal after animation completes
        setTimeout(() => {
          rulesModal.style.visibility = 'hidden';
        }, 300);
      }
      
      // Add event listeners
      if (rulesButton) {
        rulesButton.addEventListener('click', openModal);
      }
      
      // Close buttons
      closeButtons.forEach(button => {
        button.addEventListener('click', closeModal);
      });
      
      // Close when clicking outside the modal content
      modalBackdrop.addEventListener('click', closeModal);
      
      // Close when pressing Escape key
      document.addEventListener('keydown', (event) => {
        if (event.key === 'Escape' && rulesModal.classList.contains('modal-open')) {
          closeModal();
        }
      });
      
      // Add hover effect to rules button
      if (rulesButton) {
        rulesButton.addEventListener('mouseenter', () => {
          rulesButton.classList.add('scale-105');
        });
        
        rulesButton.addEventListener('mouseleave', () => {
          rulesButton.classList.remove('scale-105');
        });
      }
      
      // Add click effect to close buttons
      closeButtons.forEach(button => {
        button.addEventListener('mousedown', () => {
          button.classList.add('scale-95');
        });
        
        button.addEventListener('mouseup', () => {
          button.classList.remove('scale-95');
        });
        
        button.addEventListener('mouseleave', () => {
          button.classList.remove('scale-95');
        });
      });
    })();
  </script>
</body>
</html>

v.1.3(bug 极其严重)HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>3D Dice Roll Animation</title>
  <!-- Tailwind CSS v3 -->
  <script src="https://cdn.tailwindcss.com"></script>
  <!-- Font Awesome -->
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            primary: '#3b82f6',
            secondary: '#f97316',
            dark: '#1e293b',
            light: '#f8fafc'
          },
          fontFamily: {
            sans: ['Inter', 'system-ui', 'sans-serif'],
          },
          animation: {
            'shake': 'shake 0.5s ease-in-out',
          },
          keyframes: {
            shake: {
              '0%, 100%': { transform: 'translateX(0)' },
              '25%': { transform: 'translateX(-5px)' },
              '50%': { transform: 'translateX(5px)' },
              '75%': { transform: 'translateX(-5px)' },
            }
          }
        }
      }
    }
  </script>
  
  <style type="text/tailwindcss">
    @layer utilities {
      .preserve-3d {
        transform-style: preserve-3d;
      }
      .perspective {
        perspective: 1000px;
      }
      .backface-hidden {
        backface-visibility: hidden;
      }
      .dice-shadow {
        box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
      }
      .glass-effect {
        background: rgba(255, 255, 255, 0.7);
        backdrop-filter: blur(10px);
        -webkit-backdrop-filter: blur(10px);
      }
      .modal-backdrop {
        background-color: rgba(0, 0, 0, 0.5);
        backdrop-filter: blur(4px);
        -webkit-backdrop-filter: blur(4px);
      }
      .modal-content {
        transform: translateY(-20px);
        opacity: 0;
        transition: all 0.3s ease-out;
      }
      .modal-open .modal-content {
        transform: translateY(0);
        opacity: 1;
      }
      .modal-open .modal-backdrop {
        opacity: 1;
        visibility: visible;
      }
      .trophy-animation {
        animation: trophy-pulse 2s ease-in-out infinite;
      }
      .record-animation {
        animation: record-shine 2s ease-in-out;
      }
    }
    
    @keyframes trophy-pulse {
      0% { transform: scale(1); }
      50% { transform: scale(1.1); }
      100% { transform: scale(1); }
    }
    
    @keyframes record-shine {
      0% { box-shadow: 0 0 0 0 rgba(251, 191, 36, 0.7); }
      70% { box-shadow: 0 0 0 15px rgba(251, 191, 36, 0); }
      100% { box-shadow: 0 0 0 0 rgba(251, 191, 36, 0); }
    }
    
    /* Custom styles for 3D dice */
    .dice-scene {
      perspective: 1500px;
      width: 120px;
      height: 120px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .dice-container {
      position: relative;
      width: 100px;
      height: 100px;
      transform-style: preserve-3d;
      transition: transform 1s ease-out;
      transform: rotateX(20deg) rotateY(20deg);
    }
    
    .dice-face {
      position: absolute;
      width: 100px;
      height: 100px;
      border-radius: 8px;
      background-color: white;
      border: 2px solid #f0f0f0;
      display: flex;
      align-items: center;
      justify-content: center;
      box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
    }
    
    /* Dice face positions */
    .face-1 { transform: translateZ(50px); }
    .face-2 { transform: rotateY(90deg) translateZ(50px); }
    .face-3 { transform: rotateY(180deg) translateZ(50px); }
    .face-4 { transform: rotateY(-90deg) translateZ(50px); }
    .face-5 { transform: rotateX(90deg) translateZ(50px); }
    .face-6 { transform: rotateX(-90deg) translateZ(50px); }
    
    /* Dots on dice faces */
    .dot {
      position: absolute;
      width: 20px;
      height: 20px;
      border-radius: 50%;
      background-color: black;
    }
    
    /* Dot positions for each face */
    .face-1 .dot { top: 40px; left: 40px; }
    
    .face-2 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-2 .dot:nth-child(2) { top: 60px; left: 60px; }
    
    .face-3 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-3 .dot:nth-child(2) { top: 40px; left: 40px; }
    .face-3 .dot:nth-child(3) { top: 60px; left: 60px; }
    
    .face-4 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-4 .dot:nth-child(2) { top: 20px; left: 60px; }
    .face-4 .dot:nth-child(3) { top: 60px; left: 20px; }
    .face-4 .dot:nth-child(4) { top: 60px; left: 60px; }
    
    .face-5 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-5 .dot:nth-child(2) { top: 20px; left: 60px; }
    .face-5 .dot:nth-child(3) { top: 40px; left: 40px; }
    .face-5 .dot:nth-child(4) { top: 60px; left: 20px; }
    .face-5 .dot:nth-child(5) { top: 60px; left: 60px; }
    
    .face-6 .dot:nth-child(1) { top: 20px; left: 20px; }
    .face-6 .dot:nth-child(2) { top: 20px; left: 60px; }
    .face-6 .dot:nth-child(3) { top: 40px; left: 20px; }
    .face-6 .dot:nth-child(4) { top: 40px; left: 60px; }
    .face-6 .dot:nth-child(5) { top: 60px; left: 20px; }
    .face-6 .dot:nth-child(6) { top: 60px; left: 60px; }
    
    .dice-result {
      transition: all 0.5s ease-out;
    }
    
    /* Fixed height for result display to prevent page jumping */
    #result-display {
      height: 40px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .result-shine {
      animation: shine 0.5s ease-out;
    }
    
    .score-increase {
      color: #10b981;
      animation: scorePopup 1s ease-out;
    }
    
    .score-decrease {
      color: #ef4444;
      animation: scorePopup 1s ease-out;
    }
    
    .score-neutral {
      color: #6b7280;
      animation: scorePopup 1s ease-out;
    }
    
    /* Locked color option styles */
    .color-option.locked {
      position: relative !important;
      opacity: 0.5;
      cursor: not-allowed;
    }
    
    .color-option.locked::after {
      content: var(--content, '\f023'); /* Lock icon from Font Awesome */
      font-family: 'FontAwesome';
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      color: rgba(0, 0, 0, 0.5);
      font-size: 16px;
      z-index: 10; /* Ensure lock icon is above other content */
      display: block; /* Ensure the pseudo-element is displayed */
    }
    
    @keyframes shine {
      0% {
        box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4);
      }
      70% {
        box-shadow: 0 0 0 10px rgba(59, 130, 246, 0);
      }
      100% {
        box-shadow: 0 0 0 0 rgba(59, 130, 246, 0);
      }
    }
    
    @keyframes scorePopup {
      0% {
        transform: translateY(0);
        opacity: 0;
      }
      50% {
        transform: translateY(-10px);
        opacity: 1;
      }
      100% {
        transform: translateY(-20px);
        opacity: 0;
      }
    }
    
    .confetti {
      position: absolute;
      width: 10px;
      height: 10px;
      background-color: #f97316;
      animation: confetti-fall 3s ease-in-out infinite;
    }
    
    @keyframes confetti-fall {
      0% {
        transform: translateY(-100vh) rotate(0deg);
        opacity: 1;
      }
      100% {
        transform: translateY(100vh) rotate(720deg);
        opacity: 0;
      }
    }
    
    @keyframes lock-particle {
      0% {
        transform: translate(0, 0);
        opacity: 1;
      }
      100% {
        transform: translate(var(--tx), var(--ty));
        opacity: 0;
      }
    }
    
    /* Game Rules Modal Styles */
    .game-rules-modal {
      position: fixed;
      top: 0;
      left: 0;
      width: 100vw;
      height: 100vh;
      z-index: 50;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 1rem;
      visibility: hidden;
      box-sizing: border-box;
    }
    
    .game-rules-modal .modal-backdrop {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      opacity: 0;
      visibility: hidden;
      transition: all 0.3s ease-out;
    }
    
    .game-rules-modal .modal-content {
      position: relative;
      background-color: white;
      border-radius: 1rem;
      max-width: 90%;
      max-height: 80vh;
      width: 500px;
      overflow-y: auto;
      box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
    }
    
    .game-rules-modal .modal-header {
      padding: 1.5rem;
      border-bottom: 1px solid #e5e7eb;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
    
    .game-rules-modal .modal-title {
      font-size: 1.25rem;
      font-weight: 600;
      color: #1e293b;
    }
    
    .game-rules-modal .close-button {
      background: none;
      border: none;
      font-size: 1.5rem;
      cursor: pointer;
      color: #6b7280;
      transition: color 0.2s ease-in-out;
    }
    
    .game-rules-modal .close-button:hover {
      color: #1e293b;
    }
    
    .game-rules-modal .modal-body {
      padding: 1.5rem;
      line-height: 1.6;
      color: #374151;
    }
    
    .game-rules-modal .modal-body h3 {
      font-size: 1.1rem;
      font-weight: 600;
      margin-top: 1.5rem;
      margin-bottom: 0.75rem;
      color: #1e293b;
    }
    
    .game-rules-modal .modal-body p {
      margin-bottom: 1rem;
    }
    
    .game-rules-modal .modal-body ul {
      margin-bottom: 1rem;
      padding-left: 1.5rem;
      list-style-type: disc;
    }
    
    .game-rules-modal .modal-body li {
      margin-bottom: 0.5rem;
    }
    
    .game-rules-modal .modal-body strong {
      font-weight: 600;
      color: #1e293b;
    }
    
    .game-rules-modal .modal-footer {
      padding: 1rem 1.5rem;
      border-top: 1px solid #e5e7eb;
      display: flex;
      justify-content: flex-end;
    }
    
    .game-rules-modal .modal-footer button {
      padding: 0.5rem 1rem;
      border-radius: 0.5rem;
      background-color: #3b82f6;
      color: white;
      font-size: 1.25rem;
      font-weight: 500;
      transition: background-color 0.2s ease-in-out;
    }
    
    .game-rules-modal .modal-footer button:hover {
      background-color: #2563eb;
    }
    
    /* Game Rules Button Styles */
    .game-rules-button, .win-records-button {
      position: fixed;
      right: 1rem;
      z-index: 40;
      padding: 0.5rem 1rem;
      border-radius: 0.5rem;
      background-color: #3b82f6;
      color: white;
      font-weight: 500;
      display: flex;
      align-items: center;
      gap: 0.5rem;
      transition: all 0.2s ease-in-out;
      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
    }
    
    .game-rules-button {
      top: 1rem;
    }
    
    .win-records-button {
      top: 4.5rem;
    }
    
    .game-rules-button:hover {
      background-color: #2563eb;
      transform: translateY(-2px);
    }
    
    .game-rules-button i {
      font-size: 1.1rem;
    }
  </style>
</head>
<body class="bg-gradient-to-br from-light to-gray-200 min-h-screen flex flex-col items-center justify-center p-4 m-0">
  <!-- Game Rules Button -->
  <button id="game-rules-button" class="game-rules-button">
    <i class="fa fa-book"></i>
    <span>Game Rules</span>
  </button>
  
  <!-- Win Records Button -->
  <button id="win-records-button" class="win-records-button">
    <i class="fa fa-trophy"></i>
    <span>Win Records</span>
  </button>
  
  <!-- Game Rules Modal -->
  <div id="game-rules-modal" class="game-rules-modal">
    <div class="modal-backdrop"></div>
    <div class="modal-content">
      <div class="modal-header">
        <h2 class="modal-title">3D Dice Game Rules</h2>
        <button class="close-button">&times;</button>
      </div>
      <div class="modal-body">
        <p>Welcome to the 3D Dice Game! This is an exciting game that combines luck, strategy, and upgrading mechanics. Below is the complete game rules explanation:</p>
        
        <h3>Basic Gameplay</h3>
        <ul>
          <li>Click the "Roll Dice" button to roll the dice</li>
          <li>The dice will randomly show a number between 1-6</li>
          <li>Gain or lose points based on the number rolled</li>
          <li>The goal is to obtain the highest tier "Unique" dice</li>
        </ul>
        
        <h3>Score System</h3>
        <ul>
          <li>Rolling 1 or 2: Lose 1 point (multiplier not applied)</li>
          <li>Rolling 3: No points gained or lost</li>
          <li>Rolling 4: Gain 1 point</li>
          <li>Rolling 5: Gain 2 points</li>
          <li>Rolling 6: Gain 3 points</li>
        </ul>
        
        <h3>Dice Upgrade System</h3>
        <p>There are 10 different tiers of dice in the game, from common to rare:</p>
        <ul>
          <li><strong>Empty</strong> (Initial) - Score Multiplier ×1.0</li>
          <li><strong>Common</strong> - Score Multiplier ×1.1</li>
          <li><strong>Unusual</strong> - Score Multiplier ×1.2</li>
          <li><strong>Rare</strong> - Score Multiplier ×1.3</li>
          <li><strong>Epic</strong> - Score Multiplier ×1.4</li>
          <li><strong>Legendary</strong> - Score Multiplier ×1.5</li>
          <li><strong>Mythic</strong> - Score Multiplier ×1.6</li>
          <li><strong>Ultra</strong> - Score Multiplier ×1.7</li>
          <li><strong>Super</strong> - Score Multiplier ×1.8</li>
          <li><strong>Unique</strong> - Score Multiplier ×1.9</li>
        </ul>
        <p>Each upgrade costs (5 + current tier) points. For example, upgrading from Empty (tier 0) costs 5 points, upgrading from Common (tier 1) costs 6 points, and so on. After upgrading, you can choose to use the new dice or continue using the old one.</p>
        
        <h3>Item System</h3>
        <p>When upgrading, you have a chance to obtain item cards that can be used at critical moments:</p>
        <ul>
          <li><strong>Double Points Card</strong>: Doubles the points from one roll</li>
          <li><strong>No Penalty Card</strong>: Prevents point loss when rolling 1 or 2</li>
          <li><strong>Lucky Streak Card</strong>: Next 3 rolls of 1 or 2 won't count towards your total roll count</li>
        </ul>
        <p>Items can be stockpiled and each card can only be used once. Double Points Cards and No Penalty Cards can be used simultaneously. Lucky Streak Cards make your next 3 rolls of 1 or 2 not count towards your total roll count, giving you a chance to recover from bad luck.</p>
        
        <h3>Game Rules</h3>
        <ul>
          <li>Initial score is 10 points</li>
          <li>Score multiplier changes based on the current dice tier being used</li>
          <li>Game over when score is less than 0</li>
          <li>Game victory when obtaining the Unique dice</li>
          <li>Unlocked dice colors can be switched at any time</li>
        </ul>
        
        <h3>Operation Tips</h3>
        <ul>
          <li>Click on dice color options to switch the dice being used</li>
          <li>Click the "Upgrade Dice" button to upgrade your dice (requires 5 points)</li>
          <li>Click the "Use" button next to item cards to use them</li>
          <li>Press the ESC key to close the rules window</li>
        </ul>
        
        <p>Good luck, and may you successfully obtain the highest tier Unique dice!</p>
      </div>
      <div class="modal-footer">
        <button class="close-button bg-primary hover:bg-blue-600 text-white font-medium py-1.5 px-3 rounded text-sm">Got it</button>
      </div>
    </div>
  </div>
  
  <!-- Win Records Modal -->
  <div id="win-records-modal" class="game-rules-modal">
    <div class="modal-backdrop"></div>
    <div class="modal-content">
      <div class="modal-header">
        <h2 class="modal-title">Win Records</h2>
        <button class="close-button">&times;</button>
      </div>
      <div class="modal-body">
        <p>Here are your records for completing the game (obtaining the Unique dice):</p>
        
        <div id="no-records-message" class="text-center py-8">
          <i class="fa fa-trophy text-4xl text-gray-300 mb-4"></i>
          <p class="text-gray-500">No win records yet. Play and win to see your records!</p>
        </div>
        
        <div id="win-records-container" class="hidden">
          <div class="overflow-x-auto">
            <table class="min-w-full bg-white rounded-lg overflow-hidden">
              <thead class="bg-gray-100">
                <tr>
                  <th class="py-2 px-4 text-left text-sm font-semibold text-gray-700">Game #</th>
                  <th class="py-2 px-4 text-left text-sm font-semibold text-gray-700">Date & Time</th>
                  <th class="py-2 px-4 text-left text-sm font-semibold text-gray-700">Rolls</th>
                  <th class="py-2 px-4 text-left text-sm font-semibold text-gray-700">Time</th>
                </tr>
              </thead>
              <tbody id="win-records-list" class="divide-y divide-gray-200">
                <!-- Records will be added here by JavaScript -->
              </tbody>
            </table>
          </div>
          
          <div class="mt-6 p-4 bg-blue-50 rounded-lg">
            <h3 class="font-semibold text-blue-800 mb-2">Statistics:</h3>
            <div class="grid grid-cols-3 gap-4 text-center">
              <div>
                <p class="text-sm text-gray-600">Total Wins</p>
                <p id="total-wins" class="text-2xl font-bold text-primary">0</p>
              </div>
              <div>
                <p class="text-sm text-gray-600">Best (Fewest Rolls)</p>
                <p id="best-rolls" class="text-2xl font-bold text-primary">-</p>
              </div>
              <div>
                <p class="text-sm text-gray-600">Average Rolls</p>
                <p id="average-rolls" class="text-2xl font-bold text-primary">-</p>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="modal-footer">
        <button class="close-button bg-primary hover:bg-blue-600 text-white font-medium py-1.5 px-3 rounded text-sm">
          Close
        </button>
      </div>
    </div>
  </div>
  
  <div class="w-full max-w-md mx-auto glass-effect rounded-2xl p-6 dice-shadow relative z-10">
    <h1 class="text-3xl font-bold text-center text-dark mb-8">3D Dice Roll</h1>
    
    <div class="flex flex-col items-center justify-center mb-8">
      <!-- Dice display area -->
      <div id="dice-display" class="w-48 h-48 flex items-center justify-center mb-4 bg-gray-100 rounded-lg">
        <!-- Dice scene for 3D perspective -->
        <div class="dice-scene">
          <div id="dice" class="dice-container">
            <!-- Dice faces will be inserted here by JavaScript -->
          </div>
        </div>
      </div>
      
      <!-- Result display -->
      <div id="result-display" class="text-2xl font-bold text-center mb-4 hidden">
        Result:&nbsp;<span id="result-value" class="text-primary">0</span>
      </div>
      
      <!-- Score display -->
      <div id="score-display" class="text-xl font-bold text-center mb-2">
        Score: <span id="score-value" class="text-secondary">10</span>
        <span id="score-change" class="ml-2 text-sm font-normal"></span>
      </div>
      
      <!-- Roll count display -->
      <div id="roll-count-display" class="text-lg font-medium text-center mb-4">
        Rolls: <span id="roll-count-value" class="text-gray-700">0</span>
      </div>
      
      <!-- Roll button -->
      <button id="roll-button" class="bg-primary hover:bg-blue-600 text-white font-bold py-3 px-6 rounded-full transition-all duration-300 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-blue-300 focus:ring-opacity-50">
        <i class="fa fa-random mr-2"></i> Roll Dice
      </button>
      
      <!-- Upgrade button and current tier display -->
      <div class="flex flex-col items-center mt-4">
        <div id="current-tier" class="text-sm text-gray-600 mb-2">
          Current Dice: <span class="font-semibold text-primary">Empty</span>
        </div>
        <div id="tier-multiplier-display" class="text-sm text-gray-600 mb-2">
          Tier Multiplier: <span class="font-semibold text-purple-500">×1.0</span>
        </div>
        <button id="upgrade-button" class="bg-secondary hover:bg-orange-600 text-white font-bold py-2 px-4 rounded-full transition-all duration-300 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-orange-300 focus:ring-opacity-50">
          <i class="fa fa-arrow-up mr-1"></i> Upgrade Dice <span id="upgrade-cost">(Cost: 5)</span>
        </button>
      </div>
      
      <!-- Game message display -->
      <div id="game-message" class="mt-4 text-center font-semibold hidden"></div>
      
      <!-- Items display -->
      <div id="items-display" class="mt-6 grid grid-cols-1 md:grid-cols-2 gap-4">
        <div class="bg-white rounded-lg p-3 dice-shadow flex flex-col">
          <div class="flex items-center justify-between flex-shrink-0">
            <div class="flex items-center">
              <i class="fa fa-plus-circle text-green-500 text-xl mr-2"></i>
              <span class="font-medium">Double Points Card</span>
            </div>
            <div class="flex items-center ml-2">
              <span id="double-points-count" class="bg-green-100 text-green-800 text-xs font-semibold mr-2 px-3 py-0.5 rounded min-w-[40px] text-center whitespace-nowrap inline-block">0</span>
              <button id="use-double-points" class="bg-green-500 hover:bg-green-600 text-white text-xs py-1 px-2 rounded disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap" disabled>
                Use
              </button>
            </div>
          </div>
          <p class="text-xs text-gray-500 mt-1 flex-shrink-0">Doubles your score change for one roll</p>
        </div>
        
        <div class="bg-white rounded-lg p-3 dice-shadow flex flex-col">
          <div class="flex items-center justify-between flex-shrink-0">
            <div class="flex items-center">
              <i class="fa fa-shield text-blue-500 text-xl mr-2"></i>
              <span class="font-medium">No Penalty Card</span>
            </div>
            <div class="flex items-center ml-2">
              <span id="no-penalty-count" class="bg-blue-100 text-blue-800 text-xs font-semibold mr-2 px-3 py-0.5 rounded min-w-[40px] text-center whitespace-nowrap inline-block">0</span>
              <button id="use-no-penalty" class="bg-blue-500 hover:bg-blue-600 text-white text-xs py-1 px-2 rounded disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap" disabled>
                Use
              </button>
            </div>
          </div>
          <p class="text-xs text-gray-500 mt-1 flex-shrink-0">Prevents score loss when rolling 1 or 2</p>
        </div>
        
        <div class="bg-white rounded-lg p-3 dice-shadow flex flex-col">
          <div class="flex items-center justify-between flex-shrink-0">
            <div class="flex items-center">
              <i class="fa fa-star text-yellow-500 text-xl mr-2"></i>
              <span class="font-medium">Lucky Streak Card</span>
            </div>
            <div class="flex items-center ml-2">
              <span id="lucky-streak-count" class="bg-yellow-100 text-yellow-800 text-xs font-semibold mr-2 px-3 py-0.5 rounded min-w-[30px] text-center whitespace-nowrap inline-block">0</span>
              <button id="use-lucky-streak" class="bg-yellow-500 hover:bg-yellow-600 text-white text-xs py-1 px-2 rounded disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap" disabled>
                Use
              </button>
            </div>
          </div>
          <p class="text-xs text-gray-500 mt-1 flex-shrink-0">Next 3 rolls of 1 or 2 won't count towards your total roll count</p>
        </div>
      </div>
      
      <!-- Free rolls indicator -->
      <div id="free-rolls-indicator" class="mt-3 text-center hidden">
        <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
          <i class="fa fa-star mr-1" style="color: #f59e0b;"></i>
          <span>Free Rolls: <span id="free-rolls-count">0</span></span>
        </span>
      </div>
      
      <!-- Active item indicator -->
      <div id="active-item-indicator" class="mt-3 text-center hidden">
        <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium">
          <i id="active-item-icon" class="mr-1"></i>
          <span id="active-item-text">Active Item: None</span>
        </span>
      </div>
    </div>
    
    <!-- Dice Rarity Display -->
    <div class="mb-8">
      <label class="block text-sm font-medium text-gray-700 mb-2">Current Dice Rarity</label>
      <div class="flex items-center justify-center">
        <div id="current-rarity-display" class="flex items-center bg-white rounded-lg p-3 shadow-md">
          <div id="current-rarity-color" class="w-8 h-8 rounded-md mr-3" style="background-color: #FFFFFF; border: 1px solid #dddddd;"></div>
          <div>
            <div id="current-rarity-name" class="font-semibold">Empty</div>
            <div class="text-xs text-gray-500">Automatically upgraded to highest obtained rarity</div>
          </div>
        </div>
      </div>
    </div>
    
    <!-- History log -->
    <div class="bg-white rounded-lg p-4">
      <h2 class="text-lg font-semibold text-center mb-2">Roll History</h2>
      <div id="history-container" class="h-64 overflow-y-auto">
        <div class="grid grid-cols-3 gap-2 text-xs font-medium text-gray-500 border-b border-gray-200 sticky top-0 bg-white z-10">
          <div>Time</div>
          <div>Action</div>
          <div class="text-right">Score</div>
        </div>
        <ul id="history-list" class="text-sm">
          <!-- History items will be inserted here by JavaScript -->
        </ul>
      </div>
    </div>
  </div>
  
  <footer class="mt-8 text-center text-gray-600 text-sm">
    <p>Click the button to roll the dice and see the result!</p>
  </footer>

  <script>
    // Set up global error handler
    window.addEventListener('error', function(event) {
      console.error('Global error caught:', event.error);
      
      // Try to get roll button element
      const rollButton = document.getElementById('roll-button');
      if (rollButton && rollButton.disabled) {
        console.warn('Error during dice roll, re-enabling button');
        rollButton.disabled = false;
        rollButton.classList.remove('opacity-70', 'cursor-not-allowed');
        
        // Try to show error message
        const gameMessage = document.getElementById('game-message');
        if (gameMessage) {
          gameMessage.textContent = 'An error occurred. Please try again.';
          gameMessage.className = 'mt-4 text-center font-semibold text-red-500';
          gameMessage.classList.remove('hidden');
        }
      }
    });
    
    // DOM elements
    const diceElement = document.getElementById('dice');
    const rollButton = document.getElementById('roll-button');
    const resultDisplay = document.getElementById('result-display');
    const resultValue = document.getElementById('result-value');
    const historyList = document.getElementById('history-list');
    const colorOptions = document.querySelectorAll('.color-option');
    const scoreDisplay = document.getElementById('score-display');
    const scoreValue = document.getElementById('score-value');
    const scoreChange = document.getElementById('score-change');
    const upgradeButton = document.getElementById('upgrade-button');
    const currentTierDisplay = document.getElementById('current-tier');
    const gameMessageDisplay = document.getElementById('game-message');
    const rollCountDisplay = document.getElementById('roll-count-display');
    const rollCountValue = document.getElementById('roll-count-value');
    const upgradeCost = document.getElementById('upgrade-cost');
    
    // Item related DOM elements
    const doublePointsCount = document.getElementById('double-points-count');
    const noPenaltyCount = document.getElementById('no-penalty-count');
    const luckyStreakCount = document.getElementById('lucky-streak-count');
    const useDoublePointsButton = document.getElementById('use-double-points');
    const useNoPenaltyButton = document.getElementById('use-no-penalty');
    const useLuckyStreakButton = document.getElementById('use-lucky-streak');
    const activeItemIndicator = document.getElementById('active-item-indicator');
    const freeRollsIndicator = document.getElementById('free-rolls-indicator');
    const freeRollsCountElement = document.getElementById('free-rolls-count');
    
    // Game state
    let currentScore = 10; // Initial score
    let currentTier = 0; // Initial dice tier (0 = Empty)
    let gameOver = false; // Game over flag
    let rollCount = 0; // Number of dice rolls
    let luckyRollsRemaining = 0; // Number of lucky rolls remaining
    let isRolling = false; // Whether dice is currently rolling
    let currentSafetyTimeout = null; // Stores the current safety timeout ID
    
    // Item system
    let doublePointsCards = 0; // Number of double points cards
    let noPenaltyCards = 0; // Number of no penalty cards
    let luckyStreakCards = 0; // Number of lucky streak cards
    let freeRolls = 0; // Number of free rolls available
    let activeItems = { // Currently active items
      double: 0, // Number of active double points cards
      noPenalty: false // Whether no penalty card is active
    };
    
    // Dice tiers configuration
    const diceTiers = [
      { name: 'Empty', color: '#FFFFFF' },
      { name: 'Common', color: '#7EEF6D' },
      { name: 'Unusual', color: '#FFE65D' },
      { name: 'Rare', color: '#4d52e3' },
      { name: 'Epic', color: '#861FDE' },
      { name: 'Legendary', color: '#DE1F1F' },
      { name: 'Mythic', color: '#1fdbde' },
      { name: 'Ultra', color: '#ff2b75' },
      { name: 'Super', color: '#2bffa3' },
      { name: 'Unique', color: '#555555' }
    ];
    
    // Initialize 3D dice
    function initializeDice() {
      console.log('Initializing dice...');
      // Create 6 faces for the dice
      const faces = [1, 2, 3, 4, 5, 6];
      
      faces.forEach(faceNumber => {
        const face = document.createElement('div');
        face.className = `dice-face face-${faceNumber}`;
        
        // Add dots to the face based on the number
        for (let i = 0; i < faceNumber; i++) {
          const dot = document.createElement('div');
          dot.className = 'dot';
          face.appendChild(dot);
        }
        
        diceElement.appendChild(face);
        console.log(`Added face ${faceNumber}`);
      });
      
      console.log('Dice initialized with faces:', diceElement.children.length);
      
      // Set initial position to show face 1 clearly
      diceElement.style.transform = 'rotateX(0deg) rotateY(0deg)';
    }
    
    // Get random rotation values for the dice
    function getRandomRotation() {
      // Determine which face we want to show
      const targetFace = Math.floor(Math.random() * 6) + 1;
      
      // Get current rotation from dice element
      const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
      const matrix = new DOMMatrix(currentTransform);
      
      // Extract current rotation angles
      let currentX = 0, currentY = 0;
      
      // If transform is not identity matrix, extract rotation
      if (currentTransform !== 'none') {
        // Calculate rotation from matrix
        currentX = Math.atan2(matrix.b, matrix.a) * (180 / Math.PI);
        currentY = Math.atan2(-matrix.c, matrix.f) * (180 / Math.PI);
      }
      
      // Set target rotation based on target face
      // These values are precisely calibrated to show the correct face
      let targetX = 0, targetY = 0;
      switch(targetFace) {
        case 1: // Front face (Z+) - visible when no rotation
          targetX = 0;
          targetY = 0;
          break;
        case 2: // Left face (X-) - visible when Y rotated 270 degrees
          targetX = 0;
          targetY = 270;
          break;
        case 3: // Back face (Z-) - visible when Y rotated 180 degrees
          targetX = 0;
          targetY = 180;
          break;
        case 4: // Right face (X+) - visible when Y rotated 90 degrees
          targetX = 0;
          targetY = 90;
          break;
        case 5: // Top face (Y-) - visible when X rotated -90 degrees
          targetX = -90;
          targetY = 0;
          break;
        case 6: // Bottom face (Y+) - visible when X rotated 90 degrees
          targetX = 90;
          targetY = 0;
          break;
      }
      
      // Calculate the shortest path to the target rotation
      // This prevents large rotation values from accumulating
      let diffX = targetX - currentX;
      let diffY = targetY - currentY;
      
      // Normalize the difference to the range [-180, 180] to find the shortest path
      diffX = ((diffX + 180) % 360) - 180;
      diffY = ((diffY + 180) % 360) - 180;
      
      // Add multiple full rotations for spinning effect (2-4 full rotations)
      const fullRotations = 2 + Math.floor(Math.random() * 3);
      
      // Calculate final rotation with full spins
      // We add full rotations in the direction of the shortest path
      const spinDirectionX = diffX >= 0 ? 1 : -1;
      const spinDirectionY = diffY >= 0 ? 1 : -1;
      
      const finalX = currentX + diffX + spinDirectionX * fullRotations * 360;
      const finalY = currentY + diffY + spinDirectionY * fullRotations * 360;
      
      // Add a tiny bit of randomness to make it look more natural
      // But not enough to change which face is visible
      const randomX = (Math.random() - 0.5) * 2;
      const randomY = (Math.random() - 0.5) * 2;
      
      return {
        x: finalX + randomX,
        y: finalY + randomY,
        targetFace: targetFace // Return the target face so we don't have to recalculate it
      };
    }
    
    // Roll the dice function
    function rollDice() {
      // Check if already rolling
      if (isRolling) {
        console.log('Ignoring roll request - already rolling');
        return;
      }
      
      // Check if game is over
      if (gameOver) {
        showGameMessage('Game over! Click "Play Again" to restart.', 'text-red-500');
        return;
      }
      
      // Check if there are free rolls available
      const isFreeRoll = freeRolls > 0;
      
      // Check if in lucky streak mode
      const isLuckyRoll = luckyRollsRemaining > 0;
      
      // Increment roll count only if not a free roll (lucky rolls will be handled based on result)
      if (!isFreeRoll) {
        rollCount++;
        console.log(`Roll count: ${rollCount}`);
      } else {
        // Decrement free rolls count
        freeRolls--;
        updateFreeRollsDisplay();
        console.log(`Free roll used. Remaining free rolls: ${freeRolls}`);
      }
      
      // Update roll count display
      if (rollCountValue) {
        rollCountValue.textContent = rollCount;
      }
      
      console.log('Rolling dice...');
      console.log('Button state before disable:', rollButton.disabled);
      
      // Set rolling state and disable button during animation
      isRolling = true;
      rollButton.disabled = true;
      rollButton.classList.add('opacity-70', 'cursor-not-allowed');
      
      // Disable other interactive elements during roll
      upgradeButton.disabled = true;
      upgradeButton.classList.add('opacity-70', 'cursor-not-allowed');
      useDoublePointsButton.disabled = true;
      useNoPenaltyButton.disabled = true;
      useLuckyStreakButton.disabled = true;
      
      // Disable color options during roll
      colorOptions.forEach(option => {
        option.disabled = true;
      });
      
      console.log('Button state after disable:', rollButton.disabled);
      
      // Hide result display
      resultDisplay.classList.add('hidden');
      
      // Reset dice display height - use Tailwind class instead of inline style
      const diceDisplay = document.getElementById('dice-display');
      if (diceDisplay) {
        // Ensure the height class is applied to prevent layout shifts during animation
        diceDisplay.classList.add('h-48');
      }
      
      try {
        // Set animation duration
        const duration = 2000; // Fixed duration for consistent experience
        
        // Get random rotation values for the final position
        const rotationData = getRandomRotation();
        console.log('Rotation data:', rotationData);
        console.log('Target face:', rotationData.targetFace);
        
        // Animate the dice using JavaScript for more control
        animateDice(duration, rotationData, { isFreeRoll, isLuckyRoll });
        
        // Set a safety timeout to ensure button is re-enabled even if something goes wrong
        const safetyTimeoutId = setTimeout(() => {
          if (rollButton.disabled && isRolling) {
            console.warn('Safety timeout: Re-enabling roll button');
            enableRollButton();
          }
        }, duration + 1000); // Add 1 second buffer
        
        // Store timeout ID to clear it later if animation completes normally
        currentSafetyTimeout = safetyTimeoutId;
      } catch (error) {
        console.error('Error during dice roll:', error);
        // Re-enable button if there's an error
        enableRollButton();
        showGameMessage('An error occurred during the dice roll. Please try again.', 'text-red-500');
      }
    }
    
    // Animate the dice with spin animation
    function animateDice(duration, rotationData, rollContext) {
      console.log('Animate dice called with rotationData:', rotationData);
      console.log('Roll context:', rollContext);
      const startTime = performance.now();
      const finalRotation = rotationData;
      
      // Get current rotation from dice element
      const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
      const matrix = new DOMMatrix(currentTransform);
      
      // Extract current rotation angles
      let startX = 0, startY = 0;
      
      // If transform is not identity matrix, extract rotation
      if (currentTransform !== 'none') {
        // Calculate rotation from matrix
        startX = Math.atan2(matrix.b, matrix.a) * (180 / Math.PI);
        startY = Math.atan2(-matrix.c, matrix.f) * (180 / Math.PI);
      }
      
      // Function to handle each animation frame
      function animate(currentTime) {
        const elapsedTime = currentTime - startTime;
        const progress = Math.min(elapsedTime / duration, 1);
        
        // Apply easing function for smooth, natural animation
        const easedProgress = easeOutCubic(progress);
        
        // Calculate current rotation - smooth continuous rotation
        const currentX = startX + (finalRotation.x - startX) * easedProgress;
        const currentY = startY + (finalRotation.y - startY) * easedProgress;
        
        // Spin animation: rotate in place
        diceElement.style.transform = `rotateX(${currentX}deg) rotateY(${currentY}deg)`;
        
        // Continue animation if not complete
        if (progress < 1) {
          requestAnimationFrame(animate);
        } else {
          // Animation complete - ensure we're at the exact target rotation
          diceElement.style.transform = `rotateX(${finalRotation.x}deg) rotateY(${finalRotation.y}deg)`;
          
          // Finalize immediately after animation completes
          console.log('Animation complete, finalizing...');
          // Double-check that the transform has been applied
          const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
          console.log('Current transform after animation:', currentTransform);
          console.log('Calling finalizeAnimation...');
          finalizeAnimation(finalRotation, rollContext);
        }
      }
      
      // Start the animation
      requestAnimationFrame(animate);
    }
    
    // Helper function to normalize angles to the range [-180, 180]
    function normalizeAngle(angle) {
      angle = angle % 360;
      if (angle > 180) angle -= 360;
      if (angle < -180) angle += 360;
      return angle;
    }
    
    // Easing function for smooth, natural animation with gentle acceleration and deceleration
    // Uses a cubic easing function that starts slow, accelerates, then slows down at the end
    function easeOutCubic(t) {
      return 1 - Math.pow(1 - t, 3);
    }
    
    // Calculate score change based on dice roll result
    function calculateScoreChange(result) {
      let baseChange = 0;
      
      switch(result) {
        case 1:
        case 2:
          baseChange = -1;
          break;
        case 3:
          baseChange = 0;
          break;
        case 4:
          baseChange = 1;
          break;
        case 5:
          baseChange = 2;
          break;
        case 6:
          baseChange = 3;
          break;
        default:
          baseChange = 0;
      }
      
      // Apply current tier multiplier
      // If losing points (baseChange < 0), use multiplier of 1 instead of tier multiplier
      const tierMultiplier = 1 + currentTier / 10;
      let finalChange;
      
      if (baseChange < 0) {
        // For point loss, use multiplier of 1 regardless of tier
        finalChange = baseChange * 1;
      } else {
        // For point gain or neutral, use tier multiplier
        finalChange = baseChange * tierMultiplier;
      }
      
      // Apply active item effects
      const itemsUsed = {
        double: activeItems.double,
        noPenalty: activeItems.noPenalty
      };
      
      // Apply no penalty card first
      if (activeItems.noPenalty && baseChange < 0) {
        finalChange = 0;
      }
      
      // Apply double points cards
      if (activeItems.double > 0) {
        finalChange = finalChange * Math.pow(2, activeItems.double);
      }
      
      // Round to 2 decimal places to avoid floating point precision issues
      finalChange = Math.round(finalChange * 100) / 100;
      
      return {
        baseChange: baseChange,
        finalChange: finalChange,
        itemsUsed: itemsUsed,
        tierMultiplier: tierMultiplier
      };
    }
    
    // Enable roll button
    function enableRollButton() {
      console.log('Button state before enable:', rollButton.disabled);
      
      // Clear any existing safety timeout
      if (currentSafetyTimeout !== null) {
        clearTimeout(currentSafetyTimeout);
        currentSafetyTimeout = null;
        console.log('Cleared existing safety timeout');
      }
      
      // Directly enable the button
      rollButton.disabled = false;
      rollButton.classList.remove('opacity-70', 'cursor-not-allowed');
      
      // Re-enable other interactive buttons based on their conditions
      updateUpgradeCostDisplay(); // This will enable/disable upgrade button based on score
      updateItemsDisplay(); // This will enable/disable item buttons based on availability
      
      // Re-enable color options
      colorOptions.forEach((option, index) => {
        // Only enable unlocked color options (up to currentTier)
        if (index <= currentTier) {
          option.disabled = false;
          option.classList.remove('locked', 'opacity-50', 'cursor-not-allowed');
        } else {
          option.disabled = true;
          option.classList.add('locked', 'opacity-50', 'cursor-not-allowed');
        }
      });
      
      console.log('Button state after enable:', rollButton.disabled);
      
      // Double-check and force enable if needed
      if (rollButton.disabled) {
        console.warn('Forcing button enable');
        setTimeout(() => {
          rollButton.disabled = false;
          rollButton.classList.remove('opacity-70', 'cursor-not-allowed');
          console.log('Button state after forced enable:', rollButton.disabled);
        }, 100);
      }
      
      // Update rolling state
      isRolling = false;
    }
    
    // Finalize the animation and show result
    function finalizeAnimation(rotationData, rollContext) {
      console.log('=== Finalize animation called ===');
      console.log('Current time:', new Date().toISOString().split('T')[1]);
      console.log('Rotation data:', rotationData);
      console.log('Roll context:', rollContext);
      
      const finalRotation = rotationData;
      const isFreeRoll = rollContext && rollContext.isFreeRoll || false;
      const isLuckyRoll = rollContext && rollContext.isLuckyRoll || false;
      
      // Use the target face directly instead of recalculating
      const result = finalRotation.targetFace;
      console.log(`Final result: ${result} (should show face ${result})`);
      
      // Verify dice is in the correct position
      const currentTransform = window.getComputedStyle(diceElement).getPropertyValue('transform');
      console.log('Current dice transform:', currentTransform);
      
      // Show result display
      console.log('Showing result display...');
      resultValue.textContent = result;
      resultDisplay.classList.remove('hidden');
      
      // Add shine effect to result
      resultDisplay.classList.add('result-shine');
      setTimeout(() => {
        resultDisplay.classList.remove('result-shine');
      }, 500);
      
      // Calculate and update score
      console.log('Calculating score change...');
      const scoreChangeData = calculateScoreChange(result);
      console.log('Score change data:', scoreChangeData);
      
      currentScore += scoreChangeData.finalChange;
      console.log('Updated score:', currentScore);
      
      // Update score display with animation
      console.log('Updating score display...');
      updateScoreDisplay(scoreChangeData);
      
      // Enable button
      console.log('Enabling roll button...');
      enableRollButton();
      
      // Add to history - include whether it was a free roll or lucky roll
      addToHistory(result, scoreChangeData, isFreeRoll, isLuckyRoll);
      
      // Check if reached the Unique dice
      if (currentTier === diceTiers.length - 1) {
        showGameMessage('Congratulations! You obtained the Unique dice!', 'text-green-500');
        gameOver = true;
        createConfetti();
      }
      
      // Create confetti effect if result is 6
      if (result === 6) {
        createConfetti();
      }
      
      // Debug: log final state
      console.log(`Final precise rotation: X=${finalRotation.x}°, Y=${finalRotation.y}°`);
      console.log(`Displayed result: ${result}`);
      console.log(`Score change: ${scoreChangeData.finalChange}, Current score: ${currentScore}`);
      console.log('=== finalizeAnimation completed ===');
    }
    
    // Update score display with animation
    function updateScoreDisplay(scoreChangeData) {
      console.log('=== updateScoreDisplay called ===');
      console.log('Score change data:', scoreChangeData);
      
      const change = scoreChangeData.finalChange;
      const baseChange = scoreChangeData.baseChange;
      const itemsUsed = scoreChangeData.itemsUsed;
      const tierMultiplier = scoreChangeData.tierMultiplier;
      
      console.log('Change:', change, 'Base change:', baseChange, 'Items used:', itemsUsed);
      
      // Update the score value - round to 2 decimal places
      currentScore = Math.round(currentScore * 100) / 100;
      scoreValue.textContent = currentScore;
      console.log('Score value updated to:', currentScore);
      
      // Clear previous score change display
      scoreChange.textContent = '';
      scoreChange.className = 'ml-2 text-sm font-normal';
      console.log('Cleared previous score change display');
      
      // Show score change with appropriate styling
      if (change > 0) {
        scoreChange.textContent = `+${change}`;
        scoreChange.classList.add('score-increase');
        console.log('Score increase:', change);
      } else if (change < 0) {
        scoreChange.textContent = `${change}`;
        scoreChange.classList.add('score-decrease');
        console.log('Score decrease:', change);
      } else {
        scoreChange.textContent = `±0`;
        scoreChange.classList.add('score-neutral');
        console.log('Score neutral');
      }
      
      // Show item effect message if items were used
      if (itemsUsed && (itemsUsed.double > 0 || itemsUsed.noPenalty)) {
        // Create container for item effects
        const itemEffectsContainer = document.createElement('div');
        itemEffectsContainer.className = 'flex flex-wrap gap-2 mt-1';
        
        // Add tier multiplier effect if applicable
        if (tierMultiplier !== 1) {
          const tierEffect = document.createElement('div');
          tierEffect.className = 'text-xs text-purple-500';
          tierEffect.textContent = `Tier Multiplier ×${tierMultiplier.toFixed(1)}!`;
          itemEffectsContainer.appendChild(tierEffect);
        }
        
        // Add no penalty effect
        if (itemsUsed.noPenalty) {
          const noPenaltyEffect = document.createElement('div');
          noPenaltyEffect.className = 'text-xs text-blue-500';
          noPenaltyEffect.textContent = `No Penalty! (Score protected from ${baseChange < 0 ? baseChange : 0} loss)`;
          itemEffectsContainer.appendChild(noPenaltyEffect);
        }
        
        // Add double points effect
        if (itemsUsed.double > 0) {
          const doublePointsEffect = document.createElement('div');
          doublePointsEffect.className = 'text-xs text-green-500';
          
          // Calculate multiplier
          const multiplier = Math.pow(2, itemsUsed.double);
          let calculationText = `${baseChange}`;
          
          // Apply tier multiplier for display
          let displayChange = baseChange * tierMultiplier;
          
          // Apply no penalty first for display
          if (itemsUsed.noPenalty && baseChange < 0) {
            displayChange = 0;
            calculationText = `(${baseChange} × ${tierMultiplier.toFixed(1)} → 0)`;
          } else if (tierMultiplier !== 1) {
            calculationText = `(${baseChange} × ${tierMultiplier.toFixed(1)} = ${displayChange.toFixed(2)})`;
          }
          
          // Show multiplication steps if multiple double cards used
          if (itemsUsed.double > 1) {
            for (let i = 0; i < itemsUsed.double; i++) {
              calculationText += ` × 2`;
            }
            calculationText += ` = ${(displayChange * multiplier).toFixed(2)}`;
          } else {
            calculationText += ` × 2 = ${(displayChange * multiplier).toFixed(2)}`;
          }
          
          doublePointsEffect.textContent = `Double Points ×${itemsUsed.double}! (${calculationText})`;
          itemEffectsContainer.appendChild(doublePointsEffect);
        }
        
        // Add to score display
        scoreDisplay.appendChild(itemEffectsContainer);
        
        // Remove after animation
        setTimeout(() => {
          scoreDisplay.removeChild(itemEffectsContainer);
        }, 1000);
      }
      
      // Reset score change display after animation completes
      setTimeout(() => {
        scoreChange.textContent = '';
      }, 1000);
      
      // Clear active items after score update
      console.log('Checking if items need to be cleared...');
      if (itemsUsed && (itemsUsed.double > 0 || itemsUsed.noPenalty)) {
        console.log('Clearing active items...');
        clearActiveItems();
        console.log('Updating items display...');
        updateItemsDisplay();
      }
      
      // Check game state after score update
      console.log('Checking game state...');
      checkGameState();
      
      // Update upgrade button state
      updateUpgradeCostDisplay();
      
      console.log('=== updateScoreDisplay completed ===');
    }
    
    // Handle dice upgrade
    function upgradeDice() {
      // Check if game is already over
      if (gameOver) {
        showGameMessage('Game over! Click "Play Again" to restart.', 'text-red-500');
        return;
      }
      
      // Check if already at maximum tier
      if (currentTier >= diceTiers.length - 1) {
        // If not already game over, end the game with win condition
        if (!gameOver) {
          gameOver = true;
          endGame(true);
        } else {
          showGameMessage('Congratulations! You already have the Unique dice!', 'text-green-500');
        }
        return;
      }
      
      // Calculate required score for upgrade (5 + currentTier)
      const requiredScore = 5 + currentTier;
      
      // Check if enough score to upgrade
      if (currentScore < requiredScore) {
        showGameMessage(`Not enough score to upgrade! Need ${requiredScore} points.`, 'text-orange-500');
        // Add shake animation to score display
        scoreDisplay.classList.add('animate-shake');
        setTimeout(() => {
          scoreDisplay.classList.remove('animate-shake');
        }, 500);
        return;
      }
      
      // Deduct score for upgrade
      currentScore -= requiredScore;
      // Round to 2 decimal places
      currentScore = Math.round(currentScore * 100) / 100;
      
      // Update score display
      scoreValue.textContent = currentScore;
      showScoreChange(-requiredScore);
      
      // Increase tier
      currentTier++;
      
      // Update highest unlocked tier
      if (currentTier > highestUnlockedTier) {
        highestUnlockedTier = currentTier;
      }
      
      // Update current tier display
      currentTierDisplay.innerHTML = `Current Dice: <span class="font-semibold text-primary">${diceTiers[currentTier].name}</span>`;
      
      // Update tier multiplier display
      updateTierMultiplierDisplay();
      
      // Update current rarity display
      updateCurrentRarityDisplay();
      
      // Unlock the new dice color
      unlockDiceColor(currentTier);
      
      // Update color selection UI
      updateColorSelection(currentTier);
      
      // Update upgrade cost display
      updateUpgradeCostDisplay();
      
      // Change to the new dice color
      console.log(`Changing dice color to ${diceTiers[currentTier].color} (${diceTiers[currentTier].name})`);
      changeDiceColor(diceTiers[currentTier].color);
      
      // Check if this upgrade reached the maximum tier
      checkGameState();
      
      // Randomly get an item
      const itemChance = Math.random();
      if (itemChance < 0.30) { // 30% chance to get double points card
        doublePointsCards++;
      } else if (itemChance < 0.60) { // 30% chance to get no penalty card
        noPenaltyCards++;
      } else if (itemChance < 0.70) { // 10% chance to get lucky streak card
        luckyStreakCards++;
      } else { // 30% chance to get nothing
        // Do nothing
      }
      
      // Update items display to show new counts
      updateItemsDisplay();
      
      // Update items display
      updateItemsDisplay();
      
      // Check if reached the Unique dice
      if (currentTier === diceTiers.length - 1) {
        showGameMessage('Congratulations! You obtained the Unique dice!', 'text-green-500');
        gameOver = true;
        createConfetti();
      }
      
      // Add to history
      addToHistory('UPGRADE', -requiredScore);
      
      // Add item to history if obtained
      if (itemChance < 0.30) {
        addToHistory('ITEM', 'Double Points Card');
      } else if (itemChance < 0.60) {
        addToHistory('ITEM', 'No Penalty Card');
      } else if (itemChance < 0.70) {
        addToHistory('ITEM', 'Lucky Streak Card');
      }
      
      // Check game state after upgrade
      checkGameState();
    }
    
    // Show score change temporarily
    function showScoreChange(change) {
      scoreChange.textContent = change > 0 ? `+${change}` : change;
      scoreChange.className = `ml-2 text-sm font-normal ${change > 0 ? 'score-increase' : 'score-decrease'}`;
      
      setTimeout(() => {
        scoreChange.textContent = '';
      }, 1000);
    }
    
    // Unlock a dice color option
    function unlockDiceColor(tierIndex) {
      if (tierIndex >= 0 && tierIndex < colorOptions.length) {
        const option = colorOptions[tierIndex];
        // Show particle effect on the lock before unlocking
        createLockParticles(option);
        // Add a small delay to show the particles before unlocking
        setTimeout(() => {
          option.disabled = false;
          option.classList.remove('locked', 'opacity-50', 'cursor-not-allowed');
          
          // Update highest unlocked tier if this is higher
          if (tierIndex > highestUnlockedTier) {
            highestUnlockedTier = tierIndex;
            
            // Automatically switch to the highest unlocked tier
            currentTier = highestUnlockedTier;
            
            // Change dice color to match the new tier
            const color = option.getAttribute('data-color');
            changeDiceColor(color);
            
            // Update displays
            currentTierDisplay.innerHTML = `Current Dice: <span class="font-semibold text-primary">${diceTiers[currentTier].name}</span>`;
            updateCurrentRarityDisplay();
            updateTierMultiplierDisplay();
            
            // Show message about the new tier
            showGameMessage(`Unlocked ${diceTiers[tierIndex].name} Dice!`, 'text-green-500');
          }
        }, 300);
      }
    }
    
    // Show game message
    function showGameMessage(message, className) {
      gameMessageDisplay.textContent = message;
      gameMessageDisplay.className = `mt-4 text-center font-semibold ${className}`;
      gameMessageDisplay.classList.remove('hidden');
      
      // Hide message after 3 seconds
      setTimeout(() => {
        if (!gameOver) {
          gameMessageDisplay.classList.add('hidden');
        }
      }, 3000);
    }
    
    // Check game state (win/lose conditions)
    function checkGameState() {
      console.log('=== checkGameState called ===');
      console.log('Current score:', currentScore, 'Game over:', gameOver);
      
      // Check if score is negative (lose condition)
      if (currentScore < 0 && !gameOver) {
        console.log('Score is negative, ending game...');
        gameOver = true;
        endGame(false);
      }
      
      // Check if reached Unique dice (win condition)
      if (currentTier === diceTiers.length - 1 && !gameOver) {
        console.log('Reached Unique dice, ending game...');
        gameOver = true;
        endGame(true);
        
        // Check if this is a new record
        setTimeout(() => {
          checkWinRecord();
        }, 1000);
      }
      
      // Check if score is low (warning)
      if (currentScore >= 0 && currentScore <= 5 && !gameOver) {
        showLowScoreWarning();
      }
      
      console.log('=== checkGameState completed ===');
    }
    
    // Update items display
    function updateItemsDisplay() {
      console.log('=== updateItemsDisplay called ===');
      console.log('Current item counts:');
      console.log('doublePointsCards:', doublePointsCards);
      console.log('noPenaltyCards:', noPenaltyCards);
      console.log('luckyStreakCards:', luckyStreakCards);
      console.log('gameOver:', gameOver);
      
      // Update counts
      if (doublePointsCount) doublePointsCount.textContent = doublePointsCards;
      if (noPenaltyCount) noPenaltyCount.textContent = noPenaltyCards;
      if (luckyStreakCount) luckyStreakCount.textContent = luckyStreakCards;
      
      // Enable/disable buttons based on available items
      useDoublePointsButton.disabled = doublePointsCards <= 0 || gameOver;
      useNoPenaltyButton.disabled = noPenaltyCards <= 0 || activeItems.noPenalty || gameOver;
      useLuckyStreakButton.disabled = luckyStreakCards <= 0 || luckyRollsRemaining > 0 || gameOver;
      
      console.log('Button states after update:');
      console.log('useDoublePointsButton.disabled:', useDoublePointsButton.disabled);
      console.log('useNoPenaltyButton.disabled:', useNoPenaltyButton.disabled);
      console.log('useLuckyStreakButton.disabled:', useLuckyStreakButton.disabled);
      
      // Update free rolls display
      updateFreeRollsDisplay();
      
      // Update lucky rolls display
      updateLuckyRollsDisplay();
    }
    
    // Update free rolls display
    function updateFreeRollsDisplay() {
      if (freeRolls > 0) {
        freeRollsCountElement.textContent = freeRolls;
        freeRollsIndicator.classList.remove('hidden');
      } else {
        freeRollsIndicator.classList.add('hidden');
      }
    }
    
    // Update upgrade cost display and button state
    function updateUpgradeCostDisplay() {
      if (currentTier >= diceTiers.length - 1) {
        // Already at maximum tier
        upgradeCost.textContent = '(Max Tier)';
        upgradeButton.disabled = true;
        upgradeButton.classList.add('opacity-70', 'cursor-not-allowed');
      } else {
        const requiredScore = 5 + currentTier;
        upgradeCost.textContent = `(Cost: ${requiredScore})`;
        
        // Update button state based on available score
        if (currentScore >= requiredScore && !gameOver) {
          upgradeButton.disabled = false;
          upgradeButton.classList.remove('opacity-70', 'cursor-not-allowed');
        } else {
          upgradeButton.disabled = true;
          upgradeButton.classList.add('opacity-70', 'cursor-not-allowed');
        }
      }
    }
    
    // Use double points card
    function useDoublePointsCard() {
      if (doublePointsCards > 0 && !gameOver) {
        activeItems.double++;
        doublePointsCards--;
        
        // Update UI
        updateItemsDisplay();
        showActiveItemIndicator();
        
        // Show message
        showGameMessage('Double Points Card activated! Next roll will double your score change.', 'text-green-500');
      }
    }
    
    // Use no penalty card
    function useNoPenaltyCard() {
      if (noPenaltyCards > 0 && !activeItems.noPenalty && !gameOver) {
        activeItems.noPenalty = true;
        noPenaltyCards--;
        
        // Update UI
        updateItemsDisplay();
        showActiveItemIndicator();
        
        // Show message
        showGameMessage('No Penalty Card activated! Next roll won\'t lose points.', 'text-blue-500');
      }
    }
    
    // Use lucky streak card
    function useLuckyStreakCard() {
      if (luckyStreakCards > 0 && !gameOver && luckyRollsRemaining === 0) {
        luckyRollsRemaining = 3;
        luckyStreakCards--;
        
        // Update UI
        updateItemsDisplay();
        updateLuckyRollsDisplay();
        
        // Show message
        showGameMessage('Lucky Streak Card activated! Next 3 rolls of 1 or 2 won\'t count!', 'text-yellow-500');
        
        // Add to history
        addToHistory('ITEM USE', 'Lucky Streak Card');
      } else if (luckyRollsRemaining > 0) {
        // Show message if already has active lucky streak
        showGameMessage('You already have an active Lucky Streak!', 'text-yellow-500');
      }
    }
    
    // Update lucky rolls display
    function updateLuckyRollsDisplay() {
      if (luckyRollsRemaining > 0) {
        // Check if indicator exists, if not create it
        let luckyRollsIndicator = document.getElementById('lucky-rolls-indicator');
        if (!luckyRollsIndicator) {
          luckyRollsIndicator = document.createElement('div');
          luckyRollsIndicator.id = 'lucky-rolls-indicator';
          luckyRollsIndicator.className = 'mt-3 text-center';
          
          // Insert after free rolls indicator
          const freeRollsIndicator = document.getElementById('free-rolls-indicator');
          if (freeRollsIndicator) {
            freeRollsIndicator.parentNode.insertBefore(luckyRollsIndicator, freeRollsIndicator.nextSibling);
          } else {
            // Fallback: insert after active item indicator
            const activeItemIndicator = document.getElementById('active-item-indicator');
            if (activeItemIndicator) {
              activeItemIndicator.parentNode.insertBefore(luckyRollsIndicator, activeItemIndicator.nextSibling);
            } else {
              // Fallback: insert after items display
              const itemsDisplay = document.getElementById('items-display');
              if (itemsDisplay) {
                itemsDisplay.parentNode.insertBefore(luckyRollsIndicator, itemsDisplay.nextSibling);
              }
            }
          }
        }
        
        // Update content
        luckyRollsIndicator.innerHTML = `
          <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
            <i class="fa fa-star mr-1" style="color: #f59e0b;"></i>
            <span>Lucky Rolls: <span id="lucky-rolls-count">${luckyRollsRemaining}</span> (1-2 won't count)</span>
          </span>
        `;
        
        // Show indicator
        luckyRollsIndicator.classList.remove('hidden');
      } else {
        // Remove indicator if exists
        const luckyRollsIndicator = document.getElementById('lucky-rolls-indicator');
        if (luckyRollsIndicator) {
          luckyRollsIndicator.classList.add('hidden');
        }
      }
    }
    
    // Show active item indicator
    function showActiveItemIndicator() {
      // Clear previous content
      activeItemIndicator.innerHTML = '';
      
      // Check if any items are active
      if (activeItems.double === 0 && !activeItems.noPenalty) {
        activeItemIndicator.className = 'mt-3 text-center hidden';
        return;
      }
      
      // Create container for active items
      const itemsContainer = document.createElement('div');
      itemsContainer.className = 'flex flex-wrap justify-center gap-2';
      
      // Add double points cards indicator
      if (activeItems.double > 0) {
        const doublePointsIndicator = document.createElement('span');
        doublePointsIndicator.className = 'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800';
        doublePointsIndicator.innerHTML = `
          <i class="fa fa-plus-circle mr-1" style="color: #10b981;"></i>
          <span>Double Points ×${activeItems.double}</span>
        `;
        itemsContainer.appendChild(doublePointsIndicator);
      }
      
      // Add no penalty card indicator
      if (activeItems.noPenalty) {
        const noPenaltyIndicator = document.createElement('span');
        noPenaltyIndicator.className = 'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800';
        noPenaltyIndicator.innerHTML = `
          <i class="fa fa-shield mr-1" style="color: #3b82f6;"></i>
          <span>No Penalty</span>
        `;
        itemsContainer.appendChild(noPenaltyIndicator);
      }
      
      // Add indicators to container
      activeItemIndicator.appendChild(itemsContainer);
      activeItemIndicator.className = 'mt-3 text-center';
    }
    
    // Clear active items
    function clearActiveItems() {
      activeItems = {
        double: 0,
        noPenalty: false
      };
      showActiveItemIndicator();
    }
    
    // End the game and display appropriate message
    function endGame(isWin) {
      console.log('=== endGame called ===');
      console.log('Is win:', isWin, 'Current score:', currentScore);
      
      // Disable all interactive elements
      rollButton.disabled = true;
      upgradeButton.disabled = true;
      rollButton.classList.add('opacity-70', 'cursor-not-allowed');
      upgradeButton.classList.add('opacity-70', 'cursor-not-allowed');
      
      // Disable all interactive elements but preserve their locked/unlocked state
      colorOptions.forEach(option => {
        option.disabled = true;
        
        // For unlocked colors, we still want to show them as disabled but not locked
        // So we'll add a semi-transparent overlay effect
        if (!option.classList.contains('locked')) {
          option.classList.add('opacity-50', 'cursor-not-allowed');
          option.style.opacity = '0.7';
        }
      });
      
      // Debug: Log color options state at game end
      console.log('Color options state at game end:');
      colorOptions.forEach((option, index) => {
        console.log(`Option ${index}:`, {
          locked: option.classList.contains('locked'),
          disabled: option.disabled,
          opacity: option.style.opacity,
          position: option.style.position
        });
      });
      
      // Debug: Log color options state at game end
      console.log('Color options state at game end:');
      colorOptions.forEach((option, index) => {
        console.log(`Option ${index}:`, {
          locked: option.classList.contains('locked'),
          disabled: option.disabled,
          opacity: option.style.opacity,
          position: option.style.position
        });
      });
      
      // Disable item buttons
      useDoublePointsButton.disabled = true;
      useNoPenaltyButton.disabled = true;
      useLuckyStreakButton.disabled = true;
      
      // Hide active indicators
      activeItemIndicator.classList.add('hidden');
      const luckyRollsIndicator = document.getElementById('lucky-rolls-indicator');
      if (luckyRollsIndicator) {
        luckyRollsIndicator.classList.add('hidden');
      }
      
      // Create game over message element
      const gameOverMessage = document.createElement('div');
      gameOverMessage.className = `mt-4 p-4 rounded-lg text-center font-bold ${isWin ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}`;
      
      // Format final score to 2 decimal places
      const formattedScore = currentScore.toFixed(2);
      
      if (isWin) {
        // Save win record immediately when game is won
        saveWinRecord(rollCount);
        
        gameOverMessage.innerHTML = `
          <div class="text-2xl mb-2">Congratulations!</div>
          <p>You won the game!</p>
          <p>You obtained the Unique dice!</p>
          <p class="mt-2 text-sm">Total Rolls: ${rollCount}</p>
          <button id="play-again" class="mt-4 bg-primary hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-full transition-all duration-300 transform hover:scale-105">
            <i class="fa fa-refresh mr-1"></i> Play Again
          </button>
        `;
        createConfetti();
      } else {
        gameOverMessage.innerHTML = `
          <div class="text-2xl mb-2">Game Over!</div>
          <p>Your score went negative.</p>
          <p>Better luck next time!</p>
          <p class="mt-2 text-sm">Final Score: ${formattedScore}</p>
          <p class="mt-1 text-sm">Total Rolls: ${rollCount}</p>
          <button id="play-again" class="mt-4 bg-primary hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-full transition-all duration-300 transform hover:scale-105">
            <i class="fa fa-refresh mr-1"></i> Play Again
          </button>
        `;
      }
      
      // Add restart button event listener
      gameOverMessage.querySelector('#play-again').addEventListener('click', () => {
        // If this was a win (obtained Unique dice), save the record
        if (isWin) {
          saveWinRecord(rollCount);
        }
        
        // Debug: Log color options state before reset
        console.log('Color options state before reset:');
        colorOptions.forEach((option, index) => {
          console.log(`Option ${index}:`, {
            locked: option.classList.contains('locked'),
            disabled: option.disabled,
            opacity: option.style.opacity,
            position: option.style.position
          });
        });
        
        // Reset game without reloading page
        resetGame();
      });
      
      // Replace game message display with game over message
      const gameMessageContainer = gameMessageDisplay.parentElement;
      gameMessageContainer.replaceChild(gameOverMessage, gameMessageDisplay);
      gameMessageDisplay = gameOverMessage;
      
      // Add game end to history
      addToHistory(isWin ? 'GAME WIN' : 'GAME OVER', 0);
      
      console.log('=== endGame completed ===');
    }
    
    // Show warning when score is low
    function showLowScoreWarning() {
      // Only show warning if not already showing
      if (gameMessageDisplay.classList.contains('hidden')) {
        showGameMessage('Warning: Low score! Risk of game over.', 'text-orange-500');
      }
    }
    
    // Update color selection UI to show the currently selected color
    function updateColorSelection(selectedIndex) {
      // Remove active state from all color options
      colorOptions.forEach(opt => opt.classList.remove('ring-2', 'ring-offset-2', 'ring-primary'));
      
      // Add active state to the selected color option
      if (selectedIndex >= 0 && selectedIndex < colorOptions.length) {
        colorOptions[selectedIndex].classList.add('ring-2', 'ring-offset-2', 'ring-primary');
      }
    }
    
    // Add result to history
    function addToHistory(result, scoreChangeData, isFreeRoll = false, isLuckyRoll = false) {
      const now = new Date();
      const timeString = now.toLocaleTimeString();
      
      // Determine score change display and color
      let scoreChangeText = '';
      let scoreChangeClass = '';
      let actionText = '';
      
      if (result === 'UPGRADE') {
        actionText = 'Upgraded dice';
        scoreChangeText = `${scoreChangeData}`;
        scoreChangeClass = 'text-red-500';
      } else if (result === 'ITEM') {
        actionText = `Received <span class="font-bold text-purple-500">${scoreChangeData}</span>`;
        scoreChangeText = '+1';
        scoreChangeClass = 'text-purple-500';
      } else if (result === 'GAME WIN' || result === 'GAME OVER') {
        actionText = result;
        scoreChangeText = '';
        scoreChangeClass = '';
      } else {
        const scoreChange = scoreChangeData.finalChange;
        const baseChange = scoreChangeData.baseChange;
        const itemsUsed = scoreChangeData.itemsUsed;
        
        actionText = `Rolled a <span class="font-bold text-primary">${result}</span>`;
        
        // Add free roll indicator if applicable
        if (isFreeRoll) {
          actionText += ` <span class="text-yellow-500">(Free Roll)</span>`;
        }
        
        // Add lucky roll indicator if applicable
        if (isLuckyRoll) {
          actionText += ` <span class="text-yellow-500">(Lucky Roll)</span>`;
        }
        
        // Add item effect indicators if applicable
        const activeItemsText = [];
        if (itemsUsed && itemsUsed.double > 0) {
          activeItemsText.push(`<span class="text-green-500">(Double Points ×${itemsUsed.double})</span>`);
        }
        if (itemsUsed && itemsUsed.noPenalty) {
          activeItemsText.push(`<span class="text-blue-500">(No Penalty)</span>`);
        }
        
        if (activeItemsText.length > 0) {
          actionText += ` ${activeItemsText.join(' ')}`;
        }
        
        if (scoreChange > 0) {
          scoreChangeText = `+${scoreChange}`;
          scoreChangeClass = 'text-green-500';
        } else if (scoreChange < 0) {
          scoreChangeText = `${scoreChange}`;
          scoreChangeClass = 'text-red-500';
        } else {
          scoreChangeText = '±0';
          scoreChangeClass = 'text-gray-500';
        }
        
        // Show base change if different from final change (items were used)
        if ((itemsUsed && (itemsUsed.double > 0 || itemsUsed.noPenalty)) && baseChange !== scoreChange) {
          scoreChangeText += ` <span class="text-xs">(Base: ${baseChange > 0 ? '+' : ''}${baseChange})</span>`;
        }
      }
      
      const listItem = document.createElement('li');
      listItem.className = 'py-1 border-b border-gray-100 grid grid-cols-3 gap-2 items-center';
      listItem.innerHTML = `
        <span class="col-span-1 text-gray-500">${timeString}</span>
        <span class="col-span-1">${actionText}</span>
        <span class="col-span-1 text-right font-medium ${scoreChangeClass}">${scoreChangeText}</span>
      `;
      
      historyList.prepend(listItem);
      
      // Keep only last 10 history items
      if (historyList.children.length > 10) {
        historyList.removeChild(historyList.lastChild);
      }
      
      // Ensure scroll is at the bottom
      const historyContainer = document.getElementById('history-container');
      if (historyContainer) {
        historyContainer.scrollTop = historyContainer.scrollHeight;
      }
    }
    
    // Create confetti effect
    function createConfetti() {
      const confettiContainer = document.createElement('div');
      confettiContainer.className = 'fixed inset-0 pointer-events-none overflow-hidden';
      document.body.appendChild(confettiContainer);
      
      // Create 50 confetti pieces
      for (let i = 0; i < 50; i++) {
        const confetti = document.createElement('div');
        confetti.className = 'confetti';
        
        // Random position
        const posX = Math.random() * 100;
        const delay = Math.random() * 3;
        const duration = 3 + Math.random() * 2;
        
        // Random colors
        const colors = ['#3b82f6', '#f97316', '#10b981', '#ef4444', '#8b5cf6'];
        const color = colors[Math.floor(Math.random() * colors.length)];
        
        confetti.style.left = `${posX}%`;
        confetti.style.backgroundColor = color;
        confetti.style.animationDelay = `${delay}s`;
        confetti.style.animationDuration = `${duration}s`;
        
        confettiContainer.appendChild(confetti);
      }
      
      // Remove confetti container after animation completes
      setTimeout(() => {
        document.body.removeChild(confettiContainer);
      }, 5000);
    }
    
    // Create particle effect on lock
    function createLockParticles(lockElement) {
      // Get lock element position
      const rect = lockElement.getBoundingClientRect();
      const centerX = rect.left + rect.width / 2;
      const centerY = rect.top + rect.height / 2;
      
      // Create particle container
      const particleContainer = document.createElement('div');
      particleContainer.className = 'absolute pointer-events-none';
      particleContainer.style.left = `${centerX}px`;
      particleContainer.style.top = `${centerY}px`;
      particleContainer.style.transform = 'translate(-50%, -50%)';
      document.body.appendChild(particleContainer);
      
      // Create 15 particles
      for (let i = 0; i < 15; i++) {
        const particle = document.createElement('div');
        particle.className = 'lock-particle';
        
        // Random direction and distance
        const angle = Math.random() * Math.PI * 2;
        const distance = 10 + Math.random() * 20;
        const tx = Math.cos(angle) * distance;
        const ty = Math.sin(angle) * distance;
        
        // Random color (use the color of the unlocked dice)
        const color = lockElement.style.backgroundColor;
        
        // Random animation duration
        const duration = 0.5 + Math.random() * 0.5;
        
        // Set particle styles
        particle.style.backgroundColor = color;
        particle.style.setProperty('--tx', `${tx}px`);
        particle.style.setProperty('--ty', `${ty}px`);
        particle.style.animation = `lock-particle ${duration}s ease-out forwards`;
        
        particleContainer.appendChild(particle);
      }
      
      // Remove particle container after animation completes
      setTimeout(() => {
        document.body.removeChild(particleContainer);
      }, 1000);
    }
    
    // Function to darken a color by a certain percentage
    function darkenColor(color, percent) {
      const hex = color.replace('#', '');
      let r = parseInt(hex.substr(0, 2), 16);
      let g = parseInt(hex.substr(2, 2), 16);
      let b = parseInt(hex.substr(4, 2), 16);
      
      // Darken each channel by the percentage
      r = Math.max(0, Math.floor(r * (1 - percent / 100)));
      g = Math.max(0, Math.floor(g * (1 - percent / 100)));
      b = Math.max(0, Math.floor(b * (1 - percent / 100)));
      
      // Convert back to hex
      const darkenedHex = '#' + 
        r.toString(16).padStart(2, '0') + 
        g.toString(16).padStart(2, '0') + 
        b.toString(16).padStart(2, '0');
      
      return darkenedHex;
    }
    
    // Change dice color function
    function changeDiceColor(color) {
      console.log(`changeDiceColor called with color: ${color}`);
      const faces = document.querySelectorAll('.dice-face');
      console.log(`Found ${faces.length} dice faces`);
      let dotColor, borderColor;
      
      // Special cases for high contrast
      if (color.toUpperCase() === '#FFFFFF') {
        // White dice - use black dots and light gray borders
        dotColor = '#000000';
        borderColor = '#CCCCCC';
      } else if (color.toUpperCase() === '#555555') {
        // Dark gray dice - use white dots and slightly lighter gray borders
        dotColor = '#FFFFFF';
        borderColor = '#777777';
      } else {
        // Calculate darker color for dots and borders (40% darker for more contrast)
        dotColor = darkenColor(color, 40);
        borderColor = darkenColor(color, 30); // Slightly lighter border than dots
      }
      
      faces.forEach(face => {
        // Set face background color
        face.style.backgroundColor = color;
        
        // Set face border color
        face.style.border = `3px solid ${borderColor}`;
        
        // Set dots color
        const dots = face.querySelectorAll('.dot');
        dots.forEach(dot => {
          dot.style.backgroundColor = dotColor;
          // Add slight border to dots for better definition
          dot.style.border = color.toUpperCase() === '#FFFFFF' ? '1px solid rgba(0, 0, 0, 0.2)' : '1px solid rgba(0, 0, 0, 0.1)';
        });
      });
    }
    
    // Update tier multiplier display
    function updateTierMultiplierDisplay() {
      const display = document.getElementById('tier-multiplier-display');
      if (display) {
        display.innerHTML = `Tier Multiplier: <span class="font-semibold text-purple-500">×${(1 + currentTier / 10).toFixed(1)}</span>`;
      }
    }
    
    // Event listener for roll button
    rollButton.addEventListener('click', rollDice);
    
    // Event listener for upgrade button
    upgradeButton.addEventListener('click', upgradeDice);
    
    // Event listeners for item buttons
    useDoublePointsButton.addEventListener('click', useDoublePointsCard);
    useNoPenaltyButton.addEventListener('click', useNoPenaltyCard);
    useLuckyStreakButton.addEventListener('click', useLuckyStreakCard);
    
    // Track the highest unlocked tier
    let highestUnlockedTier = 0;
    
    // Function to update current rarity display
    function updateCurrentRarityDisplay() {
      const rarityColorElement = document.getElementById('current-rarity-color');
      const rarityNameElement = document.getElementById('current-rarity-name');
      
      if (rarityColorElement && rarityNameElement) {
        // Get the dice tier data for the current tier
        if (currentTier >= 0 && currentTier < diceTiers.length) {
          const tierData = diceTiers[currentTier];
          rarityColorElement.style.backgroundColor = tierData.color;
          
          // Special case for white color to ensure border visibility
          if (tierData.color.toUpperCase() === '#FFFFFF') {
            rarityColorElement.style.border = '1px solid #dddddd';
          } else {
            rarityColorElement.style.border = 'none';
          }
          
          // Update the rarity name
          rarityNameElement.textContent = tierData.name;
        }
      }
    }
    
    // Initialize dice on page load
    window.addEventListener('DOMContentLoaded', () => {
      console.log('=== DOMContentLoaded event fired ===');
      
      // Check if elements exist
      console.log('Checking if elements exist before initialization:');
      console.log('best-record-display exists:', !!document.getElementById('best-record-display'));
      console.log('best-record-value exists:', !!document.getElementById('best-record-value'));
      
      console.log('DOM fully loaded');
      initializeDice();
      
      // Set default color (first option)
      if (colorOptions.length > 0) {
        const defaultColor = colorOptions[0].getAttribute('data-color');
        changeDiceColor(defaultColor);
      }
      
      // Initialize highest unlocked tier
      highestUnlockedTier = 0;
      
      // Initialize current tier to highest unlocked tier
      currentTier = highestUnlockedTier;
      
      // Initialize current tier display
      currentTierDisplay.innerHTML = `Current Dice: <span class="font-semibold text-primary">${diceTiers[currentTier].name}</span>`;
      
      // Update current rarity display
      updateCurrentRarityDisplay();
      
      // Initialize tier multiplier display
      updateTierMultiplierDisplay();
      
      // Initialize items display
      updateItemsDisplay();
      
      // Initialize upgrade cost display
      updateUpgradeCostDisplay();
      
      // Show welcome message
      setTimeout(() => {
        showGameMessage('Welcome! Roll the dice to earn points and upgrade your dice!', 'text-blue-500');
      }, 1000);
    });
    
    // Also try initializing on window load
    window.addEventListener('load', () => {
      console.log('Window loaded');
      // If dice not already initialized, try again
      if (diceElement.children.length === 0) {
        console.log('Dice not initialized, trying again...');
        initializeDice();
      }
    });
    
    // Game Rules Modal Functionality
    (function() {
      // Get elements
      const rulesButton = document.getElementById('game-rules-button');
      const rulesModal = document.getElementById('game-rules-modal');
      const closeButtons = rulesModal.querySelectorAll('.close-button');
      const modalBackdrop = rulesModal.querySelector('.modal-backdrop');
      const modalContent = rulesModal.querySelector('.modal-content');
      
      // Function to prevent background scrolling
      function preventBackgroundScroll(event) {
        // Allow scrolling inside the modal content
        if (modalContent.contains(event.target)) {
          // Check if we're at the top or bottom of the modal content
          const isAtTop = modalContent.scrollTop === 0;
          const isAtBottom = modalContent.scrollTop + modalContent.clientHeight >= modalContent.scrollHeight;
          
          // Prevent scrolling if at the top and scrolling up, or at the bottom and scrolling down
          if ((isAtTop && event.deltaY < 0) || (isAtBottom && event.deltaY > 0)) {
            event.preventDefault();
          }
        } else {
          // Prevent scrolling outside the modal content
          event.preventDefault();
        }
      }
      
      // Function to open modal
      function openModal() {
        // Add event listeners to prevent background scrolling
        document.addEventListener('wheel', preventBackgroundScroll, { passive: false });
        document.addEventListener('touchmove', preventBackgroundScroll, { passive: false });
        
        // Add open class to trigger animations
        rulesModal.classList.add('modal-open');
        
        // Show the modal
        rulesModal.style.visibility = 'visible';
      }
      
      // Function to close modal
      function closeModal() {
        // Remove open class to trigger animations
        rulesModal.classList.remove('modal-open');
        
        // Remove event listeners that prevent background scrolling
        document.removeEventListener('wheel', preventBackgroundScroll);
        document.removeEventListener('touchmove', preventBackgroundScroll);
        
        // Hide the modal after animation completes
        setTimeout(() => {
          rulesModal.style.visibility = 'hidden';
        }, 300);
      }
      
      // Add event listeners
      if (rulesButton) {
        rulesButton.addEventListener('click', openModal);
      }
      
      // Close buttons
      closeButtons.forEach(button => {
        button.addEventListener('click', closeModal);
      });
      
      // Close when clicking outside the modal content
      modalBackdrop.addEventListener('click', closeModal);
      
      // Close when pressing Escape key
      document.addEventListener('keydown', (event) => {
        if (event.key === 'Escape' && rulesModal.classList.contains('modal-open')) {
          closeModal();
        }
      });
      
      // Add hover effect to rules button
      if (rulesButton) {
        rulesButton.addEventListener('mouseenter', () => {
          rulesButton.classList.add('scale-105');
        });
        
        rulesButton.addEventListener('mouseleave', () => {
          rulesButton.classList.remove('scale-105');
        });
      }
      
      // Add click effect to close buttons
      closeButtons.forEach(button => {
        button.addEventListener('mousedown', () => {
          button.classList.add('scale-95');
        });
        
        button.addEventListener('mouseup', () => {
          button.classList.remove('scale-95');
        });
        
        button.addEventListener('mouseleave', () => {
          button.classList.remove('scale-95');
        });
      });
    })();
    
    // Reset Game Functionality
    function resetGame() {
      console.log('=== resetGame called ===');
      
      // Reset game state variables
      currentScore = 10;
      currentTier = 0;
      gameOver = false;
      rollCount = 0;
      luckyRollsRemaining = 0;
      isRolling = false;
      
      // Debug: Log game state after reset
      console.log('Game state after reset:');
      console.log('currentScore:', currentScore);
      console.log('currentTier:', currentTier);
      console.log('gameOver:', gameOver);
      console.log('rollCount:', rollCount);
      console.log('luckyRollsRemaining:', luckyRollsRemaining);
      
      // Reset item system
      doublePointsCards = 0;
      noPenaltyCards = 0;
      luckyStreakCards = 0;
      freeRolls = 0;
      activeItems = {
        double: 0,
        noPenalty: false
      };
      
      // Debug: Log item counts after reset
      console.log('=== Item counts after reset ===');
      console.log('doublePointsCards:', doublePointsCards);
      console.log('noPenaltyCards:', noPenaltyCards);
      console.log('luckyStreakCards:', luckyStreakCards);
      console.log('freeRolls:', freeRolls);
      console.log('activeItems:', activeItems);
      console.log('gameOver:', gameOver);
      
      // Immediately update UI to show zero counts
      if (doublePointsCount) doublePointsCount.textContent = '0';
      if (noPenaltyCount) noPenaltyCount.textContent = '0';
      if (luckyStreakCount) luckyStreakCount.textContent = '0';
      
      // Reset highest unlocked tier
      highestUnlockedTier = 0;
      
      // Update UI
      scoreValue.textContent = currentScore;
      rollCountValue.textContent = rollCount;
      
      // Reset current tier display
      currentTierDisplay.innerHTML = `Current Dice: <span class="font-semibold text-primary">${diceTiers[currentTier].name}</span>`;
      
      // Explicitly update upgrade cost display to ensure it's correct
      updateUpgradeCostDisplay();
      
      // Reset tier multiplier display
      updateTierMultiplierDisplay();
      
      // Reset current rarity display
      updateCurrentRarityDisplay();
      
      // Reset dice color to default (Empty)
      changeDiceColor(diceTiers[0].color);
      
      // Reset color selection UI
      updateColorSelection(0);
      
      // Reset color options
      colorOptions.forEach((option, index) => {
        // Reset all color options to locked state first
        option.disabled = true;
        option.classList.add('locked', 'opacity-50', 'cursor-not-allowed');
        option.style.position = 'relative'; // Ensure position is set for lock icon
      });
      
      // Only the first color option (index 0) should be unlocked
      if (colorOptions.length > 0) {
        colorOptions[0].disabled = false;
        colorOptions[0].classList.remove('locked', 'opacity-50', 'cursor-not-allowed');
        colorOptions[0].style.position = ''; // Reset position for unlocked option
      }
      
      // Reset history
      historyList.innerHTML = '';
      
      // Hide active indicators
      activeItemIndicator.classList.add('hidden');
      const luckyRollsIndicator = document.getElementById('lucky-rolls-indicator');
      if (luckyRollsIndicator) {
        luckyRollsIndicator.classList.add('hidden');
      }
      freeRollsIndicator.classList.add('hidden');
      
      // Hide result display
      resultDisplay.classList.add('hidden');
      
      // Hide score change
      scoreChange.textContent = '';
      
      // Remove game over message and restore original game message display
      // First, try to find and remove any game over message
      const gameOverMessages = document.querySelectorAll('.bg-green-100, .bg-red-100');
      gameOverMessages.forEach(message => {
        message.remove();
      });
      
      // Now, ensure the original game message element exists
      let gameMessageContainer = null;
      if (gameMessageDisplay) {
        gameMessageContainer = gameMessageDisplay.parentElement;
        // Remove the current game message display (which might be the game over message)
        gameMessageContainer.removeChild(gameMessageDisplay);
      } else {
        // If gameMessageDisplay is not available, find the container by looking for the items display
        const itemsDisplay = document.getElementById('items-display');
        if (itemsDisplay) {
          gameMessageContainer = itemsDisplay.previousElementSibling;
        }
      }
      
      // If we found the container, create and add the original game message element
      if (gameMessageContainer) {
        // Create a new game message element
        const newGameMessage = document.createElement('div');
        newGameMessage.id = 'game-message';
        newGameMessage.className = 'mt-4 text-center font-semibold hidden';
        
        // Add the new game message element to the container
        gameMessageContainer.appendChild(newGameMessage);
        
        // Update the reference to the new game message element
        gameMessageDisplay = newGameMessage;
      } else {
        console.error('Game message container not found!');
        // Fallback: try to create the game message element and add it to the DOM
        const newGameMessage = document.createElement('div');
        newGameMessage.id = 'game-message';
        newGameMessage.className = 'mt-4 text-center font-semibold hidden';
        
        // Try to insert it after the upgrade button area
        const upgradeButtonArea = document.getElementById('upgrade-button')?.parentElement;
        if (upgradeButtonArea) {
          upgradeButtonArea.parentNode.insertBefore(newGameMessage, upgradeButtonArea.nextSibling);
          gameMessageDisplay = newGameMessage;
        }
      }
      
      // Ensure the lock icon is displayed for locked options
      colorOptions.forEach(option => {
        if (option.classList.contains('locked')) {
          option.style.position = 'relative';
          // Explicitly set the pseudo-element content to ensure it's displayed
          option.style.setProperty('--content', '\\f023');
        } else {
          option.style.position = '';
          option.style.removeProperty('--content');
        }
      });
      
      // Enable all interactive elements
      rollButton.disabled = false;
      rollButton.classList.remove('opacity-70', 'cursor-not-allowed');
      
      // Update items display
      updateItemsDisplay();
      
      // Update upgrade button state
      updateUpgradeCostDisplay();
      
      // Ensure skill card counts are properly displayed
      if (doublePointsCount) doublePointsCount.textContent = doublePointsCards;
      if (noPenaltyCount) noPenaltyCount.textContent = noPenaltyCards;
      if (luckyStreakCount) luckyStreakCount.textContent = luckyStreakCards;
      
      // Debug: Log UI state after items display update
      console.log('UI state after items display update:');
      console.log('doublePointsCount.textContent:', doublePointsCount.textContent);
      console.log('noPenaltyCount.textContent:', noPenaltyCount.textContent);
      console.log('luckyStreakCount.textContent:', luckyStreakCount.textContent);
      console.log('useDoublePointsButton.disabled:', useDoublePointsButton.disabled);
      console.log('useNoPenaltyButton.disabled:', useNoPenaltyButton.disabled);
      console.log('useLuckyStreakButton.disabled:', useLuckyStreakButton.disabled);
      
      // Show welcome message
      setTimeout(() => {
        showGameMessage('Welcome! Roll the dice to earn points and upgrade your dice!', 'text-blue-500');
      }, 500);
      
      console.log('=== resetGame completed ===');
      console.log('Current tier after reset:', currentTier);
      console.log('Highest unlocked tier after reset:', highestUnlockedTier);
    }
    
    // Save win record to localStorage
    function saveWinRecord(rolls) {
      try {
        // Get current records or initialize empty array
        let records = JSON.parse(localStorage.getItem('diceGameWinRecords')) || [];
        
        // Create new record
        const newRecord = {
          id: records.length + 1,
          date: new Date().toISOString(),
          rolls: rolls
        };
        
        // Add to records
        records.push(newRecord);
        
        // Save back to localStorage
        localStorage.setItem('diceGameWinRecords', JSON.stringify(records));
        
        console.log('Win record saved:', newRecord);
      } catch (error) {
        console.error('Error saving win record:', error);
      }
    }
    
    // Load win records from localStorage
    function loadWinRecords() {
      try {
        const records = JSON.parse(localStorage.getItem('diceGameWinRecords')) || [];
        const recordsList = document.getElementById('win-records-list');
        const noRecordsMessage = document.getElementById('no-records-message');
        const recordsContainer = document.getElementById('win-records-container');
        
        // Clear previous records
        recordsList.innerHTML = '';
        
        if (records.length === 0) {
          // Show no records message
          if (noRecordsMessage) noRecordsMessage.classList.remove('hidden');
          if (recordsContainer) recordsContainer.classList.add('hidden');
          return;
        }
        
        // Hide no records message
        if (noRecordsMessage) noRecordsMessage.classList.add('hidden');
        if (recordsContainer) recordsContainer.classList.remove('hidden');
        
        // Add records to list
        records.forEach(record => {
          const date = new Date(record.date);
          const formattedDate = date.toLocaleDateString();
          const formattedTime = date.toLocaleTimeString();
          
          const row = document.createElement('tr');
          row.className = 'hover:bg-gray-50';
          row.innerHTML = `
            <td class="py-2 px-4">${record.id}</td>
            <td class="py-2 px-4">${formattedDate} ${formattedTime}</td>
            <td class="py-2 px-4">${record.rolls}</td>
            <td class="py-2 px-4">-</td>
          `;
          
          recordsList.appendChild(row);
        });
        
        // Update statistics
        updateWinStatistics(records);
      } catch (error) {
        console.error('Error loading win records:', error);
      }
    }
    
    // Update win statistics
    function updateWinStatistics(records) {
      try {
        const totalWinsElement = document.getElementById('total-wins');
        const bestRollsElement = document.getElementById('best-rolls');
        const averageRollsElement = document.getElementById('average-rolls');
        
        if (!totalWinsElement || !bestRollsElement || !averageRollsElement) {
          console.error('Win statistics elements not found');
          return;
        }
        
        // Total wins
        totalWinsElement.textContent = records.length;
        
        // Best rolls (minimum)
        const rolls = records.map(record => record.rolls);
        const bestRolls = Math.min(...rolls);
        bestRollsElement.textContent = bestRolls;
        
        // Average rolls
        const averageRolls = rolls.reduce((sum, val) => sum + val, 0) / rolls.length;
        averageRollsElement.textContent = averageRolls.toFixed(1);
      } catch (error) {
        console.error('Error updating win statistics:', error);
      }
    }
    
    // Clear win records
    function clearWinRecords() {
      if (confirm('Are you sure you want to clear all win records? This cannot be undone.')) {
        try {
          localStorage.removeItem('diceGameWinRecords');
          loadWinRecords(); // Refresh display
          alert('All win records have been cleared.');
        } catch (error) {
          console.error('Error clearing win records:', error);
          alert('An error occurred while clearing records.');
        }
      }
    }
    
    // Win Records Modal Functionality
    (function() {
      // Get elements
      const recordsButton = document.getElementById('win-records-button');
      const recordsModal = document.getElementById('win-records-modal');
      const closeButtons = recordsModal.querySelectorAll('.close-button');
      const modalBackdrop = recordsModal.querySelector('.modal-backdrop');
      const modalContent = recordsModal.querySelector('.modal-content');
      // const clearRecordsButton = document.getElementById('clear-records-button');
      
      // Function to prevent background scrolling
      function preventBackgroundScroll(event) {
        // Allow scrolling inside the modal content
        if (modalContent.contains(event.target)) {
          // Check if we're at the top or bottom of the modal content
          const isAtTop = modalContent.scrollTop === 0;
          const isAtBottom = modalContent.scrollTop + modalContent.clientHeight >= modalContent.scrollHeight;
          
          // Prevent scrolling if at the top and scrolling up, or at the bottom and scrolling down
          if ((isAtTop && event.deltaY < 0) || (isAtBottom && event.deltaY > 0)) {
            event.preventDefault();
          }
        } else {
          // Prevent scrolling outside the modal content
          event.preventDefault();
        }
      }
      
      // Function to open modal
      function openModal() {
        // Load win records
        loadWinRecords();
        
        // Add event listeners to prevent background scrolling
        document.addEventListener('wheel', preventBackgroundScroll, { passive: false });
        document.addEventListener('touchmove', preventBackgroundScroll, { passive: false });
        
        // Add open class to trigger animations
        recordsModal.classList.add('modal-open');
        
        // Show the modal
        recordsModal.style.visibility = 'visible';
      }
      
      // Function to close modal
      function closeModal() {
        // Remove open class to trigger animations
        recordsModal.classList.remove('modal-open');
        
        // Remove event listeners that prevent background scrolling
        document.removeEventListener('wheel', preventBackgroundScroll);
        document.removeEventListener('touchmove', preventBackgroundScroll);
        
        // Hide the modal after animation completes
        setTimeout(() => {
          recordsModal.style.visibility = 'hidden';
        }, 300);
      }
      
      // Add event listeners
      if (recordsButton) {
        recordsButton.addEventListener('click', openModal);
      }
      
      // Close buttons
      closeButtons.forEach(button => {
        button.addEventListener('click', closeModal);
      });
      
      // Close when clicking outside the modal content
      modalBackdrop.addEventListener('click', closeModal);
      
      // Close when pressing Escape key
      document.addEventListener('keydown', (event) => {
        if (event.key === 'Escape' && recordsModal.classList.contains('modal-open')) {
          closeModal();
        }
      });
      
      // // Clear records button
      // if (clearRecordsButton) {
      //   clearRecordsButton.addEventListener('click', clearWinRecords);
      // }
      
      // Add hover effect to records button
      if (recordsButton) {
        recordsButton.addEventListener('mouseenter', () => {
          recordsButton.classList.add('scale-105');
        });
        
        recordsButton.addEventListener('mouseleave', () => {
          recordsButton.classList.remove('scale-105');
        });
      }
      
      // Add click effect to close buttons
      closeButtons.forEach(button => {
        button.addEventListener('mousedown', () => {
          button.classList.add('scale-95');
        });
        
        button.addEventListener('mouseup', () => {
          button.classList.remove('scale-95');
        });
        
        button.addEventListener('mouseleave', () => {
          button.classList.remove('scale-95');
        });
      });
    })();
  </script>
</body>
</html>

评论

4 条评论,欢迎与作者交流。

正在加载评论...