← Aethelgard results

Aethelgard

thinkingcap qwen3.6 27b · typescript

Initial view of Aethelgard

Browser check: Artifact runtime error. This is a technical check, not a quality review.

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 95,407 bytes · SHA-256 a0dfec65635b
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Aethelgard — Resonant Chronicles</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&amp;family=Press+Start+2P&amp;display=swap">
<style>
/* ── css: base ── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { width: 100%; height: 100%; overflow: hidden; }
body {
  font-family: 'Inter', sans-serif;
  background: linear-gradient(135deg, #0f0a1e 0%, #1a1040 30%, #0d1b2a 70%, #0a0618 100%);
  color: #e2e8f0;
}
#app { width: 100%; height: 100%; position: relative; overflow: hidden; }
.game-screen {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  opacity: 0; pointer-events: none; transition: opacity 0.4s ease, transform 0.4s ease;
  transform: scale(0.97); padding: 16px;
}
.game-screen.active { opacity: 1; pointer-events: auto; transform: scale(1); }
.hidden { display: none !important; }
.retro-title { font-family: 'Press Start 2P', monospace; letter-spacing: 1px; }
.glass-card {
  background: rgba(30, 27, 56, 0.65);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  border: 1px solid rgba(139, 92, 246, 0.25);
  border-radius: 16px; box-shadow: 0 8px 32px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.06);
}
.glass-btn {
  background: rgba(139, 92, 246, 0.2); border: 1px solid rgba(139, 92, 246, 0.4);
  color: #e2e8f0; padding: 10px 24px; border-radius: 10px; cursor: pointer;
  font-family: 'Inter', sans-serif; font-weight: 600; font-size: 14px;
  transition: all 0.2s ease; backdrop-filter: blur(8px);
}
.glass-btn:hover { background: rgba(139, 92, 246, 0.4); border-color: rgba(139, 92, 246, 0.7); transform: translateY(-1px); box-shadow: 0 4px 16px rgba(139,92,246,0.3); }
.glass-btn:active { transform: translateY(0); }
.glass-btn.danger { background: rgba(239, 68, 68, 0.2); border-color: rgba(239, 68, 68, 0.4); }
.glass-btn.danger:hover { background: rgba(239, 68, 68, 0.4); box-shadow: 0 4px 16px rgba(239,68,68,0.3); }
.glass-btn.success { background: rgba(34, 197, 94, 0.2); border-color: rgba(34, 197, 94, 0.4); }
.glass-btn.success:hover { background: rgba(34, 197, 94, 0.4); box-shadow: 0 4px 16px rgba(34,197,94,0.3); }
/* ── css: animations ── */
@keyframes shake { 0%,100%{transform:translateX(0)} 25%{transform:translateX(-6px) rotate(-1deg)} 75%{transform:translateX(6px) rotate(1deg)} }
@keyframes flashHit { 0%{filter:brightness(1)} 30%{filter:brightness(2.5)} 100%{filter:brightness(1)} }
@keyframes bounceIn { 0%{transform:scale(0);opacity:0} 60%{transform:scale(1.1)} 100%{transform:scale(1);opacity:1} }
@keyframes floatUp { 0%{transform:translateY(0) scale(1);opacity:1} 100%{transform:translateY(-40px) scale(0.5);opacity:0} }
@keyframes pulseGlow { 0%,100%{box-shadow:0 0 8px var(--glow-color,rgba(139,92,246,0.4))} 50%{box-shadow:0 0 24px var(--glow-color,rgba(139,92,246,0.7))} }
@keyframes particleDrift { 0%{transform:translateY(0) translateX(0);opacity:1} 50%{opacity:0.8} 100%{transform:translateY(-30px) translateX(var(--drift,10px));opacity:0} }
@keyframes slideInRight { from{transform:translateX(60px);opacity:0} to{transform:translateX(0);opacity:1} }
@keyframes slideInLeft { from{transform:translateX(-60px);opacity:0} to{transform:translateX(0);opacity:1} }
@keyframes evolveFlash { 0%{filter:brightness(1)} 25%{filter:brightness(3) hue-rotate(90deg)} 50%{filter:brightness(4) hue-rotate(180deg)} 75%{filter:brightness(3) hue-rotate(270deg)} 100%{filter:brightness(1)} }
.shake { animation: shake 0.4s ease; }
.flash-hit { animation: flashHit 0.3s ease; }
.bounce-in { animation: bounceIn 0.5s ease forwards; }
.evolve-flash { animation: evolveFlash 1.2s ease; }
/* ── css: elements ── */
.el-pyro { --el-color: #f97316; --glow-color: rgba(249,115,22,0.5); }
.el-hydro { --el-color: #3b82f6; --glow-color: rgba(59,130,246,0.5); }
.el-flora { --el-color: #22c55e; --glow-color: rgba(34,197,94,0.5); }
.el-volt  { --el-color: #facc15; --glow-color: rgba(250,204,21,0.5); }
.el-zephyr{ --el-color: #a78bfa; --glow-color: rgba(167,139,250,0.5); }
.el-earth { --el-color: #d97706; --glow-color: rgba(217,119,6,0.5); }
.el-cosmos{ --el-color: #c084fc; --glow-color: rgba(192,132,252,0.5); }
.type-badge { display:inline-block; padding:2px 10px; border-radius:6px; font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:0.5px; color:#fff; background:var(--el-color,rgba(139,92,246,0.6)); box-shadow:0 0 8px var(--glow-color); }
.hp-bar-bg { width:100%; height:14px; background:rgba(0,0,0,0.5); border-radius:7px; overflow:hidden; position:relative; }
.hp-bar-fill { height:100%; border-radius:7px; transition:width 0.6s ease, background 0.3s ease; }
.xp-bar-bg { width:100%; height:6px; background:rgba(0,0,0,0.4); border-radius:3px; overflow:hidden; margin-top:4px; }
.xp-bar-fill { height:100%; background:linear-gradient(90deg,#8b5cf6,#c084fc); border-radius:3px; transition:width 0.4s ease; }
.resonant-sprite { width:120px; height:120px; filter:drop-shadow(0 0 12px var(--glow-color,rgba(139,92,246,0.5))); transition:filter 0.3s ease; }
.resonant-sprite.enemy { width:100px; height:100px; }
.toast-overlay { position:absolute; inset:0; display:flex; align-items:center; justify-content:center; z-index:999; pointer-events:none; }
.toast-msg { background:rgba(30,27,56,0.9); backdrop-filter:blur(12px); border:1px solid rgba(139,92,246,0.4); padding:16px 32px; border-radius:12px; font-weight:600; animation:bounceIn 0.3s ease forwards; }
/* ── css: battle-particles ── */
.particle-container { position: absolute; inset: 0; pointer-events: none; overflow: hidden; z-index: 5; }
.battle-particle {
  position: absolute; width: 6px; height: 6px; border-radius: 50%;
  animation: particleDrift 2s ease-out forwards;
}
.status-burn { color: #f97316; }
.status-paralyze { color: #facc15; }
.status-poison { color: #a855f7; }
.status-sleep { color: #60a5fa; }

/* Scrollbar styling */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: rgba(0,0,0,0.2); border-radius: 3px; }
::-webkit-scrollbar-thumb { background: rgba(139,92,246,0.4); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: rgba(139,92,246,0.6); }

/* Victory screen */
.victory-overlay {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,0.7); z-index: 100; animation: bounceIn 0.5s ease;
}
.victory-card {
  text-align: center; padding: 48px; max-width: 500px;
  background: rgba(30,27,56,0.9); backdrop-filter: blur(20px);
  border: 1px solid rgba(192,132,252,0.4); border-radius: 20px;
  box-shadow: 0 0 60px rgba(192,132,252,0.3);
}

/* Map node pulse animation */
@keyframes nodePulse {
  0%, 100% { box-shadow: 0 0 8px var(--node-color, #8b5cf6)40; }
  50% { box-shadow: 0 0 20px var(--node-color, #8b5cf6)70; }
}
</style>
</head>
<body>
<div id="screen-menu" class="game-screen active"></div>
<div id="screen-map" class="game-screen hidden"></div>
<div id="screen-battle" class="game-screen hidden"></div>
<div id="screen-shop" class="game-screen hidden"></div>
<div id="screen-dex" class="game-screen hidden"></div>
<div id="screen-dialog" class="game-screen hidden"></div>
<div id="overlay-toast" class="toast-overlay hidden"></div>
<script>
(function () {
'use strict';
var __mods = {};
var __cache = {};
var __map = {"src/main.ts":{"./ui/game":"src/ui/game.ts"},"src/data/resonants.ts":{"../types":"src/types.ts"},"src/data/zones.ts":{"../types":"src/types.ts"},"src/state/player.ts":{"../types":"src/types.ts","../data/resonants":"src/data/resonants.ts"},"src/systems/combat.ts":{"../types":"src/types.ts","../data/resonants":"src/data/resonants.ts","../state/player":"src/state/player.ts"},"src/ui/sprites.ts":{"../data/resonants":"src/data/resonants.ts","../types":"src/types.ts"},"src/ui/game.ts":{"../types":"src/types.ts","../data/resonants":"src/data/resonants.ts","../data/zones":"src/data/zones.ts","../state/player":"src/state/player.ts","../systems/combat":"src/systems/combat.ts","../systems/synth":"src/systems/synth.ts","./sprites":"src/ui/sprites.ts"}};
function __require(id) {
  if (__cache[id]) return __cache[id].exports;
  var module = __cache[id] = { exports: {} };
  var factory = __mods[id];
  if (!factory) throw new Error("Module not found: " + id);
  factory(module.exports, function (spec) {
    var target = (__map[id] && __map[id][spec]) || spec;
    return __require(target);
  }, module);
  return module.exports;
}

// ── module: src/main.ts ──
__mods["src/main.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const game_1 = require("./ui/game");
// Initialize game on load
(0, game_1.init)();
};

// ── module: src/types.ts ──
__mods["src/types.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TYPE_ADVANTAGES = exports.ELEMENT_COLORS = void 0;
exports.ELEMENT_COLORS = {
    Pyro: '#f97316', Hydro: '#3b82f6', Flora: '#22c55e',
    Volt: '#facc15', Zephyr: '#a78bfa', Earth: '#d97706', Cosmos: '#c084fc'
};
exports.TYPE_ADVANTAGES = {
    Pyro: { strong: ['Flora'], weak: ['Hydro'] },
    Hydro: { strong: ['Pyro'], weak: ['Flora'] },
    Flora: { strong: ['Hydro'], weak: ['Pyro'] },
    Zephyr: { strong: ['Earth'], weak: ['Volt'] },
    Earth: { strong: ['Volt'], weak: ['Zephyr'] },
    Volt: { strong: ['Zephyr'], weak: ['Earth'] },
    Cosmos: { strong: [], weak: [] }
};
};

// ── module: src/data/resonants.ts ──
__mods["src/data/resonants.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ALL_IDS = exports.RESONANT_DB = void 0;
exports.getResonantDef = getResonantDef;
exports.RESONANT_DB = {
    // === PYRO LINE ===
    emberkit: {
        id: 'emberkit', name: 'Emberkit', type: 'Pyro', baseHp: 45, baseAtk: 38, baseDef: 28, baseSpd: 35,
        evolutionLevel: 8, evolvesInto: 'pyrowolf',
        moves: [
            { name: 'Ember Toss', power: 40, accuracy: 95, element: 'Pyro', unlockLevel: 1, pp: 20 },
            { name: 'Scratch', power: 30, accuracy: 100, element: 'Cosmos', unlockLevel: 1, pp: 25 },
            { name: 'Flame Burst', power: 65, accuracy: 90, element: 'Pyro', unlockLevel: 4, pp: 15 },
            { name: 'Inferno Wave', power: 85, accuracy: 85, element: 'Pyro', unlockLevel: 7, pp: 10 }
        ],
        spriteParams: { shape: 'circle', primaryColor: '#f97316', secondaryColor: '#dc2626', accentColor: '#fef3c7', features: ['eyes', 'tail'] }
    },
    pyrowolf: {
        id: 'pyrowolf', name: 'Pyrowolf', type: 'Pyro', baseHp: 70, baseAtk: 58, baseDef: 42, baseSpd: 50,
        evolutionLevel: 15, evolvesInto: 'ignisaur',
        moves: [
            { name: 'Flame Burst', power: 65, accuracy: 90, element: 'Pyro', unlockLevel: 1, pp: 15 },
            { name: 'Bite', power: 45, accuracy: 95, element: 'Cosmos', unlockLevel: 1, pp: 20 },
            { name: 'Fire Fang', power: 75, accuracy: 90, element: 'Pyro', unlockLevel: 8, pp: 12 },
            { name: 'Blaze Rush', power: 95, accuracy: 85, element: 'Pyro', unlockLevel: 12, pp: 8 }
        ],
        spriteParams: { shape: 'hexagon', primaryColor: '#f97316', secondaryColor: '#dc2626', accentColor: '#fef3c7', features: ['eyes', 'horns', 'tail'] }
    },
    ignisaur: {
        id: 'ignisaur', name: 'Ignisaur', type: 'Pyro', baseHp: 100, baseAtk: 85, baseDef: 65, baseSpd: 70,
        moves: [
            { name: 'Fire Fang', power: 75, accuracy: 90, element: 'Pyro', unlockLevel: 1, pp: 12 },
            { name: 'Inferno Wave', power: 85, accuracy: 85, element: 'Pyro', unlockLevel: 1, pp: 10 },
            { name: 'Magma Storm', power: 110, accuracy: 80, element: 'Pyro', unlockLevel: 15, pp: 6 },
            { name: 'Solar Flare', power: 130, accuracy: 75, element: 'Pyro', unlockLevel: 20, pp: 4 }
        ],
        spriteParams: { shape: 'hexagon', primaryColor: '#ef4444', secondaryColor: '#f97316', accentColor: '#fef3c7', features: ['eyes', 'horns', 'tail', 'aura'] }
    },
    // === HYDRO LINE ===
    droplet: {
        id: 'droplet', name: 'Droplet', type: 'Hydro', baseHp: 50, baseAtk: 32, baseDef: 35, baseSpd: 40,
        evolutionLevel: 8, evolvesInto: 'geoxus',
        moves: [
            { name: 'Water Splash', power: 35, accuracy: 100, element: 'Hydro', unlockLevel: 1, pp: 25 },
            { name: 'Tackle', power: 30, accuracy: 95, element: 'Cosmos', unlockLevel: 1, pp: 25 },
            { name: 'Aqua Jet', power: 60, accuracy: 95, element: 'Hydro', unlockLevel: 4, pp: 18 },
            { name: 'Tidal Surge', power: 75, accuracy: 90, element: 'Hydro', unlockLevel: 7, pp: 12 }
        ],
        spriteParams: { shape: 'circle', primaryColor: '#3b82f6', secondaryColor: '#1d4ed8', accentColor: '#dbeafe', features: ['eyes', 'aura'] }
    },
    geoxus: {
        id: 'geoxus', name: 'Geoxus', type: 'Hydro', baseHp: 75, baseAtk: 52, baseDef: 50, baseSpd: 45,
        evolutionLevel: 15, evolvesInto: 'neptunian',
        moves: [
            { name: 'Aqua Jet', power: 60, accuracy: 95, element: 'Hydro', unlockLevel: 1, pp: 18 },
            { name: 'Water Pulse', power: 70, accuracy: 90, element: 'Hydro', unlockLevel: 1, pp: 14 },
            { name: 'Tidal Surge', power: 75, accuracy: 90, element: 'Hydro', unlockLevel: 8, pp: 12 },
            { name: 'Deep Current', power: 90, accuracy: 85, element: 'Hydro', unlockLevel: 12, pp: 8 }
        ],
        spriteParams: { shape: 'diamond', primaryColor: '#3b82f6', secondaryColor: '#1e40af', accentColor: '#bfdbfe', features: ['eyes', 'horns', 'aura'] }
    },
    neptunian: {
        id: 'neptunian', name: 'Neptunian', type: 'Hydro', baseHp: 105, baseAtk: 80, baseDef: 72, baseSpd: 60,
        moves: [
            { name: 'Tidal Surge', power: 75, accuracy: 90, element: 'Hydro', unlockLevel: 1, pp: 12 },
            { name: 'Deep Current', power: 90, accuracy: 85, element: 'Hydro', unlockLevel: 1, pp: 8 },
            { name: 'Ocean Fury', power: 115, accuracy: 80, element: 'Hydro', unlockLevel: 15, pp: 6 },
            { name: 'Tsunami Blast', power: 135, accuracy: 75, element: 'Hydro', unlockLevel: 20, pp: 4 }
        ],
        spriteParams: { shape: 'diamond', primaryColor: '#2563eb', secondaryColor: '#1e3a8a', accentColor: '#93c5fd', features: ['eyes', 'horns', 'aura', 'crown'] }
    },
    // === FLORA LINE ===
    seedling: {
        id: 'seedling', name: 'Seedling', type: 'Flora', baseHp: 48, baseAtk: 30, baseDef: 32, baseSpd: 30,
        evolutionLevel: 8, evolvesInto: 'thornback',
        moves: [
            { name: 'Vine Whip', power: 35, accuracy: 100, element: 'Flora', unlockLevel: 1, pp: 25 },
            { name: 'Tackle', power: 30, accuracy: 95, element: 'Cosmos', unlockLevel: 1, pp: 25 },
            { name: 'Leaf Blade', power: 60, accuracy: 95, element: 'Flora', unlockLevel: 4, pp: 18 },
            { name: 'Thorn Barrage', power: 70, accuracy: 90, element: 'Flora', unlockLevel: 7, pp: 12 }
        ],
        spriteParams: { shape: 'circle', primaryColor: '#22c55e', secondaryColor: '#16a34a', accentColor: '#bbf7d0', features: ['eyes', 'petals'] }
    },
    thornback: {
        id: 'thornback', name: 'Thornback', type: 'Flora', baseHp: 72, baseAtk: 55, baseDef: 48, baseSpd: 38,
        evolutionLevel: 15, evolvesInto: 'bloomgoliath',
        moves: [
            { name: 'Leaf Blade', power: 60, accuracy: 95, element: 'Flora', unlockLevel: 1, pp: 18 },
            { name: 'Razor Leaf', power: 70, accuracy: 95, element: 'Flora', unlockLevel: 1, pp: 14 },
            { name: 'Thorn Barrage', power: 70, accuracy: 90, element: 'Flora', unlockLevel: 8, pp: 12 },
            { name: 'Root Crush', power: 90, accuracy: 85, element: 'Flora', unlockLevel: 12, pp: 8 }
        ],
        spriteParams: { shape: 'hexagon', primaryColor: '#22c55e', secondaryColor: '#15803d', accentColor: '#bbf7d0', features: ['eyes', 'spikes', 'petals'] }
    },
    bloomgoliath: {
        id: 'bloomgoliath', name: 'Bloomgoliath', type: 'Flora', baseHp: 108, baseAtk: 82, baseDef: 75, baseSpd: 45,
        moves: [
            { name: 'Thorn Barrage', power: 70, accuracy: 90, element: 'Flora', unlockLevel: 1, pp: 12 },
            { name: 'Root Crush', power: 90, accuracy: 85, element: 'Flora', unlockLevel: 1, pp: 8 },
            { name: 'Verdant Storm', power: 115, accuracy: 80, element: 'Flora', unlockLevel: 15, pp: 6 },
            { name: 'World Bloom', power: 130, accuracy: 75, element: 'Flora', unlockLevel: 20, pp: 4 }
        ],
        spriteParams: { shape: 'hexagon', primaryColor: '#16a34a', secondaryColor: '#14532d', accentColor: '#86efac', features: ['eyes', 'spikes', 'petals', 'crown'] }
    },
    // === VOLT LINE ===
    sparky: {
        id: 'sparky', name: 'Sparky', type: 'Volt', baseHp: 40, baseAtk: 36, baseDef: 25, baseSpd: 48,
        evolutionLevel: 8, evolvesInto: 'boltsaber',
        moves: [
            { name: 'Zap', power: 35, accuracy: 100, element: 'Volt', unlockLevel: 1, pp: 25 },
            { name: 'Quick Attack', power: 30, accuracy: 95, element: 'Cosmos', unlockLevel: 1, pp: 25 },
            { name: 'Thunder Shock', power: 60, accuracy: 95, element: 'Volt', unlockLevel: 4, pp: 18 },
            { name: 'Lightning Arc', power: 75, accuracy: 90, element: 'Volt', unlockLevel: 7, pp: 12 }
        ],
        spriteParams: { shape: 'star', primaryColor: '#facc15', secondaryColor: '#eab308', accentColor: '#fef9c3', features: ['eyes', 'horns'] }
    },
    boltsaber: {
        id: 'boltsaber', name: 'Boltsaber', type: 'Volt', baseHp: 68, baseAtk: 56, baseDef: 40, baseSpd: 62,
        evolutionLevel: 15, evolvesInto: 'stormlord',
        moves: [
            { name: 'Thunder Shock', power: 60, accuracy: 95, element: 'Volt', unlockLevel: 1, pp: 18 },
            { name: 'Spark Slash', power: 70, accuracy: 95, element: 'Volt', unlockLevel: 1, pp: 14 },
            { name: 'Lightning Arc', power: 75, accuracy: 90, element: 'Volt', unlockLevel: 8, pp: 12 },
            { name: 'Thunder Crash', power: 95, accuracy: 85, element: 'Volt', unlockLevel: 12, pp: 8 }
        ],
        spriteParams: { shape: 'star', primaryColor: '#eab308', secondaryColor: '#a16207', accentColor: '#fde047', features: ['eyes', 'horns', 'tail'] }
    },
    stormlord: {
        id: 'stormlord', name: 'Stormlord', type: 'Volt', baseHp: 95, baseAtk: 88, baseDef: 60, baseSpd: 80,
        moves: [
            { name: 'Lightning Arc', power: 75, accuracy: 90, element: 'Volt', unlockLevel: 1, pp: 12 },
            { name: 'Thunder Crash', power: 95, accuracy: 85, element: 'Volt', unlockLevel: 1, pp: 8 },
            { name: 'Tempest Strike', power: 120, accuracy: 80, element: 'Volt', unlockLevel: 15, pp: 6 },
            { name: 'Omega Bolt', power: 140, accuracy: 70, element: 'Volt', unlockLevel: 20, pp: 4 }
        ],
        spriteParams: { shape: 'star', primaryColor: '#ca8a04', secondaryColor: '#713f12', accentColor: '#fde047', features: ['eyes', 'horns', 'tail', 'aura'] }
    },
    // === ZEPHYR LINE ===
    gusty: {
        id: 'gusty', name: 'Gusty', type: 'Zephyr', baseHp: 42, baseAtk: 34, baseDef: 26, baseSpd: 50,
        evolutionLevel: 8, evolvesInto: 'slipstream',
        moves: [
            { name: 'Air Slash', power: 35, accuracy: 95, element: 'Zephyr', unlockLevel: 1, pp: 25 },
            { name: 'Tackle', power: 30, accuracy: 95, element: 'Cosmos', unlockLevel: 1, pp: 25 },
            { name: 'Gust Wave', power: 60, accuracy: 95, element: 'Zephyr', unlockLevel: 4, pp: 18 },
            { name: 'Wind Cutter', power: 70, accuracy: 90, element: 'Zephyr', unlockLevel: 7, pp: 12 }
        ],
        spriteParams: { shape: 'diamond', primaryColor: '#a78bfa', secondaryColor: '#7c3aed', accentColor: '#ede9fe', features: ['eyes', 'wings'] }
    },
    slipstream: {
        id: 'slipstream', name: 'Slipstream', type: 'Zephyr', baseHp: 65, baseAtk: 54, baseDef: 38, baseSpd: 65,
        evolutionLevel: 15, evolvesInto: 'zephyrus',
        moves: [
            { name: 'Gust Wave', power: 60, accuracy: 95, element: 'Zephyr', unlockLevel: 1, pp: 18 },
            { name: 'Air Cutter', power: 70, accuracy: 95, element: 'Zephyr', unlockLevel: 1, pp: 14 },
            { name: 'Wind Cutter', power: 70, accuracy: 90, element: 'Zephyr', unlockLevel: 8, pp: 12 },
            { name: 'Cyclone Spin', power: 90, accuracy: 85, element: 'Zephyr', unlockLevel: 12, pp: 8 }
        ],
        spriteParams: { shape: 'diamond', primaryColor: '#7c3aed', secondaryColor: '#4c1d95', accentColor: '#ddd6fe', features: ['eyes', 'wings', 'tail'] }
    },
    zephyrus: {
        id: 'zephyrus', name: 'Zephyrus', type: 'Zephyr', baseHp: 92, baseAtk: 84, baseDef: 55, baseSpd: 85,
        moves: [
            { name: 'Wind Cutter', power: 70, accuracy: 90, element: 'Zephyr', unlockLevel: 1, pp: 12 },
            { name: 'Cyclone Spin', power: 90, accuracy: 85, element: 'Zephyr', unlockLevel: 1, pp: 8 },
            { name: 'Hurricane Fury', power: 115, accuracy: 80, element: 'Zephyr', unlockLevel: 15, pp: 6 },
            { name: 'Sky Rend', power: 130, accuracy: 75, element: 'Zephyr', unlockLevel: 20, pp: 4 }
        ],
        spriteParams: { shape: 'diamond', primaryColor: '#6d28d9', secondaryColor: '#3b0764', accentColor: '#c4b5fd', features: ['eyes', 'wings', 'tail', 'aura'] }
    },
    // === EARTH LINE ===
    pebble: {
        id: 'pebble', name: 'Pebble', type: 'Earth', baseHp: 52, baseAtk: 30, baseDef: 40, baseSpd: 22,
        evolutionLevel: 8, evolvesInto: 'obsidian',
        moves: [
            { name: 'Rock Throw', power: 35, accuracy: 95, element: 'Earth', unlockLevel: 1, pp: 25 },
            { name: 'Tackle', power: 30, accuracy: 95, element: 'Cosmos', unlockLevel: 1, pp: 25 },
            { name: 'Stone Edge', power: 60, accuracy: 90, element: 'Earth', unlockLevel: 4, pp: 18 },
            { name: 'Boulder Slam', power: 75, accuracy: 85, element: 'Earth', unlockLevel: 7, pp: 12 }
        ],
        spriteParams: { shape: 'triangle', primaryColor: '#d97706', secondaryColor: '#92400e', accentColor: '#fef3c7', features: ['eyes'] }
    },
    obsidian: {
        id: 'obsidian', name: 'Obsidian', type: 'Earth', baseHp: 78, baseAtk: 52, baseDef: 60, baseSpd: 30,
        evolutionLevel: 15, evolvesInto: 'terrasunder',
        moves: [
            { name: 'Stone Edge', power: 60, accuracy: 90, element: 'Earth', unlockLevel: 1, pp: 18 },
            { name: 'Rock Blast', power: 70, accuracy: 90, element: 'Earth', unlockLevel: 1, pp: 14 },
            { name: 'Boulder Slam', power: 75, accuracy: 85, element: 'Earth', unlockLevel: 8, pp: 12 },
            { name: 'Quake Strike', power: 95, accuracy: 80, element: 'Earth', unlockLevel: 12, pp: 8 }
        ],
        spriteParams: { shape: 'triangle', primaryColor: '#78350f', secondaryColor: '#451a03', accentColor: '#d6d3d1', features: ['eyes', 'spikes'] }
    },
    terrasunder: {
        id: 'terrasunder', name: 'Terrasunder', type: 'Earth', baseHp: 112, baseAtk: 78, baseDef: 90, baseSpd: 35,
        moves: [
            { name: 'Boulder Slam', power: 75, accuracy: 85, element: 'Earth', unlockLevel: 1, pp: 12 },
            { name: 'Quake Strike', power: 95, accuracy: 80, element: 'Earth', unlockLevel: 1, pp: 8 },
            { name: 'Mountain Crush', power: 120, accuracy: 75, element: 'Earth', unlockLevel: 15, pp: 6 },
            { name: 'Continental Shift', power: 135, accuracy: 70, element: 'Earth', unlockLevel: 20, pp: 4 }
        ],
        spriteParams: { shape: 'triangle', primaryColor: '#451a03', secondaryColor: '#1c0f06', accentColor: '#d6d3d1', features: ['eyes', 'spikes', 'aura'] }
    }
};
function getResonantDef(id) {
    return exports.RESONANT_DB[id];
}
exports.ALL_IDS = Object.keys(exports.RESONANT_DB);
};

// ── module: src/data/zones.ts ──
__mods["src/data/zones.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SHOP_ITEMS = exports.CONDUCTOR_DATA = exports.BOSS_DATA = exports.ZONES = void 0;
exports.getZone = getZone;
exports.ZONES = {
    verdant_canopy: {
        id: 'verdant_canopy', name: 'The Verdant Canopy', description: 'A lush forest canopy alive with Flora and Zephyr Resonants.',
        levelRange: [1, 5], elementBias: ['Flora', 'Zephyr'], color: '#22c55e',
        nodes: [
            { id: 'vc_1', type: 'wild', label: 'Tall Grass', x: 15, y: 70, unlocked: true, completed: false },
            { id: 'vc_2', type: 'cache', label: 'Mystery Cache', x: 30, y: 60, unlocked: true, completed: false },
            { id: 'vc_3', type: 'wild', label: 'Tall Grass', x: 45, y: 72, unlocked: true, completed: false },
            { id: 'vc_4', type: 'spring', label: 'Healing Spring', x: 60, y: 58, unlocked: true, completed: false },
            { id: 'vc_5', type: 'conductor', label: 'Conductor Mira', x: 75, y: 68, unlocked: true, completed: false },
            { id: 'vc_6', type: 'wild', label: 'Tall Grass', x: 25, y: 40, unlocked: true, completed: false },
            { id: 'vc_7', type: 'cache', label: 'Mystery Cache', x: 50, y: 35, unlocked: true, completed: false },
            { id: 'vc_8', type: 'wild', label: 'Tall Grass', x: 70, y: 42, unlocked: true, completed: false },
            { id: 'vc_boss', type: 'boss', label: 'Gatekeeper: Bloomgoliath Alpha', x: 50, y: 15, unlocked: true, completed: false }
        ]
    },
    sunken_grotto: {
        id: 'sunken_grotto', name: 'The Sunken Grotto', description: 'Underground caverns echoing with Hydro and Earth Resonants.',
        levelRange: [5, 10], elementBias: ['Hydro', 'Earth'], color: '#3b82f6',
        nodes: [
            { id: 'sg_1', type: 'wild', label: 'Crystal Pool', x: 15, y: 70, unlocked: false, completed: false },
            { id: 'sg_2', type: 'cache', label: 'Mystery Cache', x: 30, y: 60, unlocked: false, completed: false },
            { id: 'sg_3', type: 'wild', label: 'Crystal Pool', x: 45, y: 72, unlocked: false, completed: false },
            { id: 'sg_4', type: 'spring', label: 'Healing Spring', x: 60, y: 58, unlocked: false, completed: false },
            { id: 'sg_5', type: 'conductor', label: 'Conductor Kael', x: 75, y: 68, unlocked: false, completed: false },
            { id: 'sg_6', type: 'wild', label: 'Crystal Pool', x: 25, y: 40, unlocked: false, completed: false },
            { id: 'sg_7', type: 'cache', label: 'Mystery Cache', x: 50, y: 35, unlocked: false, completed: false },
            { id: 'sg_8', type: 'wild', label: 'Crystal Pool', x: 70, y: 42, unlocked: false, completed: false },
            { id: 'sg_boss', type: 'boss', label: 'Gatekeeper: Neptunian Prime', x: 50, y: 15, unlocked: false, completed: false }
        ]
    },
    obsidian_crags: {
        id: 'obsidian_crags', name: 'The Obsidian Crags', description: 'Volcanic peaks crackling with Pyro and Volt energy.',
        levelRange: [10, 15], elementBias: ['Pyro', 'Volt'], color: '#f97316',
        nodes: [
            { id: 'oc_1', type: 'wild', label: 'Lava Fields', x: 15, y: 70, unlocked: false, completed: false },
            { id: 'oc_2', type: 'cache', label: 'Mystery Cache', x: 30, y: 60, unlocked: false, completed: false },
            { id: 'oc_3', type: 'wild', label: 'Lava Fields', x: 45, y: 72, unlocked: false, completed: false },
            { id: 'oc_4', type: 'spring', label: 'Healing Spring', x: 60, y: 58, unlocked: false, completed: false },
            { id: 'oc_5', type: 'conductor', label: 'Conductor Vex', x: 75, y: 68, unlocked: false, completed: false },
            { id: 'oc_6', type: 'wild', label: 'Lava Fields', x: 25, y: 40, unlocked: false, completed: false },
            { id: 'oc_7', type: 'cache', label: 'Mystery Cache', x: 50, y: 35, unlocked: false, completed: false },
            { id: 'oc_8', type: 'wild', label: 'Lava Fields', x: 70, y: 42, unlocked: false, completed: false },
            { id: 'oc_boss', type: 'boss', label: 'Gatekeeper: Ignisaur Omega', x: 50, y: 15, unlocked: false, completed: false }
        ]
    },
    apex_pillar: {
        id: 'apex_pillar', name: 'The Apex Pillar', description: 'The final ascent — a gauntlet of the strongest Resonants.',
        levelRange: [15, 20], elementBias: ['Cosmos'], color: '#c084fc',
        nodes: [
            { id: 'ap_1', type: 'wild', label: 'Aether Storm', x: 15, y: 70, unlocked: false, completed: false },
            { id: 'ap_2', type: 'cache', label: 'Mystery Cache', x: 30, y: 60, unlocked: false, completed: false },
            { id: 'ap_3', type: 'wild', label: 'Aether Storm', x: 45, y: 72, unlocked: false, completed: false },
            { id: 'ap_4', type: 'spring', label: 'Healing Spring', x: 60, y: 58, unlocked: false, completed: false },
            { id: 'ap_5', type: 'conductor', label: 'Conductor Zephyra', x: 75, y: 68, unlocked: false, completed: false },
            { id: 'ap_6', type: 'wild', label: 'Aether Storm', x: 25, y: 40, unlocked: false, completed: false },
            { id: 'ap_7', type: 'cache', label: 'Mystery Cache', x: 50, y: 35, unlocked: false, completed: false },
            { id: 'ap_boss1', type: 'boss', label: 'Boss: Stormlord Zenith', x: 25, y: 20, unlocked: false, completed: false },
            { id: 'ap_boss2', type: 'boss', label: 'Boss: Terrasunder Apex', x: 75, y: 20, unlocked: false, completed: false },
            { id: 'ap_final', type: 'boss', label: 'Final Boss: Cosmos Sovereign', x: 50, y: 8, unlocked: false, completed: false }
        ]
    }
};
exports.BOSS_DATA = {
    vc_boss: { defId: 'bloomgoliath', level: 5, dialog: 'The canopy trembles as a massive Bloomgoliath emerges from the undergrowth. "You dare challenge the guardian of this forest?"' },
    sg_boss: { defId: 'neptunian', level: 8, dialog: 'Deep beneath the grotto, an ancient Neptunian rises from the crystal waters. "The depths do not welcome intruders."' },
    oc_boss: { defId: 'ignisaur', level: 12, dialog: 'Magma erupts as Ignisaur Omega descends upon the crags. "Feel the fury of a thousand suns!"' },
    ap_boss1: { defId: 'stormlord', level: 15, dialog: 'Lightning splits the sky — Stormlord Zenith commands the tempest itself.' },
    ap_boss2: { defId: 'terrasunder', level: 16, dialog: 'The ground quakes as Terrasunder Apex rises from the bedrock. "Nothing moves me."' },
    ap_final: { defId: 'ignisaur', level: 20, dialog: 'A blinding light fills the Apex Pillar. The Cosmos Sovereign — a being of pure elemental harmony — awaits your challenge.' }
};
exports.CONDUCTOR_DATA = {
    vc_5: { name: 'Conductor Mira', resonantDefId: 'thornback', level: 3, dialog: '"I am Mira, a wandering Conductor. Let us see if your Resonants can match mine!"' },
    sg_5: { name: 'Conductor Kael', resonantDefId: 'geoxus', level: 7, dialog: '"Kael here. The grotto tests all who enter — are you worthy?"' },
    oc_5: { name: 'Conductor Vex', resonantDefId: 'pyrowolf', level: 12, dialog: '"Vex commands the flames of the crags. Prepare for battle!"' },
    ap_5: { name: 'Conductor Zephyra', resonantDefId: 'zephyrus', level: 17, dialog: '"I am Zephyra, the last guardian before the Sovereign. Prove your worth."' }
};
exports.SHOP_ITEMS = [
    { id: 'prism_basic', name: 'Harmonizer Prism', description: 'Basic capture prism — moderate catch rate.', cost: 30, icon: '💎' },
    { id: 'prism_hyper', name: 'Hyper-Conductive Prism', description: 'Premium prism — high catch rate.', cost: 80, icon: '🔮' },
    { id: 'elixir_hp', name: 'Core Restorer', description: 'Restores 50% HP to active Resonant.', cost: 25, icon: '❤️' },
    { id: 'elixir_status', name: 'Resonance Elixir', description: 'Heals all status conditions on a Resonant.', cost: 35, icon: '✨' }
];
function getZone(id) { return exports.ZONES[id]; }
};

// ── module: src/state/player.ts ──
__mods["src/state/player.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createResonant = createResonant;
exports.createDefaultState = createDefaultState;
exports.saveState = saveState;
exports.loadState = loadState;
exports.resetSave = resetSave;
exports.gainXp = gainXp;
exports.shouldEvolve = shouldEvolve;
exports.evolveResonant = evolveResonant;
exports.addItem = addItem;
exports.removeItem = removeItem;
exports.hasItem = hasItem;
const resonants_1 = require("../data/resonants");
const SAVE_KEY = 'aethelgard_save_v1';
function createResonant(defId, level) {
    const def = (0, resonants_1.getResonantDef)(defId);
    if (!def)
        throw new Error(`Unknown resonant: ${defId}`);
    const hp = Math.floor(def.baseHp * (1 + level * 0.15));
    return {
        defId, level, currentHp: hp, maxHp: hp,
        atk: Math.floor(def.baseAtk * (1 + level * 0.12)),
        def: Math.floor(def.baseDef * (1 + level * 0.12)),
        spd: Math.floor(def.baseSpd * (1 + level * 0.1)),
        xp: 0, xpToNext: level * 30 + 20,
        statusEffect: null,
        capturedMoves: def.moves.filter(m => m.unlockLevel <= level)
    };
}
function createDefaultState() {
    return {
        name: 'Conductor', shards: 100,
        party: [createResonant('emberkit', 3)],
        inventory: [{ itemId: 'prism_basic', count: 5 }, { itemId: 'elixir_hp', count: 3 }],
        unlockedZones: ['verdant_canopy'], completedBosses: [],
        currentZone: 'verdant_canopy', currentNode: '',
        dexEntries: ['emberkit'], totalBattles: 0, totalCaptures: 0
    };
}
function saveState(state) {
    try {
        localStorage.setItem(SAVE_KEY, JSON.stringify(state));
    }
    catch (e) { /* quota */ }
}
function loadState() {
    try {
        const raw = localStorage.getItem(SAVE_KEY);
        if (!raw)
            return null;
        return JSON.parse(raw);
    }
    catch {
        return null;
    }
}
function resetSave() {
    localStorage.removeItem(SAVE_KEY);
}
function gainXp(r, amount) {
    r.xp += amount;
    if (r.xp >= r.xpToNext) {
        r.level++;
        const def = (0, resonants_1.getResonantDef)(r.defId);
        r.maxHp = Math.floor(def.baseHp * (1 + r.level * 0.15));
        r.currentHp = r.maxHp;
        r.atk = Math.floor(def.baseAtk * (1 + r.level * 0.12));
        r.def = Math.floor(def.baseDef * (1 + r.level * 0.12));
        r.spd = Math.floor(def.baseSpd * (1 + r.level * 0.1));
        r.xp -= r.xpToNext;
        r.xpToNext = r.level * 30 + 20;
        // Unlock new moves
        const newMoves = def.moves.filter(m => m.unlockLevel <= r.level && !r.capturedMoves.find(cm => cm.name === m.name));
        r.capturedMoves.push(...newMoves);
        return true; // leveled up
    }
    return false;
}
function shouldEvolve(r) {
    const def = (0, resonants_1.getResonantDef)(r.defId);
    return !!(def && def.evolutionLevel === r.level);
}
function evolveResonant(r) {
    const def = (0, resonants_1.getResonantDef)(r.defId);
    if (!def || !def.evolvesInto)
        return;
    r.defId = def.evolvesInto;
    // Full heal on evolution
    const newDef = (0, resonants_1.getResonantDef)(r.defId);
    r.maxHp = Math.floor(newDef.baseHp * (1 + r.level * 0.15));
    r.currentHp = r.maxHp;
    r.atk = Math.floor(newDef.baseAtk * (1 + r.level * 0.12));
    r.def = Math.floor(newDef.baseDef * (1 + r.level * 0.12));
    r.spd = Math.floor(newDef.baseSpd * (1 + r.level * 0.1));
}
function addItem(state, itemId, count) {
    const existing = state.inventory.find(i => i.itemId === itemId);
    if (existing)
        existing.count += count;
    else
        state.inventory.push({ itemId, count });
}
function removeItem(state, itemId, count) {
    const item = state.inventory.find(i => i.itemId === itemId);
    if (!item || item.count < count)
        return false;
    item.count -= count;
    if (item.count <= 0)
        state.inventory = state.inventory.filter(i => i.itemId !== itemId);
    return true;
}
function hasItem(state, itemId, count) {
    const item = state.inventory.find(i => i.itemId === itemId);
    return !!(item && item.count >= count);
}
};

// ── module: src/systems/synth.ts ──
__mods["src/systems/synth.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.synth = exports.SynthManager = void 0;
class SynthManager {
    constructor() {
        this.ctx = null;
        this.enabled = true;
    }
    init() {
        if (!this.ctx) {
            this.ctx = new (window.AudioContext || window.webkitAudioContext)();
        }
        if (this.ctx.state === 'suspended')
            this.ctx.resume();
    }
    playTone(freq, duration, type = 'square', volume = 0.15) {
        if (!this.ctx || !this.enabled)
            return;
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.type = type;
        osc.frequency.setValueAtTime(freq, this.ctx.currentTime);
        gain.gain.setValueAtTime(volume, this.ctx.currentTime);
        gain.gain.exponentialRampToValueAtTime(0.001, this.ctx.currentTime + duration);
        osc.connect(gain).connect(this.ctx.destination);
        osc.start();
        osc.stop(this.ctx.currentTime + duration);
    }
    hover() { this.playTone(880, 0.06, 'sine', 0.05); }
    select() { this.playTone(660, 0.1, 'square', 0.12); setTimeout(() => this.playTone(990, 0.08, 'square', 0.1), 60); }
    hitPhysical() {
        if (!this.ctx || !this.enabled)
            return;
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.type = 'sawtooth';
        osc.frequency.setValueAtTime(200, this.ctx.currentTime);
        osc.frequency.exponentialRampToValueAtTime(60, this.ctx.currentTime + 0.15);
        gain.gain.setValueAtTime(0.2, this.ctx.currentTime);
        gain.gain.exponentialRampToValueAtTime(0.001, this.ctx.currentTime + 0.15);
        osc.connect(gain).connect(this.ctx.destination);
        osc.start();
        osc.stop(this.ctx.currentTime + 0.15);
    }
    hitElemental() {
        if (!this.ctx || !this.enabled)
            return;
        this.playTone(440, 0.12, 'square', 0.18);
        setTimeout(() => this.playTone(660, 0.1, 'square', 0.15), 50);
        setTimeout(() => this.playTone(880, 0.15, 'sawtooth', 0.12), 100);
    }
    superEffective() {
        if (!this.ctx || !this.enabled)
            return;
        [523, 659, 784, 1047].forEach((f, i) => {
            setTimeout(() => this.playTone(f, 0.15, 'square', 0.2), i * 60);
        });
    }
    levelUp() {
        if (!this.ctx || !this.enabled)
            return;
        [440, 554, 659, 880, 1108].forEach((f, i) => {
            setTimeout(() => this.playTone(f, 0.2, 'square', 0.18), i * 100);
        });
    }
    capture() {
        if (!this.ctx || !this.enabled)
            return;
        [330, 440, 554, 660, 880].forEach((f, i) => {
            setTimeout(() => this.playTone(f, 0.12, 'sine', 0.15), i * 80);
        });
    }
    evolve() {
        if (!this.ctx || !this.enabled)
            return;
        [262, 330, 392, 523, 659, 784, 1047].forEach((f, i) => {
            setTimeout(() => this.playTone(f, 0.25, 'sine', 0.15), i * 120);
        });
    }
    defeat() {
        if (!this.ctx || !this.enabled)
            return;
        [440, 370, 311, 262].forEach((f, i) => {
            setTimeout(() => this.playTone(f, 0.25, 'triangle', 0.15), i * 150);
        });
    }
    heal() {
        if (!this.ctx || !this.enabled)
            return;
        [392, 440, 523, 659].forEach((f, i) => {
            setTimeout(() => this.playTone(f, 0.18, 'sine', 0.1), i * 100);
        });
    }
    toggle() { this.enabled = !this.enabled; }
}
exports.SynthManager = SynthManager;
exports.synth = new SynthManager();
};

// ── module: src/systems/combat.ts ──
__mods["src/systems/combat.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.calcDamage = calcDamage;
exports.applyDamage = applyDamage;
exports.isFainted = isFainted;
exports.calcCaptureRate = calcCaptureRate;
exports.applyStatusEffect = applyStatusEffect;
exports.processStatusEffects = processStatusEffects;
exports.healResonant = healResonant;
exports.fullHealParty = fullHealParty;
exports.selectEnemyMove = selectEnemyMove;
exports.getHpColor = getHpColor;
exports.xpForDefeat = xpForDefeat;
const types_1 = require("../types");
const resonants_1 = require("../data/resonants");
function calcDamage(attacker, defender, movePower) {
    const atkDef = (0, resonants_1.getResonantDef)(attacker.defId);
    const defDef = (0, resonants_1.getResonantDef)(defender.defId);
    const typeAdv = types_1.TYPE_ADVANTAGES[atkDef.type];
    let typeMod = 1;
    if (typeAdv.strong.includes(defDef.type))
        typeMod = 1.5;
    else if (typeAdv.weak.includes(defDef.type))
        typeMod = 0.75;
    const base = (((2 * attacker.level / 5 + 2) * movePower * (attacker.atk / defender.def)) / 50 + 2);
    const random = 0.85 + Math.random() * 0.15;
    let damage = Math.max(1, Math.floor(base * typeMod * random));
    // Status effects reduce attack
    if (attacker.statusEffect === 'Burn') {
        damage = Math.floor(damage * 0.8);
    }
    if (attacker.statusEffect === 'Paralyze') {
        damage = Math.floor(damage * 0.75);
    }
    const isCrit = Math.random() < 0.1;
    if (isCrit)
        damage = Math.floor(damage * 1.5);
    return { damage, isCrit, typeMod };
}
function applyDamage(r, amount) {
    r.currentHp = Math.max(0, r.currentHp - amount);
}
function isFainted(r) {
    return r.currentHp <= 0;
}
function calcCaptureRate(enemy, prismTier) {
    const hpRatio = enemy.currentHp / enemy.maxHp;
    let base = (1 - hpRatio) * 0.85 + 0.15; // More HP = harder to catch
    if (enemy.statusEffect)
        base += 0.2;
    if (prismTier === 'hyper')
        base *= 1.6;
    return Math.min(0.95, Math.max(0.05, base));
}
function applyStatusEffect(r, effect) {
    r.statusEffect = effect;
}
function processStatusEffects(r) {
    if (!r.statusEffect)
        return null;
    switch (r.statusEffect) {
        case 'Burn':
            const burnDmg = Math.max(1, Math.floor(r.maxHp * 0.06));
            r.currentHp = Math.max(0, r.currentHp - burnDmg);
            if (Math.random() < 0.2) {
                r.statusEffect = null;
                return `${r.defId} is healed of Burn!`;
            }
            return null;
        case 'Poison':
            const poisDmg = Math.max(1, Math.floor(r.maxHp * 0.05));
            r.currentHp = Math.max(0, r.currentHp - poisDmg);
            if (Math.random() < 0.2) {
                r.statusEffect = null;
                return `${r.defId} is healed of Poison!`;
            }
            return null;
        case 'Paralyze':
            if (Math.random() < 0.15) {
                r.statusEffect = null;
                return `${r.defId} shakes off Paralysis!`;
            }
            return null;
        case 'Sleep':
            if (Math.random() < 0.3) {
                r.statusEffect = null;
                return `${r.defId} wakes up!`;
            }
            return null;
    }
    return null;
}
function healResonant(r, amount) {
    r.currentHp = Math.min(r.maxHp, r.currentHp + amount);
}
function fullHealParty(party) {
    party.forEach(r => { r.currentHp = r.maxHp; r.statusEffect = null; });
}
// AI enemy move selection
function selectEnemyMove(enemy) {
    const def = (0, resonants_1.getResonantDef)(enemy.defId);
    const availableMoves = def.moves.filter(m => m.unlockLevel <= enemy.level);
    // Prefer stronger moves, with some randomness
    if (Math.random() < 0.3 && availableMoves.length > 1) {
        return Math.floor(Math.random() * availableMoves.length);
    }
    let bestIdx = 0;
    for (let i = 1; i < availableMoves.length; i++) {
        if (availableMoves[i].power > availableMoves[bestIdx].power)
            bestIdx = i;
    }
    return bestIdx;
}
function getHpColor(ratio) {
    if (ratio > 0.5)
        return '#22c55e';
    if (ratio > 0.25)
        return '#eab308';
    return '#ef4444';
}
function xpForDefeat(level) {
    return Math.floor(15 + level * 8);
}
};

// ── module: src/ui/sprites.ts ──
__mods["src/ui/sprites.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.renderResonantSVG = renderResonantSVG;
exports.renderResonantSVGInline = renderResonantSVGInline;
const resonants_1 = require("../data/resonants");
const types_1 = require("../types");
function shapePath(shape, size) {
    const cx = size / 2, cy = size / 2, r = size * 0.38;
    switch (shape) {
        case 'circle': return `<circle cx="${cx}" cy="${cy}" r="${r}"/>`;
        case 'hexagon': {
            const pts = [];
            for (let i = 0; i < 6; i++) {
                const a = Math.PI / 3 * i - Math.PI / 6;
                pts.push(`${cx + r * Math.cos(a)},${cy + r * Math.sin(a)}`);
            }
            return `<polygon points="${pts.join(' ')}"/>`;
        }
        case 'diamond': return `<rect x="${cx - r * 0.7}" y="${cy - r * 0.7}" width="${r * 1.4}" height="${r * 1.4}" rx="6" transform="rotate(45 ${cx} ${cy})"/>`;
        case 'star': {
            const pts = [];
            for (let i = 0; i < 10; i++) {
                const a = Math.PI / 5 * i - Math.PI / 2;
                const rad = i % 2 === 0 ? r : r * 0.45;
                pts.push(`${cx + rad * Math.cos(a)},${cy + rad * Math.sin(a)}`);
            }
            return `<polygon points="${pts.join(' ')}"/>`;
        }
        case 'triangle': {
            const pts = [];
            for (let i = 0; i < 3; i++) {
                const a = Math.PI * 2 / 3 * i - Math.PI / 2;
                pts.push(`${cx + r * Math.cos(a)},${cy + r * Math.sin(a)}`);
            }
            return `<polygon points="${pts.join(' ')}" rx="4"/>`;
        }
        default: return `<circle cx="${cx}" cy="${cy}" r="${r}"/>`;
    }
}
function featureOverlay(params, size) {
    const cx = size / 2, cy = size / 2, r = size * 0.38;
    let svg = '';
    if (params.features.includes('eyes')) {
        const eyeY = cy - r * 0.15;
        svg += `<circle cx="${cx - r * 0.2}" cy="${eyeY}" r="${r * 0.1}" fill="white"/>`;
        svg += `<circle cx="${cx + r * 0.2}" cy="${eyeY}" r="${r * 0.1}" fill="white"/>`;
        svg += `<circle cx="${cx - r * 0.18}" cy="${eyeY + 1}" r="${r * 0.05}" fill="#1a1040"/>`;
        svg += `<circle cx="${cx + r * 0.22}" cy="${eyeY + 1}" r="${r * 0.05}" fill="#1a1040"/>`;
    }
    if (params.features.includes('horns')) {
        svg += `<polygon points="${cx - r * 0.3},${cy - r * 0.6} ${cx - r * 0.5},${cy - r * 1.2} ${cx - r * 0.1},${cy - r * 0.7}" fill="${params.accentColor}" opacity="0.8"/>`;
        svg += `<polygon points="${cx + r * 0.3},${cy - r * 0.6} ${cx + r * 0.5},${cy - r * 1.2} ${cx + r * 0.1},${cy - r * 0.7}" fill="${params.accentColor}" opacity="0.8"/>`;
    }
    if (params.features.includes('wings')) {
        svg += `<ellipse cx="${cx - r * 0.9}" cy="${cy - r * 0.2}" rx="${r * 0.5}" ry="${r * 0.3}" fill="${params.accentColor}" opacity="0.4" transform="rotate(-20 ${cx - r * 0.9} ${cy})"/>`;
        svg += `<ellipse cx="${cx + r * 0.9}" cy="${cy - r * 0.2}" rx="${r * 0.5}" ry="${r * 0.3}" fill="${params.accentColor}" opacity="0.4" transform="rotate(20 ${cx + r * 0.9} ${cy})"/>`;
    }
    if (params.features.includes('tail')) {
        svg += `<path d="M${cx},${cy + r * 0.7} Q${cx + r * 0.5},${cy + r * 1.3} ${cx + r * 0.2},${cy + r * 1.4}" stroke="${params.secondaryColor}" stroke-width="3" fill="none" stroke-linecap="round"/>`;
    }
    if (params.features.includes('crown')) {
        svg += `<polygon points="${cx - r * 0.35},${cy - r * 0.7} ${cx - r * 0.25},${cy - r * 1.15} ${cx - r * 0.08},${cy - r * 0.85} ${cx + r * 0.08},${cy - r * 1.15} ${cx + r * 0.25},${cy - r * 0.85} ${cx + r * 0.35},${cy - r * 0.7}" fill="${params.accentColor}" opacity="0.9"/>`;
    }
    if (params.features.includes('aura')) {
        svg += `<circle cx="${cx}" cy="${cy}" r="${r * 1.2}" fill="none" stroke="${params.primaryColor}" stroke-width="2" opacity="0.3">`;
        svg += `<animate attributeName="r" values="${r * 1.1};${r * 1.35};${r * 1.1}" dur="2s" repeatCount="indefinite"/>`;
        svg += `<animate attributeName="opacity" values="0.4;0.1;0.4" dur="2s" repeatCount="indefinite"/></circle>`;
    }
    if (params.features.includes('spikes')) {
        for (let i = 0; i < 6; i++) {
            const a = Math.PI / 3 * i;
            svg += `<line x1="${cx + r * 0.85 * Math.cos(a)}" y1="${cy + r * 0.85 * Math.sin(a)}" x2="${cx + r * 1.15 * Math.cos(a)}" y2="${cy + r * 1.15 * Math.sin(a)}" stroke="${params.secondaryColor}" stroke-width="3" stroke-linecap="round"/>`;
        }
    }
    if (params.features.includes('petals')) {
        for (let i = 0; i < 4; i++) {
            const a = Math.PI / 2 * i + Math.PI / 4;
            svg += `<ellipse cx="${cx + r * 0.7 * Math.cos(a)}" cy="${cy + r * 0.7 * Math.sin(a)}" rx="${r * 0.2}" ry="${r * 0.35}" fill="${params.accentColor}" opacity="0.5" transform="rotate(${i * 45} ${cx + r * 0.7 * Math.cos(a)} ${cy + r * 0.7 * Math.sin(a)})"/>`;
        }
    }
    return svg;
}
function renderResonantSVG(defId, size = 120) {
    const def = (0, resonants_1.getResonantDef)(defId);
    if (!def)
        return `<svg width="${size}" height="${size}"><text x="50%" y="50%" text-anchor="middle" fill="#888">?</text></svg>`;
    const p = def.spriteParams;
    const glowColor = types_1.ELEMENT_COLORS[def.type] || '#8b5cf6';
    return `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg">
    <defs>
      <radialGradient id="g_${defId}_${size}" cx="40%" cy="35%">
        <stop offset="0%" stop-color="${p.accentColor}"/>
        <stop offset="60%" stop-color="${p.primaryColor}"/>
        <stop offset="100%" stop-color="${p.secondaryColor}"/>
      </radialGradient>
      <filter id="glow_${defId}_${size}">
        <feGaussianBlur stdDeviation="3" result="blur"/>
        <feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge>
      </filter>
    </defs>
    ${shapePath(p.shape, size)}
    ${featureOverlay(p, size)}
  </svg>`;
}
function renderResonantSVGInline(defId, size = 120) {
    const container = document.createElement('div');
    container.innerHTML = renderResonantSVG(defId, size);
    return container.firstChild;
}
};

// ── module: src/ui/game.ts ──
__mods["src/ui/game.ts"] = function (exports, require, module) {
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.renderMainMenu = renderMainMenu;
exports.renderMap = renderMap;
exports.setupBattleActions = setupBattleActions;
exports.renderShop = renderShop;
exports.renderDex = renderDex;
exports.showZoneSelect = showZoneSelect;
exports.init = init;
const types_1 = require("../types");
const resonants_1 = require("../data/resonants");
const zones_1 = require("../data/zones");
const player_1 = require("../state/player");
const combat = __importStar(require("../systems/combat"));
const synth_1 = require("../systems/synth");
const sprites_1 = require("./sprites");
// ===== SCREEN MANAGEMENT =====
let currentScreen = 'menu';
let playerState;
let battleState = null;
let battleCallback = null;
function showScreen(name) {
    document.querySelectorAll('.game-screen').forEach(el => el.classList.remove('active'));
    const target = document.getElementById(`screen-${name}`);
    if (target) {
        target.classList.add('active');
    }
    currentScreen = name;
}
function showToast(msg, duration = 2000) {
    const overlay = document.getElementById('overlay-toast');
    overlay.innerHTML = `<div class="toast-msg">${msg}</div>`;
    overlay.classList.remove('hidden');
    setTimeout(() => overlay.classList.add('hidden'), duration);
}
// ===== MAIN MENU =====
function renderMainMenu() {
    const el = document.getElementById('screen-menu');
    el.innerHTML = `
    <div class="glass-card" style="padding:48px 56px;text-align:center;max-width:480px;width:90%;animation:bounceIn 0.5s ease">
      <h1 class="retro-title" style="font-size:22px;color:#c084fc;margin-bottom:8px;text-shadow:0 0 20px rgba(192,132,252,0.5)">AETHELGARD</h1>
      <p style="color:#a78bfa;font-size:13px;letter-spacing:4px;margin-bottom:36px">RESONANT CHRONICLES</p>
      <div id="menu-buttons" style="display:flex;flex-direction:column;gap:12px;align-items:center"></div>
    </div>`;
    const btns = document.getElementById('menu-buttons');
    const hasSave = localStorage.getItem('aethelgard_save_v1');
    if (hasSave) {
        addBtn(btns, 'Continue', () => { initGame(true); renderMap(); }, 'success');
    }
    addBtn(btns, 'New Game', () => { initGame(false); pickStarter(); }, '');
    addBtn(btns, 'Reset Progress', () => {
        if (confirm('Erase all progress? This cannot be undone.')) {
            localStorage.removeItem('aethelgard_save_v1');
            renderMainMenu();
        }
    }, 'danger');
}
function initGame(load) {
    synth_1.synth.init();
    playerState = load ? JSON.parse(localStorage.getItem('aethelgard_save_v1')) : (0, player_1.createDefaultState)();
}
function addBtn(parent, text, onClick, cls = '') {
    const btn = document.createElement('button');
    btn.className = `glass-btn ${cls}`;
    btn.style.width = '200px';
    btn.textContent = text;
    btn.addEventListener('click', () => { synth_1.synth.select(); onClick(); });
    btn.addEventListener('mouseenter', () => synth_1.synth.hover());
    parent.appendChild(btn);
}
// ===== STARTER SELECTION =====
function pickStarter() {
    const el = document.getElementById('screen-menu');
    const starters = ['emberkit', 'droplet', 'seedling'];
    const starterNames = ['Emberkit (Pyro)', 'Droplet (Hydro)', 'Seedling (Flora)'];
    el.innerHTML = `
    <div class="glass-card" style="padding:36px 48px;text-align:center;max-width:520px;width:90%;animation:bounceIn 0.4s ease">
      <h2 class="retro-title" style="font-size:16px;color:#c084fc;margin-bottom:24px">Choose Your Resonant</h2>
      <div id="starter-grid" style="display:flex;gap:20px;justify-content:center;flex-wrap:wrap"></div>
    </div>`;
    const grid = document.getElementById('starter-grid');
    starters.forEach((id, i) => {
        const card = document.createElement('div');
        card.className = 'glass-card';
        card.style.cssText = 'padding:20px;width:140px;text-align:center;cursor:pointer;transition:transform 0.2s,border-color 0.2s';
        card.innerHTML = `
      <div style="margin-bottom:8px">${(0, sprites_1.renderResonantSVG)(id, 80)}</div>
      <p style="font-weight:700;font-size:13px;margin-bottom:4px">${starterNames[i]}</p>`;
        card.addEventListener('mouseenter', () => { synth_1.synth.hover(); card.style.borderColor = types_1.ELEMENT_COLORS[(0, resonants_1.getResonantDef)(id).type]; });
        card.addEventListener('click', () => {
            synth_1.synth.select();
            playerState.party = [(0, player_1.createResonant)(id, 3)];
            playerState.dexEntries.push(id);
            (0, player_1.saveState)(playerState);
            showToast(`${starterNames[i]} joins your party!`);
            setTimeout(() => renderMap(), 800);
        });
        grid.appendChild(card);
    });
}
// ===== MAP RENDERING =====
function renderMap() {
    showScreen('map');
    const zone = zones_1.ZONES[playerState.currentZone];
    if (!zone)
        return;
    const el = document.getElementById('screen-map');
    el.innerHTML = `
    <div style="width:100%;max-width:800px;height:100%;display:flex;flex-direction:column">
      <div class="glass-card" style="padding:16px 24px;margin-bottom:12px;display:flex;justify-content:space-between;align-items:center;flex-shrink:0">
        <div>
          <h2 class="retro-title" style="font-size:14px;color:${zone.color}">${zone.name}</h2>
          <p style="font-size:12px;color:#94a3b8;margin-top:4px">${zone.description}</p>
        </div>
        <div style="display:flex;gap:8px">
          ${playerState.unlockedZones.length > 1 ? `<button class="glass-btn" id="btn-zones" style="padding:6px 14px;font-size:12px">🗺️ Zones</button>` : ''}
          <button class="glass-btn" id="btn-shop" style="padding:6px 14px;font-size:12px">🏪 Shop</button>
          <button class="glass-btn" id="btn-dex" style="padding:6px 14px;font-size:12px">📖 Dex</button>
          <button class="glass-btn" id="btn-party" style="padding:6px 14px;font-size:12px">👥 Party</button>
        </div>
      </div>
      <div class="glass-card" style="flex:1;position:relative;overflow:hidden;border-radius:16px" id="map-canvas"></div>
      <div style="padding:8px;text-align:center">
        <span style="font-size:12px;color:#94a3b8">💎 ${playerState.shards} Aether Shards</span>
      </div>
    </div>`;
    const canvas = document.getElementById('map-canvas');
    // Draw zone background gradient
    canvas.style.background = `radial-gradient(ellipse at center, ${zone.color}15 0%, transparent 70%), linear-gradient(180deg, #0f0a1e, #1a1040)`;
    // Draw nodes
    zone.nodes.forEach(node => {
        if (!node.unlocked)
            return;
        const nodeEl = document.createElement('div');
        const colors = { wild: '#22c55e', cache: '#facc15', conductor: '#ef4444', spring: '#3b82f6', boss: '#c084fc' };
        const icons = { wild: '🌿', cache: '📦', conductor: '⚔️', spring: '💧', boss: '👑' };
        nodeEl.style.cssText = `position:absolute;left:${node.x}%;top:${node.y}%;transform:translate(-50%,-50%);text-align:center;cursor:pointer;transition:all 0.2s;z-index:1`;
        const color = colors[node.type] || '#8b5cf6';
        nodeEl.innerHTML = `
      <div style="width:48px;height:48px;border-radius:50%;background:${color}30;border:2px solid ${color};display:flex;align-items:center;justify-content:center;font-size:20px;box-shadow:0 0 12px ${color}40">${icons[node.type] || '?'}</div>
      <p style="font-size:10px;margin-top:4px;color:${node.completed ? '#6b7280' : '#e2e8f0'};font-weight:600">${node.label}${node.completed ? ' ✓' : ''}</p>`;
        nodeEl.addEventListener('mouseenter', () => { synth_1.synth.hover(); nodeEl.style.transform = 'translate(-50%,-50%) scale(1.15)'; });
        nodeEl.addEventListener('mouseleave', () => { nodeEl.style.transform = 'translate(-50%,-50%) scale(1)'; });
        nodeEl.addEventListener('click', () => handleNodeClick(node));
        canvas.appendChild(nodeEl);
    });
    // Draw connecting lines between nodes
    const svgOverlay = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
    svgOverlay.style.cssText = 'position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:0';
    for (let i = 0; i < zone.nodes.length - 1; i++) {
        const a = zone.nodes[i], b = zone.nodes[i + 1];
        if (!a.unlocked || !b.unlocked)
            continue;
        const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
        line.setAttribute('x1', `${a.x}%`);
        line.setAttribute('y1', `${a.y}%`);
        line.setAttribute('x2', `${b.x}%`);
        line.setAttribute('y2', `${b.y}%`);
        line.setAttribute('stroke', zone.color + '30');
        line.setAttribute('stroke-width', '2');
        svgOverlay.appendChild(line);
    }
    canvas.insertBefore(svgOverlay, canvas.firstChild);
    // Button handlers
    const btnZones = document.getElementById('btn-zones');
    if (btnZones)
        btnZones.addEventListener('click', () => { synth_1.synth.select(); showZoneSelect(); });
    document.getElementById('btn-shop').addEventListener('click', () => { synth_1.synth.select(); renderShop(); });
    document.getElementById('btn-dex').addEventListener('click', () => { synth_1.synth.select(); renderDex(); });
    document.getElementById('btn-party').addEventListener('click', () => { synth_1.synth.select(); renderPartyScreen(); });
}
function handleNodeClick(node) {
    if (node.completed)
        return;
    synth_1.synth.select();
    switch (node.type) {
        case 'wild':
            startWildBattle(playerState.currentZone, node.id);
            break;
        case 'cache':
            openCache(node);
            break;
        case 'conductor':
            startConductorBattle(node.id);
            break;
        case 'spring':
            healSpring();
            break;
        case 'boss':
            startBossBattle(node.id);
            break;
    }
}
function openCache(node) {
    node.completed = true;
    const rewards = [
        () => { playerState.shards += Math.floor(15 + Math.random() * 20); showToast('Found Aether Shards!'); },
        () => { (0, player_1.addItem)(playerState, 'prism_basic', 2); showToast('Found 2 Harmonizer Prisms!'); },
        () => { (0, player_1.addItem)(playerState, 'elixir_hp', 2); showToast('Found 2 Core Restorers!'); },
        () => { playerState.shards += 30; (0, player_1.addItem)(playerState, 'prism_hyper', 1); showToast('Treasure! Shards + Hyper Prism!'); }
    ];
    rewards[Math.floor(Math.random() * rewards.length)]();
    (0, player_1.saveState)(playerState);
    renderMap();
}
function healSpring() {
    synth_1.synth.heal();
    combat.fullHealParty(playerState.party);
    showToast('Your Resonants are fully restored!');
    (0, player_1.saveState)(playerState);
    renderMap();
}
// ===== WILD BATTLE =====
function startWildBattle(zoneId, nodeId) {
    const zone = zones_1.ZONES[zoneId];
    if (!zone)
        return;
    // Pick a random resonant from the zone's element bias
    const eligibleIds = Object.keys(resonants_1.RESONANT_DB).filter(id => {
        const def = resonants_1.RESONANT_DB[id];
        return zone.elementBias.includes(def.type);
    });
    const enemyDefId = eligibleIds[Math.floor(Math.random() * eligibleIds.length)];
    const level = zone.levelRange[0] + Math.floor(Math.random() * (zone.levelRange[1] - zone.levelRange[0]));
    battleState = {
        playerResonant: playerState.party[0],
        enemyResonant: (0, player_1.createResonant)(enemyDefId, level),
        turn: 'player', phase: 'select', log: ['A wild Resonant appears!'], isWild: true, zoneId, nodeId
    };
    renderBattle();
    setupBattleActions();
}
function startConductorBattle(nodeId) {
    const data = zones_1.CONDUCTOR_DATA[nodeId];
    if (!data)
        return;
    battleState = {
        playerResonant: playerState.party[0],
        enemyResonant: (0, player_1.createResonant)(data.resonantDefId, data.level),
        turn: 'player', phase: 'select', log: [data.dialog], isWild: false, zoneId: playerState.currentZone, nodeId
    };
    renderBattle();
    setupBattleActions();
}
function startBossBattle(nodeId) {
    const data = zones_1.BOSS_DATA[nodeId];
    if (!data)
        return;
    battleState = {
        playerResonant: playerState.party[0],
        enemyResonant: (0, player_1.createResonant)(data.defId, data.level),
        turn: 'player', phase: 'select', log: [data.dialog], isWild: false, zoneId: playerState.currentZone, nodeId
    };
    renderBattle();
    setupBattleActions();
}
// ===== BATTLE RENDERING =====
function renderBattle() {
    if (!battleState)
        return;
    showScreen('battle');
    const el = document.getElementById('screen-battle');
    const pr = battleState.playerResonant;
    const er = battleState.enemyResonant;
    const pDef = (0, resonants_1.getResonantDef)(pr.defId);
    const eDef = (0, resonants_1.getResonantDef)(er.defId);
    el.innerHTML = `
    <div style="width:100%;max-width:720px;height:100%;display:flex;flex-direction:column">
      <!-- Enemy area -->
      <div class="glass-card" style="padding:16px;margin-bottom:8px;display:flex;align-items:center;gap:16px;animation:slideInRight 0.4s ease" id="enemy-area">
        <div id="enemy-sprite">${(0, sprites_1.renderResonantSVG)(er.defId, 90)}</div>
        <div style="flex:1">
          <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:4px">
            <span style="font-weight:700;font-size:15px">${eDef.name}</span>
            <span class="type-badge el-${eDef.type.toLowerCase()}">${eDef.type}</span>
          </div>
          <div style="display:flex;align-items:center;gap:8px">
            <span style="font-size:11px;color:#94a3b8">Lv.${er.level}</span>
            <div class="hp-bar-bg" style="flex:1"><div class="hp-bar-fill" id="enemy-hp-bar" style="width:${(er.currentHp / er.maxHp) * 100}%;background:${combat.getHpColor(er.currentHp / er.maxHp)}"></div></div>
            <span style="font-size:11px;color:#94a3b8">${er.currentHp}/${er.maxHp}</span>
          </div>
          ${er.statusEffect ? `<span style="font-size:10px;color:#f87171;margin-top:2px">⚠ ${er.statusEffect}</span>` : ''}
        </div>
      </div>

      <!-- Battle log -->
      <div class="glass-card" style="padding:12px 16px;flex:0 0 auto;max-height:120px;overflow-y:auto;margin-bottom:8px;font-size:13px;color:#cbd5e1;line-height:1.6" id="battle-log">
        ${battleState.log.map(l => `<div>${l}</div>`).join('')}
      </div>

      <!-- Player area -->
      <div class="glass-card" style="padding:16px;margin-bottom:8px;display:flex;align-items:center;gap:16px;animation:slideInLeft 0.4s ease" id="player-area">
        <div id="player-sprite">${(0, sprites_1.renderResonantSVG)(pr.defId, 90)}</div>
        <div style="flex:1">
          <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:4px">
            <span style="font-weight:700;font-size:15px">${pDef.name}</span>
            <span class="type-badge el-${pDef.type.toLowerCase()}">${pDef.type}</span>
          </div>
          <div style="display:flex;align-items:center;gap:8px">
            <span style="font-size:11px;color:#94a3b8">Lv.${pr.level}</span>
            <div class="hp-bar-bg" style="flex:1"><div class="hp-bar-fill" id="player-hp-bar" style="width:${(pr.currentHp / pr.maxHp) * 100}%;background:${combat.getHpColor(pr.currentHp / pr.maxHp)}"></div></div>
            <span style="font-size:11px;color:#94a3b8">${pr.currentHp}/${pr.maxHp}</span>
          </div>
          ${pr.statusEffect ? `<span style="font-size:10px;color:#f87171;margin-top:2px">⚠ ${pr.statusEffect}</span>` : ''}
          <div class="xp-bar-bg"><div class="xp-bar-fill" style="width:${(pr.xp / pr.xpToNext) * 100}%"></div></div>
        </div>
      </div>

      <!-- Action buttons -->
      <div id="battle-actions" style="display:grid;grid-template-columns:repeat(4,1fr);gap:8px;flex-shrink:0">
        ${renderActionButtons()}
      </div>
    </div>`;
    // Scroll log to bottom
    const logEl = document.getElementById('battle-log');
    if (logEl)
        logEl.scrollTop = logEl.scrollHeight;
}
function renderActionButtons() {
    if (!battleState || battleState.phase !== 'select')
        return '';
    const pr = battleState.playerResonant;
    const pDef = (0, resonants_1.getResonantDef)(pr.defId);
    let html = `<button class="glass-btn" id="btn-attack">⚔️ Attack</button>`;
    if (battleState.isWild) {
        html += `<button class="glass-btn" id="btn-prism">💎 Prism</button>`;
    }
    else {
        html += `<div></div>`; // spacer
    }
    html += `<button class="glass-btn" id="btn-exchange">🔄 Exchange</button>`;
    html += `<button class="glass-btn" id="btn-items">🎒 Items</button>`;
    return html;
}
function addBattleLog(msg) {
    if (!battleState)
        return;
    battleState.log.push(msg);
    const logEl = document.getElementById('battle-log');
    if (logEl) {
        const div = document.createElement('div');
        div.textContent = msg;
        logEl.appendChild(div);
        logEl.scrollTop = logEl.scrollHeight;
    }
}
function updateHpBars() {
    if (!battleState)
        return;
    const prBar = document.getElementById('player-hp-bar');
    const erBar = document.getElementById('enemy-hp-bar');
    if (prBar) {
        prBar.style.width = `${(battleState.playerResonant.currentHp / battleState.playerResonant.maxHp) * 100}%`;
        prBar.style.background = combat.getHpColor(battleState.playerResonant.currentHp / battleState.playerResonant.maxHp);
    }
    if (erBar) {
        erBar.style.width = `${(battleState.enemyResonant.currentHp / battleState.enemyResonant.maxHp) * 100}%`;
        erBar.style.background = combat.getHpColor(battleState.enemyResonant.currentHp / battleState.enemyResonant.maxHp);
    }
}
function shakeElement(id) {
    const el = document.getElementById(id);
    if (el) {
        el.classList.add('shake');
        setTimeout(() => el.classList.remove('shake'), 400);
    }
}
function flashElement(id) {
    const el = document.getElementById(id);
    if (el) {
        el.classList.add('flash-hit');
        setTimeout(() => el.classList.remove('flash-hit'), 300);
    }
}
// ===== BATTLE ACTIONS =====
function setupBattleActions() {
    const btnAttack = document.getElementById('btn-attack');
    const btnPrism = document.getElementById('btn-prism');
    const btnExchange = document.getElementById('btn-exchange');
    const btnItems = document.getElementById('btn-items');
    if (btnAttack)
        btnAttack.addEventListener('click', () => showMoveSelect());
    if (btnPrism)
        btnPrism.addEventListener('click', () => attemptCapture());
    if (btnExchange)
        btnExchange.addEventListener('click', () => showExchangeMenu());
    if (btnItems)
        btnItems.addEventListener('click', () => showItemMenu());
}
function showMoveSelect() {
    if (!battleState || battleState.phase !== 'select')
        return;
    synth_1.synth.select();
    const pr = battleState.playerResonant;
    const actionsEl = document.getElementById('battle-actions');
    actionsEl.innerHTML = '';
    pr.capturedMoves.forEach((move, i) => {
        const btn = document.createElement('button');
        btn.className = 'glass-btn';
        btn.style.cssText = 'padding:10px;font-size:12px;text-align:left;display:flex;justify-content:space-between';
        const elColor = types_1.ELEMENT_COLORS[move.element] || '#8b5cf6';
        btn.innerHTML = `<span>${move.name}</span><span style="color:${elColor};font-size:10px">${move.element} Pwr:${move.power}</span>`;
        btn.addEventListener('click', () => executePlayerMove(i));
        actionsEl.appendChild(btn);
    });
    const backBtn = document.createElement('button');
    backBtn.className = 'glass-btn';
    backBtn.textContent = '← Back';
    backBtn.style.gridColumn = '1 / -1';
    backBtn.addEventListener('click', () => renderBattle());
    actionsEl.appendChild(backBtn);
}
function executePlayerMove(moveIdx) {
    if (!battleState || battleState.phase !== 'select')
        return;
    const bs = battleState;
    const move = bs.playerResonant.capturedMoves[moveIdx];
    if (!move)
        return;
    bs.phase = 'animating';
    // Process status effects on player resonant first
    const pStatusMsg = combat.processStatusEffects(bs.playerResonant);
    if (pStatusMsg)
        addBattleLog(pStatusMsg);
    // Check accuracy
    if (Math.random() * 100 >= move.accuracy) {
        addBattleLog(`${bs.playerResonant.defId} uses ${move.name}... but it missed!`);
        setTimeout(() => enemyTurn(), 800);
        return;
    }
    const result = combat.calcDamage(bs.playerResonant, bs.enemyResonant, move.power);
    combat.applyDamage(bs.enemyResonant, result.damage);
    updateHpBars();
    let msg = `${bs.playerResonant.defId} uses ${move.name}!`;
    if (result.isCrit) {
        msg += ' Critical hit!';
        synth_1.synth.hitElemental();
    }
    else if (result.typeMod > 1) {
        msg += ' Super effective!';
        synth_1.synth.superEffective();
    }
    else if (result.typeMod < 1) {
        msg += ' Not very effective...';
        synth_1.synth.hitPhysical();
    }
    else
        synth_1.synth.hitPhysical();
    addBattleLog(msg);
    flashElement('enemy-area');
    shakeElement('enemy-sprite');
    // Random status effect chance for elemental moves
    if (move.element !== 'Cosmos' && Math.random() < 0.12) {
        const effects = ['Burn', 'Paralyze', 'Poison'];
        combat.applyStatusEffect(bs.enemyResonant, effects[Math.floor(Math.random() * effects.length)]);
        addBattleLog(`${bs.enemyResonant.defId} is afflicted!`);
    }
    if (combat.isFainted(bs.enemyResonant)) {
        setTimeout(() => handleEnemyDefeat(), 600);
    }
    else {
        setTimeout(() => enemyTurn(), 1000);
    }
}
function enemyTurn() {
    if (!battleState)
        return;
    const bs = battleState;
    bs.phase = 'animating';
    // Process status effects on enemy
    const eStatusMsg = combat.processStatusEffects(bs.enemyResonant);
    if (eStatusMsg)
        addBattleLog(eStatusMsg);
    if (combat.isFainted(bs.enemyResonant)) {
        handleEnemyDefeat();
        return;
    }
    // Sleep check - enemy skips turn
    if (bs.enemyResonant.statusEffect === 'Sleep') {
        addBattleLog(`${bs.enemyResonant.defId} is asleep!`);
        bs.phase = 'select';
        bs.turn = 'player';
        renderBattle();
        setupBattleActions();
        return;
    }
    const moveIdx = combat.selectEnemyMove(bs.enemyResonant);
    const eDef = (0, resonants_1.getResonantDef)(bs.enemyResonant.defId);
    const move = eDef.moves[moveIdx];
    if (!move) {
        bs.phase = 'select';
        return;
    }
    // Check accuracy
    if (Math.random() * 100 >= move.accuracy) {
        addBattleLog(`${bs.enemyResonant.defId} uses ${move.name}... but it missed!`);
        setTimeout(() => { battleState.phase = 'select'; renderBattle(); setupBattleActions(); }, 800);
        return;
    }
    const result = combat.calcDamage(bs.enemyResonant, bs.playerResonant, move.power);
    combat.applyDamage(bs.playerResonant, result.damage);
    updateHpBars();
    let msg = `${bs.enemyResonant.defId} uses ${move.name}!`;
    if (result.isCrit) {
        msg += ' Critical hit!';
        synth_1.synth.hitElemental();
    }
    else if (result.typeMod > 1) {
        msg += ' Super effective!';
        synth_1.synth.superEffective();
    }
    else
        synth_1.synth.hitPhysical();
    addBattleLog(msg);
    flashElement('player-area');
    shakeElement('player-sprite');
    // Random status effect on player
    if (move.element !== 'Cosmos' && Math.random() < 0.1) {
        const effects = ['Burn', 'Paralyze', 'Poison'];
        combat.applyStatusEffect(bs.playerResonant, effects[Math.floor(Math.random() * effects.length)]);
        addBattleLog(`${bs.playerResonant.defId} is afflicted!`);
    }
    if (combat.isFainted(bs.playerResonant)) {
        setTimeout(() => handlePlayerDefeat(), 600);
    }
    else {
        setTimeout(() => { battleState.phase = 'select'; renderBattle(); setupBattleActions(); }, 800);
    }
}
function attemptCapture() {
    if (!battleState || !battleState.isWild)
        return;
    const bs = battleState;
    synth_1.synth.select();
    const prismTier = (0, player_1.hasItem)(playerState, 'prism_hyper', 1) && Math.random() > 0.5 ? 'hyper' : 'basic';
    const itemId = prismTier === 'hyper' ? 'prism_hyper' : 'prism_basic';
    if (!(0, player_1.removeItem)(playerState, itemId, 1)) {
        addBattleLog('No prisms available!');
        return;
    }
    bs.phase = 'animating';
    const rate = combat.calcCaptureRate(bs.enemyResonant, prismTier);
    const enemyDefId = bs.enemyResonant.defId;
    const nodeId = bs.nodeId;
    const zoneId = bs.zoneId;
    addBattleLog(`Throwing ${prismTier === 'hyper' ? 'Hyper-Conductive' : 'Harmonizer'} Prism...`);
    setTimeout(() => {
        if (Math.random() < rate) {
            // Capture success!
            synth_1.synth.capture();
            const captured = bs.enemyResonant;
            playerState.party.push(captured);
            if (!playerState.dexEntries.includes(captured.defId))
                playerState.dexEntries.push(captured.defId);
            playerState.totalCaptures++;
            addBattleLog(`${(0, resonants_1.getResonantDef)(captured.defId).name} was captured!`);
            showToast(`Captured ${(0, resonants_1.getResonantDef)(captured.defId).name}!`, 2500);
            if (nodeId) {
                const zone = zones_1.ZONES[zoneId];
                const node = zone?.nodes.find(n => n.id === nodeId);
                if (node)
                    node.completed = true;
            }
            (0, player_1.saveState)(playerState);
            setTimeout(() => { battleState = null; renderMap(); }, 1500);
        }
        else {
            addBattleLog(`${(0, resonants_1.getResonantDef)(enemyDefId).name} broke free!`);
            bs.phase = 'select';
            setTimeout(() => enemyTurn(), 600);
        }
    }, 1200);
}
function showExchangeMenu() {
    if (!battleState || playerState.party.length < 2)
        return;
    const bs = battleState;
    synth_1.synth.select();
    const actionsEl = document.getElementById('battle-actions');
    actionsEl.innerHTML = '';
    playerState.party.forEach((r, i) => {
        const def = (0, resonants_1.getResonantDef)(r.defId);
        const btn = document.createElement('button');
        btn.className = 'glass-btn';
        btn.style.cssText = 'padding:10px;font-size:12px;text-align:left;display:flex;justify-content:space-between';
        btn.innerHTML = `<span>${def.name} Lv.${r.level}</span><span style="color:${combat.getHpColor(r.currentHp / r.maxHp)}">HP ${r.currentHp}/${r.maxHp}</span>`;
        if (i === 0) {
            btn.style.opacity = '0.5';
            return;
        } // active resonant
        btn.addEventListener('click', () => {
            synth_1.synth.select();
            playerState.party[0] = r;
            battleState.playerResonant = r;
            addBattleLog(`Switched to ${def.name}!`);
            renderBattle();
            setupBattleActions();
        });
        actionsEl.appendChild(btn);
    });
    const backBtn = document.createElement('button');
    backBtn.className = 'glass-btn';
    backBtn.textContent = '← Back';
    backBtn.style.gridColumn = '1 / -1';
    backBtn.addEventListener('click', () => renderBattle());
    actionsEl.appendChild(backBtn);
}
function showItemMenu() {
    synth_1.synth.select();
    const actionsEl = document.getElementById('battle-actions');
    actionsEl.innerHTML = '';
    playerState.inventory.forEach(item => {
        if (item.count <= 0)
            return;
        const shopItem = zones_1.SHOP_ITEMS.find(s => s.id === item.itemId);
        if (!shopItem)
            return;
        const btn = document.createElement('button');
        btn.className = 'glass-btn';
        btn.style.cssText = 'padding:10px;font-size:12px;text-align:left;display:flex;justify-content:space-between';
        btn.innerHTML = `<span>${shopItem.icon} ${shopItem.name}</span><span style="color:#94a3b8">×${item.count}</span>`;
        const itemId = item.itemId;
        btn.addEventListener('click', () => useBattleItem(itemId));
        actionsEl.appendChild(btn);
    });
    const backBtn = document.createElement('button');
    backBtn.className = 'glass-btn';
    backBtn.textContent = '← Back';
    backBtn.style.gridColumn = '1 / -1';
    backBtn.addEventListener('click', () => renderBattle());
    actionsEl.appendChild(backBtn);
}
function useBattleItem(itemId) {
    if (!battleState)
        return;
    synth_1.synth.select();
    switch (itemId) {
        case 'elixir_hp':
            if (!(0, player_1.removeItem)(playerState, itemId, 1))
                return;
            const healAmt = Math.floor(battleState.playerResonant.maxHp * 0.5);
            combat.healResonant(battleState.playerResonant, healAmt);
            addBattleLog(`Used Core Restorer! Healed ${healAmt} HP.`);
            synth_1.synth.heal();
            updateHpBars();
            setTimeout(() => enemyTurn(), 600);
            break;
        case 'elixir_status':
            if (!(0, player_1.removeItem)(playerState, itemId, 1))
                return;
            battleState.playerResonant.statusEffect = null;
            addBattleLog('Used Resonance Elixir! Status cleared.');
            synth_1.synth.heal();
            setTimeout(() => enemyTurn(), 600);
            break;
        default:
            addBattleLog("Can't use that in battle.");
            renderBattle();
            setupBattleActions();
    }
}
function handleEnemyDefeat() {
    if (!battleState)
        return;
    const bs = battleState; // capture reference
    synth_1.synth.defeat();
    const xp = combat.xpForDefeat(bs.enemyResonant.level);
    const shardsReward = Math.floor(5 + bs.enemyResonant.level * 3);
    addBattleLog(`${(0, resonants_1.getResonantDef)(bs.enemyResonant.defId).name} fainted!`);
    addBattleLog(`Gained ${xp} XP and ${shardsReward} Aether Shards.`);
    playerState.shards += shardsReward;
    playerState.totalBattles++;
    const leveled = (0, player_1.gainXp)(bs.playerResonant, xp);
    if (leveled) {
        synth_1.synth.levelUp();
        addBattleLog(`${bs.playerResonant.defId} reached Level ${bs.playerResonant.level}!`);
        showToast(`Level Up! Lv.${bs.playerResonant.level}`, 2000);
        // Check evolution
        if ((0, player_1.shouldEvolve)(bs.playerResonant)) {
            const oldName = bs.playerResonant.defId;
            (0, player_1.evolveResonant)(bs.playerResonant);
            synth_1.synth.evolve();
            addBattleLog(`${oldName} evolved into ${bs.playerResonant.defId}!`);
            showToast(`Evolved to ${(0, resonants_1.getResonantDef)(bs.playerResonant.defId).name}!`, 2500);
            playerState.dexEntries.push(bs.playerResonant.defId);
            const spriteEl = document.getElementById('player-sprite');
            if (spriteEl) {
                spriteEl.classList.add('evolve-flash');
                setTimeout(() => spriteEl.classList.remove('evolve-flash'), 1200);
            }
        }
    }
    // Mark node complete and unlock next zone nodes if boss defeated
    const nodeId = bs.nodeId;
    const zoneId = bs.zoneId;
    let gameComplete = false;
    if (nodeId) {
        const zone = zones_1.ZONES[zoneId];
        const node = zone?.nodes.find(n => n.id === nodeId);
        if (node) {
            node.completed = true;
            // If boss, unlock next zone
            if (node.type === 'boss') {
                playerState.completedBosses.push(node.id);
                const zoneOrder = ['verdant_canopy', 'sunken_grotto', 'obsidian_crags', 'apex_pillar'];
                const idx = zoneOrder.indexOf(zoneId);
                if (idx < zoneOrder.length - 1) {
                    const nextZoneId = zoneOrder[idx + 1];
                    if (!playerState.unlockedZones.includes(nextZoneId)) {
                        playerState.unlockedZones.push(nextZoneId);
                        zones_1.ZONES[nextZoneId].nodes.forEach(n => n.unlocked = true);
                        addBattleLog(`🎉 ${zones_1.ZONES[nextZoneId].name} unlocked!`);
                    }
                }
            }
            // Check if final boss defeated
            if (node.id === 'ap_final') {
                gameComplete = true;
            }
        }
    }
    (0, player_1.saveState)(playerState);
    setTimeout(() => {
        battleState = null;
        if (gameComplete) {
            showVictoryScreen();
        }
        else {
            renderMap();
        }
    }, 1500);
}
function handlePlayerDefeat() {
    if (!battleState)
        return;
    const bs = battleState;
    synth_1.synth.defeat();
    addBattleLog(`${bs.playerResonant.defId} fainted...`);
    // Heal to half HP and continue
    setTimeout(() => {
        bs.playerResonant.currentHp = Math.floor(bs.playerResonant.maxHp * 0.3);
        bs.playerResonant.statusEffect = null;
        addBattleLog('Your Resonant was revived at camp.');
        showToast('Defeated... but you recover.', 2000);
        (0, player_1.saveState)(playerState);
        setTimeout(() => { battleState = null; renderMap(); }, 1500);
    }, 1500);
}
// ===== SHOP =====
function renderShop() {
    showScreen('shop');
    const el = document.getElementById('screen-shop');
    el.innerHTML = `
    <div class="glass-card" style="padding:32px;max-width:500px;width:90%;animation:bounceIn 0.4s ease">
      <h2 class="retro-title" style="font-size:16px;color:#c084fc;margin-bottom:20px;text-align:center">🏪 Camp Shop</h2>
      <p style="text-align:center;font-size:13px;color:#94a3b8;margin-bottom:20px">💎 ${playerState.shards} Aether Shards</p>
      <div id="shop-items" style="display:flex;flex-direction:column;gap:10px"></div>
      <button class="glass-btn" id="btn-shop-back" style="margin-top:20px;width:100%">← Back to Map</button>
    </div>`;
    const container = document.getElementById('shop-items');
    zones_1.SHOP_ITEMS.forEach(item => {
        const owned = playerState.inventory.find(i => i.itemId === item.id)?.count || 0;
        const card = document.createElement('div');
        card.className = 'glass-card';
        card.style.cssText = 'padding:14px;display:flex;justify-content:space-between;align-items:center';
        card.innerHTML = `
      <div>
        <span style="font-size:20px">${item.icon}</span>
        <strong style="margin-left:8px;font-size:13px">${item.name}</strong>
        <p style="font-size:11px;color:#94a3b8;margin-top:2px">${item.description}</p>
        ${owned > 0 ? `<span style="font-size:10px;color:#6ee7b7">Owned: ${owned}</span>` : ''}
      </div>
      <button class="glass-btn success" data-item="${item.id}" style="padding:6px 14px;font-size:12px;white-space:nowrap">${item.cost} 💎</button>`;
        container.appendChild(card);
        const buyBtn = card.querySelector('button[data-item]');
        if (buyBtn) {
            buyBtn.addEventListener('click', () => {
                if (playerState.shards < item.cost) {
                    showToast('Not enough shards!');
                    return;
                }
                synth_1.synth.select();
                playerState.shards -= item.cost;
                (0, player_1.addItem)(playerState, item.id, 1);
                (0, player_1.saveState)(playerState);
                showToast(`Bought ${item.name}!`);
                renderShop();
            });
        }
    });
    document.getElementById('btn-shop-back').addEventListener('click', () => { synth_1.synth.select(); renderMap(); });
}
// ===== DEX =====
function renderDex() {
    showScreen('dex');
    const el = document.getElementById('screen-dex');
    const entries = Object.values(resonants_1.RESONANT_DB);
    let html = `
    <div style="width:100%;max-width:700px;height:100%;display:flex;flex-direction:column">
      <div class="glass-card" style="padding:16px 24px;margin-bottom:12px;display:flex;justify-content:space-between;align-items:center;flex-shrink:0">
        <h2 class="retro-title" style="font-size:14px;color:#c084fc">📖 Resonant Dex</h2>
        <span style="font-size:12px;color:#94a3b8">${playerState.dexEntries.length}/18 discovered</span>
      </div>
      <div class="glass-card" style="flex:1;overflow-y:auto;padding:16px;display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px;align-content:start">`;
    entries.forEach(def => {
        const discovered = playerState.dexEntries.includes(def.id);
        html += `
        <div class="glass-card" style="padding:14px;text-align:center;opacity:${discovered ? '1' : '0.35'}">
          ${discovered ? `<div style="margin-bottom:8px">${(0, sprites_1.renderResonantSVG)(def.id, 60)}</div>` : '<div style="width:60px;height:60px;margin:0 auto 8px;border-radius:50%;background:#1e293b;display:flex;align-items:center;justify-content:center;font-size:24px">?</div>'}
          <p style="font-weight:700;font-size:13px">${discovered ? def.name : '???'}</p>
          ${discovered ? `<span class="type-badge el-${def.type.toLowerCase()}" style="margin-top:4px">${def.type}</span>` : ''}
        </div>`;
    });
    html += `</div>
      <button class="glass-btn" id="btn-dex-back" style="margin-top:12px;width:100%;flex-shrink:0">← Back to Map</button>
    </div>`;
    el.innerHTML = html;
    document.getElementById('btn-dex-back').addEventListener('click', () => { synth_1.synth.select(); renderMap(); });
}
// ===== PARTY SCREEN =====
function renderPartyScreen() {
    showScreen('dialog');
    const el = document.getElementById('screen-dialog');
    let html = `
    <div class="glass-card" style="padding:32px;max-width:500px;width:90%;animation:bounceIn 0.4s ease">
      <h2 class="retro-title" style="font-size:16px;color:#c084fc;margin-bottom:20px;text-align:center">👥 Your Party</h2>
      <div id="party-list" style="display:flex;flex-direction:column;gap:10px"></div>
      <button class="glass-btn" id="btn-party-back" style="margin-top:20px;width:100%">← Back to Map</button>
    </div>`;
    el.innerHTML = html;
    const listEl = document.getElementById('party-list');
    playerState.party.forEach((r, i) => {
        const def = (0, resonants_1.getResonantDef)(r.defId);
        const card = document.createElement('div');
        card.className = 'glass-card';
        card.style.cssText = 'padding:14px;display:flex;align-items:center;gap:12px';
        card.innerHTML = `
      <div style="flex-shrink:0">${(0, sprites_1.renderResonantSVG)(r.defId, 50)}</div>
      <div style="flex:1">
        <p style="font-weight:700;font-size:13px">${def.name} <span class="type-badge el-${def.type.toLowerCase()}" style="font-size:9px;padding:1px 6px">Lv.${r.level}</span></p>
        <div class="hp-bar-bg" style="margin-top:4px"><div class="hp-bar-fill" style="width:${(r.currentHp / r.maxHp) * 100}%;background:${combat.getHpColor(r.currentHp / r.maxHp)}"></div></div>
        <p style="font-size:10px;color:#94a3b8;margin-top:2px">HP ${r.currentHp}/${r.maxHp} | ATK ${r.atk} | DEF ${r.def} | SPD ${r.spd}</p>
      </div>`;
        listEl.appendChild(card);
    });
    document.getElementById('btn-party-back').addEventListener('click', () => { synth_1.synth.select(); renderMap(); });
}
// ===== ZONE SELECT (when multiple zones unlocked) =====
function showZoneSelect() {
    showScreen('dialog');
    const el = document.getElementById('screen-dialog');
    let html = `
    <div class="glass-card" style="padding:36px 48px;text-align:center;max-width:500px;width:90%;animation:bounceIn 0.4s ease">
      <h2 class="retro-title" style="font-size:16px;color:#c084fc;margin-bottom:24px">🗺️ Select Zone</h2>
      <div id="zone-list" style="display:flex;flex-direction:column;gap:10px"></div>
      <button class="glass-btn" id="btn-zone-back" style="margin-top:20px;width:100%">← Back to Map</button>
    </div>`;
    el.innerHTML = html;
    const listEl = document.getElementById('zone-list');
    playerState.unlockedZones.forEach(zoneId => {
        const zone = zones_1.ZONES[zoneId];
        if (!zone)
            return;
        const btn = document.createElement('button');
        btn.className = 'glass-btn';
        btn.style.width = '100%';
        const isCurrent = playerState.currentZone === zoneId;
        btn.innerHTML = `<span style="color:${zone.color}">●</span> ${zone.name}${isCurrent ? ' (current)' : ''}`;
        if (isCurrent)
            btn.style.opacity = '0.6';
        btn.addEventListener('click', () => {
            synth_1.synth.select();
            playerState.currentZone = zoneId;
            (0, player_1.saveState)(playerState);
            renderMap();
        });
        listEl.appendChild(btn);
    });
    document.getElementById('btn-zone-back').addEventListener('click', () => { synth_1.synth.select(); renderMap(); });
}
// ===== VICTORY SCREEN =====
function showVictoryScreen() {
    showScreen('dialog');
    const el = document.getElementById('screen-dialog');
    el.innerHTML = `
    <div class="victory-overlay">
      <div class="victory-card glass-card">
        <h1 class="retro-title" style="font-size:20px;color:#c084fc;margin-bottom:16px;text-shadow:0 0 30px rgba(192,132,252,0.6)">🏆 VICTORY 🏆</h1>
        <p style="font-size:14px;color:#e2e8f0;margin-bottom:8px">You have conquered all of Aethelgard!</p>
        <p style="font-size:13px;color:#94a3b8;margin-bottom:24px">The Cosmos Sovereign has been harmonized. Peace returns to the land.</p>
        <div style="display:flex;flex-direction:column;gap:6px;font-size:12px;color:#cbd5e1;margin-bottom:24px;text-align:left;padding:0 20px">
          <p>Total Battles: ${playerState.totalBattles}</p>
          <p>Resonants Captured: ${playerState.totalCaptures + playerState.dexEntries.length}</p>
          <p>Dex Completion: ${playerState.dexEntries.length}/18</p>
          <p>Aether Shards Earned: ${playerState.shards}</p>
        </div>
        <button class="glass-btn success" id="btn-victory-menu" style="width:200px;margin:0 auto">Return to Menu</button>
      </div>
    </div>`;
    document.getElementById('btn-victory-menu').addEventListener('click', () => { synth_1.synth.select(); renderMainMenu(); });
}
// ===== GAME INIT =====
function init() {
    const saved = localStorage.getItem('aethelgard_save_v1');
    if (saved) {
        renderMainMenu();
    }
    else {
        renderMainMenu();
    }
}
};

// ── entry ──
__require("src/main.ts");
})();
</script>
</body>
</html>
<!-- agent-meta {"model":"thinkingcap-qwen3.6-27b","provider":"lmstudio","persona":"typescript","sessionId":"a6badb3d-1198-4f83-bbd0-47249d6b2fe5","tokensIn":4787878,"tokensOut":49466,"tokensTotal":4837344,"turns":87,"toolCalls":86,"failedToolCalls":0,"timestamp":"2026-07-31T06:39:58.537Z"} -->