← Deckbuilder results

Deckbuilder

thinkingcap qwen3.6 27b · basic

Initial view of Deckbuilder

Reviews & generation details

Reviews

No human review yet. Unreviewed does not mean unsuccessful.

Generation context

Imported historical artifact. Its exact original instructions and lineage are not known.

Generation prompt · exact text unavailable

See the current prompt for reference. It may differ from the instructions used to generate this artifact.

Inspect original source 50,984 bytes · SHA-256 89174cd2a8c5
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Shadows of Aethelgard</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@400;700;900&family=Crimson+Text:ital,wght@0,400;0,600;1,400&display=swap');

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
  background: #0a0a0f;
  color: #d4c5a9;
  font-family: 'Crimson Text', serif;
  overflow: hidden;
  height: 100vh;
  width: 100vw;
}

#game-container {
  width: 100vw;
  height: 100vh;
  position: relative;
  background: radial-gradient(ellipse at center, #1a1520 0%, #0a0a0f 70%);
}

.screen { display: none; width: 100%; height: 100%; position: absolute; top: 0; left: 0; }
.screen.active { display: flex; }

/* Main Menu */
#main-menu {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: radial-gradient(ellipse at center, #1a1520 0%, #050508 100%);
}

.title {
  font-family: 'Cinzel', serif;
  font-size: 3.5em;
  font-weight: 900;
  color: #c9a84c;
  text-shadow: 0 0 20px rgba(201,168,76,0.5), 0 0 40px rgba(201,168,76,0.2);
  margin-bottom: 10px;
  letter-spacing: 4px;
}

.subtitle {
  font-family: 'Cinzel', serif;
  font-size: 1.2em;
  color: #8a7a5a;
  margin-bottom: 50px;
  letter-spacing: 6px;
}

.menu-btn {
  font-family: 'Cinzel', serif;
  font-size: 1.3em;
  padding: 14px 50px;
  margin: 8px;
  background: linear-gradient(180deg, #2a2530, #1a1520);
  border: 2px solid #4a3f5c;
  color: #c9a84c;
  cursor: pointer;
  letter-spacing: 3px;
  transition: all 0.3s;
  min-width: 280px;
}

.menu-btn:hover {
  background: linear-gradient(180deg, #3a3540, #2a2530);
  border-color: #c9a84c;
  box-shadow: 0 0 15px rgba(201,168,76,0.3);
}

/* Class Selection */
#class-select {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: radial-gradient(ellipse at center, #1a1520 0%, #050508 100%);
}

.class-cards {
  display: flex;
  gap: 30px;
  margin-top: 30px;
}

.class-card {
  width: 260px;
  padding: 25px;
  background: linear-gradient(180deg, #1e1a25, #12101a);
  border: 2px solid #3a3545;
  cursor: pointer;
  transition: all 0.3s;
  text-align: center;
}

.class-card:hover {
  transform: translateY(-8px);
  box-shadow: 0 10px 30px rgba(0,0,0,0.5);
}

.class-card.bastion:hover { border-color: #a0b0c0; box-shadow: 0 10px 30px rgba(160,176,192,0.3); }
.class-card.wither:hover { border-color: #d45a2a; box-shadow: 0 10px 30px rgba(212,90,42,0.3); }
.class-card.shroud:hover { border-color: #8a6aaa; box-shadow: 0 10px 30px rgba(138,106,170,0.3); }

.class-name {
  font-family: 'Cinzel', serif;
  font-size: 1.5em;
  font-weight: 700;
  margin-bottom: 8px;
}

.bastion .class-name { color: #a0b0c0; }
.wither .class-name { color: #d45a2a; }
.shroud .class-name { color: #8a6aaa; }

.class-desc { font-size: 0.9em; color: #8a7a6a; margin-bottom: 12px; line-height: 1.4; }
.class-stats { font-size: 0.85em; color: #6a6a7a; }

/* Combat Screen */
#combat-screen {
  flex-direction: column;
  background: radial-gradient(ellipse at center, #1a1520 0%, #0a0a0f 100%);
}

.top-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 20px;
  background: linear-gradient(180deg, rgba(30,25,40,0.95), rgba(20,16,30,0.9));
  border-bottom: 1px solid #2a2535;
  height: 45px;
  flex-shrink: 0;
}

.top-bar-section { display: flex; align-items: center; gap: 15px; }

.stat-label { font-family: 'Cinzel', serif; font-size: 0.8em; color: #6a6a7a; letter-spacing: 2px; }
.stat-value { font-family: 'Cinzel', serif; font-size: 1em; color: #c9a84c; }

.gold-icon { color: #f0c040; }
.floor-icon { color: #7ab; }

.combat-area {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  min-height: 0;
}

.enemy-zone {
  text-align: center;
  position: relative;
}

.enemy-sprite {
  width: 120px;
  height: 140px;
  margin: 0 auto 10px;
  position: relative;
}

.enemy-hp-bar-container {
  width: 160px;
  height: 18px;
  background: #1a1520;
  border: 1px solid #3a3545;
  margin: 0 auto;
  position: relative;
}

.enemy-hp-bar {
  height: 100%;
  background: linear-gradient(90deg, #8b2020, #c0392b);
  transition: width 0.5s;
}

.enemy-hp-text {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Cinzel', serif;
  font-size: 0.7em;
  color: #fff;
  text-shadow: 1px 1px 2px rgba(0,0,0,0.8);
}

.enemy-name {
  font-family: 'Cinzel', serif;
  font-size: 1em;
  color: #a09080;
  margin-bottom: 5px;
}

.enemy-statuses {
  display: flex;
  gap: 5px;
  justify-content: center;
  margin-top: 5px;
}

.status-badge {
  font-size: 0.7em;
  padding: 2px 6px;
  border-radius: 3px;
  font-family: 'Cinzel', serif;
}

.status-burn { background: #4a3510; color: #d4a020; border: 1px solid #6a5020; }
.status-poison { background: #1a3a1a; color: #60c060; border: 1px solid #306030; }
.status-stun { background: #2a2a4a; color: #8080d0; border: 1px solid #404080; }

.player-zone {
  position: absolute;
  bottom: 10px;
  left: 50%;
  transform: translateX(-50%);
}

.player-stats-bar {
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 8px 20px;
  background: linear-gradient(180deg, rgba(30,25,40,0.9), rgba(20,16,30,0.8));
  border: 1px solid #2a2535;
  margin-bottom: 8px;
}

.player-hp-bar-container {
  width: 180px;
  height: 14px;
  background: #1a1520;
  border: 1px solid #3a3545;
}

.player-hp-bar {
  height: 100%;
  background: linear-gradient(90deg, #1a6b1a, #2ecc40);
  transition: width 0.5s;
}

.energy-display {
  display: flex;
  gap: 3px;
}

.energy-pip {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #2a2540;
  border: 1px solid #4a4560;
  transition: all 0.3s;
}

.energy-pip.filled {
  background: radial-gradient(circle, #7080e0, #4050a0);
  box-shadow: 0 0 6px rgba(100,120,220,0.5);
}

.defense-display {
  font-family: 'Cinzel', serif;
  color: #7ab8d4;
  font-size: 0.9em;
}

/* Card Hand */
.card-hand-area {
  height: 220px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10px;
  position: relative;
}

.card-hand {
  display: flex;
  gap: 8px;
  perspective: 800px;
}

.game-card {
  width: 130px;
  height: 190px;
  cursor: pointer;
  transition: all 0.25s ease;
  position: relative;
  flex-shrink: 0;
}

.game-card:hover {
  transform: translateY(-20px) scale(1.08);
  z-index: 10;
}

.game-card.disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.game-card.disabled:hover {
  transform: none;
}

.card-svg-frame {
  width: 100%;
  height: 100%;
}

/* Shop Screen */
#shop-screen {
  flex-direction: column;
  align-items: center;
  background: radial-gradient(ellipse at center, #1a1520 0%, #050508 100%);
}

.shop-title {
  font-family: 'Cinzel', serif;
  font-size: 2em;
  color: #c9a84c;
  margin-top: 30px;
  letter-spacing: 4px;
}

.shop-gold {
  font-family: 'Cinzel', serif;
  font-size: 1.2em;
  color: #f0c040;
  margin: 10px 0 20px;
}

.shop-cards {
  display: flex;
  gap: 15px;
  flex-wrap: wrap;
  justify-content: center;
  max-width: 900px;
  padding: 20px;
}

.shop-card-wrapper {
  text-align: center;
}

.shop-card-price {
  font-family: 'Cinzel', serif;
  font-size: 0.85em;
  color: #f0c040;
  margin-top: 6px;
}

.shop-card-count {
  font-size: 0.7em;
  color: #6a6a7a;
}

/* Game Over / Victory */
#game-over, #victory-screen {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: radial-gradient(ellipse at center, #1a1520 0%, #050508 100%);
}

.game-over-title {
  font-family: 'Cinzel', serif;
  font-size: 3em;
  color: #c0392b;
  text-shadow: 0 0 20px rgba(192,57,43,0.5);
  margin-bottom: 20px;
}

.victory-title {
  font-family: 'Cinzel', serif;
  font-size: 3em;
  color: #c9a84c;
  text-shadow: 0 0 20px rgba(201,168,76,0.5);
  margin-bottom: 20px;
}

/* Damage numbers */
.damage-number {
  position: absolute;
  font-family: 'Cinzel', serif;
  font-weight: 900;
  pointer-events: none;
  animation: floatUp 1s ease-out forwards;
  z-index: 100;
}

@keyframes floatUp {
  0% { opacity: 1; transform: translateY(0) scale(1.2); }
  100% { opacity: 0; transform: translateY(-60px) scale(0.8); }
}

/* Turn indicator */
.turn-indicator {
  font-family: 'Cinzel', serif;
  font-size: 0.9em;
  color: #7ab;
  letter-spacing: 2px;
  padding: 4px 15px;
  border: 1px solid #3a3545;
  background: rgba(20,16,30,0.8);
}

/* End Turn Button */
.end-turn-btn {
  font-family: 'Cinzel', serif;
  font-size: 1em;
  padding: 10px 40px;
  background: linear-gradient(180deg, #3a2520, #2a1a15);
  border: 2px solid #6a4a3a;
  color: #d4a070;
  cursor: pointer;
  letter-spacing: 2px;
  transition: all 0.3s;
}

.end-turn-btn:hover {
  background: linear-gradient(180deg, #4a3530, #3a2520);
  border-color: #d4a070;
  box-shadow: 0 0 10px rgba(212,160,112,0.3);
}

.end-turn-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Room transition */
#room-transition {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: #050508;
  z-index: 200;
}

.room-text {
  font-family: 'Cinzel', serif;
  font-size: 1.8em;
  color: #c9a84c;
  letter-spacing: 3px;
  animation: fadeInText 1s ease-in;
}

@keyframes fadeInText {
  from { opacity: 0; transform: translateY(20px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Card tooltip */
.card-tooltip {
  display: none;
  position: absolute;
  bottom: 105%;
  left: 50%;
  transform: translateX(-50%);
  width: 200px;
  padding: 10px;
  background: rgba(15,12,20,0.95);
  border: 1px solid #4a3f5c;
  z-index: 50;
  pointer-events: none;
}

.game-card:hover .card-tooltip { display: block; }

.tooltip-name {
  font-family: 'Cinzel', serif;
  font-size: 0.85em;
  color: #c9a84c;
  margin-bottom: 4px;
}

.tooltip-type {
  font-size: 0.7em;
  letter-spacing: 1px;
  margin-bottom: 6px;
}

.tooltip-desc {
  font-size: 0.75em;
  color: #a09888;
  line-height: 1.3;
}

/* Enemy attack animation */
.enemy-attack-anim {
  animation: enemyAttack 0.4s ease-in-out;
}

@keyframes enemyAttack {
  0% { transform: translateX(0); }
  30% { transform: translateX(-30px) scale(1.1); }
  60% { transform: translateX(20px); }
  100% { transform: translateX(0) scale(1); }
}

.player-hit-anim {
  animation: playerHit 0.3s ease-in-out;
}

@keyframes playerHit {
  0%, 100% { filter: brightness(1); }
  50% { filter: brightness(2) hue-rotate(20deg); }
}

/* Scrollbar */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: #0a0a0f; }
::-webkit-scrollbar-thumb { background: #3a3545; border-radius: 3px; }

.shop-scroll-area {
  flex: 1;
  overflow-y: auto;
  width: 100%;
  display: flex;
  justify-content: center;
  padding-bottom: 20px;
}

/* Card play animation */
.card-play-anim {
  animation: cardPlay 0.4s ease-out forwards;
}

@keyframes cardPlay {
  0% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.3) translateY(-40px); opacity: 0.8; }
  100% { transform: scale(0.5) translateY(-80px); opacity: 0; }
}

/* Boss indicator */
.boss-indicator {
  font-family: 'Cinzel', serif;
  color: #c0392b;
  font-size: 0.75em;
  letter-spacing: 2px;
  text-shadow: 0 0 8px rgba(192,57,43,0.5);
}

/* Deck info */
.deck-info {
  font-family: 'Cinzel', serif;
  font-size: 0.75em;
  color: #6a6a7a;
}
</style>
</head>
<body>
<div id="game-container">

<!-- Main Menu -->
<div id="main-menu" class="screen active">
  <div class="title">SHADOWS OF AETHELGARD</div>
  <div class="subtitle">A ROGUELIKE CARD BATTLER</div>
  <button class="menu-btn" onclick="showClassSelect()">BEGIN DESCENT</button>
</div>

<!-- Class Selection -->
<div id="class-select" class="screen">
  <div class="title" style="font-size:2em;">CHOOSE YOUR HERO</div>
  <div class="class-cards">
    <div class="class-card bastion" onclick="selectClass('bastion')">
      <div class="class-name">THE BASTION</div>
      <div class="class-desc">Immovable Object. High Defense, High Block, Low Speed.</div>
      <div class="class-stats">HP: 35 | Energy: 3</div>
    </div>
    <div class="class-card wither" onclick="selectClass('wither')">
      <div class="class-name">THE WITHER</div>
      <div class="class-desc">Rot and Burn. Status Effects, Debuff Control.</div>
      <div class="class-stats">HP: 30 | Energy: 5</div>
    </div>
    <div class="class-card shroud" onclick="selectClass('shroud')">
      <div class="class-name">THE SHROUD</div>
      <div class="class-desc">Shadow and Speed. Evasion, Assassination.</div>
      <div class="class-stats">HP: 28 | Energy: 5</div>
    </div>
  </div>
</div>

<!-- Room Transition -->
<div id="room-transition" class="screen">
  <div class="room-text" id="room-text"></div>
</div>

<!-- Combat Screen -->
<div id="combat-screen" class="screen">
  <div class="top-bar">
    <div class="top-bar-section">
      <span class="stat-label">GOLD</span>
      <span class="stat-value gold-icon" id="gold-display">0</span>
    </div>
    <div class="top-bar-section">
      <span class="turn-indicator" id="turn-indicator">TURN 1</span>
      <span class="boss-indicator" id="boss-indicator"></span>
    </div>
    <div class="top-bar-section">
      <span class="stat-label">FLOOR</span>
      <span class="stat-value floor-icon" id="floor-display">1</span>
      <span class="deck-info" id="deck-count"></span>
    </div>
  </div>

  <div class="combat-area">
    <div class="enemy-zone" id="enemy-zone">
      <div class="enemy-name" id="enemy-name">Goblin</div>
      <svg class="enemy-sprite" id="enemy-svg" viewBox="0 0 120 140"></svg>
      <div class="enemy-hp-bar-container">
        <div class="enemy-hp-bar" id="enemy-hp-bar" style="width:100%"></div>
        <div class="enemy-hp-text" id="enemy-hp-text">20/20</div>
      </div>
      <div class="enemy-statuses" id="enemy-statuses"></div>
    </div>

    <div class="player-zone">
      <div class="player-stats-bar">
        <span style="font-family:'Cinzel',serif;font-size:0.85em;color:#a09080;">HP</span>
        <div class="player-hp-bar-container">
          <div class="player-hp-bar" id="player-hp-bar" style="width:100%"></div>
        </div>
        <span id="player-hp-text" style="font-family:'Cinzel',serif;font-size:0.85em;color:#d4c5a9;">30/30</span>
        <span style="color:#6a6a7a;margin:0 5px;">|</span>
        <span style="font-family:'Cinzel',serif;font-size:0.85em;color:#7ab;">ENERGY</span>
        <div class="energy-display" id="energy-display"></div>
        <span style="color:#6a6a7a;margin:0 5px;">|</span>
        <span class="defense-display" id="defense-display">DEF: 0</span>
      </div>
    </div>
  </div>

  <div class="card-hand-area">
    <div class="card-hand" id="card-hand"></div>
  </div>

  <div style="text-align:center;padding-bottom:15px;">
    <button class="end-turn-btn" id="end-turn-btn" onclick="endPlayerTurn()">END TURN</button>
  </div>
</div>

<!-- Shop Screen -->
<div id="shop-screen" class="screen">
  <div class="shop-title">CARD SHOP</div>
  <div class="shop-gold" id="shop-gold-display">Gold: 0</div>
  <div class="shop-scroll-area">
    <div class="shop-cards" id="shop-cards"></div>
  </div>
  <button class="menu-btn" onclick="nextRoom()" style="margin-top:15px;">CONTINUE DESCENT</button>
</div>

<!-- Game Over -->
<div id="game-over" class="screen">
  <div class="game-over-title">YOU HAVE FALLEN</div>
  <div style="color:#8a7a6a;margin-bottom:30px;">The Void consumes all...</div>
  <button class="menu-btn" onclick="returnToMenu()">RETURN TO MENU</button>
</div>

<!-- Victory -->
<div id="victory-screen" class="screen">
  <div class="victory-title">VICTORY</div>
  <div style="color:#c9a84c;margin-bottom:10px;font-family:'Cinzel',serif;">The Void has been vanquished!</div>
  <div style="color:#8a7a6a;margin-bottom:30px;">Aethelgard is reclaimed.</div>
  <button class="menu-btn" onclick="returnToMenu()">RETURN TO MENU</button>
</div>

</div>

<script>
// ==================== CARD DATA ====================
const ALL_CARDS = {
  // BASTION CARDS
  'BA-A01': { id:'BA-A01', name:'Slam', type:'Attack', cost:2, atk:3, def:0, desc:'Deals 3 damage. If you have 30+ HP, draw 1 card.', class:'bastion' },
  'BA-A02': { id:'BA-A02', name:'Earthquake', type:'Attack', cost:3, atk:4, def:0, desc:'Deals 4 damage to all enemies.', class:'bastion', aoe:true },
  'BA-A03': { id:'BA-A03', name:'Stone Fist', type:'Attack', cost:1, atk:2, def:0, desc:'Deals 2 damage.', class:'bastion' },
  'BA-A04': { id:'BA-A04', name:'Boulder', type:'Attack', cost:4, atk:6, def:0, desc:'Deals 6 damage. Costs 4 Energy.', class:'bastion' },
  'BA-D01': { id:'BA-D01', name:'Shield Wall', type:'Defense', cost:0, atk:0, def:4, desc:'Gain 4 Defense for this turn.', class:'bastion' },
  'BA-D02': { id:'BA-D02', name:'Iron Skin', type:'Defense', cost:2, atk:0, def:5, desc:'Gain 5 Defense permanently. Discard 1 card.', class:'bastion', permanent:true },
  'BA-D03': { id:'BA-D03', name:'Stand Firm', type:'Defense', cost:1, atk:0, def:2, desc:'Gain 2 Defense.', class:'bastion' },
  'BA-D04': { id:'BA-D04', name:'Taunt', type:'Defense', cost:2, atk:0, def:3, desc:'Gain 3 Defense. Stun 1 enemy for 1 turn.', class:'bastion', stun:true },
  'BA-U01': { id:'BA-U01', name:'Search', type:'Other', cost:2, atk:0, def:0, desc:'Draw 1 card. Discard hand if > 5 cards.', class:'bastion' },
  'BA-U02': { id:'BA-U02', name:'Repair', type:'Other', cost:3, atk:0, def:0, desc:'Heal 6 HP.', class:'bastion', heal:6 },
  'BA-U03': { id:'BA-U03', name:'Rally', type:'Other', cost:1, atk:0, def:0, desc:'Draw 1 card. Gain 1 Energy.', class:'bastion' },
  'BA-U04': { id:'BA-U04', name:'Loot', type:'Other', cost:2, atk:0, def:0, desc:'Gain 5 Gold.', class:'bastion', gold:5 },

  // WITHER CARDS
  'WI-A01': { id:'WI-A01', name:'Fireball', type:'Attack', cost:2, atk:3, def:0, desc:'Deals 3 damage. Apply 1 Burn to target.', class:'wither', burn:1 },
  'WI-A02': { id:'WI-A02', name:'Inferno', type:'Attack', cost:3, atk:4, def:0, desc:'Deals 4 damage. Applies 3 Burn.', class:'wither', burn:3 },
  'WI-A03': { id:'WI-A03', name:'Ember', type:'Attack', cost:1, atk:2, def:0, desc:'Deals 2 damage. Deals 1 damage every turn to target.', class:'wither', burn:1 },
  'WI-A04': { id:'WI-A04', name:'Pyre', type:'Attack', cost:4, atk:5, def:0, desc:'Deals 5 damage. All enemies take 1 damage next turn.', class:'wither', aoe:true, burn:1 },
  'WI-D01': { id:'WI-D01', name:'Scorch Shield', type:'Defense', cost:2, atk:0, def:3, desc:'Gain 3 Defense. Block 1 Burn damage.', class:'wither' },
  'WI-D02': { id:'WI-D02', name:'Heat Resist', type:'Defense', cost:1, atk:0, def:1, desc:'Gain 1 Defense. Gain 1 Energy.', class:'wither' },
  'WI-D03': { id:'WI-D03', name:'Smoke', type:'Defense', cost:2, atk:0, def:4, desc:'Gain 4 Defense. Block 1 Burn damage.', class:'wither' },
  'WI-D04': { id:'WI-D04', name:'Endure', type:'Defense', cost:3, atk:0, def:2, desc:'Gain 2 Defense. Heal 2 HP.', class:'wither', heal:2 },
  'WI-U01': { id:'WI-U01', name:'Poison', type:'Other', cost:2, atk:0, def:0, desc:'Apply 1 Poison to target.', class:'wither', poison:1 },
  'WI-U02': { id:'WI-U02', name:'Burn', type:'Other', cost:3, atk:0, def:0, desc:'Deal 3 damage + 2 Burn to all enemies.', class:'wither', aoe:true, burn:2, atkVal:3 },
  'WI-U03': { id:'WI-U03', name:'Slow', type:'Other', cost:1, atk:0, def:0, desc:'Draw 1 card. Target cannot move next turn (Stun).', class:'wither', stun:true },
  'WI-U04': { id:'WI-U04', name:'Wither', type:'Other', cost:2, atk:0, def:0, desc:'Heal 5 HP. Reduce enemy Attack by 1.', class:'wither', heal:5 },

  // SHROUD CARDS
  'SH-A01': { id:'SH-A01', name:'Backstab', type:'Attack', cost:2, atk:4, def:0, desc:'Deals 4 damage. +1 Damage if target has no Armor.', class:'shroud' },
  'SH-A02': { id:'SH-A02', name:'Shadow Bolt', type:'Attack', cost:3, atk:5, def:0, desc:'Deals 5 damage. Target cannot block.', class:'shroud', unblockable:true },
  'SH-A03': { id:'SH-A03', name:'Silence', type:'Attack', cost:1, atk:3, def:0, desc:'Deals 3 damage. Target loses ability to use cards.', class:'shroud' },
  'SH-A04': { id:'SH-A04', name:'Vengeance', type:'Attack', cost:3, atk:6, def:0, desc:'Deals 6 damage. Gain 2 Energy.', class:'shroud' },
  'SH-D01': { id:'SH-D01', name:'Blur', type:'Defense', cost:3, atk:0, def:2, desc:'Gain 2 Defense. Ignore next attack.', class:'shroud', dodge:true },
  'SH-D02': { id:'SH-D02', name:'Step', type:'Defense', cost:2, atk:0, def:3, desc:'Gain 3 Defense. Gain 1 Energy.', class:'shroud' },
  'SH-D03': { id:'SH-D03', name:'Evasion', type:'Defense', cost:1, atk:0, def:1, desc:'Gain 1 Defense. Skip enemy action.', class:'shroud', skipEnemy:true },
  'SH-D04': { id:'SH-D04', name:'Phantom', type:'Defense', cost:2, atk:0, def:4, desc:'Gain 4 Defense. Ghost form for 1 turn.', class:'shroud' },
  'SH-U01': { id:'SH-U01', name:'Dash', type:'Other', cost:1, atk:0, def:0, desc:'Gain 1 Energy. Skip enemy attack.', class:'shroud', skipEnemy:true },
  'SH-U02': { id:'SH-U02', name:'Teleport', type:'Other', cost:2, atk:0, def:0, desc:'Move to back row. Deal 2 damage.', class:'shroud', atkVal:2 },
  'SH-U03': { id:'SH-U03', name:'Hide', type:'Other', cost:2, atk:0, def:1, desc:'Gain 1 Defense. Discard 1 card. Draw 2 cards.', class:'shroud' },
  'SH-U04': { id:'SH-U04', name:'Assassinate', type:'Other', cost:3, atk:0, def:0, desc:'Deal 8 damage. Cannot be blocked this turn.', class:'shroud', atkVal:8, unblockable:true }
};

// ==================== GAME STATE ====================
let game = {
  screen: 'main-menu',
  heroClass: null,
  hero: null,
  enemy: null,
  floor: 1,
  room: 0,
  turn: 1,
  playerTurn: true,
  combatActive: false,
  deckCounts: {},
  shopCards: [],
  bossDefeated: [false, false, false]
};

// ==================== SVG CARD FRAMES ====================
function getCardFrameSVG(cardData) {
  const cls = cardData.class;
  const type = cardData.type;
  let borderColor, glowColor, accentColor, innerBorder;

  if (cls === 'bastion') {
    borderColor = '#8a9aaa';
    glowColor = 'rgba(138,154,170,0.3)';
    accentColor = '#6a7a8a';
    innerBorder = '#5a6a7a';
  } else if (cls === 'wither') {
    borderColor = '#c05020';
    glowColor = 'rgba(192,80,32,0.3)';
    accentColor = '#a04018';
    innerBorder = '#803010';
  } else {
    borderColor = '#7a5aaa';
    glowColor = 'rgba(122,90,170,0.3)';
    accentColor = '#6040a0';
    innerBorder = '#503080';
  }

  let typeGlow;
  if (type === 'Attack') typeGlow = '#d44a2a';
  else if (type === 'Defense') typeGlow = '#6ab0d4';
  else typeGlow = '#9a7ac0';

  return `<svg viewBox="0 0 130 190" xmlns="http://www.w3.org/2000/svg">
    <defs>
      <filter id="glow-${cls}"><feGaussianBlur stdDeviation="2" result="blur"/><feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
      <linearGradient id="bg-${cls}" x1="0%" y1="0%" x2="0%" y2="100%">
        <stop offset="0%" style="stop-color:#1e1a25"/>
        <stop offset="100%" style="stop-color:#12101a"/>
      </linearGradient>
    </defs>
    <!-- Outer glow -->
    <rect x="2" y="2" width="126" height="186" rx="8" fill="none" stroke="${glowColor}" stroke-width="3" filter="url(#glow-${cls})"/>
    <!-- Main border -->
    <rect x="4" y="4" width="122" height="182" rx="7" fill="url(#bg-${cls})" stroke="${borderColor}" stroke-width="2"/>
    <!-- Inner decorative border -->
    <rect x="9" y="9" width="112" height="172" rx="4" fill="none" stroke="${innerBorder}" stroke-width="0.5"/>
    ${cls === 'bastion' ? `
      <!-- Bastion: Shield emblem top -->
      <polygon points="65,14 58,22 65,30 72,22" fill="${accentColor}" opacity="0.6"/>
      <line x1="9" y1="35" x2="121" y2="35" stroke="${innerBorder}" stroke-width="0.5"/>
    ` : cls === 'wither' ? `
      <!-- Wither: Flame emblem top -->
      <path d="M65,14 Q60,22 65,30 Q70,22 65,14" fill="${accentColor}" opacity="0.6"/>
      <line x1="9" y1="35" x2="121" y2="35" stroke="${innerBorder}" stroke-width="0.5"/>
    ` : `
      <!-- Shroud: Eye emblem top -->
      <ellipse cx="65" cy="22" rx="8" ry="4" fill="none" stroke="${accentColor}" stroke-width="1" opacity="0.6"/>
      <circle cx="65" cy="22" r="2" fill="${accentColor}" opacity="0.6"/>
      <line x1="9" y1="35" x2="121" y2="35" stroke="${innerBorder}" stroke-width="0.5"/>
    `}
    <!-- Cost circle -->
    <circle cx="22" cy="22" r="10" fill="#1a1520" stroke="${borderColor}" stroke-width="1.5"/>
    <text x="22" y="26" text-anchor="middle" font-family="Cinzel,serif" font-size="13" font-weight="bold" fill="${typeGlow}">${cardData.cost}</text>
    <!-- Card name -->
    <text x="65" y="48" text-anchor="middle" font-family="Cinzel,serif" font-size="9" font-weight="bold" fill="#c9a84c">${cardData.name}</text>
    <!-- Type label -->
    <text x="65" y="58" text-anchor="middle" font-family="Cinzel,serif" font-size="6" letter-spacing="1" fill="${typeGlow}" opacity="0.8">${type.toUpperCase()}</text>
    <!-- Image placeholder area -->
    <rect x="14" y="63" width="102" height="70" rx="3" fill="#0e0c15" stroke="${innerBorder}" stroke-width="0.5"/>
    ${cls === 'bastion' ? `
      <!-- Bastion placeholder: stone texture lines -->
      <line x1="20" y1="80" x2="110" y2="80" stroke="#2a2535" stroke-width="0.5"/>
      <line x1="20" y1="95" x2="110" y2="95" stroke="#2a2535" stroke-width="0.5"/>
      <line x1="20" y1="110" x2="110" y2="110" stroke="#2a2535" stroke-width="0.5"/>
      <text x="65" y="102" text-anchor="middle" font-size="7" fill="#3a3545">STONE</text>
    ` : cls === 'wither' ? `
      <!-- Wither placeholder: flame pattern -->
      <path d="M65,85 Q55,95 60,105 Q50,100 55,112" fill="none" stroke="#3a2520" stroke-width="1"/>
      <path d="M65,85 Q75,95 70,105 Q80,100 75,112" fill="none" stroke="#3a2520" stroke-width="1"/>
      <text x="65" y="102" text-anchor="middle" font-size="7" fill="#3a2520">FLAME</text>
    ` : `
      <!-- Shroud placeholder: shadow pattern -->
      <circle cx="65" cy="98" r="15" fill="none" stroke="#2a2540" stroke-width="0.5"/>
      <circle cx="65" cy="98" r="8" fill="none" stroke="#2a2540" stroke-width="0.5"/>
      <text x="65" y="102" text-anchor="middle" font-size="7" fill="#2a2540">SHADOW</text>
    `}
    <!-- Description area -->
    <rect x="14" y="138" width="102" height="42" rx="2" fill="#0e0c15" stroke="${innerBorder}" stroke-width="0.5"/>
    <text x="65" y="152" text-anchor="middle" font-size="5.5" fill="#a09888">${cardData.desc.substring(0,35)}${cardData.desc.length>35?'...':''}</text>
    ${cardData.atk > 0 ? `<text x="65" y="162" text-anchor="middle" font-size="6" fill="#d44a2a">ATK: ${cardData.atk}</text>` : ''}
    ${cardData.def > 0 ? `<text x="65" y="${cardData.atk>0?170:162}" text-anchor="middle" font-size="6" fill="#6ab0d4">DEF: ${cardData.def}</text>` : ''}
    <!-- Bottom decorative line -->
    <line x1="9" y1="185" x2="121" y2="185" stroke="${innerBorder}" stroke-width="0.5"/>
  </svg>`;
}

function getCardBackSVG(cls) {
  let borderColor, accentColor, patternColor;
  if (cls === 'bastion') {
    borderColor = '#6a7a8a'; accentColor = '#4a5a6a'; patternColor = '#3a4a5a';
  } else if (cls === 'wither') {
    borderColor = '#803010'; accentColor = '#602008'; patternColor = '#501808';
  } else {
    borderColor = '#503080'; accentColor = '#402070'; patternColor = '#301860';
  }

  return `<svg viewBox="0 0 130 190" xmlns="http://www.w3.org/2000/svg">
    <defs>
      <linearGradient id="back-${cls}" x1="0%" y1="0%" x2="100%" y2="100%">
        <stop offset="0%" style="stop-color:#1a1520"/>
        <stop offset="100%" style="stop-color:#0e0c15"/>
      </linearGradient>
    </defs>
    <rect x="4" y="4" width="122" height="182" rx="7" fill="url(#back-${cls})" stroke="${borderColor}" stroke-width="2"/>
    <rect x="9" y="9" width="112" height="172" rx="4" fill="none" stroke="${accentColor}" stroke-width="0.5"/>
    ${cls === 'bastion' ? `
      <!-- Bastion back: Shield pattern -->
      <polygon points="65,30 45,50 45,100 65,120 85,100 85,50" fill="none" stroke="${patternColor}" stroke-width="1.5"/>
      <polygon points="65,40 52,55 52,90 65,105 78,90 78,55" fill="none" stroke="${accentColor}" stroke-width="0.8"/>
      <line x1="65" y1="30" x2="65" y2="120" stroke="${patternColor}" stroke-width="0.5"/>
      <line x1="45" y1="75" x2="85" y2="75" stroke="${patternColor}" stroke-width="0.5"/>
    ` : cls === 'wither' ? `
      <!-- Wither back: Flame pattern -->
      <path d="M65,35 Q45,60 55,90 Q40,100 50,120" fill="none" stroke="${patternColor}" stroke-width="1.5"/>
      <path d="M65,35 Q85,60 75,90 Q90,100 80,120" fill="none" stroke="${patternColor}" stroke-width="1.5"/>
      <circle cx="65" cy="75" r="12" fill="none" stroke="${accentColor}" stroke-width="0.8"/>
      <path d="M65,55 Q58,70 65,85 Q72,70 65,55" fill="${patternColor}" opacity="0.3"/>
    ` : `
      <!-- Shroud back: Eye pattern -->
      <ellipse cx="65" cy="75" rx="30" ry="18" fill="none" stroke="${patternColor}" stroke-width="1.5"/>
      <circle cx="65" cy="75" r="12" fill="none" stroke="${accentColor}" stroke-width="1"/>
      <circle cx="65" cy="75" r="5" fill="${patternColor}" opacity="0.4"/>
      <line x1="35" y1="75" x2="95" y2="75" stroke="${patternColor}" stroke-width="0.5"/>
      <path d="M65,57 Q50,75 65,93 Q80,75 65,57" fill="none" stroke="${accentColor}" stroke-width="0.5"/>
    `}
    <!-- Corner decorations -->
    <circle cx="18" cy="18" r="2" fill="${patternColor}" opacity="0.5"/>
    <circle cx="112" cy="18" r="2" fill="${patternColor}" opacity="0.5"/>
    <circle cx="18" cy="172" r="2" fill="${patternColor}" opacity="0.5"/>
    <circle cx="112" cy="172" r="2" fill="${patternColor}" opacity="0.5"/>
  </svg>`;
}

// ==================== ENEMY SVG SPRITES ====================
function getEnemySVG(type, floor) {
  let color1, color2, bodyShape;
  if (floor === 1) {
    color1 = '#4a6a30'; color2 = '#3a5a20';
    bodyShape = `<ellipse cx="60" cy="80" rx="25" ry="30" fill="${color1}"/>
      <circle cx="60" cy="45" r="18" fill="${color1}"/>
      <circle cx="52" cy="42" r="3" fill="#ffcc00"/>
      <circle cx="68" cy="42" r="3" fill="#ffcc00"/>
      <path d="M50,50 Q60,58 70,50" fill="none" stroke="${color2}" stroke-width="1.5"/>
      <rect x="35" y="90" width="10" height="25" rx="3" fill="${color2}"/>
      <rect x="75" y="90" width="10" height="25" rx="3" fill="${color2}"/>
      <rect x="40" y="110" width="8" height="20" rx="3" fill="${color2}"/>
      <rect x="72" y="110" width="8" height="20" rx="3" fill="${color2}"/>`;
  } else if (floor === 2) {
    color1 = '#6a2040'; color2 = '#5a1830';
    bodyShape = `<ellipse cx="60" cy="75" rx="28" ry="35" fill="${color1}"/>
      <circle cx="60" cy="40" r="20" fill="${color1}"/>
      <polygon points="45,25 40,10 55,22" fill="${color2}"/>
      <polygon points="75,25 80,10 65,22" fill="${color2}"/>
      <circle cx="52" cy="38" r="3" fill="#ff4444"/>
      <circle cx="68" cy="38" r="3" fill="#ff4444"/>
      <path d="M48,48 Q60,55 72,48" fill="none" stroke="${color2}" stroke-width="1.5"/>
      <rect x="30" y="95" width="12" height="28" rx="4" fill="${color2}"/>
      <rect x="78" y="95" width="12" height="28" rx="4" fill="${color2}"/>
      <rect x="38" y="118" width="10" height="22" rx="4" fill="${color2}"/>
      <rect x="72" y="118" width="10" height="22" rx="4" fill="${color2}"/>`;
  } else {
    color1 = '#3a1060'; color2 = '#2a0850';
    bodyShape = `<ellipse cx="60" cy="75" rx="30" ry="38" fill="${color1}"/>
      <circle cx="60" cy="38" r="22" fill="${color1}"/>
      <path d="M40,20 Q35,5 50,18" fill="${color2}"/>
      <path d="M80,20 Q85,5 70,18" fill="${color2}"/>
      <circle cx="50" cy="35" r="4" fill="#aa44ff"/>
      <circle cx="70" cy="35" r="4" fill="#aa44ff"/>
      <path d="M46,48 Q60,58 74,48" fill="none" stroke="${color2}" stroke-width="2"/>
      <rect x="28" y="98" width="14" height="30" rx="4" fill="${color2}"/>
      <rect x="78" y="98" width="14" height="30" rx="4" fill="${color2}"/>
      <rect x="36" y="122" width="12" height="25" rx="4" fill="${color2}"/>
      <rect x="72" y="122" width="12" height="25" rx="4" fill="${color2}"/>`;
  }

  return `<svg viewBox="0 0 120 140" xmlns="http://www.w3.org/2000/svg">
    <defs>
      <filter id="enemyGlow"><feGaussianBlur stdDeviation="3" result="blur"/><feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
    </defs>
    ${bodyShape}
  </svg>`;
}

// ==================== GAME FUNCTIONS ====================
function showScreen(id) {
  document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
  document.getElementById(id).classList.add('active');
  game.screen = id;
}

function returnToMenu() {
  showScreen('main-menu');
}

function showClassSelect() {
  showScreen('class-select');
}

function selectClass(cls) {
  game.heroClass = cls;
  const hpMap = { bastion: 35, wither: 30, shroud: 28 };
  const energyMap = { bastion: 3, wither: 5, shroud: 5 };

  // Build starter deck (1 copy of each class card)
  let starterDeck = [];
  Object.values(ALL_CARDS).forEach(c => {
    if (c.class === cls) starterDeck.push(c.id);
  });

  game.hero = {
    hp: hpMap[cls],
    maxHp: hpMap[cls],
    energy: energyMap[cls],
    maxEnergy: energyMap[cls],
    handSize: 4,
    gold: 0,
    defense: 0,
    permanentDefense: 0,
    deck: [...starterDeck],
    hand: [],
    discardPile: [],
    dodgeNextAttack: false,
    skipEnemyAction: false
  };

  game.deckCounts = {};
  starterDeck.forEach(id => { game.deckCounts[id] = (game.deckCounts[id] || 0) + 1; });

  game.floor = 1;
  game.room = 0;
  game.turn = 1;
  game.bossDefeated = [false, false, false];

  showRoomTransition();
}

function showRoomTransition() {
  const isBoss = (game.room === 3);
  let enemyName;
  if (isBoss) {
    const bossNames = ['The Gatekeeper', 'The Corrupted', 'The Void Lord'];
    enemyName = bossNames[game.floor - 1];
  } else {
    const floorEnemies = [
      ['Goblin Scout', 'Rat Swarm', 'Cave Goblin'],
      ['Vampire Knight', 'Ogre Brute', 'Dark Cultist'],
      ['Void Warrior', 'Shadow Priest', 'Abyssal Guard']
    ];
    enemyName = floorEnemies[game.floor - 1][Math.min(game.room, 2)];
  }

  const text = isBoss ? `⚔ BOSS: ${enemyName} ⚔` : `Floor ${game.floor} — Room ${game.room + 1}`;
  document.getElementById('room-text').textContent = text;
  showScreen('room-transition');

  setTimeout(() => {
    startCombat(enemyName, isBoss);
  }, 1500);
}

function createEnemy(name, isBoss) {
  let hp, dmg;
  if (isBoss) {
    hp = 80;
    dmg = 15;
  } else {
    const floorStats = [
      { hp: 20, dmg: 3 },
      { hp: 30, dmg: 5 },
      { hp: 40, dmg: 8 }
    ];
    hp = floorStats[game.floor - 1].hp;
    dmg = floorStats[game.floor - 1].dmg;
  }

  return {
    name: name,
    hp: hp,
    maxHp: hp,
    damage: dmg,
    defense: 0,
    isBoss: isBoss,
    burn: 0,
    poison: 0,
    stun: 0,
    attackReduction: 0
  };
}

function startCombat(enemyName, isBoss) {
  game.enemy = createEnemy(enemyName, isBoss);
  game.turn = 1;
  game.playerTurn = true;
  game.combatActive = true;
  game.hero.defense = game.hero.permanentDefense;
  game.hero.dodgeNextAttack = false;
  game.hero.skipEnemyAction = false;

  // Reset deck from discard
  game.hero.deck.push(...game.hero.discardPile);
  game.hero.discardPile = [];
  shuffleArray(game.hero.deck);

  showScreen('combat-screen');
  updateCombatUI();
  drawCardsToHand();
}

function shuffleArray(arr) {
  for (let i = arr.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [arr[i], arr[j]] = [arr[j], arr[i]];
  }
}

function drawCardsToHand() {
  while (game.hero.hand.length < game.hero.handSize && game.hero.deck.length > 0) {
    game.hero.hand.push(game.hero.deck.pop());
  }
}

function updateCombatUI() {
  // Gold
  document.getElementById('gold-display').textContent = game.hero.gold;
  // Floor
  document.getElementById('floor-display').textContent = game.floor;
  // Turn
  document.getElementById('turn-indicator').textContent = `TURN ${game.turn}`;
  // Boss indicator
  document.getElementById('boss-indicator').textContent = game.enemy.isBoss ? '⚔ BOSS ⚔' : '';
  // Deck count
  document.getElementById('deck-count').textContent = `${game.hero.deck.length} in deck`;

  // Enemy
  document.getElementById('enemy-name').textContent = game.enemy.name;
  const hpPct = Math.max(0, (game.enemy.hp / game.enemy.maxHp) * 100);
  document.getElementById('enemy-hp-bar').style.width = hpPct + '%';
  document.getElementById('enemy-hp-text').textContent = `${Math.max(0, game.enemy.hp)}/${game.enemy.maxHp}`;

  // Enemy SVG
  document.getElementById('enemy-svg').innerHTML = getEnemySVG(game.enemy.name, game.floor);

  // Enemy statuses
  let statusHTML = '';
  if (game.enemy.burn > 0) statusHTML += `<span class="status-badge status-burn">Burn ${game.enemy.burn}</span>`;
  if (game.enemy.poison > 0) statusHTML += `<span class="status-badge status-poison">Poison ${game.enemy.poison}</span>`;
  if (game.enemy.stun > 0) statusHTML += `<span class="status-badge status-stun">Stun</span>`;
  document.getElementById('enemy-statuses').innerHTML = statusHTML;

  // Player HP
  const playerHpPct = Math.max(0, (game.hero.hp / game.hero.maxHp) * 100);
  document.getElementById('player-hp-bar').style.width = playerHpPct + '%';
  document.getElementById('player-hp-text').textContent = `${Math.max(0, game.hero.hp)}/${game.hero.maxHp}`;

  // Energy pips
  let energyHTML = '';
  for (let i = 0; i < game.hero.maxEnergy; i++) {
    energyHTML += `<div class="energy-pip ${i < game.hero.energy ? 'filled' : ''}"></div>`;
  }
  document.getElementById('energy-display').innerHTML = energyHTML;

  // Defense
  document.getElementById('defense-display').textContent = `DEF: ${game.hero.defense}`;

  // Render hand
  renderHand();
}

function renderHand() {
  const handEl = document.getElementById('card-hand');
  handEl.innerHTML = '';

  game.hero.hand.forEach((cardId, idx) => {
    const cardData = ALL_CARDS[cardId];
    if (!cardData) return;

    const canPlay = game.playerTurn && game.hero.energy >= cardData.cost;

    const cardDiv = document.createElement('div');
    cardDiv.className = `game-card ${canPlay ? '' : 'disabled'}`;
    cardDiv.innerHTML = getCardFrameSVG(cardData);

    // Tooltip
    const tooltip = document.createElement('div');
    tooltip.className = 'card-tooltip';
    tooltip.innerHTML = `
      <div class="tooltip-name">${cardData.name}</div>
      <div class="tooltip-type" style="color:${cardData.type==='Attack'?'#d44a2a':cardData.type==='Defense'?'#6ab0d4':'#9a7ac0'}">${cardData.type} | Cost: ${cardData.cost}</div>
      <div class="tooltip-desc">${cardData.desc}</div>
    `;
    cardDiv.appendChild(tooltip);

    if (canPlay) {
      cardDiv.onclick = () => playCard(idx);
    }

    handEl.appendChild(cardDiv);
  });
}

function playCard(handIdx) {
  if (!game.playerTurn || !game.combatActive) return;

  const cardId = game.hero.hand[handIdx];
  const cardData = ALL_CARDS[cardId];
  if (!cardData || game.hero.energy < cardData.cost) return;

  // Pay energy cost
  game.hero.energy -= cardData.cost;

  // Remove from hand
  game.hero.hand.splice(handIdx, 1);

  // Animate card play
  const cards = document.querySelectorAll('.game-card');
  if (cards[handIdx]) {
    cards[handIdx].classList.add('card-play-anim');
  }

  // Resolve card effects
  resolveCardEffect(cardData);

  // Move to discard
  game.hero.discardPile.push(cardId);

  setTimeout(() => {
    updateCombatUI();
    checkEnemyDeath();
  }, 400);
}

function resolveCardEffect(card) {
  const enemy = game.enemy;

  if (card.type === 'Attack') {
    let dmg = card.atk;

    // Bastion Slam: +draw if HP >= 30
    if (card.id === 'BA-A01' && game.hero.hp >= 30) {
      drawCardsToHand();
    }

    // Shroud Backstab: +1 if no armor
    if (card.id === 'SH-A01' && enemy.defense <= 0) {
      dmg += 1;
    }

    // Apply damage to enemy
    let actualDmg = applyDamageToEnemy(dmg, card.unblockable);
    showDamageNumber(actualDmg, '#d44a2a');

    // Burn effects
    if (card.burn) {
      enemy.burn += card.burn;
    }

    // Shroud Vengeance: gain 2 energy
    if (card.id === 'SH-A04') {
      game.hero.energy = Math.min(game.hero.maxEnergy, game.hero.energy + 2);
    }
  }

  if (card.type === 'Defense') {
    let defAmount = card.def;

    // Permanent defense
    if (card.permanent) {
      game.hero.permanentDefense += defAmount;
      // Discard 1 card
      if (game.hero.hand.length > 0) {
        const discarded = game.hero.hand.pop();
        game.hero.discardPile.push(discarded);
      }
    } else {
      game.hero.defense += defAmount;
    }

    // Stun enemy
    if (card.stun) {
      enemy.stun = 1;
    }

    // Heal effects on defense cards
    if (card.heal) {
      game.hero.hp = Math.min(game.hero.maxHp, game.hero.hp + card.heal);
    }

    // Energy gain
    if (card.id === 'WI-D02' || card.id === 'SH-D02') {
      game.hero.energy = Math.min(game.hero.maxEnergy, game.hero.energy + 1);
    }

    // Dodge / skip enemy
    if (card.dodge) {
      game.hero.dodgeNextAttack = true;
    }
    if (card.skipEnemy) {
      game.hero.skipEnemyAction = true;
    }
  }

  if (card.type === 'Other') {
    // Search: draw 1, discard if > 5
    if (card.id === 'BA-U01') {
      drawCardsToHand();
      while (game.hero.hand.length > 5) {
        const d = game.hero.hand.pop();
        game.hero.discardPile.push(d);
      }
    }

    // Rally: draw 1, gain 1 energy
    if (card.id === 'BA-U03') {
      drawCardsToHand();
      game.hero.energy = Math.min(game.hero.maxEnergy, game.hero.energy + 1);
    }

    // Loot: gain gold
    if (card.gold) {
      game.hero.gold += card.gold;
    }

    // Heal
    if (card.heal) {
      game.hero.hp = Math.min(game.hero.maxHp, game.hero.hp + card.heal);
    }

    // Poison
    if (card.poison) {
      enemy.poison += card.poison;
    }

    // Burn AoE
    if (card.id === 'WI-U02') {
      let dmg = applyDamageToEnemy(card.atkVal || 3, false);
      showDamageNumber(dmg, '#d4a020');
      enemy.burn += card.burn;
    }

    // Slow: draw + stun
    if (card.id === 'WI-U03') {
      drawCardsToHand();
      enemy.stun = 1;
    }

    // Wither: heal + reduce attack
    if (card.id === 'WI-U04') {
      game.hero.hp = Math.min(game.hero.maxHp, game.hero.hp + card.heal);
      enemy.attackReduction += 1;
    }

    // Dash: energy + skip enemy
    if (card.id === 'SH-U01') {
      game.hero.energy = Math.min(game.hero.maxEnergy, game.hero.energy + 1);
      game.hero.skipEnemyAction = true;
    }

    // Teleport: deal damage
    if (card.id === 'SH-U02') {
      let dmg = applyDamageToEnemy(card.atkVal || 2, false);
      showDamageNumber(dmg, '#8a6aaa');
    }

    // Hide: defense + discard + draw
    if (card.id === 'SH-U03') {
      game.hero.defense += card.def;
      if (game.hero.hand.length > 0) {
        const d = game.hero.hand.pop();
        game.hero.discardPile.push(d);
      }
      drawCardsToHand();
      drawCardsToHand();
    }

    // Assassinate: unblockable damage
    if (card.id === 'SH-U04') {
      let dmg = applyDamageToEnemy(card.atkVal || 8, true);
      showDamageNumber(dmg, '#c0392b');
    }

    // Skip enemy action
    if (card.skipEnemy) {
      game.hero.skipEnemyAction = true;
    }
  }
}

function applyDamageToEnemy(amount, unblockable) {
  let dmg = amount;
  if (!unblockable && enemyHasDefense()) {
    const blocked = Math.min(dmg, game.enemy.defense);
    game.enemy.defense -= blocked;
    dmg -= blocked;
  }
  game.enemy.hp -= dmg;
  return dmg;
}

function enemyHasDefense() {
  // Boss 1 blocks 5 per turn until HP < 20
  if (game.enemy.isBoss && game.floor === 1 && game.enemy.hp >= 20) {
    return true;
  }
  return false;
}

function showDamageNumber(amount, color) {
  const zone = document.getElementById('enemy-zone');
  const num = document.createElement('div');
  num.className = 'damage-number';
  num.textContent = `-${amount}`;
  num.style.color = color;
  num.style.fontSize = '1.5em';
  num.style.left = '50%';
  num.style.top = '30%';
  num.style.transform = 'translateX(-50%)';
  zone.appendChild(num);
  setTimeout(() => num.remove(), 1000);
}

function showPlayerDamageNumber(amount) {
  const zone = document.querySelector('.player-zone');
  if (!zone) return;
  const num = document.createElement('div');
  num.className = 'damage-number';
  num.textContent = `-${amount}`;
  num.style.color = '#c0392b';
  num.style.fontSize = '1.5em';
  num.style.left = '50%';
  num.style.top = '-20px';
  num.style.transform = 'translateX(-50%)';
  zone.appendChild(num);
  setTimeout(() => num.remove(), 1000);
}

function checkEnemyDeath() {
  if (game.enemy.hp <= 0) {
    game.combatActive = false;
    let goldReward = game.enemy.isBoss ? 15 : 5;
    game.hero.gold += goldReward;

    if (game.enemy.isBoss) {
      game.bossDefeated[game.floor - 1] = true;
    }

    setTimeout(() => {
      if (game.floor === 3 && game.room >= 3) {
        showScreen('victory-screen');
      } else {
        openShop();
      }
    }, 800);
  }
}

function endPlayerTurn() {
  if (!game.playerTurn || !game.combatActive) return;
  game.playerTurn = false;

  // Discard hand to discard pile
  while (game.hero.hand.length > 0) {
    game.hero.discardPile.push(game.hero.hand.pop());
  }

  updateCombatUI();

  setTimeout(() => enemyTurn(), 600);
}

function enemyTurn() {
  if (!game.combatActive) return;

  const enemy = game.enemy;

  // Apply burn damage to enemy
  if (enemy.burn > 0) {
    enemy.hp -= enemy.burn;
    showDamageNumber(enemy.burn, '#d4a020');
    enemy.burn--;
  }

  // Apply poison damage to enemy
  if (enemy.poison > 0) {
    enemy.hp -= enemy.poison;
    showDamageNumber(enemy.poison, '#60c060');
    enemy.poison--;
  }

  // Boss 3 regen: +10 HP per turn
  if (enemy.isBoss && game.floor === 3) {
    enemy.hp = Math.min(enemy.maxHp + 40, enemy.hp + 10);
  }

  // Check enemy death from DoT
  if (enemy.hp <= 0) {
    checkEnemyDeath();
    return;
  }

  // Boss 1: gain defense each turn until HP < 20
  if (enemy.isBoss && game.floor === 1 && enemy.hp >= 20) {
    enemy.defense += 5;
  } else if (!enemy.isBoss || enemy.hp < 20) {
    // Reset non-boss defense each turn
    if (!enemy.isBoss) enemy.defense = 0;
  }

  // Stun check
  if (enemy.stun > 0) {
    enemy.stun--;
    updateCombatUI();
    startPlayerTurn();
    return;
  }

  // Skip enemy action check
  if (game.hero.skipEnemyAction) {
    game.hero.skipEnemyAction = false;
    updateCombatUI();
    startPlayerTurn();
    return;
  }

  // Enemy attacks
  let dmg = Math.max(0, enemy.damage - enemy.attackReduction);

  // Boss 2: deals 20 damage if player has < 3 energy
  if (enemy.isBoss && game.floor === 2 && game.hero.energy < 3) {
    dmg = 20;
  }

  // Dodge check
  if (game.hero.dodgeNextAttack) {
    game.hero.dodgeNextAttack = false;
    showDamageNumber(0, '#7ab');
    updateCombatUI();
    startPlayerTurn();
    return;
  }

  // Apply damage: first to defense, then to HP
  let remainingDmg = dmg;
  if (game.hero.defense > 0) {
    const blocked = Math.min(remainingDmg, game.hero.defense);
    game.hero.defense -= blocked;
    remainingDmg -= blocked;
  }

  if (remainingDmg > 0) {
    game.hero.hp -= remainingDmg;
    showPlayerDamageNumber(remainingDmg);

    // Hit animation
    const enemySvg = document.getElementById('enemy-svg');
    enemySvg.classList.add('enemy-attack-anim');
    setTimeout(() => enemySvg.classList.remove('enemy-attack-anim'), 400);
  }

  updateCombatUI();

  if (game.hero.hp <= 0) {
    game.combatActive = false;
    setTimeout(() => showScreen('game-over'), 500);
    return;
  }

  startPlayerTurn();
}

function startPlayerTurn() {
  game.turn++;
  game.playerTurn = true;

  // Reset temporary defense (permanent stays)
  game.hero.defense = game.hero.permanentDefense;

  // Recover energy
  game.hero.energy = Math.min(game.hero.maxEnergy, game.hero.energy + 1);

  // Draw cards
  drawCardsToHand();

  updateCombatUI();
}

// ==================== SHOP ====================
function openShop() {
  showScreen('shop-screen');
  document.getElementById('shop-gold-display').textContent = `Gold: ${game.hero.gold}`;

  const shopEl = document.getElementById('shop-cards');
  shopEl.innerHTML = '';

  // Generate random shop cards (5-7 cards)
  game.shopCards = [];
  const numShopCards = 5 + Math.floor(Math.random() * 3);
  const allCardIds = Object.keys(ALL_CARDS);

  for (let i = 0; i < numShopCards; i++) {
    const randomId = allCardIds[Math.floor(Math.random() * allCardIds.length)];
    game.shopCards.push(randomId);
  }

  game.shopCards.forEach(cardId => {
    const cardData = ALL_CARDS[cardId];
    const count = game.deckCounts[cardId] || 0;
    let cost = 1 + Math.floor(count / 3) * 9; // 1 gold normally, 10 for 4th+ copy
    if (count >= 5) cost = 999; // Max copies reached

    const wrapper = document.createElement('div');
    wrapper.className = 'shop-card-wrapper';

    const cardDiv = document.createElement('div');
    cardDiv.className = `game-card ${cost > game.hero.gold || count >= 5 ? 'disabled' : ''}`;
    cardDiv.innerHTML = getCardFrameSVG(cardData);

    if (cost <= game.hero.gold && count < 5) {
      cardDiv.onclick = () => buyCard(cardId, cost);
    }

    const priceLabel = document.createElement('div');
    priceLabel.className = 'shop-card-price';
    priceLabel.textContent = count >= 5 ? 'MAX COPIES' : `${cost} Gold`;

    const countLabel = document.createElement('div');
    countLabel.className = 'shop-card-count';
    countLabel.textContent = `Owned: ${count}/5`;

    wrapper.appendChild(cardDiv);
    wrapper.appendChild(priceLabel);
    wrapper.appendChild(countLabel);
    shopEl.appendChild(wrapper);
  });
}

function buyCard(cardId, cost) {
  if (game.hero.gold < cost || (game.deckCounts[cardId] || 0) >= 5) return;

  game.hero.gold -= cost;
  game.deckCounts[cardId] = (game.deckCounts[cardId] || 0) + 1;
  game.hero.deck.push(cardId);

  document.getElementById('shop-gold-display').textContent = `Gold: ${game.hero.gold}`;
  openShop(); // Refresh shop
}

function nextRoom() {
  game.room++;

  if (game.room > 3) {
    // Floor complete, move to next floor
    game.floor++;
    game.room = 0;

    if (game.floor > 3) {
      showScreen('victory-screen');
      return;
    }
  }

  showRoomTransition();
}

// ==================== INIT ====================
document.addEventListener('DOMContentLoaded', () => {
  // Preload fonts and initialize
});
</script>
</body>
</html>
<!-- agent-meta {"model":"thinkingcap-qwen3.6-27b","provider":"lmstudio","persona":"basic","sessionId":"0ffe2772-66a1-4672-8d1d-b9c929aa73e9","tokensIn":3609,"tokensOut":19107,"tokensTotal":22716,"turns":1,"toolCalls":0,"failedToolCalls":0,"timestamp":"2026-07-19T02:07:34.910Z"} -->