← Deckbuilder results

Deckbuilder

inkling · full

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 44,099 bytes · SHA-256 810fb855e50b
<!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 — Prototype</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Cinzel+Decorative:wght@400;700;900&family=Cinzel:wght@400;600;900&family=Cormorant+Garamond:ital,wght@0,300;0,600;1,400&display=swap');

:root{
  --bg:#06060a;
  --surface:#0d0d14;
  --surface2:#13131f;
  --gold:#d4a84b;
  --red:#b83528;
  --red-glow:#ff5e3a44;
  --blue:#3a7db8;
  --blue-glow:#3a7db844;
  --green:#2e8a4e;
  --green-glow:#2e8a4e44;
  --purple:#7a3ab8;
  --purple-glow:#7a3ab844;
  --text:#e6dccf;
  --text-dim:#9a8e82;
  --void:#1a0f2e;
  --bastion:#6b5328;
  --wither:#8a2e2e;
  --shroud:#18283a;
}

*{box-sizing:border-box;user-select:none;-webkit-user-select:none;}
html,body{margin:0;padding:0;height:100%;overflow:hidden;background:var(--bg);color:var(--text);font-family:'Cinzel',Georgia,serif;}

/* Ambient glow behind everything */
.ambient{
  position:fixed;inset:0;pointer-events:none;z-index:0;
  background:
    radial-gradient(circle at 20% 30%, rgba(212,168,75,0.06) 0%, transparent 50%),
    radial-gradient(circle at 80% 70%, rgba(122,58,184,0.05) 0%, transparent 50%),
    radial-gradient(circle at 50% 20%, rgba(58,125,184,0.04) 0%, transparent 50%);
}

/* Main layout */
#game{
  position:relative;z-index:1;width:100%;height:100vh;display:flex;flex-direction:column;
  background:linear-gradient(180deg,#08080c 0%,#0b0b12 60%,#060610 100%);
}

/* Header */
.header{
  display:flex;align-items:center;justify-content:space-between;padding:14px 24px;
  border-bottom:1px solid rgba(212,168,75,0.12);background:rgba(6,6,10,0.75);
  backdrop-filter:blur(6px);box-shadow:0 2px 24px rgba(0,0,0,0.6);
}
.header .brand h1{margin:0;font-family:'Cinzel Decorative',serif;font-size:1.35rem;color:var(--gold);letter-spacing:2px;text-shadow:0 0 20px rgba(212,168,75,0.3);}
.header .brand span{font-family:'Cormorant Garamond',serif;font-style:italic;color:var(--text-dim);font-size:0.95rem;letter-spacing:1px;}

.stats-row{display:flex;gap:18px;align-items:center;}
.stat{display:flex;align-items:center;gap:7px;font-size:0.85rem;color:var(--text-dim);}
.stat .val{color:var(--text);font-weight:700;font-size:1.05rem;}
.stat-icon{font-size:1.1rem;}

/* Main stage */
.main-stage{
  flex:1;display:flex;align-items:center;justify-content:center;position:relative;padding:20px 24px;
}

/* Enemy center */
.enemy-zone{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);text-align:center;z-index:2;
  transition:transform 0.3s ease, opacity 0.3s ease;
}
.enemy-zone.flicker{animation:flicker 0.15s ease 2;}
@keyframes flicker{0%{filter:brightness(1)}50%{filter:brightness(1.6)}100%{filter:brightness(1)}}

.enemy-frame{
  width:220px;height:220px;border-radius:50%;border:2px solid rgba(122,58,184,0.35);
  box-shadow:0 0 40px rgba(122,58,184,0.15),inset 0 0 40px rgba(0,0,0,0.7);
  background:radial-gradient(circle at 50% 40%,rgba(122,58,184,0.15) 0%,rgba(10,10,20,0.9) 70%);
  display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden;
  transition:box-shadow 0.3s;
}
.enemy-frame:hover{box-shadow:0 0 60px rgba(122,58,184,0.35),inset 0 0 40px rgba(0,0,0,0.5);}

.enemy-img{
  width:140px;height:140px;filter:drop-shadow(0 0 20px rgba(122,58,184,0.35));
  animation:float 4s ease-in-out infinite;
}
@keyframes float{0%,100%{transform:translateY(0)}50%{transform:translateY(-6px)}}

.enemy-hp{margin-top:10px;color:var(--red);font-weight:900;font-size:1.1rem;letter-spacing:1px;}
.enemy-name{font-family:'Cinzel Decorative',serif;color:#b8a898;font-size:1.05rem;margin-top:2px;letter-spacing:2px;}
.enemy-status{margin-top:6px;display:flex;justify-content:center;gap:8px;min-height:22px;}

/* Player / Cards area */
.player-zone{
  position:absolute;bottom:0;left:0;right:0;padding:0 24px 28px;display:flex;flex-direction:column;align-items:center;z-index:3;
}

.hand{display:flex;gap:14px;justify-content:center;align-items:flex-end;min-height:200px;perspective:900px;}

/* Card base styles */
.card{
  width:150px;height:210px;border-radius:14px;position:relative;cursor:pointer;
  transition:transform 0.2s ease, box-shadow 0.2s ease, filter 0.2s ease;
  box-shadow:0 8px 24px rgba(0,0,0,0.7),inset 0 1px 0 rgba(255,255,255,0.05);
  overflow:hidden;font-size:0.85rem;
}
.card:hover:not(.disabled){transform:translateY(-22px) rotate(-1deg);box-shadow:0 16px 40px rgba(0,0,0,0.8),0 0 0 2px rgba(212,168,75,0.25);}
.card.played{transform:scale(0.9) translateY(-40px) rotate(0);opacity:0.45;pointer-events:none;}
.card.disabled{filter:brightness(0.45) grayscale(0.8);cursor:not-allowed;}

/* Card frame SVG */
.card-frame{
  position:absolute;inset:0;z-index:1;pointer-events:none;
  drop-shadow:0 0 6px rgba(0,0,0,0.8);
}

/* Card content */
.card-inner{
  position:relative;z-index:2;height:100%;padding:10px 8px;display:flex;flex-direction:column;gap:6px;
  background:linear-gradient(180deg,#14121f 0%,#0c0b14 100%);
  border-radius:14px;overflow:hidden;
}

/* Card type colors */
.card.type-attack .card-inner{border-top:3px solid var(--red);box-shadow:inset 0 0 30px rgba(184,53,40,0.12);}
.card.type-defend .card-inner{border-top:3px solid var(--blue);box-shadow:inset 0 0 30px rgba(58,125,184,0.12);}
.card.type-other .card-inner{border-top:3px solid var(--purple);box-shadow:inset 0 0 30px rgba(122,58,184,0.12);}

.card-header{display:flex;justify-content:space-between;align-items:center;padding:0 2px;}
.card-cost{
  background:linear-gradient(135deg,#2a2418,#3a2e1a);border:1px solid rgba(212,168,75,0.25);
  color:var(--gold);font-weight:900;font-size:0.95rem;width:28px;height:28px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;box-shadow:0 2px 6px rgba(0,0,0,0.6);
}
.card-id{color:rgba(255,255,255,0.2);font-family:'Courier New',monospace;font-size:0.65rem;letter-spacing:0.5px;}

.card-title{
  font-family:'Cinzel Decorative',serif;font-size:0.95rem;color:#e8dcc8;text-align:center;
  margin-top:4px;letter-spacing:1px;text-shadow:0 2px 8px rgba(0,0,0,0.8);
}
.card-desc{
  font-family:'Cormorant Garamond',serif;font-size:0.82rem;color:#b5a898;line-height:1.35;text-align:center;flex:1;}
.card-stats{
  display:flex;justify-content:center;gap:10px;align-items:center;
  font-size:0.75rem;color:var(--text-dim);font-weight:600;
}

/* Card back */
.card-back{
  position:absolute;inset:0;background:#0a0810;border-radius:14px;
  display:flex;align-items:center;justify-content:center;box-shadow:inset 0 0 30px rgba(0,0,0,0.8);
  border:2px solid rgba(212,168,75,0.2);
}
.card-back svg{width:90px;height:120px;filter:drop-shadow(0 0 10px rgba(212,168,75,0.15));}

/* Action area (center bottom) */
.action-bar{
  display:flex;align-items:center;justify-content:center;gap:20px;margin-top:20px;
}
.btn{
  background:linear-gradient(180deg,#2a2418,#1a160e);border:1px solid rgba(212,168,75,0.25);
  color:var(--gold);font-family:'Cinzel',serif;font-weight:700;padding:10px 28px;border-radius:8px;cursor:pointer;
  letter-spacing:2px;box-shadow:0 4px 12px rgba(0,0,0,0.6),inset 0 1px 0 rgba(255,255,255,0.05);
  transition:all 0.15s ease;
}
.btn:hover:not(:disabled){background:linear-gradient(180deg,#3a2e1e,#2a1e14);border-color:rgba(212,168,75,0.45);transform:translateY(-2px);box-shadow:0 8px 20px rgba(212,168,75,0.15);}
.btn:disabled{opacity:0.35;cursor:not-allowed;}

/* Panels overlay */
.overlay{
  position:fixed;inset:0;background:rgba(4,4,8,0.85);z-index:50;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity 0.3s ease;backdrop-filter:blur(4px);
}
.overlay.active{opacity:1;pointer-events:auto;}

.panel{
  background:linear-gradient(180deg,#10101a 0%,#080810 100%);border:1px solid rgba(212,168,75,0.15);border-radius:16px;padding:28px 36px;max-width:520px;width:92%;box-shadow:0 30px 80px rgba(0,0,0,0.9),inset 0 1px 0 rgba(255,255,255,0.03);position:relative;
}
.panel::before{
  content:'';position:absolute;top:0;left:20px;right:20px;height:2px;background:linear-gradient(90deg,transparent,rgba(212,168,75,0.5),transparent);border-radius:50%;
}

.panel h2{font-family:'Cinzel Decorative',serif;color:var(--gold);margin:0 0 16px;text-align:center;letter-spacing:3px;font-size:1.3rem;}
.panel p{font-family:'Cormorant Garamond',serif;color:var(--text-dim);font-size:1.05rem;line-height:1.5;margin:0 0 18px;text-align:center;}

/* Class selection cards */
.class-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;}
.class-card{
  background:linear-gradient(180deg,#121220,#0a0a12);border:1px solid rgba(255,255,255,0.06);border-radius:12px;padding:18px;text-align:center;cursor:pointer;transition:all 0.2s;
}
.class-card:hover{border-color:rgba(212,168,75,0.3);transform:translateY(-4px);box-shadow:0 10px 24px rgba(0,0,0,0.6);}
.class-card.active{border-color:var(--gold);box-shadow:0 0 20px rgba(212,168,75,0.15);}
.class-card h3{margin:0 0 8px;font-family:'Cinzel',serif;font-size:1rem;color:var(--text);}
.class-card span{color:var(--text-dim);font-family:'Cormorant Garamond',serif;font-style:italic;font-size:0.85rem;}

/* Shop cards */
.shop-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;}
.shop-card{background:rgba(255,255,255,0.03);border:1px solid rgba(255,255,255,0.06);border-radius:10px;padding:14px;text-align:center;transition:all 0.2s;}
.shop-card:hover:not(.sold){border-color:rgba(212,168,75,0.25);transform:translateY(-3px);box-shadow:0 6px 16px rgba(0,0,0,0.5);}
.shop-card h4{margin:0 0 4px;font-family:'Cinzel Decorative',serif;color:var(--gold);font-size:0.85rem;letter-spacing:1px;}
.shop-card .price{font-family:'Cinzel',serif;font-weight:700;color:var(--gold);font-size:0.95rem;margin-bottom:4px;}
.shop-card .qty{font-size:0.7rem;color:var(--text-dim);}
.shop-card.sold{opacity:0.35;pointer-events:none;}

/* Status badges */
.badge{display:inline-block;padding:2px 8px;border-radius:4px;font-size:0.7rem;font-weight:700;letter-spacing:0.5px;background:rgba(184,53,40,0.15);color:var(--red);border:1px solid rgba(184,53,40,0.2);margin:0 2px;}
.badge.def{background:rgba(58,125,184,0.15);color:var(--blue);border-color:rgba(58,125,184,0.2);}

/* Log / text */
.log-area{margin-top:14px;padding:10px 14px;background:rgba(6,6,10,0.6);border:1px solid rgba(255,255,255,0.04);border-radius:8px;font-family:'Cormorant Garamond',serif;font-size:0.9rem;color:var(--text-dim);line-height:1.5;min-height:52px;}

/* Enemy damage indicator */
.enemy-attack-indicator{
  margin-top:6px;font-size:0.8rem;color:#b83528;font-family:'Cinzel',serif;font-weight:600;letter-spacing:1px;
}

/* Small decorative corner ornaments */
.corner-orn{position:absolute;width:24px;height:24px;border:2px solid rgba(212,168,75,0.15);border-radius:4px;pointer-events:none;}
.corner-orn.tl{top:10px;left:10px;border-right:0;border-bottom:0;}
.corner-orn.tr{top:10px;right:10px;border-left:0;border-bottom:0;}
.corner-orn.bl{bottom:10px;left:10px;border-right:0;border-top:0;}
.corner-orn.br{bottom:10px;right:10px;border-left:0;border-top:0;}
</style>
</head>
<body>
<div class="ambient"></div>
<div id="game">
  <div class="header">
    <div class="brand"><h1>SHADOWS OF AETHELGARD</h1><span>Dark Fantasy Roguelite Prototype</span></div>
    <div class="stats-row">
      <div class="stat"><span class="stat-icon">⚔</span> <span>Floor <span class="val" id="floor-label">1</span></span></div>
      <div class="stat"><span class="stat-icon">✦</span> <span>HP <span class="val" id="hp-val">30</span></span></div>
      <div class="stat"><span class="stat-icon">✶</span> <span>Def <span class="val" id="def-val">0</span></span></div>
      <div class="stat"><span class="stat-icon">⚡</span> <span>Energy <span class="val" id="energy-val">5</span> / <span id="max-energy">5</span></span></div>
      <div class="stat"><span class="stat-icon">✦</span> <span>Gold <span class="val" id="gold-val">0</span></span></div>
    </div>
  </div>

  <div class="main-stage">
    <!-- Enemy center -->
    <div class="enemy-zone" id="enemy-zone">
      <div class="enemy-frame" id="enemy-frame">
        <svg class="enemy-img" viewBox="0 0 140 140" id="enemy-svg">
          <defs>
            <linearGradient id="evil-grad" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#4a1c5a"/><stop offset="100%" stop-color="#140a1a"/></linearGradient>
          </defs>
          <circle cx="70" cy="60" r="22" fill="#4a1c5a" opacity="0.9"/>
          <path d="M50 70 Q55 120 90 120 Q125 100 105 70 Z" fill="#2a0e2a" stroke="#7a3ab8" stroke-width="2"/>
          <path d="M40 90 Q70 130 100 90" stroke="#7a3ab8" stroke-width="3" fill="none" opacity="0.7"/>
          <circle cx="70" cy="58" r="10" fill="#0a0a14" stroke="#b83528" stroke-width="2"/>
          <path d="M60 78 Q70 88 80 78" stroke="#b83528" stroke-width="2" fill="none"/>
          <circle cx="60" cy="55" r="3" fill="#b83528" opacity="0.8"/>
          <circle cx="80" cy="55" r="3" fill="#b83528" opacity="0.8"/>
        </svg>
      </div>
      <div class="enemy-name" id="enemy-name">Void Spawn</div>
      <div class="enemy-hp" id="enemy-hp">20 / 20 HP</div>
      <div class="enemy-attack-indicator" id="enemy-atk">Attack: 3</div>
      <div class="enemy-status" id="enemy-status"></div>
    </div>

    <!-- Player -->
    <div class="player-zone">
      <div class="hand" id="hand"></div>
      <div class="action-bar">
        <button class="btn" id="btn-play" onclick="startTurn()">Begin Turn</button>
        <button class="btn" id="btn-shop" onclick="openShop()" disabled>Enter Shop</button>
        <button class="btn" onclick="restartGame()">Restart</button>
      </div>
      <div class="log-area" id="log">Select a class to begin your descent.</div>
    </div>
  </div>
</div>

<!-- Overlays -->
<div class="overlay" id="overlay-class">
  <div class="panel" style="max-width:620px;">
    <h2>Choose Your Hero</h2>
    <p>Three classes, each with a unique starter deck and playstyle. The Void awaits.</p>
    <div class="class-grid" id="class-grid"></div>
    <div style="text-align:center;margin-top:14px;color:var(--text-dim);font-size:0.8rem;font-family:'Cormorant Garamond',serif;">All cards are Common and available in the shop.</div>
  </div>
</div>

<div class="overlay" id="overlay-shop">
  <div class="panel" style="max-width:640px;">
    <h2>The Merchant of Aethelgard</h2>
    <p>Buy cards with Gold. Duplicates cost more. You may purchase up to 5 copies of each card.</p>
    <div class="shop-grid" id="shop-grid"></div>
    <div style="display:flex;justify-content:space-between;align-items:center;margin-top:14px;">
      <button class="btn" onclick="closeShop()">Continue</button>
      <span style="color:var(--gold);font-weight:700;font-family:'Cinzel';">Gold: <span id="shop-gold">0</span></span>
    </div>
  </div>
</div>

<div class="overlay" id="overlay-win">
  <div class="panel" style="max-width:460px;text-align:center;">
    <h2 style="font-size:1.6rem;">Victory Over the Void</h2>
    <p style="font-size:1.1rem;">You have slain the Void Lord and reclaimed Aethelgard. The shadows recede.</p>
    <button class="btn" onclick="restartGame()" style="margin-top:10px;padding:12px 36px;font-size:1rem;">Return to Menu</button>
  </div>
</div>

<div class="overlay" id="overlay-lose">
  <div class="panel" style="max-width:420px;text-align:center;">
    <h2 style="font-size:1.6rem;color:var(--red);">Defeat</h2>
    <p>You have fallen to the Void. Aethelgard is lost to darkness.</p>
    <button class="btn" onclick="restartGame()" style="margin-top:10px;padding:12px 36px;font-size:1rem;">Try Again</button>
  </div>
</div>

<script>
/* ==================== DATA ==================== */
const CLASSES = {
  bastion: {name:'The Bastion',desc:'High Defense · Block · AoE',hp:35,energy:3,maxEnergy:3,deck:['BA-A01','BA-A02','BA-A03','BA-D01','BA-D02','BA-U01','BA-U02','BA-A01','BA-D01','BA-U03']},
  wither: {name:'The Wither',desc:'Burn · Debuff · Status',hp:30,energy:5,maxEnergy:5,deck:['WI-A01','WI-A02','WI-A03','WI-D01','WI-D02','WI-U01','WI-U02','WI-U03','WI-A01','WI-D01']},
  shroud: {name:'The Shroud',desc:'Speed · Evasion · Assassination',hp:30,energy:5,maxEnergy:5,deck:['SH-A01','SH-A02','SH-A03','SH-D01','SH-D02','SH-U01','SH-U02','SH-A01','SH-D02','SH-U01']},
};

const CARD_DATA = {
  'BA-A01':{id:'BA-A01',title:'Slam',type:'attack',cost:2,stats:{atk:3,def:0},desc:'Deals 3 damage. If you have 30 HP, draw 1 card.',cls:'bastion'},
  'BA-A02':{id:'BA-A02',title:'Earthquake',type:'attack',cost:3,stats:{atk:4,def:0},desc:'Deals 4 damage to all enemies.',cls:'bastion'},
  'BA-A03':{id:'BA-A03',title:'Stone Fist',type:'attack',cost:1,stats:{atk:2,def:0},desc:'Deals 2 damage.',cls:'bastion'},
  'BA-A04':{id:'BA-A04',title:'Boulder',type:'attack',cost:4,stats:{atk:6,def:0},desc:'Deals 6 damage. Costs 4 Energy.',cls:'bastion'},
  'BA-D01':{id:'BA-D01',title:'Shield Wall',type:'defend',cost:0,stats:{atk:0,def:4},desc:'Gain 4 Defense for this turn.',cls:'bastion'},
  'BA-D02':{id:'BA-D02',title:'Iron Skin',type:'defend',cost:2,stats:{atk:0,def:5},desc:'Gain 5 Defense permanently. Discard 1 card.',cls:'bastion'},
  'BA-D03':{id:'BA-D03',title:'Stand Firm',type:'defend',cost:1,stats:{atk:0,def:2},desc:'Gain 2 Defense. Blocks 1 incoming damage.',cls:'bastion'},
  'BA-D04':{id:'BA-D04',title:'Taunt',type:'defend',cost:2,stats:{atk:0,def:3},desc:'Gain 3 Defense. Stun 1 enemy for 1 turn.',cls:'bastion'},
  'BA-U01':{id:'BA-U01',title:'Search',type:'other',cost:2,stats:{atk:0,def:0},desc:'Draw 1 card. Discard hand if > 5 cards.',cls:'bastion'},
  'BA-U02':{id:'BA-U02',title:'Repair',type:'other',cost:3,stats:{atk:0,def:0},desc:'Heal 6 HP.',cls:'bastion'},
  'BA-U03':{id:'BA-U03',title:'Rally',type:'other',cost:1,stats:{atk:0,def:0},desc:'Draw 1 card. Gain 1 Energy.',cls:'bastion'},
  'BA-U04':{id:'BA-U04',title:'Loot',type:'other',cost:2,stats:{atk:0,def:0},desc:'Gain 5 Gold.',cls:'bastion'},

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

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

const ENEMY_TYPES = [
  {name:'Goblin',hp:20,dmg:3},
  {name:'Rat Swarm',hp:20,dmg:3},
  {name:'Vampire Knight',hp:30,dmg:5},
  {name:'Ogre',hp:30,dmg:5},
  {name:'Void Warrior',hp:40,dmg:8},
  {name:'Cultist',hp:40,dmg:8},
];

/* ==================== STATE ==================== */
let state = {
  cls:null,
  hp:30,
  maxHp:30,
  energy:5,
  maxEnergy:5,
  defense:0,
  gold:0,
  floor:1,
  room:0,
  deck:[],
  hand:[],
  discard:[],
  logText:'',
  enemy:{name:'',hp:20,maxHp:20,dmg:3,status:{burn:0,poison:0,stun:0},attacksNextTurn:0,blockedNext:0},
  turnPhase:'start', // start, player_action, player_done, enemy_action, end
  cardsPlayed:0,
  currentRoundStarted:false,
  inventory:{},
  selectedCards:[],
};

/* ==================== INIT ==================== */
function initGame() {
  // Build class selection
  const grid = document.getElementById('class-grid');
  grid.innerHTML = '';
  for (const [key,cls] of Object.entries(CLASSES)) {
    const card = document.createElement('div');
    card.className = 'class-card';
    card.innerHTML = `<h3>${cls.name}</h3><span>${cls.desc}</span>`;
    card.onclick = () => selectClass(key);
    grid.appendChild(card);
  }
  openOverlay('overlay-class');
}

function selectClass(key) {
  state.cls = CLASSES[key];
  state.hp = state.cls.hp;
  state.maxHp = state.cls.hp;
  state.energy = state.cls.energy;
  state.maxEnergy = state.cls.maxEnergy;
  state.defense = 0;
  state.gold = 5; // Starting gold
  state.floor = 1;
  state.room = 0;
  state.deck = [...state.cls.deck];
  state.hand = [];
  state.discard = [];
  state.enemy = {name:'',hp:0,maxHp:0,dmg:0,status:{burn:0,poison:0,stun:0},attacksNextTurn:0,blockedNext:0};
  state.turnPhase = 'start';
  state.cardsPlayed = 0;
  state.currentRoundStarted = false;
  state.inventory = {};
  // Initialize inventory with starter cards
  for (const c of state.cls.deck) { state.inventory[c] = (state.inventory[c]||0)+1; }
  // Add extra starter copies to make it playable quickly
  for (const c of state.cls.deck) { state.inventory[c] = (state.inventory[c]||0)+1; }
  closeOverlay('overlay-class');
  nextRoom();
  refreshUI();
  log('You descend into Aethelgard. Choose your cards wisely.');
}

/* ==================== GAME LOOP ==================== */
function nextRoom() {
  state.room++;
  if (state.room > 9 && state.floor < 3) {
    state.floor++;
    state.room = 1;
    log(`You reach Floor ${state.floor}. The air grows thicker.`);
  }
  if (state.floor === 3 && state.room > 3) {
    // Boss on floor 3 room 3 then room 4? Let's say rooms 1-3 standard then boss on 4.
  }
  if (state.room === 4 || (state.floor===1 && state.room===4) || (state.floor===2 && state.room===4) || (state.floor===3 && state.room===4)) {
    spawnBoss();
  } else {
    spawnStandardEnemy();
  }
  state.currentRoundStarted = false;
  state.turnPhase = 'start';
  state.cardsPlayed = 0;
  state.hand = [];
  refreshUI();
  document.getElementById('btn-play').disabled = false;
  document.getElementById('btn-play').textContent = 'Begin Turn';
  document.getElementById('btn-shop').disabled = false;
  log(`Room ${state.room} — ${state.enemy.name} approaches.`);
}

function spawnStandardEnemy() {
  const tier = Math.min(state.floor, ENEMY_TYPES.length - 2); // skip bosses from list
  const et = ENEMY_TYPES[tier];
  const scale = 1 + (state.room-1)*0.2;
  const enemy = {
    name: et.name,
    hp: Math.round(et.hp * scale),
    maxHp: Math.round(et.hp * scale),
    dmg: Math.round(et.dmg * scale),
    status: {burn:0, poison:0, stun:0},
    attacksNextTurn: 0,
    blockedNext: 0,
  };
  state.enemy = enemy;
}

function spawnBoss() {
  const bossConfigs = [
    {name:'The Gatekeeper',hp:80,dmg:15,mechanic:'Blocks 5 damage per turn until HP < 20.'},
    {name:'The Corrupted',hp:80,dmg:15,mechanic:'Deals 20 damage if you have < 3 Energy.'},
    {name:'The Void Lord',hp:120,dmg:15,mechanic:'Regenerates 10 HP each turn. Cannot block.'},
  ];
  const idx = Math.min(state.floor-1, bossConfigs.length-1);
  const b = bossConfigs[idx];
  state.enemy = {
    name: b.name,
    hp: b.hp,
    maxHp: b.hp,
    dmg: b.dmg,
    status: {burn:0, poison:0, stun:0},
    attacksNextTurn: 0,
    blockedNext: 0,
  };
  log(`BOSS BATTLE: ${b.name} — ${b.mechanic}`);
}

/* ==================== HAND / CARDS ==================== */
function drawHand(num = 5) {
  // Draw from deck or shuffle discard
  if (state.deck.length < num) {
    state.deck = [...state.discard];
    state.discard = [];
    shuffle(state.deck);
  }
  for (let i = 0; i < num; i++) {
    if (state.hand.length >= 5) break; // max hand 5 for simplicity
    const cardId = state.deck.pop();
    if (cardId) state.hand.push({id: cardId, played: false, selected: false});
  }
}

function shuffle(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]]; }
}

/* ==================== TURN LOGIC ==================== */
function startTurn() {
  if (state.turnPhase !== 'start') return;
  drawHand();
  state.turnPhase = 'player_action';
  state.cardsPlayed = 0;
  state.currentRoundStarted = true;
  state.energy = Math.min(state.maxEnergy, state.energy + 1); // regen at start (simplified)
  refreshUI();
  document.getElementById('btn-play').disabled = true;
  document.getElementById('btn-play').textContent = 'End Turn';
  document.getElementById('btn-play').onclick = endTurn;
  log('Draw phase — play your cards.');
}

function playCard(idx) {
  if (state.turnPhase !== 'player_action') return;
  const card = state.hand[idx];
  if (card.played || card.selected) return;
  const info = CARD_DATA[card.id];
  if (!info) return;
  if (state.energy < info.cost) {
    log('Not enough Energy to play ' + info.title + '.');
    return;
  }
  // Mark selected / played
  card.played = true;
  card.selected = true;
  state.energy -= info.cost;
  state.cardsPlayed++;

  // Resolve effects
  resolveCardEffect(info, card.id);
  refreshUI();
  // Auto remove after short visual delay or just keep showing played
  setTimeout(() => renderHand(), 250);
}

function resolveCardEffect(info, cardId) {
  const type = info.type;
  const desc = info.desc.toLowerCase();
  const atk = info.stats.atk || 0;
  const def = info.stats.def || 0;

  if (type === 'attack') {
    let dmg = atk;
    // Boss mechanics adjustments
    if (state.enemy.name === 'The Gatekeeper' && state.enemy.hp > 20) {
      dmg = Math.max(0, dmg - 5);
      log('Gatekeeper blocks 5 damage while above 20 HP.');
    }
    if (state.enemy.name === 'The Void Lord') {
      dmg = dmg; // cannot block, full dmg
    }
    // Apply damage
    state.enemy.hp = Math.max(0, state.enemy.hp - dmg);
    log(`You played ${info.title} for ${dmg} damage.`);
    // Apply status from desc keywords (simplified parsing)
    if (desc.includes('burn')) state.enemy.status.burn = (state.enemy.status.burn||0) + (desc.includes('3 burn')?3:1);
    if (desc.includes('poison')) state.enemy.status.poison = (state.enemy.status.poison||0) + 1;
    if (desc.includes('stun')) state.enemy.status.stun = (state.enemy.status.stun||0) + 1;
  } else if (type === 'defend') {
    state.defense += def;
    if (desc.includes('permanently')) {
      // Permanent defense stays across turns
    } else {
      log(`You gained ${def} Defense.`);
    }
    if (desc.includes('stun')) state.enemy.status.stun = 1;
    if (desc.includes('heal')) {
      // Heal from defense cards (e.g. Endure)
      const healMatch = desc.match(/heal (\d+)/i);
      if (healMatch) { state.hp = Math.min(state.maxHp, state.hp + parseInt(healMatch[1])); }
    }
    if (desc.includes('draw')) {
      const drawMatch = desc.match(/draw (\d+)/i);
      if (drawMatch) drawHand(parseInt(drawMatch[1]));
    }
  } else if (type === 'other') {
    if (desc.includes('heal')) {
      const healMatch = desc.match(/heal (\d+)/i);
      if (healMatch) { state.hp = Math.min(state.maxHp, state.hp + parseInt(healMatch[1])); log(`Restored ${healMatch[1]} HP.`); }
    }
    if (desc.includes('draw 1')) {
      drawHand(1);
      log('Drew 1 card.');
    }
    if (desc.includes('gain 1 energy')) {
      state.energy = Math.min(state.maxEnergy, state.energy + 1);
      log('Gained 1 Energy.');
    }
    if (desc.includes('gain 5 gold')) {
      state.gold += 5;
      log('Gained 5 Gold.');
    }
    if (desc.includes('discard 1 card')) {
      // Simulate discard: remove first non-played from hand if possible
      const discardable = state.hand.find(c => !c.played);
      if (discardable) { discardable.played = true; state.discard.push(discardable.id); state.hand = state.hand.filter(c=>!c.played); }
    }
    if (desc.includes('skip enemy') || desc.includes('skip enemy action')) {
      state.enemy.status.stun = 1;
      log('Enemy action skipped.');
    }
    if (desc.includes('deal 8 damage')) {
      let dmg = 8;
      if (state.enemy.name === 'The Gatekeeper' && state.enemy.hp > 20) dmg = Math.max(0, dmg - 5);
      state.enemy.hp = Math.max(0, state.enemy.hp - dmg);
      log('Assassinate dealt 8 damage (unblockable).');
    }
    if (desc.includes('deal 3 damage') && desc.includes('burn') && desc.includes('all')) {
      // WI-U02 Burn
      state.enemy.hp = Math.max(0, state.enemy.hp - 3);
      state.enemy.status.burn = (state.enemy.status.burn||0) + 2;
      log('Burn: 3 damage + 2 Burn to enemy.');
    }
    if (desc.includes('apply 1 poison')) { state.enemy.status.poison = (state.enemy.status.poison||0) + 1; log('Applied Poison.'); }
    if (desc.includes('reduce enemy attack')) { state.enemy.dmg = Math.max(1, state.enemy.dmg - 1); log('Enemy attack reduced by 1.'); }
    // Handle draw + discard from Search / Rally etc
  }
  // Handle card draw if description mentions draw but we haven't parsed it
  if (desc.includes('draw') && !desc.includes('draw 1')) {
    // Already handled by generic draw logic earlier; if missed, draw 1
  }
}

/* ==================== ENEMY TURN ==================== */
function enemyTurn() {
  if (state.turnPhase !== 'player_action' && state.turnPhase !== 'player_done') return;
  state.turnPhase = 'enemy_action';

  // Apply DoT first
  let burnDmg = (state.enemy.status.burn || 0);
  let poisonDmg = (state.enemy.status.poison || 0);
  if (burnDmg > 0 || poisonDmg > 0) {
    const total = burnDmg + poisonDmg;
    state.enemy.hp = Math.max(0, state.enemy.hp - total);
    log(`Status effects dealt ${total} damage.`);
    state.enemy.status.burn = Math.max(0, state.enemy.status.burn - 1);
    state.enemy.status.poison = Math.max(0, state.enemy.status.poison - 1);
  }

  // Boss mechanics
  if (state.enemy.name === 'The Corrupted' && state.energy < 3) {
    state.hp -= 20;
    log('The Corrupted bursts: +20 damage because you have < 3 Energy!');
  }
  if (state.enemy.name === 'The Void Lord') {
    state.enemy.hp = Math.min(state.enemy.maxHp, state.enemy.hp + 10);
    log('The Void Lord regenerates 10 HP.');
  }

  // Enemy stunned?
  if (state.enemy.status.stun > 0) {
    state.enemy.status.stun = Math.max(0, state.enemy.status.stun - 1);
    log('Enemy is stunned and skips its attack.');
    state.turnPhase = 'end';
    refreshUI();
    setTimeout(endTurnSequence, 600);
    return;
  }

  // Enemy attacks
  let dmg = state.enemy.dmg;
  // Check defense
  if (state.defense > 0) {
    const absorbed = Math.min(dmg, state.defense);
    state.defense -= absorbed;
    dmg -= absorbed;
    log(`Your Defense absorbed ${absorbed} damage.`);
  }
  if (dmg > 0) {
    state.hp -= dmg;
    log(`Enemy deals ${dmg} damage.`);
  }

  // Enemy blocked?
  if (state.enemy.blockedNext > 0) {
    state.enemy.blockedNext = 0;
    log('Enemy blocked damage this turn.');
  }

  state.turnPhase = 'end';
  refreshUI();
  if (state.hp <= 0) {
    log('You have fallen.');
    setTimeout(() => openOverlay('overlay-lose'), 800);
    return;
  }
  if (state.enemy.hp <= 0) {
    const goldGain = state.enemy.name.includes('Boss') ? 15 : 5;
    state.gold += goldGain;
    log(`${state.enemy.name} defeated! Gained ${goldGain} Gold.`);
    if (state.floor >= 3 && (state.enemy.name === 'The Void Lord')) {
      setTimeout(() => openOverlay('overlay-win'), 1000);
    }
    // Go to shop / next room
    state.defense = 0; // reset defense after combat? In GDD, defense resets per turn but some cards say permanent
    setTimeout(() => openShop(), 600);
    return;
  }
  setTimeout(endTurnSequence, 600);
}

/* ==================== TURN END ==================== */
function endTurnSequence() {
  // Recover energy if not exhausted (simplified)
  state.energy = Math.min(state.maxEnergy, state.energy + 1);
  // Discard played cards
  state.discard.push(...state.hand.filter(c=>c.played).map(c=>c.id));
  state.hand = state.hand.filter(c=>!c.played);
  state.defense = 0; // reset temporary defense
  state.turnPhase = 'start';
  state.cardsPlayed = 0;
  refreshUI();
  document.getElementById('btn-play').textContent = 'Begin Turn';
  document.getElementById('btn-play').onclick = startTurn;
  document.getElementById('btn-play').disabled = false;
  log('Turn ended. Energy recovered.');
  // Check enemy death after effects
  if (state.enemy.hp <= 0) {
    const goldGain = state.enemy.name.includes('Boss') ? 15 : 5;
    state.gold += goldGain;
    log(`${state.enemy.name} defeated! Gained ${goldGain} Gold.`);
    if (state.floor >= 3 && state.enemy.name === 'The Void Lord') {
      setTimeout(() => openOverlay('overlay-win'), 800);
    } else {
      setTimeout(() => openShop(), 600);
    }
  }
}

function endTurn() {
  if (state.turnPhase !== 'player_action') return;
  state.turnPhase = 'player_done';
  document.getElementById('btn-play').textContent = 'Enemy Turn...';
  document.getElementById('btn-play').disabled = true;
  refreshUI();
  setTimeout(enemyTurn, 500);
}

/* ==================== SHOP ==================== */
function openShop() {
  if (state.enemy.hp > 0) return;
  openOverlay('overlay-shop');
  renderShop();
  document.getElementById('shop-gold').textContent = state.gold;
}

function closeShop() {
  closeOverlay('overlay-shop');
  nextRoom();
}

function renderShop() {
  const grid = document.getElementById('shop-grid');
  grid.innerHTML = '';
  const cards = Object.values(CARD_DATA);
  // Show 4 random cards from pool
  const pool = cards.filter(c => (state.inventory[c.id]||0) < 5);
  const picks = pool.sort(() => Math.random()-0.5).slice(0, 4);
  for (const card of picks) {
    const count = state.inventory[card.id] || 0;
    const baseCost = card.cost; // simplified cost
    const cost = Math.min(50, baseCost + count);
    const sold = state.gold < cost || count >= 5;
    const div = document.createElement('div');
    div.className = 'shop-card' + (sold ? ' sold' : '');
    div.innerHTML = `<h4>${CARD_DATA[card.id].title}</h4><div class="price">${cost}G</div><div class="qty">Owned: ${count}</div>`;
    div.onclick = () => buyCard(card.id);
    grid.appendChild(div);
  }
}

function buyCard(id) {
  const card = CARD_DATA[id];
  if (!card) return;
  const count = state.inventory[id] || 0;
  const cost = Math.min(50, card.cost + count);
  if (state.gold < cost) {
    log('Not enough gold.');
    return;
  }
  if (count >= 5) {
    log('Maximum copies reached.');
    return;
  }
  state.gold -= cost;
  state.inventory[id] = count + 1;
  state.deck.push(id);
  log(`Bought ${card.title} for ${cost} Gold.`);
  document.getElementById('shop-gold').textContent = state.gold;
  renderShop();
}

/* ==================== UI ==================== */
function refreshUI() {
  document.getElementById('hp-val').textContent = Math.max(0, state.hp) + ' / ' + state.maxHp;
  document.getElementById('def-val').textContent = state.defense;
  document.getElementById('energy-val').textContent = state.energy;
  document.getElementById('max-energy').textContent = state.maxEnergy;
  document.getElementById('gold-val').textContent = state.gold;
  document.getElementById('floor-label').textContent = state.floor;
  document.getElementById('enemy-name').textContent = state.enemy.name || '--';
  document.getElementById('enemy-hp').textContent = Math.max(0, state.enemy.hp) + ' / ' + state.enemy.maxHp + ' HP';
  document.getElementById('enemy-atk').textContent = 'Attack: ' + (state.enemy.dmg || 0);
  const statusDiv = document.getElementById('enemy-status');
  let badges = '';
  if (state.enemy.status.burn > 0) badges += '<span class="badge">Burn</span>';
  if (state.enemy.status.poison > 0) badges += '<span class="badge">Poison</span>';
  if (state.enemy.status.stun > 0) badges += '<span class="badge def">Stunned</span>';
  statusDiv.innerHTML = badges;
  renderHand();
}

function renderHand() {
  const container = document.getElementById('hand');
  container.innerHTML = '';
  for (let i = 0; i < state.hand.length; i++) {
    const cardObj = state.hand[i];
    const info = CARD_DATA[cardObj.id];
    if (!info) continue;
    const cardEl = document.createElement('div');
    cardEl.className = `card type-${info.type}` + (cardObj.played ? ' played' : '') + (state.turnPhase !== 'player_action' || info.cost > state.energy ? ' disabled' : '');
    cardEl.innerHTML = `
      <svg class="card-frame" viewBox="0 0 150 210" preserveAspectRatio="none">
        <defs>
          <linearGradient id="card-grad-${info.cls}" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stop-color="#2a2115"/>
            <stop offset="50%" stop-color="#1a180e"/>
            <stop offset="100%" stop-color="#0f0d14"/>
          </linearGradient>
        </defs>
        <rect width="150" height="210" rx="14" ry="14" fill="url(#card-grad-${info.cls})" stroke="#bfa85a" stroke-width="1.5" opacity="0.9"/>
        <rect x="6" y="6" width="138" height="198" rx="10" ry="10" fill="none" stroke="#6b5a2a" stroke-width="0.5"/>
        <path d="M10 20 Q75 15 140 20" stroke="#bfa85a" stroke-width="0.8" fill="none" opacity="0.5"/>
        <path d="M10 190 Q75 195 140 190" stroke="#bfa85a" stroke-width="0.8" fill="none" opacity="0.5"/>
      </svg>
      <div class="card-inner">
        <div class="card-header">
          <span class="card-cost">${info.cost}</span>
          <span class="card-id">${info.id}</span>
        </div>
        <div class="card-title">${info.title}</div>
        <div class="card-desc">${info.desc}</div>
        <div class="card-stats">${info.stats.atk > 0 ? `ATK ${info.stats.atk}` : ''} ${info.stats.def > 0 ? `DEF ${info.stats.def}` : ''}</div>
      </div>`;
    cardEl.onclick = () => playCard(i);
    container.appendChild(cardEl);
  }
}

/* ==================== OVERLAYS ==================== */
function openOverlay(id) { document.getElementById(id).classList.add('active'); }
function closeOverlay(id) { document.getElementById(id).classList.remove('active'); }

function log(msg) {
  document.getElementById('log').textContent = msg;
}

function restartGame() {
  closeOverlay('overlay-win');
  closeOverlay('overlay-lose');
  state = {
    cls:null, hp:30, maxHp:30, energy:5, maxEnergy:5, defense:0, gold:0, floor:1, room:0,
    deck:[], hand:[], discard:[], logText:'', enemy:{name:'',hp:0,maxHp:0,dmg:0,status:{burn:0,poison:0,stun:0},attacksNextTurn:0,blockedNext:0},
    turnPhase:'start', cardsPlayed:0, currentRoundStarted:false, inventory:{}, selectedCards:[],
  };
  document.getElementById('btn-play').textContent = 'Select Class';
  document.getElementById('btn-play').onclick = () => { openOverlay('overlay-class'); };
  initGame();
}

/* ==================== BOOT ==================== */
window.addEventListener('DOMContentLoaded', () => {
  initGame();
});
</script>
<style>
.card-art{height:80px;border-radius:8px;background:linear-gradient(180deg,#0f0d14,#1a161f);border:1px solid rgba(212,168,75,0.12);margin:4px 0;display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden;box-shadow:inset 0 0 20px rgba(0,0,0,0.6);}
.card-art img{width:55px;height:55px;opacity:0.35;filter:drop-shadow(0 0 8px rgba(212,168,75,0.25));}
.card-back.bastion-back{border-color:rgba(107,83,40,0.35);background:linear-gradient(135deg,#1a160e,#2a2014);}
.card-back.wither-back{border-color:rgba(138,46,46,0.35);background:linear-gradient(135deg,#1a0e10,#2a1414);}
.card-back.shroud-back{border-color:rgba(24,40,58,0.35);background:linear-gradient(135deg,#0e121a,#141e2a);}
</style>
<script>
// Add placeholder art to cards and unique card back SVGs
function enhanceCards() {
  const backs = {
    bastion: '<svg viewBox="0 0 90 120"><rect width="90" height="120" rx="8" fill="#2a1e10" stroke="#6b5328" stroke-width="2"/><circle cx="45" cy="55" r="22" fill="#4a2e1a" stroke="#bfa85a" stroke-width="1"/><path d="M30 75 Q45 95 60 75 L45 60 Z" fill="#8a6e3e"/></svg>',
    wither: '<svg viewBox="0 0 90 120"><rect width="90" height="120" rx="8" fill="#2a1014" stroke="#8a2e2e" stroke-width="2"/><circle cx="45" cy="55" r="20" fill="#5a1818" stroke="#ff5e3a" stroke-width="1"/><path d="M35 60 Q45 75 55 60 Q45 45 35 60" fill="#7a2e2e"/></svg>',
    shroud: '<svg viewBox="0 0 90 120"><rect width="90" height="120" rx="8" fill="#101420" stroke="#18283a" stroke-width="2"/><circle cx="45" cy="55" r="22" fill="#182040" stroke="#3a7db8" stroke-width="1"/><path d="M35 50 Q45 65 55 50 L45 35 Z" fill="#2a3548"/></svg>',
  };
  // Patch renderHand to inject placeholder art
  const originalRender = window.renderHand || (()=>{});
  // We can't easily monkey-patch, so we'll observe mutations
  const observer = new MutationObserver((muts) => {
    for (const m of muts) {
      for (const node of m.addedNodes) {
        if (node.nodeType === 1 && node.classList && node.classList.contains('card')) {
          if (!node.querySelector('.card-art')) {
            const art = document.createElement('div');
            art.className = 'card-art';
            art.innerHTML = '<svg viewBox="0 0 60 60"><circle cx="30" cy="30" r="18" fill="#3a2e1a" stroke="#bfa85a" stroke-width="2"/><path d="M15 35 L30 15 L45 35 Z" fill="#6b4328" stroke="#bfa85a" stroke-width="1"/></svg>';
            const inner = node.querySelector('.card-inner');
            if (inner) {
              const title = inner.querySelector('.card-title');
              if (title) title.insertAdjacentElement('afterend', art);
            }
          }
        }
      }
    }
  });
  observer.observe(document.getElementById('hand') || document.body, {childList:true, subtree:true});
}
window.addEventListener('DOMContentLoaded', enhanceCards);
</script>
</body>
</html>
<!-- agent-meta {"model":"thinkingmachines/inkling","provider":"openrouter","persona":"full","sessionId":"293ece5d-15d8-48a7-b95e-a3f0c756743e","tokensIn":674973,"tokensOut":19202,"tokensTotal":694175,"turns":19,"toolCalls":18,"failedToolCalls":4,"timestamp":"2026-07-18T21:55:42.803Z"} -->