← Deckbuilder results

Deckbuilder

thinkingcap qwen3.6 27b · middle

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,174 bytes · SHA-256 f929039507e2
<!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; }

  :root {
    --bg-dark: #0a0a0f;
    --bg-mid: #151520;
    --bg-light: #1e1e30;
    --gold: #c9a84c;
    --gold-dim: #8a7030;
    --red-attack: #d44a2a;
    --blue-defense: #3a6fd4;
    --purple-other: #8b3ad4;
    --green-heal: #3ad45c;
    --burn-orange: #e8961e;
    --poison-green: #2ecc71;
    --hp-red: #cc2222;
    --hp-bg: #331111;
    --text-main: #d4cfc0;
    --text-dim: #8a8578;
  }

  body {
    background: var(--bg-dark);
    color: var(--text-main);
    font-family: 'Crimson Text', Georgia, serif;
    overflow: hidden;
    height: 100vh;
    width: 100vw;
    user-select: none;
  }

  h1, h2, h3, .title-font { font-family: 'Cinzel', serif; }

  /* ===== SCREENS ===== */
  .screen { display: none; position: absolute; top: 0; left: 0; width: 100%; height: 100%; flex-direction: column; align-items: center; justify-content: center; z-index: 1; }
  .screen.active { display: flex; }

  /* ===== TITLE SCREEN ===== */
  #title-screen {
    background: radial-gradient(ellipse at center, #1a1a2e 0%, #0a0a0f 70%);
  }
  #title-screen h1 {
    font-size: 3.5em;
    color: var(--gold);
    text-shadow: 0 0 30px rgba(201,168,76,0.4), 0 2px 4px rgba(0,0,0,0.8);
    letter-spacing: 4px;
    margin-bottom: 8px;
  }
  #title-screen .subtitle {
    font-size: 1.2em;
    color: var(--text-dim);
    margin-bottom: 50px;
    font-style: italic;
  }

  /* ===== BUTTONS ===== */
  .btn {
    background: linear-gradient(180deg, #2a2a3e, #1a1a28);
    border: 1px solid var(--gold-dim);
    color: var(--gold);
    padding: 14px 40px;
    font-family: 'Cinzel', serif;
    font-size: 1.1em;
    cursor: pointer;
    letter-spacing: 2px;
    transition: all 0.2s;
    margin: 6px;
    min-width: 200px;
    text-align: center;
  }
  .btn:hover { background: linear-gradient(180deg, #3a3a5e, #2a2a40); border-color: var(--gold); box-shadow: 0 0 15px rgba(201,168,76,0.2); }
  .btn:active { transform: scale(0.97); }
  .btn:disabled { opacity: 0.4; cursor: not-allowed; }

  /* ===== CLASS SELECT ===== */
  #class-select { background: radial-gradient(ellipse at center, #1a1a2e 0%, #0a0a0f 70%); }
  .class-cards { display: flex; gap: 30px; margin-top: 30px; }
  .class-card {
    width: 220px; padding: 25px 18px; text-align: center; cursor: pointer;
    background: linear-gradient(180deg, #1e1e30, #12121c);
    border: 2px solid var(--gold-dim);
    transition: all 0.3s;
  }
  .class-card:hover { border-color: var(--gold); transform: translateY(-5px); box-shadow: 0 8px 25px rgba(201,168,76,0.15); }
  .class-card h3 { color: var(--gold); font-size: 1.3em; margin-bottom: 10px; }
  .class-card p { color: var(--text-dim); font-size: 0.9em; line-height: 1.4; }
  .class-card .stats-preview { margin-top: 12px; font-size: 0.85em; color: #aaa; }

  /* ===== COMBAT SCREEN ===== */
  #combat-screen { justify-content: flex-start; padding: 0; background: radial-gradient(ellipse at 50% 40%, #1a1a2e, #0a0a0f); }

  .top-bar {
    width: 100%; height: 56px; display: flex; align-items: center; justify-content: space-between;
    padding: 0 24px; background: linear-gradient(180deg, #1a1a2e, transparent);
    border-bottom: 1px solid rgba(201,168,76,0.15);
    z-index: 10; flex-shrink: 0;
  }
  .top-bar .stat { display: flex; align-items: center; gap: 8px; font-family: 'Cinzel', serif; font-size: 0.95em; }
  .top-bar .gold-icon { color: var(--gold); }

  .combat-area {
    flex: 1; width: 100%; display: flex; align-items: center; justify-content: center; position: relative; overflow: hidden;
  }

  /* Enemy */
  .enemy-container { text-align: center; z-index: 5; transition: all 0.3s; }
  .enemy-sprite { width: 160px; height: 180px; position: relative; margin-bottom: 12px; }
  .enemy-hp-bar-container { width: 180px; margin: 0 auto; }
  .hp-bar-bg { background: var(--hp-bg); border-radius: 4px; height: 16px; overflow: hidden; position: relative; border: 1px solid #553333; }
  .hp-bar-fill { height: 100%; background: linear-gradient(90deg, #cc2222, #ee4444); transition: width 0.4s ease; border-radius: 3px; }
  .hp-text { position: absolute; top: 0; left: 50%; transform: translateX(-50%); font-size: 10px; color: #fff; line-height: 16px; text-shadow: 0 1px 2px rgba(0,0,0,0.8); }
  .enemy-name { margin-top: 6px; font-family: 'Cinzel', serif; color: var(--gold-dim); font-size: 0.9em; }
  .enemy-statuses { display: flex; gap: 4px; justify-content: center; margin-top: 4px; min-height: 20px; }
  .status-badge { font-size: 10px; padding: 2px 6px; border-radius: 3px; color: #fff; }
  .status-burn { background: var(--burn-orange); }
  .status-poison { background: var(--poison-green); }
  .status-stun { background: #555; }

  /* Player info */
  .player-info-bar {
    width: 100%; padding: 8px 24px; display: flex; align-items: center; justify-content: space-between;
    background: linear-gradient(0deg, rgba(10,10,15,0.9), transparent);
    z-index: 10; flex-shrink: 0;
  }
  .player-hp-section { display: flex; align-items: center; gap: 12px; }
  .player-hp-bar-container { width: 200px; }
  .energy-display { display: flex; gap: 4px; align-items: center; }
  .energy-pip { width: 18px; height: 18px; border-radius: 50%; background: #3a6fd4; box-shadow: 0 0 6px rgba(58,111,212,0.5); transition: all 0.2s; }
  .energy-pip.empty { background: #1a1a2e; box-shadow: none; border: 1px solid #333; }

  /* Hand */
  .hand-area {
    width: 100%; padding: 10px 20px 16px; display: flex; justify-content: center; gap: 8px;
    min-height: 200px; align-items: flex-end; z-index: 10; flex-shrink: 0;
    perspective: 800px;
  }

  /* Cards */
  .card {
    width: 130px; height: 185px; position: relative; cursor: pointer;
    transition: transform 0.2s, box-shadow 0.2s; flex-shrink: 0;
    border-radius: 6px; overflow: hidden;
  }
  .card:hover { transform: translateY(-18px) scale(1.05); z-index: 20; }
  .card.unplayable { opacity: 0.45; cursor: not-allowed; filter: grayscale(0.3); }
  .card.unplayable:hover { transform: none; }

  .card-inner {
    width: 100%; height: 100%; position: relative;
    border-radius: 6px; overflow: hidden;
  }

  .card-cost {
    position: absolute; top: 4px; left: 4px; width: 28px; height: 28px;
    background: radial-gradient(circle, #3a6fd4, #1a3a7d);
    border-radius: 50%; display: flex; align-items: center; justify-content: center;
    font-family: 'Cinzel', serif; font-weight: 900; font-size: 14px; color: #fff;
    z-index: 3; box-shadow: 0 2px 6px rgba(0,0,0,0.5);
  }

  .card-image {
    width: 100%; height: 70px; margin-top: 34px; position: relative; overflow: hidden;
  }

  .card-body {
    padding: 6px 8px; font-size: 11px; line-height: 1.3; color: #ccc;
    height: calc(100% - 70px - 34px); display: flex; flex-direction: column; justify-content: space-between;
  }

  .card-name { font-family: 'Cinzel', serif; font-size: 12px; color: #fff; text-align: center; margin-bottom: 2px; }
  .card-type-label { font-size: 9px; text-transform: uppercase; letter-spacing: 1px; text-align: center; opacity: 0.7; }
  .card-desc { font-size: 10px; color: #aaa; line-height: 1.3; flex: 1; }

  /* Card type glows */
  .card[data-type="Attack"] .card-inner { border: 2px solid var(--red-attack); box-shadow: inset 0 0 20px rgba(212,74,42,0.15), 0 2px 8px rgba(0,0,0,0.5); }
  .card[data-type="Defense"] .card-inner { border: 2px solid var(--blue-defense); box-shadow: inset 0 0 20px rgba(58,111,212,0.15), 0 2px 8px rgba(0,0,0,0.5); }
  .card[data-type="Other"] .card-inner { border: 2px solid var(--purple-other); box-shadow: inset 0 0 20px rgba(139,58,212,0.15), 0 2px 8px rgba(0,0,0,0.5); }

  /* Controls */
  .controls-bar {
    width: 100%; padding: 6px 24px; display: flex; justify-content: center; gap: 16px;
    background: linear-gradient(0deg, #0a0a0f, transparent); z-index: 10; flex-shrink: 0;
  }

  /* ===== SHOP SCREEN ===== */
  #shop-screen { background: radial-gradient(ellipse at center, #1e1e30, #0a0a0f); padding-top: 40px; }
  .shop-title { font-size: 2em; color: var(--gold); margin-bottom: 8px; }
  .shop-gold { color: var(--text-dim); margin-bottom: 30px; font-size: 1.1em; }
  .shop-cards { display: flex; gap: 16px; flex-wrap: wrap; justify-content: center; max-width: 800px; margin-bottom: 30px; }
  .shop-card { cursor: pointer; transition: all 0.2s; position: relative; }
  .shop-card:hover { transform: translateY(-5px); }
  .shop-card .card-cost-overlay {
    position: absolute; bottom: -8px; left: 50%; transform: translateX(-50%);
    background: var(--gold-dim); color: #fff; padding: 2px 10px; border-radius: 4px;
    font-size: 11px; font-family: 'Cinzel', serif; white-space: nowrap; z-index: 5;
  }

  /* ===== GAME OVER / VICTORY ===== */
  #gameover-screen, #victory-screen { background: radial-gradient(ellipse at center, #1a0a0a, #0a0a0f); }
  #victory-screen { background: radial-gradient(ellipse at center, #1a1a2e, #0a0a0f); }
  .end-title { font-size: 3em; margin-bottom: 16px; text-shadow: 0 0 30px currentColor; }

  /* ===== DAMAGE NUMBERS ===== */
  .damage-number {
    position: absolute; pointer-events: none; z-index: 100;
    font-family: 'Cinzel', serif; font-weight: 900; font-size: 28px;
    animation: floatUp 1s ease-out forwards;
  }
  @keyframes floatUp {
    0% { opacity: 1; transform: translateY(0) scale(1.2); }
    100% { opacity: 0; transform: translateY(-60px) scale(0.8); }
  }

  /* ===== ROOM TRANSITION ===== */
  .room-transition {
    position: fixed; top: 0; left: 0; width: 100%; height: 100%;
    background: #0a0a0f; z-index: 200; display: flex; align-items: center; justify-content: center;
    animation: fadeInOut 1.5s ease-in-out forwards; pointer-events: none;
  }
  @keyframes fadeInOut {
    0% { opacity: 0; } 30% { opacity: 1; } 70% { opacity: 1; } 100% { opacity: 0; }
  }

  /* ===== DEFENSE INDICATOR ===== */
  .defense-indicator {
    display: flex; align-items: center; gap: 4px; font-family: 'Cinzel', serif; font-size: 0.9em; color: var(--blue-defense);
  }

  /* ===== ENEMY SVG STYLES ===== */
  .enemy-svg-container svg { width: 100%; height: 100%; }

  /* ===== PARTICLES ===== */
  .particle-bg {
    position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 0; overflow: hidden;
  }
  .particle {
    position: absolute; width: 2px; height: 2px; background: rgba(201,168,76,0.3); border-radius: 50%;
    animation: drift linear infinite;
  }
  @keyframes drift {
    0% { transform: translateY(100vh) rotate(0deg); opacity: 0; }
    10% { opacity: 1; }
    90% { opacity: 1; }
    100% { transform: translateY(-20px) rotate(360deg); opacity: 0; }
  }

  /* ===== TURN INDICATOR ===== */
  .turn-indicator {
    position: absolute; top: 70px; left: 50%; transform: translateX(-50%);
    font-family: 'Cinzel', serif; color: var(--gold-dim); font-size: 0.85em; letter-spacing: 2px;
    opacity: 0.6; z-index: 10;
  }

  /* ===== DECK INFO ===== */
  .deck-info { display: flex; gap: 16px; align-items: center; font-size: 0.85em; color: var(--text-dim); }
</style>
</head>
<body>

<!-- SVG DEFINITIONS (hidden) -->
<svg style="display:none">
  <!-- BASTION CARD FRAME -->
  <defs id="bastion-frame-defs">
    <linearGradient id="bastion-bg" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" style="stop-color:#2a2530"/>
      <stop offset="100%" style="stop-color:#1a1820"/>
    </linearGradient>
  </defs>

  <!-- WITHER CARD FRAME -->
  <defs id="wither-frame-defs">
    <linearGradient id="wither-bg" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" style="stop-color:#2a1a18"/>
      <stop offset="100%" style="stop-color:#1a1010"/>
    </linearGradient>
  </defs>

  <!-- SHROUD CARD FRAME -->
  <defs id="shroud-frame-defs">
    <linearGradient id="shroud-bg" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" style="stop-color:#1a1830"/>
      <stop offset="100%" style="stop-color:#0e0c1a"/>
    </linearGradient>
  </defs>
</svg>

<!-- TITLE SCREEN -->
<div id="title-screen" class="screen active">
  <div class="particle-bg" id="particles"></div>
  <h1>Shadows of Aethelgard</h1>
  <p class="subtitle">The Void consumes all. Only the brave descend.</p>
  <button class="btn" onclick="showClassSelect()">Begin Descent</button>
</div>

<!-- CLASS SELECT -->
<div id="class-select" class="screen">
  <h2 style="color:var(--gold); font-size:1.8em; margin-bottom:6px;">Choose Your Champion</h2>
  <p style="color:var(--text-dim); margin-bottom:10px;">Each hero carries a unique deck into the darkness.</p>
  <div class="class-cards">
    <div class="class-card" onclick="selectClass('bastion')">
      <h3>The Bastion</h3>
      <p>Immovable object. High defense and block, low speed.</p>
      <div class="stats-preview">HP: 35 | Energy: 3</div>
    </div>
    <div class="class-card" onclick="selectClass('wither')">
      <h3>The Wither</h3>
      <p>Rot and burn. Status effects, debuffs, AoE damage.</p>
      <div class="stats-preview">HP: 28 | Energy: 4</div>
    </div>
    <div class="class-card" onclick="selectClass('shroud')">
      <h3>The Shroud</h3>
      <p>Shadow and speed. Evasion, assassination, high crit.</p>
      <div class="stats-preview">HP: 28 | Energy: 4</div>
    </div>
  </div>
</div>

<!-- COMBAT SCREEN -->
<div id="combat-screen" class="screen">
  <div class="top-bar">
    <div class="stat"><span class="gold-icon">◆</span> <span id="ui-gold">0</span></div>
    <div class="stat title-font" style="color:var(--gold)">Floor <span id="ui-floor">1</span> — Room <span id="ui-room">1</span></div>
    <div class="deck-info">Deck: <span id="ui-deck-count">0</span> | Hand: <span id="ui-hand-size">4</span></div>
  </div>

  <div class="turn-indicator" id="turn-indicator">YOUR TURN</div>

  <div class="combat-area" id="combat-area">
    <div class="enemy-container" id="enemy-container">
      <div class="enemy-sprite" id="enemy-sprite"></div>
      <div class="enemy-hp-bar-container">
        <div class="hp-bar-bg"><div class="hp-bar-fill" id="enemy-hp-fill" style="width:100%"></div><span class="hp-text" id="enemy-hp-text">20/20</span></div>
      </div>
      <div class="enemy-name" id="enemy-name">Goblin Scout</div>
      <div class="enemy-statuses" id="enemy-statuses"></div>
    </div>
  </div>

  <div class="player-info-bar">
    <div class="player-hp-section">
      <span style="font-family:'Cinzel',serif; font-size:0.9em;">HP</span>
      <div class="player-hp-bar-container">
        <div class="hp-bar-bg"><div class="hp-bar-fill" id="player-hp-fill" style="width:100%"></div><span class="hp-text" id="player-hp-text">35/35</span></div>
      </div>
    </div>
    <div class="defense-indicator">🛡️ <span id="ui-defense">0</span></div>
    <div class="energy-display" id="energy-display"></div>
  </div>

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

  <div class="controls-bar">
    <button class="btn" id="end-turn-btn" onclick="endTurn()">End Turn</button>
  </div>
</div>

<!-- SHOP SCREEN -->
<div id="shop-screen" class="screen">
  <h2 class="shop-title title-font">Merchant's Tent</h2>
  <p class="shop-gold">Gold: <span id="shop-gold-display" style="color:var(--gold)">0</span></p>
  <div class="shop-cards" id="shop-cards"></div>
  <button class="btn" onclick="leaveShop()">Continue Deeper</button>
</div>

<!-- GAME OVER -->
<div id="gameover-screen" class="screen">
  <h1 class="end-title title-font" style="color:var(--hp-red)">Defeated</h1>
  <p style="color:var(--text-dim); margin-bottom:30px;">The Void claims another soul...</p>
  <button class="btn" onclick="location.reload()">Try Again</button>
</div>

<!-- VICTORY -->
<div id="victory-screen" class="screen">
  <h1 class="end-title title-font" style="color:var(--gold)">Victory!</h1>
  <p style="color:var(--text-dim); margin-bottom:30px;">Aethelgard is freed from the Void.</p>
  <button class="btn" onclick="location.reload()">Play Again</button>
</div>

<script>
// ============================================================
// GAME DATA
// ============================================================

const CARD_DATA = {
  // 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.', aoe:true, class:'bastion' },
  '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.', class:'bastion' },
  'BA-D01': { id:'BA-D01', name:'Shield Wall', type:'Defense', cost:0, atk:0, def:4, desc:'Gain 4 Defense this turn.', class:'bastion' },
  'BA-D02': { id:'BA-D02', name:'Iron Skin', type:'Defense', cost:2, atk:0, def:5, desc:'Gain 5 permanent Defense. Discard 1 card.', permDef:true, discardAfter:true, class:'bastion' },
  'BA-D03': { id:'BA-D03', name:'Stand Firm', type:'Defense', cost:1, atk:0, def:2, desc:'Gain 2 Defense. Blocks 1 incoming damage.', blockTrigger:true, 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.', stunEnemy:true, class:'bastion' },
  'BA-U01': { id:'BA-U01', name:'Search', type:'Other', cost:2, atk:0, def:0, desc:'Draw 1 card. Discard hand if >5 cards.', drawCard:true, discardIfOver5:true, class:'bastion' },
  'BA-U02': { id:'BA-U02', name:'Repair', type:'Other', cost:3, atk:0, def:0, desc:'Heal 6 HP.', heal:6, class:'bastion' },
  'BA-U03': { id:'BA-U03', name:'Rally', type:'Other', cost:1, atk:0, def:0, desc:'Draw 1 card. Gain 1 Energy.', drawCard:true, gainEnergy:1, class:'bastion' },
  'BA-U04': { id:'BA-U04', name:'Loot', type:'Other', cost:2, atk:0, def:0, desc:'Gain 5 Gold.', gold:5, class:'bastion' },

  // WITHER CARDS
  'WI-A01': { id:'WI-A01', name:'Fireball', type:'Attack', cost:2, atk:3, def:0, desc:'Deals 3 damage. Apply 1 Burn.', burn:1, class:'wither' },
  'WI-A02': { id:'WI-A02', name:'Inferno', type:'Attack', cost:3, atk:4, def:0, desc:'Deals 4 damage. Applies 3 Burn.', burn:3, aoe:true, class:'wither' },
  'WI-A03': { id:'WI-A03', name:'Ember', type:'Attack', cost:1, atk:2, def:0, desc:'Deals 2 damage. Deals 1 dmg/turn to target.', burn:1, class:'wither' },
  'WI-A04': { id:'WI-A04', name:'Pyre', type:'Attack', cost:4, atk:5, def:0, desc:'Deals 5 damage. All enemies take 1 dmg next turn.', aoe:true, class:'wither' },
  'WI-D01': { id:'WI-D01', name:'Scorch Shield', type:'Defense', cost:2, atk:0, def:3, desc:'Gain 3 Defense. Block 1 Burn damage.', blockBurn:true, 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.', gainEnergy:1, 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.', blockBurn:true, class:'wither' },
  'WI-D04': { id:'WI-D04', name:'Endure', type:'Defense', cost:3, atk:0, def:2, desc:'Gain 2 Defense. Heal 2 HP.', heal:2, class:'wither' },
  'WI-U01': { id:'WI-U01', name:'Poison', type:'Other', cost:2, atk:0, def:0, desc:'Apply 1 Poison to target enemy.', poison:1, class:'wither' },
  'WI-U02': { id:'WI-U02', name:'Burn', type:'Other', cost:3, atk:0, def:0, desc:'Deal 3 damage + 2 Burn to all enemies.', aoe:true, burn:2, otherDmg:3, class:'wither' },
  'WI-U03': { id:'WI-U03', name:'Slow', type:'Other', cost:1, atk:0, def:0, desc:'Draw 1 card. Stun target enemy.', drawCard:true, stunEnemy:true, class:'wither' },
  'WI-U04': { id:'WI-U04', name:'Wither', type:'Other', cost:2, atk:0, def:0, desc:'Heal 5 HP. Reduce enemy Attack by 1.', heal:5, debuffAtk:true, class:'wither' },

  // SHROUD CARDS
  'SH-A01': { id:'SH-A01', name:'Backstab', type:'Attack', cost:2, atk:4, def:0, desc:'Deals 4 damage. +1 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.', unblockable:true, class:'shroud' },
  'SH-A03': { id:'SH-A03', name:'Silence', type:'Attack', cost:1, atk:3, def:0, desc:'Deals 3 damage. Target silenced.', silenceEnemy:true, class:'shroud' },
  'SH-A04': { id:'SH-A04', name:'Vengeance', type:'Attack', cost:3, atk:6, def:0, desc:'Deals 6 damage. Gain 2 Energy.', gainEnergy:2, class:'shroud' },
  'SH-D01': { id:'SH-D01', name:'Blur', type:'Defense', cost:3, atk:0, def:2, desc:'Gain 2 Defense. Ignore next attack.', dodgeNext:true, class:'shroud' },
  'SH-D02': { id:'SH-D02', name:'Step', type:'Defense', cost:2, atk:0, def:3, desc:'Gain 3 Defense. Gain 1 Energy.', gainEnergy:1, class:'shroud' },
  'SH-D03': { id:'SH-D03', name:'Evasion', type:'Defense', cost:1, atk:0, def:1, desc:'Gain 1 Defense. Skip enemy action.', skipEnemy:true, class:'shroud' },
  'SH-D04': { id:'SH-D04', name:'Phantom', type:'Defense', cost:2, atk:0, def:4, desc:'Gain 4 Defense. Ghost form for 1 turn.', dodgeNext:true, class:'shroud' },
  'SH-U01': { id:'SH-U01', name:'Dash', type:'Other', cost:1, atk:0, def:0, desc:'Gain 1 Energy. Skip enemy attack.', gainEnergy:1, skipEnemy:true, class:'shroud' },
  'SH-U02': { id:'SH-U02', name:'Teleport', type:'Other', cost:2, atk:0, def:0, desc:'Deal 2 damage to all enemies.', aoe:true, otherDmg:2, class:'shroud' },
  'SH-U03': { id:'SH-U03', name:'Hide', type:'Other', cost:2, atk:0, def:0, desc:'Gain 1 Defense. Discard 1 card. Draw 2 cards.', drawCard:true, drawCount:2, discardAfter:true, class:'shroud' },
  'SH-U04': { id:'SH-U04', name:'Assassinate', type:'Attack', cost:3, atk:8, def:0, desc:'Deals 8 damage. Cannot be blocked.', unblockable:true, class:'shroud' }
};

const CLASS_CONFIG = {
  bastion: { hp:35, energy:3, handSize:4, name:'The Bastion', starterDeck:['BA-A01','BA-A02','BA-A03','BA-D01','BA-D02','BA-U01'] },
  wither:  { hp:28, energy:4, handSize:4, name:'The Wither', starterDeck:['WI-A01','WI-A02','WI-A03','WI-D01','WI-D03','WI-U01'] },
  shroud:  { hp:28, energy:4, handSize:4, name:'The Shroud', starterDeck:['SH-A01','SH-A02','SH-A03','SH-D01','SH-D02','SH-U01'] }
};

const ENEMY_TYPES = {
  floor1: [
    { name:'Goblin Scout', hp:20, dmg:3 },
    { name:'Rat Swarm', hp:18, dmg:2 },
    { name:'Goblin Brute', hp:25, dmg:4 }
  ],
  floor2: [
    { name:'Vampire Knight', hp:30, dmg:5 },
    { name:'Ogre', hp:35, dmg:6 },
    { name:'Dark Archer', hp:28, dmg:5 }
  ],
  floor3: [
    { name:'Void Warrior', hp:40, dmg:8 },
    { name:'Cultist', hp:38, dmg:7 },
    { name:'Abyssal Guard', hp:45, dmg:9 }
  ]
};

const BOSS_TYPES = [
  { name:'The Gatekeeper', hp:80, dmg:12, blockPerTurn:5, desc:'Blocks 5 damage/turn until HP<20' },
  { name:'The Corrupted', hp:80, dmg:10, burstDmg:20, desc:'Deals 20 damage if you have <3 Energy' },
  { name:'The Void Lord', hp:40, dmg:15, regenPerTurn:10, desc:'Regenerates 10 HP/turn. Cannot block.' }
];

// ============================================================
// GAME STATE
// ============================================================

let G = {}; // game state

function initGame(classId) {
  const cfg = CLASS_CONFIG[classId];
  G = {
    class: classId,
    hp: cfg.hp,
    maxHp: cfg.hp,
    energy: cfg.energy,
    maxEnergy: cfg.energy,
    handSize: cfg.handSize,
    gold: 0,
    defense: 0,
    permDefense: 0,
    floor: 1,
    room: 1,
    deck: [...cfg.starterDeck],
    hand: [],
    discardPile: [],
    enemy: null,
    isBoss: false,
    turnNumber: 1,
    dodgeNextAttack: false,
    skipEnemyAction: false,
    blockBurnDamage: false,
    cardCounts: {},
    combatActive: true
  };

  // Count cards in deck
  G.deck.forEach(id => { G.cardCounts[id] = (G.cardCounts[id]||0) + 1; });

  shuffleDeck();
}

function shuffleDeck() {
  for (let i = G.discardPile.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [G.discardPile[i], G.discardPile[j]] = [G.discardPile[j], G.discardPile[i]];
  }
  // If deck is empty, reshuffle discard
  if (G.deck.length === 0 && G.discardPile.length > 0) {
    G.deck = [...G.discardPile];
    G.discardPile = [];
    shuffleArray(G.deck);
  }
}

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]];
  }
}

// ============================================================
// SVG CARD GENERATION
// ============================================================

function getCardSVG(cardId, faceUp) {
  const card = CARD_DATA[cardId];
  if (!faceUp) return getCardBackSVG(G.class);

  let frameColor, accentColor, innerGlow;
  switch (G.class) {
    case 'bastion':
      frameColor = '#5a4a3a'; accentColor = '#8a7060'; innerGlow = 'rgba(138,112,96,0.15)'; break;
    case 'wither':
      frameColor = '#5a2a2a'; accentColor = '#8a4040'; innerGlow = 'rgba(138,64,64,0.15)'; break;
    case 'shroud':
      frameColor = '#2a2a5a'; accentColor = '#40408a'; innerGlow = 'rgba(64,64,138,0.15)'; break;
  }

  let typeColor;
  switch (card.type) {
    case 'Attack': typeColor = '#d44a2a'; break;
    case 'Defense': typeColor = '#3a6fd4'; break;
    case 'Other': typeColor = '#8b3ad4'; break;
  }

  // Unique frame decorations per class
  let frameDecorations = '';
  if (G.class === 'bastion') {
    // Shield/armor pattern
    frameDecorations = `
      <path d="M10,25 L60,15 L110,25" stroke="${accentColor}" fill="none" stroke-width="1.5"/>
      <path d="M10,160 L60,170 L110,160" stroke="${accentColor}" fill="none" stroke-width="1.5"/>
      <rect x="8" y="28" width="4" height="130" rx="1" fill="${frameColor}" opacity="0.5"/>
      <rect x="118" y="28" width="4" height="130" rx="1" fill="${frameColor}" opacity="0.5"/>
    `;
  } else if (G.class === 'wither') {
    // Flame/rot pattern
    frameDecorations = `
      <path d="M20,28 Q60,45 100,28" stroke="${accentColor}" fill="none" stroke-width="1.5"/>
      <path d="M20,157 Q60,140 100,157" stroke="${accentColor}" fill="none" stroke-width="1.5"/>
      <circle cx="30" cy="35" r="2" fill="${frameColor}" opacity="0.4"/>
      <circle cx="90" cy="35" r="2" fill="${frameColor}" opacity="0.4"/>
      <circle cx="30" cy="152" r="2" fill="${frameColor}" opacity="0.4"/>
      <circle cx="90" cy="152" r="2" fill="${frameColor}" opacity="0.4"/>
    `;
  } else {
    // Shadow/mist pattern
    frameDecorations = `
      <path d="M15,30 Q60,20 105,30" stroke="${accentColor}" fill="none" stroke-width="1.5"/>
      <path d="M15,155 Q60,165 105,155" stroke="${accentColor}" fill="none" stroke-width="1.5"/>
      <line x1="25" y1="38" x2="25" y2="147" stroke="${frameColor}" opacity="0.3" stroke-width="1"/>
      <line x1="95" y1="38" x2="95" y2="147" stroke="${frameColor}" opacity="0.3" stroke-width="1"/>
    `;
  }

  // Placeholder image area decoration per class
  let placeholderDecor = '';
  if (G.class === 'bastion') {
    placeholderDecor = `<rect x="25" y="48" width="80" height="44" rx="3" fill="#1a1820" stroke="${frameColor}" stroke-width="1"/>
      <text x="65" y="72" text-anchor="middle" font-size="10" fill="${accentColor}" opacity="0.5">⚔</text>`;
  } else if (G.class === 'wither') {
    placeholderDecor = `<rect x="25" y="48" width="80" height="44" rx="3" fill="#1a1010" stroke="${frameColor}" stroke-width="1"/>
      <text x="65" y="72" text-anchor="middle" font-size="10" fill="${accentColor}" opacity="0.5">🔥</text>`;
  } else {
    placeholderDecor = `<rect x="25" y="48" width="80" height="44" rx="3" fill="#0e0c1a" stroke="${frameColor}" stroke-width="1"/>
      <text x="65" y="72" text-anchor="middle" font-size="10" fill="${accentColor}" opacity="0.5">👁</text>`;
  }

  return `<svg viewBox="0 0 130 185" xmlns="http://www.w3.org/2000/svg">
    <defs>
      <linearGradient id="cbg_${cardId}" x1="0%" y1="0%" x2="100%" y2="100%">
        <stop offset="0%" style="stop-color:#2a2530"/>
        <stop offset="100%" style="stop-color:#141218"/>
      </linearGradient>
    </defs>
    <rect x="2" y="2" width="126" height="181" rx="6" fill="url(#cbg_${cardId})" stroke="${frameColor}" stroke-width="2"/>
    ${frameDecorations}
    <!-- Cost circle -->
    <circle cx="20" cy="20" r="13" fill="#1a3a7d" stroke="#4a8aff" stroke-width="1.5"/>
    <text x="20" y="24" text-anchor="middle" font-family="'Cinzel',serif" font-weight="900" font-size="14" fill="#fff">${card.cost}</text>
    <!-- Image placeholder -->
    ${placeholderDecor}
    <!-- Card name -->
    <text x="65" y="112" text-anchor="middle" font-family="'Cinzel',serif" font-weight="700" font-size="11" fill="#fff">${card.name}</text>
    <!-- Type label -->
    <text x="65" y="124" text-anchor="middle" font-size="8" fill="${typeColor}" letter-spacing="1.5">${card.type.toUpperCase()}</text>
    <!-- Description -->
    <text x="65" y="138" text-anchor="middle" font-size="7.5" fill="#aaa" font-family="'Crimson Text',serif">
      ${card.desc.length > 40 ? card.desc.substring(0,40)+'…' : card.desc}
    </text>
    <!-- Stats -->
    <text x="65" y="172" text-anchor="middle" font-family="'Cinzel',serif" font-size="9" fill="${typeColor}">
      ${card.atk > 0 ? '⚔'+card.atk : ''}${card.def > 0 ? (card.atk>0?' | ':'')+'🛡'+card.def : ''}
    </text>
  </svg>`;
}

function getCardBackSVG(classId) {
  let colors, pattern;
  switch (classId) {
    case 'bastion':
      colors = { bg:'#1a1820', frame:'#5a4a3a', accent:'#8a7060' };
      pattern = `
        <rect x="20" y="20" width="90" height="145" rx="4" fill="none" stroke="${colors.accent}" stroke-width="1.5"/>
        <path d="M65,35 L80,70 L65,60 L50,70 Z" fill="${colors.frame}" opacity="0.6"/>
        <path d="M65,150 L80,115 L65,125 L50,115 Z" fill="${colors.frame}" opacity="0.6"/>
        <circle cx="65" cy="92" r="18" fill="none" stroke="${colors.accent}" stroke-width="2"/>
        <text x="65" y="97" text-anchor="middle" font-size="14" fill="${colors.accent}">⛊</text>
      `;
      break;
    case 'wither':
      colors = { bg:'#1a1010', frame:'#5a2a2a', accent:'#8a4040' };
      pattern = `
        <rect x="20" y="20" width="90" height="145" rx="4" fill="none" stroke="${colors.accent}" stroke-width="1.5"/>
        <path d="M65,30 Q85,70 65,92 Q45,70 65,30Z" fill="${colors.frame}" opacity="0.4"/>
        <path d="M65,155 Q85,115 65,92 Q45,115 65,155Z" fill="${colors.frame}" opacity="0.4"/>
        <circle cx="65" cy="92" r="15" fill="none" stroke="${colors.accent}" stroke-width="2"/>
        <text x="65" y="97" text-anchor="middle" font-size="14" fill="${colors.accent}">🔥</text>
      `;
      break;
    case 'shroud':
      colors = { bg:'#0e0c1a', frame:'#2a2a5a', accent:'#40408a' };
      pattern = `
        <rect x="20" y="20" width="90" height="145" rx="4" fill="none" stroke="${colors.accent}" stroke-width="1.5"/>
        <path d="M65,35 L78,80 L65,70 L52,80 Z" fill="${colors.frame}" opacity="0.5"/>
        <path d="M65,150 L78,105 L65,115 L52,105 Z" fill="${colors.frame}" opacity="0.5"/>
        <circle cx="65" cy="92" r="18" fill="none" stroke="${colors.accent}" stroke-width="2"/>
        <text x="65" y="97" text-anchor="middle" font-size="14" fill="${colors.accent}">👁</text>
      `;
      break;
  }

  return `<svg viewBox="0 0 130 185" xmlns="http://www.w3.org/2000/svg">
    <rect x="2" y="2" width="126" height="181" rx="6" fill="${colors.bg}" stroke="${colors.frame}" stroke-width="2"/>
    ${pattern}
  </svg>`;
}

// ============================================================
// ENEMY SVG GENERATION
// ============================================================

function getEnemySVG(enemy) {
  let svg = '';
  if (G.isBoss) {
    // Boss - larger, more menacing
    const bossColors = ['#8b0000','#4a0080','#1a0030'];
    const c = bossColors[G.floor - 1] || '#8b0000';
    svg = `<svg viewBox="0 0 160 180" xmlns="http://www.w3.org/2000/svg">
      <defs>
        <radialGradient id="bossGlow"><stop offset="0%" style="stop-color:${c};stop-opacity:0.4"/>
          <stop offset="100%" style="stop-color:#0a0a0f;stop-opacity:0"/></radialGradient>
      </defs>
      <circle cx="80" cy="90" r="75" fill="url(#bossGlow)"/>
      <!-- Body -->
      <path d="M50,160 L60,100 L45,80 L55,60 L80,35 L105,60 L115,80 L100,100 L110,160 Z" fill="#2a1a1a" stroke="${c}" stroke-width="2"/>
      <!-- Eyes -->
      <ellipse cx="70" cy="70" rx="6" ry="4" fill="${c}">
        <animate attributeName="opacity" values="1;0.3;1" dur="2s" repeatCount="indefinite"/>
      </ellipse>
      <ellipse cx="90" cy="70" rx="6" ry="4" fill="${c}">
        <animate attributeName="opacity" values="1;0.3;1" dur="2s" repeatCount="indefinite"/>
      </ellipse>
      <!-- Crown/Horns -->
      <path d="M55,60 L48,30 L65,50 M105,60 L112,30 L95,50" stroke="${c}" fill="none" stroke-width="2"/>
      <!-- Aura particles -->
      <circle cx="40" cy="50" r="2" fill="${c}" opacity="0.5">
        <animate attributeName="cy" values="50;30;50" dur="3s" repeatCount="indefinite"/>
      </circle>
      <circle cx="120" cy="60" r="2" fill="${c}" opacity="0.5">
        <animate attributeName="cy" values="60;40;60" dur="3.5s" repeatCount="indefinite"/>
      </circle>
    </svg>`;
  } else {
    // Regular enemy
    const floorColors = ['#4a7a2a','#8b3a3a','#5a1a6a'];
    const c = floorColors[G.floor - 1] || '#4a7a2a';
    svg = `<svg viewBox="0 0 160 180" xmlns="http://www.w3.org/2000/svg">
      <!-- Body -->
      <path d="M55,155 L62,105 L50,90 L58,72 L80,50 L102,72 L110,90 L98,105 L105,155 Z" fill="#1a1a1a" stroke="${c}" stroke-width="1.5"/>
      <!-- Eyes -->
      <ellipse cx="73" cy="68" rx="4" ry="3" fill="${c}"/>
      <ellipse cx="87" cy="68" rx="4" ry="3" fill="${c}"/>
      <!-- Weapon hint -->
      <line x1="105" y1="90" x2="125" y2="60" stroke="${c}" stroke-width="2" opacity="0.7"/>
    </svg>`;
  }
  return svg;
}

// ============================================================
// SCREEN MANAGEMENT
// ============================================================

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

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

function selectClass(classId) {
  initGame(classId);
  startCombat();
}

// ============================================================
// COMBAT SYSTEM
// ============================================================

function startCombat() {
  G.combatActive = true;
  G.turnNumber = 1;
  G.defense = G.permDefense; // permanent defense carries over
  G.dodgeNextAttack = false;
  G.skipEnemyAction = false;
  G.blockBurnDamage = false;

  // Generate enemy
  if (G.room > 9) {
    // Boss fight
    G.isBoss = true;
    const bossIdx = Math.min(G.floor - 1, BOSS_TYPES.length - 1);
    const boss = BOSS_TYPES[bossIdx];
    G.enemy = {
      name: boss.name, hp: boss.hp, maxHp: boss.hp, dmg: boss.dmg,
      burn: 0, poison: 0, stunned: false, silenced: false,
      blockPerTurn: boss.blockPerTurn || 0, burstDmg: boss.burstDmg || 0, regenPerTurn: boss.regenPerTurn || 0,
      currentBlock: 0
    };
  } else {
    G.isBoss = false;
    const floorKey = 'floor' + G.floor;
    const types = ENEMY_TYPES[floorKey];
    const type = types[Math.floor(Math.random() * types.length)];
    G.enemy = {
      name: type.name, hp: type.hp, maxHp: type.hp, dmg: type.dmg,
      burn: 0, poison: 0, stunned: false, silenced: false,
      blockPerTurn: 0, burstDmg: 0, regenPerTurn: 0, currentBlock: 0
    };
  }

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

function drawCardsToHand() {
  while (G.hand.length < G.handSize && G.deck.length > 0) {
    const cardId = G.deck.pop();
    G.hand.push(cardId);
  }
  if (G.deck.length === 0 && G.discardPile.length > 0) {
    shuffleArray(G.discardPile);
    G.deck = [...G.discardPile];
    G.discardPile = [];
  }
}

function playCard(handIndex) {
  if (!G.combatActive) return;
  const cardId = G.hand[handIndex];
  const card = CARD_DATA[cardId];
  if (G.energy < card.cost) return;

  // Pay cost
  G.energy -= card.cost;

  // Resolve card effects
  resolveCard(card, handIndex);

  // Remove from hand and add to discard
  G.hand.splice(handIndex, 1);
  G.discardPile.push(cardId);

  updateUI();
}

function resolveCard(card, handIndex) {
  const enemy = G.enemy;

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

    // Bastion Slam bonus
    if (card.id === 'BA-A01' && G.hp >= 30) {
      drawCardsToHand();
    }

    // Shroud Backstab bonus
    if (card.id === 'SH-A01') {
      dmg += 1; // simplified: always +1
    }

    // Unblockable attacks ignore enemy block
    if (!card.unblockable && enemy.currentBlock > 0) {
      const blocked = Math.min(dmg, enemy.currentBlock);
      enemy.currentBlock -= blocked;
      dmg -= blocked;
    }

    if (dmg > 0) {
      dealDamageToEnemy(dmg);
      showDamageNumber(dmg, 'enemy');
    }

    // AoE attacks hit all enemies (simplified: just the one enemy in this prototype)
    if (card.aoe && card.id === 'BA-A02') {
      // Already handled above for single enemy
    }

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

    // Stun effect
    if (card.stunEnemy) {
      enemy.stunned = true;
    }

    // Silence effect
    if (card.silenceEnemy) {
      enemy.silenced = true;
    }

    // Energy gain
    if (card.gainEnergy) {
      G.energy = Math.min(G.maxEnergy, G.energy + card.gainEnergy);
    }

  } else if (card.type === 'Defense') {
    G.defense += card.def;

    if (card.permDef) {
      G.permDefense += card.def;
    }

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

    // Stun enemy
    if (card.stunEnemy) {
      enemy.stunned = true;
    }

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

    // Dodge next attack
    if (card.dodgeNext) {
      G.dodgeNextAttack = true;
    }

    // Block burn damage
    if (card.blockBurn) {
      G.blockBurnDamage = true;
    }

    // Energy gain
    if (card.gainEnergy) {
      G.energy = Math.min(G.maxEnergy, G.energy + card.gainEnergy);
    }

    // Discard after effect
    if (card.discardAfter && G.hand.length > 0) {
      const idx = Math.floor(Math.random() * G.hand.length);
      G.discardPile.push(G.hand[idx]);
      G.hand.splice(idx, 1);
    }

  } else if (card.type === 'Other') {
    // Damage effects
    if (card.otherDmg) {
      dealDamageToEnemy(card.otherDmg);
      showDamageNumber(card.otherDmg, 'enemy');
    }

    // Burn on other cards
    if (card.burn && !card.atk) {
      G.enemy.burn += card.burn;
    }

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

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

    // Draw cards
    if (card.drawCard) {
      const count = card.drawCount || 1;
      for (let i = 0; i < count; i++) drawCardsToHand();
      if (card.discardIfOver5 && G.hand.length > 5) {
        while (G.hand.length > 5) {
          G.discardPile.push(G.hand.pop());
        }
      }
    }

    // Gold
    if (card.gold) {
      G.gold += card.gold;
    }

    // Energy gain
    if (card.gainEnergy) {
      G.energy = Math.min(G.maxEnergy, G.energy + card.gainEnergy);
    }

    // Stun enemy
    if (card.stunEnemy) {
      G.enemy.stunned = true;
    }

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

    // Debuff attack
    if (card.debuffAtk) {
      G.enemy.dmg = Math.max(1, G.enemy.dmg - 1);
    }

    // Discard after effect
    if (card.discardAfter && G.hand.length > 0) {
      const idx = Math.floor(Math.random() * G.hand.length);
      G.discardPile.push(G.hand[idx]);
      G.hand.splice(idx, 1);
    }
  }

  // Check enemy death
  if (G.enemy.hp <= 0) {
    enemyDefeated();
  }
}

function dealDamageToEnemy(dmg) {
  G.enemy.hp = Math.max(0, G.enemy.hp - dmg);
}

function endTurn() {
  if (!G.combatActive) return;

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

  // Apply burn/poison to enemy at start of their turn
  applyStatusToEnemy();

  // Enemy action
  if (!G.skipEnemyAction && !G.enemy.stunned) {
    enemyAttack();
  } else {
    G.skipEnemyAction = false;
  }

  // Boss regen
  if (G.isBoss && G.enemy.regenPerTurn > 0 && G.enemy.hp > 0) {
    G.enemy.hp = Math.min(G.enemy.maxHp, G.enemy.hp + G.enemy.regenPerTurn);
  }

  // Boss block
  if (G.isBoss && G.enemy.blockPerTurn > 0 && G.enemy.hp >= 20 && G.enemy.hp > 0) {
    G.enemy.currentBlock += G.enemy.blockPerTurn;
  }

  // Reset per-turn defense
  G.defense = G.permDefense;
  G.dodgeNextAttack = false;
  G.skipEnemyAction = false;
  G.blockBurnDamage = false;

  // Enemy stun wears off
  if (G.enemy.stunned) {
    G.enemy.stunned = false;
  }

  // Check player death
  if (G.hp <= 0) {
    G.combatActive = false;
    updateUI();
    setTimeout(() => showScreen('gameover-screen'), 500);
    return;
  }

  // Next turn - draw cards and recover energy
  G.turnNumber++;
  G.energy = Math.min(G.maxEnergy, G.energy + 1);
  drawCardsToHand();

  updateUI();
}

function applyStatusToEnemy() {
  const enemy = G.enemy;
  if (enemy.burn > 0) {
    let burnDmg = enemy.burn;
    if (G.blockBurnDamage) burnDmg = Math.max(0, burnDmg - 1);
    dealDamageToEnemy(burnDmg);
    showDamageNumber(burnDmg, 'enemy', '#e8961e');
    enemy.burn = Math.max(0, enemy.burn - 1);
  }
  if (enemy.poison > 0) {
    dealDamageToEnemy(enemy.poison);
    showDamageNumber(enemy.poison, 'enemy', '#2ecc71');
    enemy.poison = Math.max(0, enemy.poison - 1);
  }
}

function enemyAttack() {
  const enemy = G.enemy;
  let dmg = enemy.dmg;

  // Boss 2 burst damage check
  if (G.isBoss && enemy.burstDmg > 0 && G.energy < 3) {
    dmg = enemy.burstDmg;
  }

  // Dodge
  if (G.dodgeNextAttack) {
    showDamageNumber(0, 'player', '#888');
    return;
  }

  // Apply defense
  let actualDmg = Math.max(0, dmg - G.defense);
  G.defense = Math.max(0, G.defense - dmg);

  if (actualDmg > 0) {
    G.hp -= actualDmg;
    showDamageNumber(actualDmg, 'player', '#cc2222');
  }
}

function enemyDefeated() {
  G.combatActive = false;
  const goldReward = G.isBoss ? 15 : 5;
  G.gold += goldReward;

  updateUI();

  setTimeout(() => {
    if (G.isBoss) {
      // Boss defeated
      if (G.floor >= 3 && G.room > 9) {
        showScreen('victory-screen');
      } else {
        G.floor++;
        G.room = 1;
        transitionRoom();
      }
    } else {
      G.room++;
      if (G.room > 9) {
        // Boss room
        transitionRoom();
      } else if (G.room % 3 === 0) {
        // Shop after every 3 rooms
        showShop();
      } else {
        transitionRoom();
      }
    }
  }, 800);
}

function transitionRoom() {
  const overlay = document.createElement('div');
  overlay.className = 'room-transition';
  overlay.innerHTML = `<h2 class="title-font" style="color:var(--gold)">Floor ${G.floor} — Room ${G.room}</h2>`;
  document.body.appendChild(overlay);

  setTimeout(() => {
    overlay.remove();
    startCombat();
  }, 1500);
}

// ============================================================
// SHOP SYSTEM
// ============================================================

function showShop() {
  showScreen('shop-screen');
  updateShopUI();
}

function getCardCost(cardId) {
  const count = G.cardCounts[cardId] || 0;
  if (count >= 3) return 10; // duplication cost
  return Math.min(50, 1 + count);
}

function updateShopUI() {
  document.getElementById('shop-gold-display').textContent = G.gold;

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

  // Show random cards from all classes (not just player's class)
  const allCards = Object.values(CARD_DATA);
  const shuffled = [...allCards].sort(() => Math.random() - 0.5).slice(0, 6);

  shuffled.forEach(card => {
    const cost = getCardCost(card.id);
    const canAfford = G.gold >= cost;
    const maxed = (G.cardCounts[card.id] || 0) >= 5;

    const div = document.createElement('div');
    div.className = 'shop-card';
    if (!canAfford || maxed) div.style.opacity = '0.4';
    div.innerHTML = getCardSVG(card.id, true);

    if (maxed) {
      div.innerHTML += `<div class="card-cost-overlay" style="background:#555">MAX</div>`;
    } else {
      div.innerHTML += `<div class="card-cost-overlay">${cost} Gold</div>`;
    }

    if (canAfford && !maxed) {
      div.onclick = () => buyCard(card.id, cost);
    }

    container.appendChild(div);
  });
}

function buyCard(cardId, cost) {
  if (G.gold < cost || (G.cardCounts[cardId]||0) >= 5) return;
  G.gold -= cost;
  G.deck.push(cardId);
  G.cardCounts[cardId] = (G.cardCounts[cardId]||0) + 1;
  updateShopUI();
}

function leaveShop() {
  transitionRoom();
}

// ============================================================
// UI UPDATE
// ============================================================

function updateUI() {
  // Top bar
  document.getElementById('ui-gold').textContent = G.gold;
  document.getElementById('ui-floor').textContent = G.floor;
  document.getElementById('ui-room').textContent = G.room > 9 ? 'BOSS' : G.room;
  document.getElementById('ui-deck-count').textContent = G.deck.length + G.discardPile.length;
  document.getElementById('ui-hand-size').textContent = G.handSize;

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

  // Defense
  document.getElementById('ui-defense').textContent = G.defense;

  // Energy pips
  const energyDiv = document.getElementById('energy-display');
  energyDiv.innerHTML = '';
  for (let i = 0; i < G.maxEnergy; i++) {
    const pip = document.createElement('div');
    pip.className = 'energy-pip' + (i >= G.energy ? ' empty' : '');
    energyDiv.appendChild(pip);
  }

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

    // Enemy sprite
    document.getElementById('enemy-sprite').innerHTML = getEnemySVG(G.enemy);

    // Statuses
    const statusDiv = document.getElementById('enemy-statuses');
    statusDiv.innerHTML = '';
    if (G.enemy.burn > 0) {
      statusDiv.innerHTML += `<span class="status-badge status-burn">🔥${G.enemy.burn}</span>`;
    }
    if (G.enemy.poison > 0) {
      statusDiv.innerHTML += `<span class="status-badge status-poison">☠${G.enemy.poison}</span>`;
    }
    if (G.enemy.stunned) {
      statusDiv.innerHTML += `<span class="status-badge status-stun">💫Stunned</span>`;
    }
  }

  // Hand
  renderHand();

  // Turn indicator
  document.getElementById('turn-indicator').textContent = G.combatActive ? 'YOUR TURN' : (G.enemy && G.enemy.hp <= 0 ? 'ENEMY DEFEATED!' : '');
}

function renderHand() {
  const handArea = document.getElementById('hand-area');
  handArea.innerHTML = '';

  G.hand.forEach((cardId, idx) => {
    const card = CARD_DATA[cardId];
    if (!card) return;

    const div = document.createElement('div');
    div.className = 'card';
    div.dataset.type = card.type;
    if (G.energy < card.cost || !G.combatActive) div.classList.add('unplayable');

    div.innerHTML = `<div class="card-inner">${getCardSVG(cardId, true)}</div>`;

    // Stagger cards slightly
    const offset = Math.max(-15, 15 - idx * 3);
    div.style.transform = `translateY(${offset}px)`;

    if (G.combatActive && G.energy >= card.cost) {
      div.onclick = () => playCard(idx);
    }

    handArea.appendChild(div);
  });
}

// ============================================================
// DAMAGE NUMBERS
// ============================================================

function showDamageNumber(amount, target, color) {
  const area = document.getElementById('combat-area');
  const num = document.createElement('div');
  num.className = 'damage-number';
  num.textContent = amount > 0 ? `-${amount}` : 'MISS';
  num.style.color = color || (target === 'enemy' ? '#ff4444' : '#cc2222');

  if (target === 'enemy') {
    num.style.left = '50%';
    num.style.top = '35%';
    num.style.transform = 'translateX(-50%)';
  } else {
    num.style.left = '50%';
    num.style.bottom = '25%';
    num.style.transform = 'translateX(-50%)';
  }

  area.appendChild(num);
  setTimeout(() => num.remove(), 1000);
}

// ============================================================
// PARTICLES (Title Screen)
// ============================================================

function initParticles() {
  const container = document.getElementById('particles');
  for (let i = 0; i < 30; i++) {
    const p = document.createElement('div');
    p.className = 'particle';
    p.style.left = Math.random() * 100 + '%';
    p.style.animationDuration = (5 + Math.random() * 10) + 's';
    p.style.animationDelay = Math.random() * 10 + 's';
    p.style.width = (1 + Math.random() * 2) + 'px';
    p.style.height = p.style.width;
    container.appendChild(p);
  }
}

// ============================================================
// INIT
// ============================================================

initParticles();
</script>
</body>
</html>
<!-- agent-meta {"model":"thinkingcap-qwen3.6-27b","provider":"lmstudio","persona":"middle","sessionId":"4cc40e53-dc1f-40aa-bde7-88a87d14b162","tokensIn":27327,"tokensOut":18683,"tokensTotal":46010,"turns":2,"toolCalls":1,"failedToolCalls":0,"timestamp":"2026-07-18T23:08:27.829Z"} -->