← Shadows results

Shadows

inkling · full

Initial view of Shadows

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 53,579 bytes · SHA-256 b76218de4de9
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Shadows of the Abyss</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Cinzel+Decorative:wght@400;700&family=Cormorant+Garamond:ital,wght@0,300;0,600;1,300&display=swap');

:root{
  --bg:#0b0a12;
  --surface:#12101f;
  --surface2:#18142a;
  --border:#2a1a3e;
  --gold:#d6b55a;
  --crimson:#8a1c2b;
  --shadow:#3a2a5a;
  --text:#e8e0d0;
  --sub:#a99e8e;
  --danger:#a82e2e;
  --heal:#4a8c6e;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%;width:100%;overflow:hidden;background:var(--bg);color:var(--text);font-family:'Cormorant Garamond',Georgia,serif}

/* Canvas background pattern */
#gameCanvas{position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:0;pointer-events:none;opacity:0.35}

/* Main UI layers */
#ui{position:relative;z-index:10;height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:1.5rem;pointer-events:none}
#ui>*{pointer-events:auto}

/* Title screen */
.screen{max-width:980px;width:92%;display:flex;flex-direction:column;align-items:center;gap:1.5rem;animation:fadeUp 1.2s ease-out both}
@keyframes fadeUp{from{opacity:0;transform:translateY(24px)}to{opacity:1;transform:translateY(0)}}

div.title{font-family:'Cinzel Decorative',serif;text-align:center}
div.title h1{font-size:clamp(2.6rem,7vw,4.2rem);letter-spacing:0.12em;color:var(--gold);text-shadow:0 0 40px rgba(214,181,90,0.35),0 4px 14px rgba(0,0,0,0.8);line-height:1.05}
div.title h2{font-family:'Cormorant Garamond',serif;font-size:1.15rem;color:var(--sub);font-weight:300;font-style:italic;letter-spacing:0.08em;margin-top:0.6rem}

/* Archetype cards */
.arch-row{display:flex;gap:1rem;flex-wrap:wrap;justify-content:center;margin-top:1.2rem}
.arch-card{background:linear-gradient(160deg,#151025 0%,#0f0b19 100%);border:1px solid var(--border);border-radius:14px;padding:1.2rem 1.1rem;width:240px;transition:transform .25s ease,border-color .25s,box-shadow .25s;cursor:pointer;box-shadow:0 6px 24px rgba(0,0,0,.55);position:relative;overflow:hidden}
.arch-card::before{content:'';position:absolute;top:0;left:0;right:0;height:4px;background:linear-gradient(90deg,transparent 10%,var(--gold) 50%,transparent 90%);opacity:0.25}
.arch-card:hover{transform:translateY(-6px);border-color:#4a2a5a;box-shadow:0 14px 40px rgba(138,28,43,.15)}

.arch-card h3{font-family:'Cinzel Decorative',serif;font-size:1.15rem;color:var(--gold);margin-bottom:.4rem;letter-spacing:.06em}
.arch-card .type-label{font-size:.7rem;text-transform:uppercase;letter-spacing:.12em;color:var(--sub);margin-bottom:.6rem}
.arch-card ul{list-style:none;font-size:.92rem;line-height:1.6;color:#cfc9bf}
.arch-card ul strong{color:var(--text);font-weight:600}

/* Game HUD */
#hud{display:none;position:absolute;top:0;left:0;right:0;padding:1rem 1.5rem;background:linear-gradient(180deg,rgba(11,10,18,.92) 0%,rgba(11,10,18,.45) 100%);pointer-events:none;z-index:30;display:flex;align-items:center;justify-content:space-between}
#hud.active{display:flex}

/* Center turn indicator for combat */
#turn-indicator{position:absolute;top:1rem;left:50%;transform:translateX(-50%);z-index:30;background:rgba(18,16,31,.85);border:1px solid var(--border);border-radius:999px;padding:.35rem 1rem;color:var(--gold);font-family:'Cinzel Decorative',serif;font-size:.85rem;letter-spacing:.1em;pointer-events:none;box-shadow:0 4px 14px rgba(0,0,0,.6);display:none}
#turn-indicator.active{display:block}

/* Player stats bar */
.stats-bar{display:flex;gap:1.2rem;align-items:center;padding:.3rem .7rem;background:rgba(18,16,31,.7);border:1px solid var(--border);border-radius:8px;backdrop-filter:blur(8px)}
.stat{display:flex;align-items:center;gap:.35rem;font-family:'Cinzel Decorative',serif;font-size:.95rem;color:var(--text)}
.stat .label{font-size:.65rem;color:var(--sub);text-transform:uppercase;letter-spacing:.08em}
.stat .value{font-weight:700;color:var(--gold)}
.hp-bar{width:140px;height:10px;background:#1a1525;border-radius:4px;overflow:hidden;margin-left:.2rem}
.hp-fill{height:100%;width:100%;background:linear-gradient(90deg,#a83232,#c06666);border-radius:4px;transition:width .35s ease}

/* Card zone */
#card-zone{position:absolute;bottom:0;left:0;right:0;height:28vh;display:flex;align-items:flex-end;justify-content:center;padding:0 1rem 1.2rem;pointer-events:none;gap:.35rem;z-index:20;transform:translateY(6vh);transition:transform .45s ease}
#card-zone.visible{transform:translateY(0)}

.card{width:130px;height:170px;background:linear-gradient(160deg,#18142a,#0f0b19);border:1.5px solid var(--border);border-radius:10px;padding:.7rem .6rem;font-size:.72rem;display:flex;flex-direction:column;color:var(--text);pointer-events:auto;box-shadow:0 8px 22px rgba(0,0,0,.55);transition:transform .18s ease,box-shadow .18s ease;position:relative;overflow:hidden;user-select:none;cursor:pointer}
.card:hover:not(.disabled){transform:translateY(-14px);box-shadow:0 16px 32px rgba(214,181,90,.18),0 8px 22px rgba(0,0,0,.55)}
.card.selected{border-color:var(--gold);box-shadow:0 0 0 2px var(--gold),0 16px 32px rgba(214,181,90,.15);transform:translateY(-10px)}
.card.disabled{opacity:.35;cursor:default;pointer-events:none}

.card .card-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:.35rem}
.card .card-cost{width:24px;height:24px;background:linear-gradient(135deg,#3a2a5a,#24143a);border-radius:50%;display:flex;align-items:center;justify-content:center;font-family:'Cinzel Decorative',serif;font-size:.8rem;color:var(--gold);box-shadow:0 2px 6px rgba(0,0,0,.45);font-weight:700}
.card .card-type{font-size:.58rem;text-transform:uppercase;letter-spacing:.1em;color:var(--sub);font-weight:600}
.card h4{font-family:'Cinzel Decorative',serif;font-size:.85rem;color:var(--gold);margin-bottom:.35rem;line-height:1.15;letter-spacing:.02em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.card p{font-size:.68rem;color:#ccc8be;line-height:1.35;flex-grow:1;overflow:hidden}
.card .card-rarity{position:absolute;bottom:.35rem;left:.6rem;font-size:.55rem;text-transform:uppercase;letter-spacing:.1em;color:var(--sub);font-weight:500}

/* Enemy box */
.enemy-panel{display:flex;gap:1.2rem;align-items:center;justify-content:center;margin-top:3.5rem;pointer-events:none}
.enemy{width:160px;height:180px;background:linear-gradient(160deg,#18101a,#0b080e);border:1.5px solid #2a1820;border-radius:10px;padding:.75rem .8rem;display:flex;flex-direction:column;align-items:center;box-shadow:0 8px 22px rgba(120,20,30,.15),0 6px 18px rgba(0,0,0,.5);position:relative;pointer-events:auto}
.enemy-icon{width:60px;height:60px;background:#1a0f14;border:1.5px solid #3a1a2a;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:1.6rem;color:#a85a5a;margin-bottom:.4rem;box-shadow:inset 0 0 20px rgba(138,28,43,.35)}
.enemy h4{font-family:'Cinzel Decorative',serif;font-size:.95rem;color:#e0c0b0;margin-bottom:.2rem;text-align:center;letter-spacing:.04em}
.enemy .hp-bar{width:100px;height:8px;background:#1a0f14;border-radius:4px;overflow:hidden;margin:.15rem 0}
.enemy .hp-fill{height:100%;width:100%;background:linear-gradient(90deg,#6a1a2a,#a85a5a);border-radius:4px;transition:width .35s ease}
.enemy .intent{margin-top:.3rem;font-size:.7rem;color:#e8b0a0;letter-spacing:.05em;min-height:1.2rem;text-align:center;font-family:'Cormorant Garamond',serif;font-style:italic}

/* Action bar */
.action-bar{position:absolute;bottom:28vh;left:50%;transform:translateX(-50%);display:flex;gap:.7rem;pointer-events:auto}
.btn{padding:.6rem 1.3rem;border:1.5px solid var(--gold);background:transparent;color:var(--gold);font-family:'Cinzel Decorative',serif;letter-spacing:.1em;font-size:.85rem;cursor:pointer;border-radius:6px;transition:background .2s,color .2s,box-shadow .2s;box-shadow:0 4px 14px rgba(214,181,90,.15)}
.btn:hover{background:rgba(214,181,90,.1);box-shadow:0 6px 22px rgba(214,181,90,.25)}
.btn:disabled{opacity:.35;cursor:default;border-color:#5a5040}

/* Status badges */
.status-row{display:flex;gap:.45rem;margin-top:.35rem;flex-wrap:wrap;justify-content:center}
.badge{padding:.15rem .4rem;border-radius:4px;font-size:.6rem;text-transform:uppercase;letter-spacing:.06em;font-weight:600;background:#1a1525;border:1px solid var(--border);color:#ccc}
.badge.strength{border-color:#8a6a4a;color:#e0c090}
.badge.weaken{border-color:#6a4a8a;color:#b8a0d0}
.badge.vulnerable{border-color:#8a4a4a;color:#e0a0a0}

/* Combat overlay */
#combat-overlay{position:absolute;top:0;left:0;right:0;bottom:0;background:rgba(5,4,10,.7);z-index:25;display:none;pointer-events:none}
#combat-overlay.active{display:block}

/* End turn screen overlay */
.end-turn-modal{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:30;background:#0f0b19;border:2px solid var(--gold);border-radius:14px;padding:2rem 2.4rem;text-align:center;box-shadow:0 20px 60px rgba(0,0,0,.8);display:none;animation:fadeUp .3s ease}
.end-turn-modal.active{display:block}
.end-turn-modal h3{font-family:'Cinzel Decorative',serif;color:var(--gold);font-size:1.4rem;margin-bottom:.4rem;letter-spacing:.08em}
.end-turn-modal p{color:var(--sub);font-style:italic;margin-bottom:1rem}

/* Reward screen */
#reward-screen{display:none;position:absolute;top:0;left:0;right:0;bottom:0;background:rgba(5,4,10,.8);z-index:40;align-items:center;justify-content:center;flex-direction:column;animation:fadeUp .4s ease}
#reward-screen.active{display:flex}
.rewards-grid{display:flex;gap:1.2rem;flex-wrap:wrap;justify-content:center;max-width:800px;margin-top:1rem}
.reward-card{width:140px;height:160px;background:linear-gradient(160deg,#18142a,#0f0b19);border:1.5px solid var(--border);border-radius:10px;padding:1rem;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.3rem;cursor:pointer;transition:transform .2s,border-color .2s;box-shadow:0 6px 18px rgba(0,0,0,.5)}
.reward-card:hover{border-color:#8a5a4a;transform:translateY(-6px)}
.reward-card h5{font-family:'Cinzel Decorative',serif;color:var(--gold);font-size:1rem;letter-spacing:.06em}
.reward-card span{font-size:.75rem;color:#ccc8be;text-align:center;line-height:1.3}

/* Map screen */
#map-screen{display:none;position:absolute;top:0;left:0;right:0;bottom:0;z-index:30;background:linear-gradient(180deg,#08060e 0%,#0b0a12 60%,#11101f 100%);align-items:center;justify-content:center;flex-direction:column;gap:2rem}
#map-screen.active{display:flex}
#map-screen h2{font-family:'Cinzel Decorative',serif;font-size:1.6rem;color:var(--gold);letter-spacing:.1em;text-shadow:0 0 30px rgba(214,181,90,.3)}
.map-row{display:flex;gap:1.5rem;justify-content:center;align-items:center}
.map-node{width:60px;height:60px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:1.3rem;background:#12101f;border:2px solid #2a1828;box-shadow:0 4px 14px rgba(0,0,0,.6);cursor:pointer;transition:transform .2s,border-color .2s;position:relative}
.map-node:hover:not(.disabled){transform:scale(1.15);border-color:#8a6a4a}
.map-node.active{border-color:var(--gold);box-shadow:0 0 14px rgba(214,181,90,.35)}
.map-node.completed{opacity:.45;pointer-events:none}
.map-node.boss{border-color:#a82e2e;box-shadow:0 0 14px rgba(168,46,46,.25)}
.map-node.boss.active{border-color:#d44a4a}
.map-node.rest{border-color:#4a8c6e;box-shadow:0 0 14px rgba(74,140,110,.25)}
.map-node.rest.active{border-color:#6ac08a}

/* Scrollable card list for deck view */
#deck-view{display:none;position:absolute;top:0;left:0;right:0;bottom:0;z-index:50;background:rgba(8,6,14,.85);padding-top:4rem;padding-left:2rem;padding-right:2rem;overflow-y:auto;align-items:center;justify-content:flex-start;flex-direction:column}
#deck-view.active{display:flex}
#deck-view h2{font-family:'Cinzel Decorative',serif;color:var(--gold);font-size:1.5rem;margin-bottom:1.5rem;letter-spacing:.1em}
.deck-cards{display:flex;flex-wrap:wrap;gap:.7rem;max-width:700px;justify-content:center}

/* Text log area */
#log-area{position:absolute;top:52vh;left:50%;transform:translateX(-50%);width:80%;max-width:720px;text-align:center;color:#ccc8be;font-size:.95rem;font-family:'Cormorant Garamond',serif;font-style:italic;pointer-events:none;line-height:1.5;min-height:3rem;z-index:25;text-shadow:0 2px 8px rgba(0,0,0,.7)}
#log-area.error{color:#e85a5a}
#log-area.success{color:#6ac08a}

/* Responsive tweaks */
@media(max-width:640px){
  .arch-row{flex-direction:column;align-items:center}
  .arch-card{width:92%;max-width:300px}
  .enemy{width:120px;height:150px}
  .card{width:110px;height:150px;font-size:.65rem}
}
</style>
</head>
<body>

<!-- Dark ambient canvas -->
<canvas id="gameCanvas"></canvas>

<!-- HUD for combat -->
<div id="hud">
  <div class="stats-bar">
    <div class="stat"><span class="label">HP</span><span class="value" id="hp-text">70/70</span>
      <div class="hp-bar"><div class="hp-fill" id="hp-fill"></div></div>
    </div>
    <div class="stat"><span class="label">Energy</span><span class="value" id="energy-text">3</span></div>
    <div class="stat"><span class="label">Draw</span><span class="value" id="draw-text">5</span></div>
    <div class="stat"><span class="label">Block</span><span class="value" id="block-text">0</span></div>
  </div>
  <div class="stats-bar" style="font-size:.85rem;color:var(--sub);padding:.3rem .7rem;gap:.7rem">
    <span>Act <strong style="color:var(--gold)" id="act-label">1</strong></span>
    <span>Gold <strong style="color:var(--gold)" id="gold-label">99</strong></span>
    <span>Run <span id="run-label" style="font-style:italic">Blood Reaper</span></span>
  </div>
</div>

<div id="turn-indicator">Your Turn</div>

<div id="ui">
  <div class="screen" id="title-screen">
    <div class="title">
      <h1>Shadows of the Abyss</h1>
      <h2>A dark fantasy deckbuilder — choose your curse and face the abyss.</h2>
    </div>
    <p style="color:var(--sub);font-style:italic;max-width:500px;text-align:center;font-size:1rem">Defeat the Archdemon in Act 3. Death is permanent. Your cards, your relics, and your choices shape the fate of the fallen.</p>

    <div class="arch-row">
      <button class="arch-card" onclick="startRun('Blood Reaper')">
        <h3>Blood Reaper</h3>
        <div class="type-label">The Sanguine Curse</div>
        <ul>
          <li><strong>Sacrifice HP</strong> for overwhelming damage.</li>
          <li>Apply <strong>Bleed</strong> and heal with strikes.</li>
          <li>Signature: <strong>Sanguine Strike</strong> — deal 8, heal 2.</li>
        </ul>
      </button>
      <button class="arch-card" onclick="startRun('Shadowmancer')">
        <h3>Shadowmancer</h3>
        <div class="type-label">The Veil of Night</div>
        <ul>
          <li>Weaken, confuse, and make <strong>Intangible</strong>.</li>
          <li>Draw and manipulate cards freely.</li>
          <li>Signature: <strong>Shadow Bolt</strong> — deal 6, apply Weak.</li>
        </ul>
      </button>
      <button class="arch-card" onclick="startRun('Hellforged')">
        <h3>Hellforged</h3>
        <div class="type-label">The Inferno Pact</div>
        <ul>
          <li>Apply <strong>Burn</strong>, summon Imps, and manipulate energy.</li>
          <li>Fast, fiery, and volatile.</li>
          <li>Signature: <strong>Firebolt</strong> — deal 7, apply 2 Burn.</li>
        </ul>
      </button>
    </div>
  </div>
</div>

<!-- Log area -->
<div id="log-area"></div>

<!-- Card zone -->
<div id="card-zone"></div>

<!-- Enemy panel -->
<div class="enemy-panel" id="enemy-panel"></div>

<!-- Action bar -->
<div class="action-bar" id="action-bar">
  <button class="btn" onclick="endTurn()" id="end-btn">End Turn</button>
  <button class="btn" onclick="showDeck()">Deck</button>
</div>

<!-- End turn modal -->
<div class="end-turn-modal" id="end-turn-modal">
  <h3>End of Turn</h3>
  <p>All unplayed cards discarded. Block resets.</p>
  <button class="btn" onclick="resolveEndTurn()">Continue</button>
</div>

<!-- Reward screen -->
<div id="reward-screen"></div>

<!-- Map screen -->
<div id="map-screen">
  <h2>The Path Ahead</h2>
  <div id="map-container"></div>
</div>

<!-- Deck view -->
<div id="deck-view">
  <h2>Your Deck</h2>
  <div class="deck-cards" id="deck-cards"></div>
  <button class="btn" onclick="hideDeck()" style="margin-top:1.2rem">Close</button>
</div>

<!-- Combat overlay (darken behind cards) -->
<div id="combat-overlay"></div>

<script>
/* ============================
   GAME ENGINE
   ============================ */

const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');

let W = window.innerWidth, H = window.innerHeight;
window.addEventListener('resize', () => { W = window.innerWidth; H = window.innerHeight; canvas.width = W; canvas.height = H; drawBG(); });
canvas.width = W; canvas.height = H;

function drawBG() {
  const c = ctx;
  c.fillStyle = '#0b0a12';
  c.fillRect(0,0,W,H);
  // Subtle radial glow
  const g = c.createRadialGradient(W/2,H*0.3,W*0.15,W/2,H*0.3,W*0.65);
  g.addColorStop(0,'rgba(138,28,43,0.08)');
  g.addColorStop(1,'rgba(11,10,18,1)');
  c.fillStyle = g;
  c.fillRect(0,0,W,H);
  // Vertical lines (bars of shadow)
  c.save();
  c.globalAlpha = 0.05;
  for(let i=0;i<60;i++){
    const x = (W/60)*(i+Math.sin(i*0.3+Date.now()*0.0005)*2);
    const wLine = 1 + Math.random()*2;
    c.fillStyle = `rgba(214,181,90,${0.25+Math.random()*0.3})`;
    c.fillRect(x,0,wLine,H);
  }
  c.restore();
}
function animBG() {
  drawBG();
  requestAnimationFrame(animBG);
}
animBG();

/* ============================
   STATE
   ============================ */
let runData = null; // {class, hp, maxHp, gold, energy, deck, hand, discard, block, status, act, actProgress}
let combatState = null; // {enemies, turnPhase, playerTurnEnd, selectedCards}

function logMsg(msg, cls=''){
  const el = document.getElementById('log-area');
  el.className = cls ? 'error' : '';
  el.textContent = msg;
  el.style.display = msg ? 'block' : 'none';
  if(msg) setTimeout(()=>{ if(el.textContent===msg) el.style.display='none'; }, 3500);
}

/* ============================
   CARD DATA
   ============================ */
const CARD_POOL = {
  'Blood Reaper': [
    {name:'Sanguine Strike',cost:1,type:'Attack',desc:'Deal 8 damage. Heal 2 HP.',rarity:'Common'},
    {name:'Hemorrhage',cost:1,type:'Attack',desc:'Deal 5 damage. Apply 3 Bleed.',rarity:'Common'},
    {name:'Bloodletting',cost:1,type:'Attack',desc:'Lose 3 HP. Deal 12 damage.',rarity:'Uncommon'},
    {name:'Crimson Eruption',cost:2,type:'Attack',desc:'Deal 8 damage to ALL enemies. Lose 2 HP.',rarity:'Rare'},
    {name:'Crimson Shield',cost:1,type:'Skill',desc:'Gain 6 Block. Lose 2 HP.',rarity:'Common'},
    {name:'Blood Ward',cost:1,type:'Skill',desc:'Gain 3 Block. Gain 1 Regeneration.',rarity:'Common'},
    {name:'Sacrificial Barrier',cost:2,type:'Skill',desc:'Gain 10 Block. Lose 5 HP.',rarity:'Uncommon'},
    {name:'Vital Surge',cost:'X',type:'Skill',desc:'Gain Block equal to missing HP. Exhaust.',rarity:'Rare'},
    {name:'Life Tap',cost:0,type:'Skill',desc:'Draw 2 cards. Lose 3 HP.',rarity:'Common'},
    {name:'Rend Flesh',cost:1,type:'Skill',desc:'Apply 5 Bleed to ALL. Lose 2 HP.',rarity:'Uncommon'},
    {name:'Soul Siphon',cost:2,type:'Power',desc:'At start of turn, gain 1 Energy and lose 1 HP.',rarity:'Uncommon'},
    {name:'Blood Pact',cost:1,type:'Power',desc:'Whenever you lose HP from a card, gain 1 Strength.',rarity:'Rare'},
  ],
  'Shadowmancer': [
    {name:'Shadow Bolt',cost:1,type:'Attack',desc:'Deal 6 damage. Apply 1 Weak.',rarity:'Common'},
    {name:'Grasp of Despair',cost:1,type:'Attack',desc:'Deal 4 damage. Apply 1 Vulnerable.',rarity:'Common'},
    {name:'Nightmare Lash',cost:2,type:'Attack',desc:'Deal 7 damage. If enemy has Weak, deal 7 more.',rarity:'Uncommon'},
    {name:'Eternal Darkness',cost:2,type:'Attack',desc:'Deal 3 damage to a random enemy 3 times.',rarity:'Rare'},
    {name:'Cloak of Shadows',cost:1,type:'Skill',desc:'Gain 5 Block. Draw 1 card.',rarity:'Common'},
    {name:'Haunting Mist',cost:1,type:'Skill',desc:'Gain 7 Block. Apply 1 Weak to ALL enemies.',rarity:'Common'},
    {name:'Phantom Armor',cost:1,type:'Skill',desc:'Gain 8 Block. Next turn, gain 2 Dexterity.',rarity:'Uncommon'},
    {name:'Whispering Shroud',cost:1,type:'Skill',desc:'Gain 4 Block. Next turn, gain 4 Block.',rarity:'Rare'},
    {name:'Shadowform',cost:2,type:'Skill',desc:'Gain 2 Intangible. Exhaust.',rarity:'Uncommon'},
    {name:'Curse of Misfortune',cost:1,type:'Skill',desc:'Enemy loses 3 Strength this turn. Apply 1 Vulnerable.',rarity:'Common'},
    {name:'Dark Ritual',cost:0,type:'Skill',desc:'Gain 2 Energy. Shuffle Dazed into draw.',rarity:'Uncommon'},
    {name:'Umbral Mastery',cost:2,type:'Power',desc:'At start of turn, apply 1 Weak to ALL enemies.',rarity:'Rare'},
  ],
  'Hellforged': [
    {name:'Firebolt',cost:1,type:'Attack',desc:'Deal 7 damage. Apply 2 Burn.',rarity:'Common'},
    {name:'Hellfire Blast',cost:2,type:'Attack',desc:'Deal 9 damage to ALL enemies.',rarity:'Uncommon'},
    {name:'Searing Strike',cost:1,type:'Attack',desc:'Deal 6 damage. Gain 1 Energy next turn.',rarity:'Common'},
    {name:'Immolate',cost:2,type:'Attack',desc:'Deal 12 damage. Exhaust.',rarity:'Rare'},
    {name:'Obsidian Skin',cost:1,type:'Skill',desc:'Gain 7 Block.',rarity:'Common'},
    {name:'Flame Ward',cost:1,type:'Skill',desc:'Gain 5 Block. Apply 2 Burn to random enemy.',rarity:'Common'},
    {name:'Demonic Resilience',cost:1,type:'Skill',desc:'Gain 4 Block. Heal 2 HP.',rarity:'Uncommon'},
    {name:'Brimstone Shield',cost:1,type:'Skill',desc:'Gain 3 Block. Gain 2 Strength this turn.',rarity:'Rare'},
    {name:'Summon Imp',cost:1,type:'Skill',desc:'Add an Imp Claw (0-cost Attack, deal 4 damage, Exhaust) to hand. Exhaust.',rarity:'Common'},
    {name:'Infernal Pact',cost:0,type:'Skill',desc:'Lose 2 HP. Gain 2 Energy. Add Imp Claw to hand.',rarity:'Uncommon'},
    {name:'Hellfire Aura',cost:2,type:'Power',desc:'At start of turn, deal 3 damage to ALL enemies.',rarity:'Rare'},
    {name:'Soul Burn',cost:1,type:'Skill',desc:'Apply 8 Burn to an enemy. Draw 1 card.',rarity:'Uncommon'},
  ]
};

const BASIC_DECK = [
  {name:'Strike',cost:1,type:'Attack',desc:'Deal 6 damage.',rarity:'Basic'},
  {name:'Strike',cost:1,type:'Attack',desc:'Deal 6 damage.',rarity:'Basic'},
  {name:'Strike',cost:1,type:'Attack',desc:'Deal 6 damage.',rarity:'Basic'},
  {name:'Strike',cost:1,type:'Attack',desc:'Deal 6 damage.',rarity:'Basic'},
  {name:'Strike',cost:1,type:'Attack',desc:'Deal 6 damage.',rarity:'Basic'},
  {name:'Defend',cost:1,type:'Skill',desc:'Gain 5 Block.',rarity:'Basic'},
  {name:'Defend',cost:1,type:'Skill',desc:'Gain 5 Block.',rarity:'Basic'},
  {name:'Defend',cost:1,type:'Skill',desc:'Gain 5 Block.',rarity:'Basic'},
  {name:'Defend',cost:1,type:'Skill',desc:'Gain 5 Block.',rarity:'Basic'},
];

/* ============================
   ENEMY DATA
   ============================ */
const ENEMY_POOL_ACT1 = [
  {name:'Skeleton Warrior',hp:22,intents:['Attack 6','Attack 6','Defend 8'],pattern:[0,1,2]},
  {name:'Zombie Brute',hp:28,intents:['Attack 8','Apply Weak 2','Attack 8'],pattern:[0,1,2]},
  {name:'Dark Cultist',hp:20,intents:['Gain 3 Strength','Attack 5','Attack 5'],pattern:[0,1,2]},
  {name:'Rat Swarm',hp:15,intents:['2x3 Damage','2x3 Damage'],pattern:[0,1]},
];
const ELITE_POOL_ACT1 = [
  {name:'Tomb Guardian',hp:42,intents:['Attack 6 + Block 8','3x4 Damage','Attack 12'],pattern:[0,1,2]},
  {name:'Blood Witch',hp:36,intents:['Attack 5 + Heal 4','Apply Weak & Vulnerable','Attack 7 + Heal 4'],pattern:[0,1,2]},
];
const BOSS_ACT1 = {name:'Lich King',hp:65,intents:['Summon Minion','Attack 8','Defend 12 Block'],pattern:[0,1,2],phase2HP:30};
const BOSS_ACT2 = {name:'Eldritch Treant',hp:75,intents:['Attack 10 + Weak 2','Defend 15 + Regen 2','2x8 Damage'],pattern:[0,1,2],phase2HP:40};
const BOSS_ACT3 = {name:'Archdemon',hp:85,intents:['Summon Hellhound','Attack 12 + Burn 2','Defend 15 + Strength 3'],pattern:[0,1,2],phase2HP:45};

/* ============================
   START
   ============================ */
function startRun(cls) {
  const classPool = CARD_POOL[cls];
  const sig = classPool.filter(c=>c.name==='Sanguine Strike' || c.name==='Shadow Bolt' || c.name==='Firebolt')[0];
  const deck = [...BASIC_DECK, {...sig}];
  runData = {
    class: cls,
    hp: 70,
    maxHp: 70,
    gold: 99,
    energy: 3,
    maxEnergy: 3,
    deck,
    hand: [],
    discard: [],
    drawPile: [],
    block: 0,
    status: {}, // {strength, weak, vulnerable, regen, bleed, burn, intangible}
    act: 1,
    actProgress: 0,
    combatDeck: [...deck.map(c=>({...c}))],
    combatDiscard: [],
    combatHand: [],
    combatDraw: [],
  };
  document.getElementById('title-screen').style.display = 'none';
  document.getElementById('map-screen').classList.add('active');
  renderMap();
  document.getElementById('run-label').textContent = cls;
  document.getElementById('act-label').textContent = '1';
  document.getElementById('gold-label').textContent = '99';
  logMsg('You descend into The Crypts. The first act awaits.', 'success');
}

/* ============================
   MAP
   ============================ */
function getMapLayout(act) {
  // Simplified path: 14 nodes + boss
  const nodes = [
    {id:1, type:'enemy', label:'Fight', completed:false},
    {id:2, type:'enemy', label:'Fight', completed:false},
    {id:3, type:'event', label:'Event', completed:false},
    {id:4, type:'shop', label:'Shop', completed:false},
    {id:5, type:'enemy', label:'Fight', completed:false},
    {id:6, type:'rest', label:'Rest', completed:false},
    {id:7, type:'enemy', label:'Fight', completed:false},
    {id:8, type:'elite', label:'Elite', completed:false},
    {id:9, type:'enemy', label:'Fight', completed:false},
    {id:10, type:'event', label:'Event', completed:false},
    {id:11, type:'elite', label:'Elite', completed:false},
    {id:12, type:'enemy', label:'Fight', completed:false},
    {id:13, type:'rest', label:'Rest', completed:false},
    {id:14, type:'boss', label:'Boss', completed:false},
  ];
  return nodes;
}

function renderMap() {
  const container = document.getElementById('map-container');
  const layout = getMapLayout(runData.act);
  container.innerHTML = '';
  // Show rows: 2 columns branching then back
  // Simplified: 4 rows showing progression
  const rows = [
    [layout[0], layout[1], layout[2], layout[3]],
    [layout[4], layout[5], layout[6], layout[7]],
    [layout[8], layout[9], layout[10], layout[11]],
    [layout[12], layout[13], null, layout[14]]
  ];
  const html = rows.map(row => `
    <div class="map-row">
      ${row.map(node => node ? `<button class="map-node ${node.type} ${node.completed?'completed':''} ${node.type==='boss'?'boss':''}" onclick="selectMapNode(${node.id})" title="${node.label}">${node.type==='boss'?'⚔':'●'}</button>` : '<div style="width:60px"></div>').join('')}
    </div>
  `).join('');
  container.innerHTML = html;
  // Highlight active path: the first uncompleted node
  const firstActive = layout.find(n=>!n.completed);
  if(firstActive){
    const btns = container.querySelectorAll('.map-node');
    btns.forEach(b=>b.classList.remove('active'));
    const btn = Array.from(btns).find(b=>b.textContent.includes('⚔') || b.textContent==='●');
    // Better approach: just leave active state for clickability
  }
  // Highlight next available nodes
  const btns = container.querySelectorAll('.map-node');
  btns.forEach(b=>{
    const idStr = b.getAttribute('onclick') || '';
    const match = idStr.match(/(\d+)/);
    if(match){
      const id = parseInt(match[1]);
      const node = layout.find(n=>n.id===id);
      b.classList.remove('active');
      if(node && !node.completed) b.classList.add('active');
    }
  });
}

function selectMapNode(id) {
  const layout = getMapLayout(runData.act);
  const node = layout.find(n=>n.id===id);
  if(!node || node.completed) return;
  node.completed = true;
  // Mark previous nodes completed implicitly
  for(const n of layout) if(n.id < id) n.completed = true;
  document.getElementById('map-screen').classList.remove('active');

  if(node.type === 'enemy') startCombat(generateEnemies(node));
  else if(node.type === 'elite') startCombat(generateElite());
  else if(node.type === 'boss') startCombat(generateBoss());
  else if(node.type === 'rest') startRest();
  else if(node.type === 'shop') startShop();
  else if(node.type === 'event') startEvent();
}

/* ============================
   ENEMY GENERATION
   ============================ */
function generateEnemies(node) {
  return [cloneEnemy(randomChoice(ENEMY_POOL_ACT1))];
}
function generateElite() {
  return [cloneEnemy(randomChoice(ELITE_POOL_ACT1))];
}
function generateBoss() {
  const b = runData.act === 1 ? BOSS_ACT1 : runData.act === 2 ? BOSS_ACT2 : BOSS_ACT3;
  return [cloneEnemy(b)];
}
function cloneEnemy(src) {
  return JSON.parse(JSON.stringify(src));
}
function randomChoice(arr) { return arr[Math.floor(Math.random()*arr.length)]; }

/* ============================
   COMBAT
   ============================ */
function startCombat(enemies) {
  combatState = {
    enemies,
    playerTurnEnd: false,
    selectedCards: [],
    energy: 3,
    turnCount: 1,
  };
  // Reset combat deck and shuffle
  runData.combatDeck = [...runData.deck.map(c=>({...c}))];
  runData.combatDiscard = [];
  runData.combatHand = [];
  runData.block = 0;
  runData.status = {strength:0, weak:0, vulnerable:0, regen:0, bleed:0, burn:0, intangible:0};
  drawHand();
  renderCombat();
  document.getElementById('hud').classList.add('active');
  document.getElementById('turn-indicator').classList.add('active');
  document.getElementById('turn-indicator').textContent = 'Your Turn';
  document.getElementById('card-zone').classList.add('visible');
  document.getElementById('combat-overlay').classList.add('active');
  logMsg('Combat begins! Play your cards.', 'success');
}

function drawHand() {
  const handSize = 5;
  while(runData.combatHand.length < handSize && (runData.combatDeck.length > 0 || runData.combatDiscard.length > 0)) {
    if(runData.combatDeck.length === 0) {
      runData.combatDeck = shuffle([...runData.combatDiscard]);
      runData.combatDiscard = [];
    }
    runData.combatHand.push(runData.combatDeck.pop());
  }
}

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

function renderCombat() {
  // HUD
  const hpEl = document.getElementById('hp-text');
  const hpFill = document.getElementById('hp-fill');
  hpEl.textContent = `${runData.hp}/${runData.maxHp}`;
  hpFill.style.width = `${Math.max(0, (runData.hp/runData.maxHp)*100)}%`;
  document.getElementById('energy-text').textContent = combatState ? combatState.energy : '3';
  document.getElementById('block-text').textContent = runData.block || '0';

  // Cards in hand
  const zone = document.getElementById('card-zone');
  zone.innerHTML = '';
  runData.combatHand.forEach((card, i) => {
    const el = document.createElement('div');
    el.className = 'card';
    if(card.cost > combatState.energy && card.cost !== 'X') el.classList.add('disabled');
    if(card.type === 'Power') el.style.borderColor = '#5a4a8a';
    el.innerHTML = `
      <div class="card-top">
        <span class="card-cost">${card.cost}</span>
        <span class="card-type">${card.type}</span>
      </div>
      <h4>${card.name}</h4>
      <p>${card.desc}</p>
      <span class="card-rarity">${card.rarity}</span>
    `;
    el.onclick = () => selectCard(i);
    zone.appendChild(el);
  });

  // Enemies
  const panel = document.getElementById('enemy-panel');
  panel.innerHTML = '';
  combatState.enemies.forEach((en, i) => {
    const intent = en.intents[en.pattern[en.pattern.length-1]] || en.intents[0]; // simplified
    // Actually compute next intent
    const turnCycle = en.pattern || [0];
    // We'll just show the next in cycle based on turn count
    const idx = (combatState.turnCount - 1) % turnCycle.length;
    const nextIntent = en.intents[turnCycle[idx]];
    const el = document.createElement('div');
    el.className = 'enemy';
    el.innerHTML = `
      <div class="enemy-icon">${en.name.includes('Skeleton') ? '☠' : en.name.includes('Brute') ? '💀' : en.name.includes('Witch') ? '🩸' : en.name.includes('King') ? '👑' : en.name.includes('Treant') ? '🌲' : en.name.includes('Demon') ? '🔥' : '⚔'}</div>
      <h4>${en.name}</h4>
      <div class="hp-bar"><div class="hp-fill" style="width:${Math.max(0,(en.hp/en.hp)*100)}%"></div></div>
      <div style="font-size:.75rem;color:#ccc">HP: ${en.hp}</div>
      <div class="intent">Next: ${nextIntent}</div>
      <div class="status-row">
        ${Object.entries(en.status||{}).map(([k,v])=>v>0?`<span class="badge ${k}">${k} ${v}</span>`:'').join('')}
      </div>
    `;
    panel.appendChild(el);
  });
}

function selectCard(index) {
  const card = runData.combatHand[index];
  if(!card) return;
  // Can't play if energy insufficient and not special
  const cost = card.cost === 'X' ? Math.min(combatState.energy, 5) : card.cost;
  if(card.cost > combatState.energy && card.cost !== 'X' && card.cost !== 0) return;

  // Pay cost
  if(card.cost === 'X') combatState.energy = 0; else if(card.cost !== 0) combatState.energy -= card.cost;

  // Apply effects
  applyCardEffect(card);

  // Play sound / visual would go here; we'll use text feedback
  logMsg('You played: ' + card.name, 'success');

  // Remove from hand
  runData.combatHand.splice(index, 1);
  // If exhaust, discard permanently from combat; otherwise discard
  if(card.desc.includes('Exhaust')) {
    // Card removed for combat only
  } else {
    runData.combatDiscard.push(card);
  }

  // Power cards go to a separate zone for the combat; for simplicity just discard after combat for basic implementation, but let's treat them as persistent effects. We'll just keep them active by tracking.
  if(card.type === 'Power') {
    // For simplicity, apply effect once then discard — full persistent state is complex in one file, but we'll simulate.
    logMsg('Power: ' + card.name + ' activates!', 'success');
    runData.combatDiscard.push(card); // In full version it stays; we'll approximate by applying on play.
  }

  // Redraw
  renderCombat();
  document.getElementById('energy-text').textContent = combatState.energy;

  // Check win/loss after effect
  setTimeout(checkCombatState, 500);
}

function applyCardEffect(card) {
  const target = combatState.enemies[0]; // Simplified: first enemy or all
  // Apply to all or single based on card text
  const all = card.desc.toLowerCase().includes('all enemies');
  const targets = all ? combatState.enemies : [target];

  if(card.desc.includes('Deal')) {
    let dmg = 0;
    if(card.name === 'Strike') dmg = 6;
    else if(card.name === 'Sanguine Strike') { dmg = 8; runData.hp = Math.min(runData.maxHp, runData.hp+2); }
    else if(card.name === 'Shadow Bolt') { dmg = 6; applyStatus('weak', 1, target); }
    else if(card.name === 'Firebolt') { dmg = 7; applyStatus('burn', 2, target); }
    else if(card.name === 'Hemorrhage') { dmg = 5; applyStatus('bleed', 3, target); }
    else if(card.name === 'Grasp of Despair') { dmg = 4; applyStatus('vulnerable', 1, target); }
    else if(card.name === 'Bloodletting') { dmg = 12; runData.hp = Math.max(0, runData.hp - 3); }
    else if(card.name === 'Crimson Eruption') { dmg = 8; runData.hp = Math.max(0, runData.hp - 2); }
    else if(card.desc.includes('Deal 6 damage')) dmg = 6; // generic
    else if(card.desc.includes('Deal 8 damage')) dmg = 8;
    else dmg = 5; // default

    // Modify by strength / vulnerable (simplified)
    dmg += (runData.status.strength || 0);
    if(target && target.status && target.status.vulnerable) dmg *= 1.5;

    targets.forEach(t => {
      const blocked = Math.max(0, t.block || 0);
      const actual = Math.max(0, Math.round(dmg) - blocked);
      t.hp = Math.max(0, t.hp - actual);
      if(blocked > 0 && actual > 0) { t.block = 0; }
    });
  }

  if(card.desc.includes('Gain')) {
    const blockVal = card.desc.includes('Gain 5') ? 5 : card.desc.includes('Gain 7') ? 7 : card.desc.includes('Gain 10') ? 10 : card.desc.includes('Gain 8') ? 8 : 5;
    // For simplicity block increases; we'll add directly
    runData.block += blockVal;
    if(card.desc.includes('Lose 2 HP')) runData.hp = Math.max(0, runData.hp-2);
    if(card.desc.includes('Lose 5 HP')) runData.hp = Math.max(0, runData.hp-5);
  }

  if(card.desc.includes('Apply')) {
    if(card.desc.includes('Bleed')) applyStatus('bleed', 3, target);
    if(card.desc.includes('Burn')) applyStatus('burn', 2, target);
    if(card.desc.includes('Weak')) applyStatus('weak', 1, target);
    if(card.desc.includes('Vulnerable')) applyStatus('vulnerable', 1, target);
  }

  if(card.desc.includes('Draw')) {
    const drawCount = card.desc.includes('Draw 2') ? 2 : 1;
    for(let i=0;i<drawCount;i++) drawHand();
  }

  // Heal from Blood Ward, etc.
  if(card.desc.includes('Heal')) runData.hp = Math.min(runData.maxHp, runData.hp + 2);

  // Update UI after effects
  updateUI();
}

function applyStatus(type, amount, enemy) {
  if(!enemy) return;
  if(!enemy.status) enemy.status = {};
  enemy.status[type] = (enemy.status[type] || 0) + amount;
}

function endTurn() {
  if(!combatState || combatState.playerTurnEnd) return;
  combatState.playerTurnEnd = true;
  document.getElementById('turn-indicator').textContent = 'Enemy Turn';
  document.getElementById('end-turn-modal').classList.add('active');
}

function resolveEndTurn() {
  document.getElementById('end-turn-modal').classList.remove('active');

  // Discard hand
  runData.combatDiscard = [...runData.combatDiscard, ...runData.combatHand];
  runData.combatHand = [];
  runData.block = 0; // Block resets at start of turn per design
  document.getElementById('turn-indicator').textContent = 'Enemy Turn';

  // Status updates: Intangible decrements, Weak/Vulnerable decrease by 1, Bleed/Burn halve
  for(const en of combatState.enemies) {
    if(en.status) {
      if(en.status.intangible !== undefined) en.status.intangible = Math.max(0, en.status.intangible - 1);
      if(en.status.weak !== undefined) en.status.weak = Math.max(0, en.status.weak - 1);
      if(en.status.vulnerable !== undefined) en.status.vulnerable = Math.max(0, en.status.vulnerable - 1);
      if(en.status.bleed !== undefined) { en.hp = Math.max(0, en.hp - en.status.bleed); en.status.bleed = Math.floor(en.status.bleed/2); }
      if(en.status.burn !== undefined) { en.hp = Math.max(0, en.hp - en.status.burn); en.status.burn = Math.floor(en.status.burn/2); }
    }
  }
  // Player status updates
  for(const key in runData.status) {
    if(key === 'bleed') { runData.hp = Math.max(0, runData.hp - runData.status.bleed); runData.status.bleed = Math.floor(runData.status.bleed/2); }
    else if(key === 'burn') { runData.hp = Math.max(0, runData.hp - runData.status.burn); runData.status.burn = Math.floor(runData.status.burn/2); }
    else if(key === 'intangible') runData.status.intangible = Math.max(0, runData.status.intangible - 1);
    else if(key === 'regen') { runData.hp = Math.min(runData.maxHp, runData.hp + runData.status.regen); runData.status.regen = Math.max(0, runData.status.regen - 1); }
    else if(typeof runData.status[key] === 'number') runData.status[key] = Math.max(0, runData.status[key] - 1);
  }

  // Enemy actions
  combatState.enemies.forEach(en => {
    const turnCycle = en.pattern || [0];
    const idx = (combatState.turnCount - 1) % turnCycle.length;
    const intentIdx = turnCycle[idx];
    const intentStr = en.intents[intentIdx];
    applyEnemyIntent(en, intentStr);
  });

  combatState.turnCount++;
  combatState.playerTurnEnd = false;
  combatState.energy = 3;
  document.getElementById('turn-indicator').textContent = 'Your Turn';
  document.getElementById('turn-indicator').classList.add('active');

  // Draw cards for new turn
  drawHand();
  renderCombat();
  document.getElementById('energy-text').textContent = 3;
  checkCombatState();
}

function applyEnemyIntent(en, intentStr) {
  if(intentStr.includes('Attack')) {
    const dmg = parseInt(intentStr.match(/(\d+)/)?.[1]) || 5;
    const blockReduce = Math.min(runData.block, dmg);
    runData.block = Math.max(0, runData.block - blockReduce);
    const actual = Math.max(0, dmg - blockReduce);
    // Intangible reduces damage to 1
    const finalDmg = (runData.status.intangible && runData.status.intangible > 0) ? 1 : actual;
    runData.hp = Math.max(0, runData.hp - finalDmg);
    logMsg(`${en.name} attacked for ${finalDmg} damage!`, 'error');
  } else if(intentStr.includes('Defend')) {
    const val = parseInt(intentStr.match(/(\d+)/)?.[1]) || 8;
    en.block = (en.block || 0) + val;
  } else if(intentStr.includes('Weak')) {
    runData.status.weak = (runData.status.weak || 0) + (parseInt(intentStr.match(/(\d+)/)?.[1]) || 1);
  } else if(intentStr.includes('Vulnerable')) {
    runData.status.vulnerable = (runData.status.vulnerable || 0) + 1;
  } else if(intentStr.includes('Bleed')) {
    runData.status.bleed = (runData.status.bleed || 0) + (parseInt(intentStr.match(/(\d+)/)?.[1]) || 3);
  } else if(intentStr.includes('Strength')) {
    en.status = en.status || {};
    en.status.strength = (en.status.strength || 0) + (parseInt(intentStr.match(/(\d+)/)?.[1]) || 2);
  }
}

function checkCombatState() {
  // Check enemy defeat
  const alive = combatState.enemies.filter(e=>e.hp > 0);
  if(alive.length === 0) {
    logMsg('Victory!', 'success');
    setTimeout(endCombat, 1200);
    return;
  }
  combatState.enemies = alive;
  // Player death
  if(runData.hp <= 0) {
    logMsg('You have fallen. Run over.', 'error');
    setTimeout(()=>{
      document.getElementById('map-screen').classList.remove('active');
      document.getElementById('title-screen').style.display = 'flex';
      document.getElementById('hud').classList.remove('active');
      document.getElementById('turn-indicator').classList.remove('active');
      document.getElementById('card-zone').classList.remove('visible');
      document.getElementById('combat-overlay').classList.remove('active');
      runData = null;
    }, 2500);
  } else {
    renderCombat();
  }
}

function endCombat() {
  // Give rewards
  showRewards();
  document.getElementById('hud').classList.remove('active');
  document.getElementById('turn-indicator').classList.remove('active');
  document.getElementById('card-zone').classList.remove('visible');
  document.getElementById('combat-overlay').classList.remove('active');
  combatState = null;
}

function showRewards() {
  document.getElementById('reward-screen').innerHTML = `
    <h3 style="font-family:'Cinzel Decorative',serif;color:var(--gold);font-size:1.6rem;letter-spacing:.1em">Victory!</h3>
    <p style="color:var(--sub);font-style:italic;margin-bottom:1rem">Choose a reward.</p>
    <div class="rewards-grid">
      <button class="reward-card" onclick="pickReward('card')"><h5>New Card</h5><span>Gain a card from your class pool.</span></button>
      <button class="reward-card" onclick="pickReward('gold')"><h5>Gold</h5><span>Gain 30 Gold.</span></button>
      <button class="reward-card" onclick="pickReward('potion')"><h5>Potion</h5><span>Gain a random potion.</span></button>
    </div>
  `;
  document.getElementById('reward-screen').classList.add('active');
}

function pickReward(type) {
  document.getElementById('reward-screen').classList.remove('active');
  if(type === 'card') {
    const options = getRandomCards(3);
    showCardChoice(options);
  } else if(type === 'gold') {
    runData.gold += 30;
    document.getElementById('gold-label').textContent = runData.gold;
    logMsg('+30 Gold!', 'success');
    finishRunProgress();
  } else {
    logMsg('You gained a potion.', 'success');
    finishRunProgress();
  }
}

function getRandomCards(count) {
  const pool = CARD_POOL[runData.class] || CARD_POOL['Blood Reaper'];
  const picks = [];
  for(let i=0;i<count;i++) picks.push({...randomChoice(pool)});
  return picks;
}

function showCardChoice(options) {
  document.getElementById('reward-screen').innerHTML = `
    <h3 style="font-family:'Cinzel Decorative',serif;color:var(--gold);font-size:1.3rem">Choose a Card</h3>
    <div class="rewards-grid">
      ${options.map((c,i) => `
        <button class="reward-card" onclick="addCardAndContinue(${i})">
          <h5>${c.name}</h5>
          <span style="font-size:.65rem;color:#aaa">${c.desc}</span>
        </button>
      `).join('')}
    </div>
  `;
  document.getElementById('reward-screen').classList.add('active');
  // Store options temporarily
  window.tempCardOptions = options;
}

function addCardAndContinue(i) {
  const opt = window.tempCardOptions[i];
  runData.deck.push({...opt});
  document.getElementById('reward-screen').classList.remove('active');
  logMsg('Card added: ' + opt.name, 'success');
  finishRunProgress();
}

function finishRunProgress() {
  // Go back to map for next choice; if boss, advance act
  if(combatState && combatState.enemies[0] && combatState.enemies[0].name.includes('King')) {
    // Boss defeated - next act
    runData.act = Math.min(3, runData.act + 1);
    runData.hp = runData.maxHp; // Heal after boss
    logMsg('You have defeated the boss and moved to Act ' + runData.act, 'success');
  }
  document.getElementById('map-screen').classList.add('active');
  renderMap();
}

/* ============================
   NODE EVENTS (Rest, Event)
   ============================ */
function startRest() {
  document.getElementById('map-screen').classList.remove('active');
  document.getElementById('reward-screen').innerHTML = `
    <h3 style="font-family:'Cinzel Decorative',serif;color:var(--gold);font-size:1.3rem">Rest Site</h3>
    <p style="color:var(--sub);font-style:italic;margin-bottom:1.2rem">Choose an action.</p>
    <div class="rewards-grid" style="flex-direction:column;align-items:center;gap:.6rem">
      <button class="btn" onclick="restAction('heal')">Rest — Heal 25% HP</button>
      <button class="btn" onclick="restAction('forge')">Forge — Upgrade a Card</button>
      <button class="btn" onclick="restAction('meditate')">Meditate — Remove a Card</button>
    </div>
  `;
  document.getElementById('reward-screen').classList.add('active');
}
function restAction(action) {
  document.getElementById('reward-screen').classList.remove('active');
  if(action === 'heal') {
    const amount = Math.floor(runData.maxHp * 0.25);
    runData.hp = Math.min(runData.maxHp, runData.hp + amount);
    logMsg(`Restored ${amount} HP.`, 'success');
  } else if(action === 'forge') {
    // Show deck cards to upgrade
    showDeckForUpgrade();
    return; // Don't finish progress yet
  } else {
    logMsg('Meditated. Remove a card.', 'success');
    showDeckForRemoval();
    return;
  }
  finishRunProgress();
}

function startEvent() {
  document.getElementById('map-screen').classList.remove('active');
  const eventText = 'A strange event unfolds...';
  document.getElementById('reward-screen').innerHTML = `
    <h3 style="font-family:'Cinzel Decorative',serif;color:var(--gold);font-size:1.3rem">Event</h3>
    <p style="color:#ccc8be;margin-bottom:1.2rem;max-width:420px;margin-left:auto;margin-right:auto;text-align:center">A mysterious altar pulses with forbidden energy. You feel a choice must be made.</p>
    <div class="rewards-grid" style="flex-direction:column;align-items:center;gap:.6rem">
      <button class="btn" onclick="resolveEvent('offer')">Offer 15 HP → Gain a Rare Relic</button>
      <button class="btn" onclick="resolveEvent('pray')">Pray → Heal 10 HP, gain Doubt (Curse)</button>
      <button class="btn" onclick="resolveEvent('leave')">Leave → Nothing</button>
    </div>
  `;
  document.getElementById('reward-screen').classList.add('active');
}
function resolveEvent(choice) {
  document.getElementById('reward-screen').classList.remove('active');
  if(choice === 'offer') {
    runData.hp = Math.max(0, runData.hp - 15);
    logMsg('Relic obtained!', 'success');
  } else if(choice === 'pray') {
    runData.hp = Math.min(runData.maxHp, runData.hp + 10);
    runData.deck.push({name:'Doubt',cost:0,type:'Curse',desc:'Unplayable. At end of turn, lose 1 HP.',rarity:'Curse'});
    logMsg('Healed, but gained Doubt.', 'success');
  } else {
    logMsg('You leave the altar behind.', 'success');
  }
  finishRunProgress();
}

function startShop() {
  document.getElementById('map-screen').classList.remove('active');
  document.getElementById('reward-screen').innerHTML = `
    <h3 style="font-family:'Cinzel Decorative',serif;color:var(--gold);font-size:1.3rem">Shop</h3>
    <p style="color:#ccc8be;margin-bottom:1rem">Gold: <strong style="color:var(--gold)">${runData.gold}</strong></p>
    <div class="rewards-grid">
      <button class="reward-card" onclick="buyShopItem('card')"><h5>Card (50g)</h5><span>Random class card.</span></button>
      <button class="reward-card" onclick="buyShopItem('relic')"><h5>Relic (150g)</h5><span>A powerful relic.</span></button>
      <button class="reward-card" onclick="buyShopItem('remove')"><h5>Remove Card (75g)</h5><span>Remove a card permanently.</span></button>
    </div>
  `;
  document.getElementById('reward-screen').classList.add('active');
}
function buyShopItem(type) {
  if(type === 'card') {
    if(runData.gold < 50) { logMsg('Not enough gold.', 'error'); return; }
    runData.gold -= 50;
    runData.deck.push({...randomChoice(CARD_POOL[runData.class])});
    logMsg('Card purchased.', 'success');
  } else if(type === 'relic') {
    if(runData.gold < 150) { logMsg('Not enough gold.', 'error'); return; }
    runData.gold -= 150;
    logMsg('Relic obtained!', 'success');
  } else {
    if(runData.gold < 75) { logMsg('Not enough gold.', 'error'); return; }
    runData.gold -= 75;
    logMsg('Select a card to remove.', 'success');
    showDeckForRemovalFromShop();
    return;
  }
  document.getElementById('gold-label').textContent = runData.gold;
  document.getElementById('reward-screen').classList.remove('active');
  finishRunProgress();
}

function showDeckForUpgrade() {
  document.getElementById('reward-screen').classList.remove('active');
  // Show deck in a temporary overlay
  showDeck('upgrade');
}
function showDeckForRemoval() {
  showDeck('remove');
}
function showDeckForRemovalFromShop() {
  showDeck('removeShop');
}

function showDeck(mode) {
  document.getElementById('deck-view').classList.add('active');
  document.getElementById('deck-cards').innerHTML = runData.deck.map((c,i) => `
    <button class="card" onclick="selectDeckCard(${i}, '${mode}')">
      <div class="card-top"><span class="card-cost">${c.cost}</span><span class="card-type">${c.type}</span></div>
      <h4>${c.name}</h4>
      <p>${c.desc}</p>
      <span class="card-rarity">${c.rarity}</span>
    </button>
  `).join('');
}

function selectDeckCard(i, mode) {
  if(mode === 'upgrade') {
    const card = runData.deck[i];
    // Upgrade to + version (simplified)
    card.name += '+';
    if(card.desc.includes('Deal 6')) card.desc = card.desc.replace('6','8');
    else if(card.desc.includes('Gain 5')) card.desc = card.desc.replace('5','8');
    else card.desc = card.desc.replace('2 HP', '3 HP');
    logMsg('Upgraded: ' + card.name, 'success');
    document.getElementById('deck-view').classList.remove('active');
    finishRunProgress();
  } else if(mode === 'remove' || mode === 'removeShop') {
    const card = runData.deck[i];
    runData.deck.splice(i, 1);
    logMsg('Removed: ' + card.name, 'success');
    document.getElementById('deck-view').classList.remove('active');
    if(mode === 'remove') finishRunProgress();
    else {
      // For shop removal we already paid
      document.getElementById('reward-screen').classList.remove('active');
      finishRunProgress();
    }
  }
}

function showDeck() {
  document.getElementById('deck-view').classList.add('active');
  document.getElementById('deck-cards').innerHTML = runData.deck.map((c) => `
    <div class="card" style="cursor:default">
      <div class="card-top"><span class="card-cost">${c.cost}</span><span class="card-type">${c.type}</span></div>
      <h4>${c.name}</h4>
      <p>${c.desc}</p>
      <span class="card-rarity">${c.rarity}</span>
    </div>
  `).join('');
  document.getElementById('deck-cards').dataset.mode = 'view';
}
function hideDeck() {
  document.getElementById('deck-view').classList.remove('active');
}

/* ============================
   UI UPDATES
   ============================ */
function updateUI() {
  document.getElementById('hp-text').textContent = `${runData.hp}/${runData.maxHp}`;
  document.getElementById('hp-fill').style.width = `${Math.max(0,(runData.hp/runData.maxHp)*100)}%`;
  document.getElementById('block-text').textContent = runData.block || '0';
  document.getElementById('draw-text').textContent = '5';
}

/* ============================
   INITIAL STATE FOR NON-COMBAT
   ============================ */
function initUI() {
  document.getElementById('card-zone').classList.remove('visible');
  document.getElementById('turn-indicator').classList.remove('active');
}
initUI();

</script>
</body>
</html>
<!-- agent-meta {"model":"thinkingmachines/inkling","provider":"openrouter","persona":"full","sessionId":"b332148d-13a5-465d-98fe-8f69d7acaeff","tokensIn":69238,"tokensOut":17841,"tokensTotal":87079,"turns":3,"toolCalls":2,"failedToolCalls":0,"timestamp":"2026-07-18T21:51:34.426Z"} -->