← Aethelgard results

Aethelgard

inkling · composer

Initial view of Aethelgard

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 34,498 bytes · SHA-256 c6b2dc6d5010
<!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>
<script src="https://cdn.tailwindcss.com/"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;800&amp;family=Orbitron:wght@700;900&amp;display=swap">
<style>
/* ── css: theme ── */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;800&family=Orbitron:wght@700;900&display=swap');

:root {
  --bg-deep: #0a0912;
  --bg-card: rgba(255, 255, 255, 0.04);
  --glass-border: rgba(255, 255, 255, 0.08);
  --text-primary: #f0ecf5;
  --text-dim: #a09aa8;
  --accent-violet: #7c3aed;
  --accent-cyan: #22d3ee;
  --accent-amber: #f59e0b;
  --pyro: #ff502f;
  --hydro: #3b82f6;
  --flora: #22c55e;
  --zephyr: #a855f7;
  --earth: #8b6914;
  --volt: #facc15;
  --cosmos: #c0c0ff;
}

* { box-sizing: border-box; }

body {
  margin: 0; padding: 0;
  background: linear-gradient(135deg, #0a0912 0%, #140b1e 50%, #0f1220 100%);
  color: var(--text-primary);
  font-family: 'Inter', sans-serif;
  min-height: 100vh;
  overflow-x: hidden;
  background-attachment: fixed;
}

.glass {
  background: var(--bg-card);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  border: 1px solid var(--glass-border);
  border-radius: 1.25rem;
  box-shadow: 0 8px 32px rgba(0,0,0,0.35), inset 0 1px 0 rgba(255,255,255,0.05);
}

.glass-card {
  background: linear-gradient(145deg, rgba(255,255,255,0.03) 0%, rgba(255,255,255,0.01) 100%);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 1rem;
  backdrop-filter: blur(16px);
  box-shadow: 0 8px 32px rgba(0,0,0,0.25);
}

.neon-border-pyro { box-shadow: 0 0 12px rgba(255,80,47,0.4), 0 0 24px rgba(255,80,47,0.15); border-color: rgba(255,80,47,0.35); }
.neon-border-hydro { box-shadow: 0 0 12px rgba(59,130,246,0.4), 0 0 24px rgba(59,130,246,0.15); border-color: rgba(59,130,246,0.35); }
.neon-border-flora { box-shadow: 0 0 12px rgba(34,197,94,0.4), 0 0 24px rgba(34,197,94,0.15); border-color: rgba(34,197,94,0.35); }
.neon-border-zephyr { box-shadow: 0 0 12px rgba(168,85,247,0.4), 0 0 24px rgba(168,85,247,0.15); border-color: rgba(168,85,247,0.35); }
.neon-border-earth { box-shadow: 0 0 12px rgba(139,105,20,0.4), 0 0 24px rgba(139,105,20,0.15); border-color: rgba(139,105,20,0.35); }
.neon-border-volt { box-shadow: 0 0 12px rgba(250,204,21,0.4), 0 0 24px rgba(250,204,21,0.15); border-color: rgba(250,204,21,0.35); }
.neon-border-cosmos { box-shadow: 0 0 12px rgba(192,192,255,0.45), 0 0 24px rgba(192,192,255,0.15); border-color: rgba(192,192,255,0.35); }

.screen-enter { animation: fadeSlideIn 0.45s ease-out both; }
.screen-exit { animation: fadeSlideOut 0.35s ease-in both; }

@keyframes fadeSlideIn {
  from { opacity: 0; transform: translateY(18px) scale(0.985); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes fadeSlideOut {
  from { opacity: 1; transform: translateY(0); }
  to { opacity: 0; transform: translateY(-12px); }
}

.shake { animation: shake 0.35s ease; }
@keyframes shake {
  0%,100%{transform:translateX(0)} 10%{transform:translateX(-6px)} 30%{transform:translateX(5px)} 50%{transform:translateX(-4px)} 70%{transform:translateX(3px)} 90%{transform:translateX(-2px)}
}

.flash { animation: flash 0.25s ease; }
@keyframes flash {
  0%{filter:brightness(1)} 40%{filter:brightness(2.5)} 100%{filter:brightness(1)}
}

.bounce { animation: bounce 1.6s ease-in-out infinite; }
@keyframes bounce {
  0%,100%{transform:translateY(0)} 45%{transform:translateY(-6px)}
}

.particle-drift {
  position: absolute; width: 8px; height: 8px; border-radius: 50%; opacity: 0.6;
  animation: drift 3s linear infinite;
}
@keyframes drift {
  0%{transform:translateY(0) translateX(0); opacity:0.6} 100%{transform:translateY(-60px) translateX(20px); opacity:0}
}

.hp-bar-fill { transition: width 0.4s ease, background-color 0.3s ease; }

.gradient-text {
  background: linear-gradient(135deg, #f0ecf5 20%, #7c3aed 80%);
  -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
}

.btn-glass {
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 0.75rem;
  padding: 0.65rem 1.25rem;
  color: var(--text-primary);
  font-family: 'Inter', sans-serif;
  font-weight: 600;
  font-size: 0.9rem;
  cursor: pointer;
  transition: all 0.2s ease;
  backdrop-filter: blur(6px);
}
.btn-glass:hover { background: rgba(255,255,255,0.1); border-color: rgba(255,255,255,0.25); transform: translateY(-1px); }
.btn-glass:active { transform: translateY(0); }

.node-trail { display: flex; flex-wrap: wrap; gap: 0.75rem; justify-content: center; }
.node-trail .node-btn {
  width: 80px; height: 80px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.75rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em;
  border: 2px solid rgba(255,255,255,0.1); background: rgba(255,255,255,0.03);
  transition: all 0.25s ease; cursor: pointer; color: var(--text-primary);
}
.node-trail .node-btn:hover { transform: scale(1.08); border-color: rgba(255,255,255,0.3); box-shadow: 0 0 18px rgba(255,255,255,0.08); }
.node-btn.encounter { border-color: rgba(34,197,94,0.45); box-shadow: 0 0 10px rgba(34,197,94,0.15); }
.node-btn.mystery { border-color: rgba(250,204,21,0.45); box-shadow: 0 0 10px rgba(250,204,21,0.15); }
.node-btn.battle { border-color: rgba(255,80,47,0.45); box-shadow: 0 0 10px rgba(255,80,47,0.15); }
.node-btn.heal { border-color: rgba(59,130,246,0.45); box-shadow: 0 0 10px rgba(59,130,246,0.15); }
.node-btn.boss { border-color: rgba(168,85,247,0.55); box-shadow: 0 0 18px rgba(168,85,247,0.3); animation: pulse-boss 2s infinite; }
@keyframes pulse-boss { 0%,100%{box-shadow:0 0 18px rgba(168,85,247,0.3)} 50%{box-shadow:0 0 28px rgba(168,85,247,0.5)} }
</style>
</head>
<body>
<div id="app" class="min-h-screen w-full relative">

  <!-- Main Menu -->
  <section id="screen-menu" class="screen-enter absolute inset-0 flex flex-col items-center justify-center z-50">
    <div class="text-center mb-10">
      <h1 class="font-['Orbitron'] text-6xl md:text-8xl font-black tracking-tighter mb-2 gradient-text drop-shadow-2xl">AETHELGARD</h1>
      <p class="text-xl md:text-2xl text-violet-300 tracking-[0.2em] uppercase font-light">Resonant Chronicles</p>
      <div class="w-32 h-1 mx-auto mt-6 rounded-full bg-gradient-to-r from-transparent via-violet-500 to-transparent opacity-60"></div>
    </div>
    <div class="glass p-8 md:p-10 max-w-md w-full text-center space-y-4 relative overflow-hidden">
      <div class="absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-violet-500 via-cyan-400 to-amber-400"></div>
      <h2 class="text-2xl font-bold mb-2">Welcome, Conductor</h2>
      <p class="text-sm text-[var(--text-dim)] mb-6">The harmonic frequencies of Aethelgard await. Capture the 18 Resonants. Master the 4 zones.</p>
      <button onclick="startGame()" class="btn-glass w-full text-base py-3 rounded-xl bg-gradient-to-r from-violet-700/40 to-cyan-700/30 border-violet-500/30 hover:scale-[1.02]">Begin Journey</button>
      <div class="flex gap-3 justify-center mt-2">
        <button onclick="loadSave()" class="btn-glass text-sm py-2 px-4">Continue Save</button>
      </div>
      <p class="text-xs text-[var(--text-dim)] mt-4">Progress saved automatically to local storage</p>
    </div>
  </section>

  <!-- Overworld / Zone Map -->
  <section id="screen-world" class="hidden absolute inset-0 flex flex-col z-40 p-4 md:p-8">
    <header class="flex items-center justify-between mb-6">
      <div>
        <h2 class="font-['Orbitron'] text-3xl font-black tracking-tight">Aethelgard</h2>
        <p id="zone-name" class="text-sm text-violet-300 font-medium">Zone: Verdant Canopy</p>
      </div>
      <div class="flex gap-3 items-center">
        <div class="glass px-4 py-2 text-xs flex items-center gap-2">
          <span class="w-2 h-2 rounded-full bg-amber-400 animate-pulse"></span>
          <span><strong id="shard-display">0</strong> Aether Shards</span>
        </div>
        <button onclick="openDex()" class="btn-glass">Dex</button>
        <button onclick="openShop()" class="btn-glass">Camp</button>
        <button onclick="openMenuBack()" class="btn-glass text-xs">Menu</button>
      </div>
    </header>

    <main class="flex-1 flex flex-col items-center justify-center">
      <div class="glass-card p-8 md:p-10 max-w-3xl w-full">
        <h3 class="text-xl font-bold mb-6 text-center">Zone Node Trail</h3>
        <p id="zone-desc" class="text-sm text-[var(--text-dim)] text-center mb-6 max-w-lg mx-auto">Navigate through the harmonic nodes. Defeat the Gatekeeper to unlock the next zone.</p>
        <div id="node-map" class="node-trail"></div>
      </div>
    </main>
  </section>

  <!-- Battle Screen -->
  <section id="screen-battle" class="hidden absolute inset-0 z-50 bg-gradient-to-b from-[#0a0912] via-[#140b1e] to-[#080614] overflow-hidden">
    <div class="absolute inset-0 z-0" id="battle-bg"></div>
    <div class="relative z-10 p-4 md:p-6 h-full flex flex-col">
      <div class="flex justify-between items-start mb-4">
        <h3 class="font-['Orbitron'] text-xl font-black">Resonance Duel</h3>
        <button onclick="fleeBattle()" class="btn-glass text-xs">Flee</button>
      </div>

      <div class="flex-1 flex flex-col md:flex-row gap-4 md:gap-8 items-start justify-center">
        <!-- Player Resonant -->
        <div class="glass-card w-full md:w-80 p-5 relative">
          <div class="flex items-center gap-3 mb-3">
            <div id="player-sprite" class="w-16 h-16 rounded-xl overflow-hidden flex items-center justify-center bg-gradient-to-br from-violet-900/40 to-violet-600/30"></div>
            <div>
              <h4 id="player-name" class="font-bold text-lg">Conductor</h4>
              <span id="player-type" class="text-xs px-2 py-0.5 rounded-full bg-violet-500/20 text-violet-300">Cosmos</span>
            </div>
          </div>
          <div class="mb-1 flex justify-between text-xs"><span>HP</span><span id="player-hp-text">100/100</span></div>
          <div class="h-4 w-full rounded-full bg-black/30 overflow-hidden mb-3">
            <div id="player-hp-bar" class="hp-bar-fill h-full w-full rounded-full bg-gradient-to-r from-emerald-400 to-emerald-600"></div>
          </div>
          <div class="flex justify-between text-xs text-[var(--text-dim)]"><span>Lv. <span id="player-level">1</span></span><span>XP <span id="player-xp">0</span>/<span id="player-xp-next">100</span></span></div>
          <div id="player-status" class="mt-2 text-xs h-4"></div>
        </div>

        <!-- Enemy -->
        <div class="glass-card w-full md:w-80 p-5 relative">
          <div class="flex items-center gap-3 mb-3">
            <div id="enemy-sprite" class="w-16 h-16 rounded-xl overflow-hidden flex items-center justify-center bg-gradient-to-br from-red-900/40 to-red-600/30"></div>
            <div>
              <h4 id="enemy-name" class="font-bold text-lg">Wild Resonant</h4>
              <span id="enemy-type" class="text-xs px-2 py-0.5 rounded-full bg-red-500/20 text-red-300">Pyro</span>
            </div>
          </div>
          <div class="mb-1 flex justify-between text-xs"><span>HP</span><span id="enemy-hp-text">100/100</span></div>
          <div class="h-4 w-full rounded-full bg-black/30 overflow-hidden mb-3">
            <div id="enemy-hp-bar" class="hp-bar-fill h-full w-full rounded-full bg-gradient-to-r from-rose-400 to-rose-600"></div>
          </div>
          <div class="flex justify-between text-xs text-[var(--text-dim)]"><span>Lv. <span id="enemy-level">1</span></span></div>
          <div id="enemy-status" class="mt-2 text-xs h-4"></div>
        </div>
      </div>

      <div class="glass mt-4 p-3 h-24 overflow-y-auto text-sm" id="battle-log"><div class="text-[var(--text-dim)]">The battle begins...</div></div>

      <div id="battle-actions" class="grid grid-cols-2 md:grid-cols-4 gap-2 mt-4">
        <button onclick="battleAttack()" class="btn-glass text-sm">Attack</button>
        <button onclick="battlePrism()" class="btn-glass text-sm">Aether Prism</button>
        <button onclick="battleSwapUI()" class="btn-glass text-sm">Exchange</button>
        <button onclick="battleItemUI()" class="btn-glass text-sm">Item</button>
      </div>
    </div>
  </section>

  <!-- Dex / Encyclopedia -->
  <section id="screen-dex" class="hidden absolute inset-0 z-40 p-4 md:p-8 overflow-y-auto">
    <div class="max-w-5xl mx-auto">
      <div class="flex justify-between items-center mb-6">
        <h2 class="font-['Orbitron'] text-3xl font-black">Conductors Dex</h2>
        <button onclick="closeDex()" class="btn-glass">Back</button>
      </div>
      <div id="dex-grid" class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4"></div>
    </div>
  </section>

  <!-- Shop -->
  <section id="screen-shop" class="hidden absolute inset-0 z-40 p-4 md:p-8 flex flex-col">
    <div class="max-w-3xl mx-auto w-full">
      <div class="flex justify-between items-center mb-6">
        <h2 class="font-['Orbitron'] text-3xl font-black">Camp Shop</h2>
        <button onclick="closeShop()" class="btn-glass">Back</button>
      </div>
      <div class="glass-card p-6 mb-6">
        <p class="text-sm text-[var(--text-dim)]">Spend Aether Shards to purchase harmonic supplies.</p>
        <p class="text-lg font-bold mt-1"><span id="shop-shards">0</span> Shards Available</p>
      </div>
      <div id="shop-items" class="grid grid-cols-1 md:grid-cols-2 gap-4"></div>
    </div>
  </section>

  <!-- Inventory / Exchange -->
  <section id="screen-inventory" class="hidden absolute inset-0 z-40 p-4 md:p-8 flex flex-col">
    <div class="max-w-3xl mx-auto w-full">
      <div class="flex justify-between items-center mb-6">
        <h2 class="font-['Orbitron'] text-2xl font-black">Inventory &amp; Exchange</h2>
        <button onclick="closeInventory()" class="btn-glass">Back</button>
      </div>
      <div id="party-display" class="grid grid-cols-3 gap-3 mb-6"></div>
    </div>
  </section>

  <!-- Save / Reset Overlay -->
  <section id="screen-saveoverlay" class="hidden absolute inset-0 z-50 bg-black/60 backdrop-blur-md flex items-center justify-center p-6">
    <div class="glass max-w-md w-full p-8 text-center">
      <h3 class="text-2xl font-bold mb-4">Reset Progress</h3>
      <p class="text-sm text-[var(--text-dim)] mb-6">This will erase all saved data and restart your journey from the beginning.</p>
      <div class="flex gap-3 justify-center">
        <button onclick="resetProgress()" class="btn-glass bg-red-900/20 border-red-500/30 hover:bg-red-900/30">Confirm Reset</button>
        <button onclick="closeSaveOverlay()" class="btn-glass">Cancel</button>
      </div>
    </div>
  </section>

  <div id="toast" class="fixed top-4 left-1/2 -translate-x-1/2 z-[60] glass px-6 py-3 rounded-xl text-sm font-semibold opacity-0 transition-opacity duration-300 pointer-events-none">Notification</div>
</div>
<script>
'use strict';

// ── class: Synth ──
class Synth {
  constructor() {
    this.ctx = new (window.AudioContext || window.webkitAudioContext)();
    this.gain = this.ctx.createGain();
    this.gain.connect(this.ctx.destination);
  }
  tone(freq, duration, type = 'square', gainVal = 0.08) {
    try {
      const osc = this.ctx.createOscillator();
      osc.type = type;
      osc.frequency.setValueAtTime(freq, this.ctx.currentTime);
      const env = this.ctx.createGain();
      env.gain.setValueAtTime(gainVal, this.ctx.currentTime);
      env.gain.exponentialRampToValueAtTime(0.001, this.ctx.currentTime + duration);
      osc.connect(env); env.connect(this.gain);
      osc.start(); osc.stop(this.ctx.currentTime + duration);
    } catch (e) {}
  }
  playHover() { this.tone(880, 0.08, 'sine', 0.05); }
  playSelect() { this.tone(1100, 0.12, 'triangle', 0.06); }
  playHitPhysical() { this.tone(120, 0.2, 'sawtooth', 0.06); this.tone(60, 0.2, 'sine', 0.05); }
  playHitElemental() { this.tone(660, 0.15, 'triangle', 0.06); this.tone(880, 0.15, 'triangle', 0.05); }
  playLevelUp() { [440, 554, 659, 880].forEach((f, i) => setTimeout(() => this.tone(f, 0.15, 'sine', 0.06), i * 60)); }
  playCapture() { this.tone(440, 0.1, 'triangle', 0.05); this.tone(880, 0.15, 'triangle', 0.05); this.tone(1320, 0.2, 'sine', 0.05); }
}

// ── const: RESONANTS ──
const RESONANTS = [
  // Pyro Family
  { id: 'emberkit', name: 'Emberkit', type: 'Pyro', tier: 1, level: 1, baseHP: 65, baseAtk: 55, baseDef: 35, baseSpd: 52,
    moves: [{name:'Ember Spark', power: 40, accuracy: 0.95, element:'Pyro', unlockLevel:1}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="eg"><stop offset="0%" stop-color="#ff6b35"/><stop offset="100%" stop-color="#a02010"/></radialGradient></defs><circle cx="50" cy="50" r="30" fill="url(#eg)"/><circle cx="38" cy="44" r="6" fill="#ffccaa"/><circle cx="62" cy="44" r="6" fill="#ffccaa"/><polygon points="50,70 40,85 60,85" fill="#ffccaa"/></svg>', evolutionLevel: 8, evolutionTo: 'pyrowolf'
  },
  { id: 'pyrowolf', name: 'Pyrowolf', type: 'Pyro', tier: 2, level: 8, baseHP: 110, baseAtk: 95, baseDef: 60, baseSpd: 85,
    moves: [{name:'Ember Spark', power: 40, accuracy: 0.95, element:'Pyro', unlockLevel:1}, {name:'Inferno Lash', power: 75, accuracy: 0.9, element:'Pyro', unlockLevel:8}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="pw"><stop offset="0%" stop-color="#ff4500"/><stop offset="100%" stop-color="#6b1205"/></radialGradient></defs><ellipse cx="50" cy="48" rx="32" ry="28" fill="url(#pw)"/><circle cx="38" cy="42" r="6" fill="#ffccaa"/><circle cx="62" cy="42" r="6" fill="#ffccaa"/><polygon points="50,72 42,92 58,92" fill="#ffccaa"/><polygon points="20,30 5,50 20,40" fill="#ff4d00"/></svg>', evolutionLevel: 15, evolutionTo: 'ignisaur'
  },
  { id: 'ignisaur', name: 'Ignisaur', type: 'Pyro', tier: 3, level: 15, baseHP: 170, baseAtk: 145, baseDef: 100, baseSpd: 110,
    moves: [{name:'Ember Spark', power: 40, accuracy: 0.95, element:'Pyro', unlockLevel:1}, {name:'Inferno Lash', power: 75, accuracy: 0.9, element:'Pyro', unlockLevel:8}, {name:'Solar Eruption', power: 110, accuracy: 0.85, element:'Pyro', unlockLevel:15}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><linearGradient id="ig"><stop offset="0%" stop-color="#ff6a00"/><stop offset="100%" stop-color="#4a0e00"/></linearGradient></defs><ellipse cx="50" cy="55" rx="36" ry="30" fill="url(#ig)"/><circle cx="35" cy="46" r="8" fill="#fff0cc"/><circle cx="65" cy="46" r="8" fill="#fff0cc"/><polygon points="50,80 38,100 62,100" fill="#ffccaa"/><polygon points="14,40 5,65 22,50" fill="#ff8c00"/><polygon points="86,40 95,65 78,50" fill="#ff8c00"/></svg>', evolutionLevel: null, evolutionTo: null
  },

  // Hydro Family
  { id: 'droplet', name: 'Droplet', type: 'Hydro', tier: 1, level: 1, baseHP: 70, baseAtk: 45, baseDef: 50, baseSpd: 48,
    moves: [{name:'Splash', power: 40, accuracy: 0.98, element:'Hydro', unlockLevel:1}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="dr"><stop offset="0%" stop-color="#4fc3f7"/><stop offset="100%" stop-color="#0a5a8a"/></radialGradient></defs><circle cx="50" cy="48" r="28" fill="url(#dr)"/><ellipse cx="48" cy="52" rx="4" ry="8" fill="#a0e8ff"/><circle cx="38" cy="42" r="5" fill="#e0f7ff"/><circle cx="62" cy="42" r="5" fill="#e0f7ff"/></svg>', evolutionLevel: 8, evolutionTo: 'geoxus'
  },
  { id: 'geoxus', name: 'Geoxus', type: 'Hydro', tier: 2, level: 8, baseHP: 115, baseAtk: 80, baseDef: 85, baseSpd: 75,
    moves: [{name:'Splash', power: 40, accuracy: 0.98, element:'Hydro', unlockLevel:1}, {name:'Tidal Crash', power: 80, accuracy: 0.85, element:'Hydro', unlockLevel:8}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><linearGradient id="gx"><stop offset="0%" stop-color="#1a8fff"/><stop offset="100%" stop-color="#003a66"/></linearGradient></defs><ellipse cx="50" cy="50" rx="34" ry="26" fill="url(#gx)"/><circle cx="36" cy="44" r="7" fill="#d0f0ff"/><circle cx="64" cy="44" r="7" fill="#d0f0ff"/><ellipse cx="50" cy="65" rx="10" ry="6" fill="#a0e8ff"/></svg>', evolutionLevel: 15, evolutionTo: 'neptunian'
  },
  { id: 'neptunian', name: 'Neptunian', type: 'Hydro', tier: 3, level: 15, baseHP: 175, baseAtk: 125, baseDef: 120, baseSpd: 105,
    moves: [{name:'Splash', power: 40, accuracy: 0.98, element:'Hydro', unlockLevel:1}, {name:'Tidal Crash', power: 80, accuracy: 0.85, element:'Hydro', unlockLevel:8}, {name:'Abyssal Vortex', power: 115, accuracy: 0.8, element:'Hydro', unlockLevel:15}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="np"><stop offset="0%" stop-color="#00bfff"/><stop offset="100%" stop-color="#001f3f"/></radialGradient></defs><ellipse cx="50" cy="52" rx="38" ry="28" fill="url(#np)"/><circle cx="32" cy="44" r="9" fill="#e0faff"/><circle cx="68" cy="44" r="9" fill="#e0faff"/><polygon points="50,82 42,102 58,102" fill="#00aaff"/></svg>', evolutionLevel: null, evolutionTo: null
  },

  // Flora Family
  { id: 'seedling', name: 'Seedling', type: 'Flora', tier: 1, level: 1, baseHP: 68, baseAtk: 48, baseDef: 40, baseSpd: 55,
    moves: [{name:'Vine Whip', power: 45, accuracy: 0.95, element:'Flora', unlockLevel:1}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="sl"><stop offset="0%" stop-color="#66cc66"/><stop offset="100%" stop-color="#0a4a0a"/></radialGradient></defs><circle cx="50" cy="52" r="28" fill="url(#sl)"/><ellipse cx="50" cy="48" rx="6" ry="10" fill="#99ff99"/><circle cx="42" cy="58" r="5" fill="#66dd66"/><circle cx="58" cy="58" r="5" fill="#66dd66"/></svg>', evolutionLevel: 8, evolutionTo: 'thornback'
  },
  { id: 'thornback', name: 'Thornback', type: 'Flora', tier: 2, level: 8, baseHP: 120, baseAtk: 90, baseDef: 75, baseSpd: 80,
    moves: [{name:'Vine Whip', power: 45, accuracy: 0.95, element:'Flora', unlockLevel:1}, {name:'Thorn Barrage', power: 75, accuracy: 0.85, element:'Flora', unlockLevel:8}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><linearGradient id="tb"><stop offset="0%" stop-color="#44aa44"/><stop offset="100%" stop-color="#0f3a0f"/></linearGradient></defs><ellipse cx="50" cy="48" rx="32" ry="30" fill="url(#tb)"/><polygon points="50,25 42,12 58,12" fill="#55bb55"/><circle cx="36" cy="50" r="8" fill="#88dd88"/><circle cx="64" cy="50" r="8" fill="#88dd88"/></svg>', evolutionLevel: 15, evolutionTo: 'bloomgoliath'
  },
  { id: 'bloomgoliath', name: 'Bloomgoliath', type: 'Flora', tier: 3, level: 15, baseHP: 180, baseAtk: 135, baseDef: 115, baseSpd: 90,
    moves: [{name:'Vine Whip', power: 45, accuracy: 0.95, element:'Flora', unlockLevel:1}, {name:'Thorn Barrage', power: 75, accuracy: 0.85, element:'Flora', unlockLevel:8}, {name:'Flora Colossus', power: 110, accuracy: 0.8, element:'Flora', unlockLevel:15}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="bg"><stop offset="0%" stop-color="#55bb55"/><stop offset="100%" stop-color="#143314"/></radialGradient></defs><ellipse cx="50" cy="48" rx="36" ry="32" fill="url(#bg)"/><polygon points="50,18 42,5 58,5" fill="#77cc77"/><circle cx="30" cy="48" r="10" fill="#99ee99"/><circle cx="70" cy="48" r="10" fill="#99ee99"/><polygon points="50,82 36,95 64,95" fill="#66aa66"/></svg>', evolutionLevel: null, evolutionTo: null
  },

  // Zephyr Family
  { id: 'gusty', name: 'Gusty', type: 'Zephyr', tier: 1, level: 1, baseHP: 60, baseAtk: 58, baseDef: 32, baseSpd: 65,
    moves: [{name:'Gust', power: 40, accuracy: 0.95, element:'Zephyr', unlockLevel:1}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="gu"><stop offset="0%" stop-color="#b388ff"/><stop offset="100%" stop-color="#4a1a80"/></radialGradient></defs><circle cx="50" cy="50" r="28" fill="url(#gu)"/><ellipse cx="50" cy="40" rx="8" ry="4" fill="#d4b4ff"/><circle cx="38" cy="55" r="6" fill="#e0ccff"/><circle cx="62" cy="55" r="6" fill="#e0ccff"/></svg>', evolutionLevel: 8, evolutionTo: 'slipstream'
  },
  { id: 'slipstream', name: 'Slipstream', type: 'Zephyr', tier: 2, level: 8, baseHP: 105, baseAtk: 100, baseDef: 55, baseSpd: 100,
    moves: [{name:'Gust', power: 40, accuracy: 0.95, element:'Zephyr', unlockLevel:1}, {name:'Sky Shear', power: 80, accuracy: 0.85, element:'Zephyr', unlockLevel:8}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><linearGradient id="ss"><stop offset="0%" stop-color="#9a6aff"/><stop offset="100%" stop-color="#2d0f5c"/></linearGradient></defs><ellipse cx="50" cy="48" rx="34" ry="26" fill="url(#ss)"/><ellipse cx="50" cy="36" rx="10" ry="4" fill="#caa0ff"/><circle cx="34" cy="52" r="7" fill="#d0b8ff"/><circle cx="66" cy="52" r="7" fill="#d0b8ff"/></svg>', evolutionLevel: 15, evolutionTo: 'zephyrus'
  },
  { id: 'zephyrus', name: 'Zephyrus', type: 'Zephyr', tier: 3, level: 15, baseHP: 160, baseAtk: 145, baseDef: 85, baseSpd: 130,
    moves: [{name:'Gust', power: 40, accuracy: 0.95, element:'Zephyr', unlockLevel:1}, {name:'Sky Shear', power: 80, accuracy: 0.85, element:'Zephyr', unlockLevel:8}, {name:'Tempest Burst', power: 115, accuracy: 0.8, element:'Zephyr', unlockLevel:15}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="ze"><stop offset="0%" stop-color="#aa77ff"/><stop offset="100%" stop-color="#2a0640"/></radialGradient></defs><ellipse cx="50" cy="48" rx="38" ry="26" fill="url(#ze)"/><polygon points="50,20 44,8 56,8" fill="#bb88ff"/><circle cx="30" cy="50" r="9" fill="#ccaaff"/><circle cx="70" cy="50" r="9" fill="#ccaaff"/></svg>', evolutionLevel: null, evolutionTo: null
  },

  // Earth Family
  { id: 'pebble', name: 'Pebble', type: 'Earth', tier: 1, level: 1, baseHP: 72, baseAtk: 42, baseDef: 58, baseSpd: 35,
    moves: [{name:'Stone Throw', power: 42, accuracy: 0.95, element:'Earth', unlockLevel:1}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="pb"><stop offset="0%" stop-color="#bfa55a"/><stop offset="100%" stop-color="#5c3a0a"/></radialGradient></defs><circle cx="50" cy="52" r="28" fill="url(#pb)"/><circle cx="38" cy="48" r="6" fill="#e0c080"/><circle cx="62" cy="48" r="6" fill="#e0c080"/><polygon points="50,78 40,92 60,92" fill="#d0a050"/></svg>', evolutionLevel: 8, evolutionTo: 'obsidian'
  },
  { id: 'obsidian', name: 'Obsidian', type: 'Earth', tier: 2, level: 8, baseHP: 125, baseAtk: 85, baseDef: 100, baseSpd: 55,
    moves: [{name:'Stone Throw', power: 42, accuracy: 0.95, element:'Earth', unlockLevel:1}, {name:'Rock Slide', power: 80, accuracy: 0.9, element:'Earth', unlockLevel:8}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><linearGradient id="ob"><stop offset="0%" stop-color="#7a5a2a"/><stop offset="100%" stop-color="#2a150a"/></linearGradient></defs><ellipse cx="50" cy="50" rx="34" ry="28" fill="url(#ob)"/><polygon points="50,22 40,10 60,10" fill="#8a6a3a"/><circle cx="36" cy="48" r="8" fill="#c0a070"/><circle cx="64" cy="48" r="8" fill="#c0a070"/></svg>', evolutionLevel: 15, evolutionTo: 'terrasunder'
  },
  { id: 'terrasunder', name: 'Terrasunder', type: 'Earth', tier: 3, level: 15, baseHP: 190, baseAtk: 125, baseDef: 140, baseSpd: 70,
    moves: [{name:'Stone Throw', power: 42, accuracy: 0.95, element:'Earth', unlockLevel:1}, {name:'Rock Slide', power: 80, accuracy: 0.9, element:'Earth', unlockLevel:8}, {name:'Seismic Rupture', power: 110, accuracy: 0.8, element:'Earth', unlockLevel:15}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="ts"><stop offset="0%" stop-color="#8a6a3a"/><stop offset="100%" stop-color="#1a0d04"/></radialGradient></defs><ellipse cx="50" cy="48" rx="38" ry="30" fill="url(#ts)"/><polygon points="50,18 42,5 58,5" fill="#a88a5a"/><circle cx="32" cy="46" r="9" fill="#d0b080"/><circle cx="68" cy="46" r="9" fill="#d0b080"/></svg>', evolutionLevel: null, evolutionTo: null
  },

  // Volt Family
  { id: 'sparky', name: 'Sparky', type: 'Volt', tier: 1, level: 1, baseHP: 62, baseAtk: 60, baseDef: 30, baseSpd: 70,
    moves: [{name:'Spark', power: 40, accuracy: 0.95, element:'Volt', unlockLevel:1}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="sp"><stop offset="0%" stop-color="#f0e030"/><stop offset="100%" stop-color="#8a7010"/></radialGradient></defs><circle cx="50" cy="50" r="26" fill="url(#sp)"/><polygon points="50,30 42,18 58,18" fill="#ffee55"/><circle cx="38" cy="52" r="7" fill="#ffeeaa"/><circle cx="62" cy="52" r="7" fill="#ffeeaa"/></svg>', evolutionLevel: 8, evolutionTo: 'boltsaber'
  },
  { id: 'boltsaber', name: 'Boltsaber', type: 'Volt', tier: 2, level: 8, baseHP: 108, baseAtk: 105, baseDef: 55, baseSpd: 110,
    moves: [{name:'Spark', power: 40, accuracy: 0.95, element:'Volt', unlockLevel:1}, {name:'Volt Slash', power: 80, accuracy: 0.85, element:'Volt', unlockLevel:8}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><linearGradient id="bs"><stop offset="0%" stop-color="#ffe030"/><stop offset="100%" stop-color="#8a6a10"/></linearGradient></defs><ellipse cx="50" cy="48" rx="32" ry="24" fill="url(#bs)"/><polygon points="50,22 42,10 58,10" fill="#ffee55"/><circle cx="34" cy="48" r="8" fill="#ffeeaa"/><circle cx="66" cy="48" r="8" fill="#ffeeaa"/></svg>', evolutionLevel: 15, evolutionTo: 'stormlord'
  },
  { id: 'stormlord', name: 'Stormlord', type: 'Volt', tier: 3, level: 15, baseHP: 168, baseAtk: 150, baseDef: 90, baseSpd: 135,
    moves: [{name:'Spark', power: 40, accuracy: 0.95, element:'Volt', unlockLevel:1}, {name:'Volt Slash', power: 80, accuracy: 0.85, element:'Volt', unlockLevel:8}, {name:'Thunderstorm', power: 115, accuracy: 0.8, element:'Volt', unlockLevel:15}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="sl"><stop offset="0%" stop-color="#ffee55"/><stop offset="100%" stop-color="#4a3008"/></radialGradient></defs><ellipse cx="50" cy="48" rx="36" ry="26" fill="url(#sl)"/><polygon points="50,18 44,6 56,6" fill="#ffeeaa"/><circle cx="32" cy="46" r="9" fill="#ffeeee"/><circle cx="68" cy="46" r="9" fill="#ffeeee"/></svg>', evolutionLevel: null, evolutionTo: null
  },

  // Cosmos Family
  { id: 'astralshard', name: 'Astral Shard', type: 'Cosmos', tier: 3, level: 15, baseHP: 155, baseAtk: 110, baseDef: 95, baseSpd: 95,
    moves: [{name:'Star Pulse', power: 55, accuracy: 0.9, element:'Cosmos', unlockLevel:1}, {name:'Void Rift', power: 90, accuracy: 0.85, element:'Cosmos', unlockLevel:8}, {name:'Nebula Collapse', power: 120, accuracy: 0.75, element:'Cosmos', unlockLevel:15}],
    spriteSVG: '<svg viewBox="0 0 100 100"><defs><radialGradient id="as"><stop offset="0%" stop-color="#e0e0ff"/><stop offset="100%" stop-color="#2a1a4a"/></radialGradient></defs><circle cx="50" cy="48" r="28" fill="url(#as)"/><polygon points="50,28 42,40 58,40" fill="#f0f0ff"/><circle cx="36" cy="48" r="7" fill="#ffffff"/><circle cx="64" cy="48" r="7" fill="#ffffff"/></svg>', evolutionLevel: null, evolutionTo: null
  }
];

// ── const: TYPE_ADVANTAGE ──
const TYPE_ADVANTAGE = {
  '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: null, weak: null }
};

// ── const: ZONES ──
const ZONES = [
  { id: 1, name: 'Verdant Canopy', levels: '1-5', desc: 'Thick harmonic vines pulse with Flora and Zephyr energy. The air is thick with pollen and static.', types: ['Flora','Zephyr'], gatekeeper: { id: 'thornback', level: 5 } },
  { id: 2, name: 'Sunken Grotto', levels: '5-10', desc: 'Crystal pools reflect Hydro and Earth frequencies. Echoes ripple through underwater caverns.', types: ['Hydro','Earth'], gatekeeper: { id: 'geoxus', level: 10 } },
  { id: 3, name: 'Obsidian Crags', levels: '10-15', desc: 'Molten fissures crack black stone. Pyro and Volt energies clash in violent storms.', types: ['Pyro','Volt'], gatekeeper: { id: 'boltsaber', level: 15 } },
  { id: 4, name: 'Apex Pillar', levels: '15+', desc: 'The harmonic apex of Aethelgard. Only the strongest Conductors survive its resonance storms.', types: ['Cosmos','Fire','Hydro','Flora','Zephyr','Earth','Volt'], gatekeeper: { id: 'stormlord', level: 18 } }
];

// ── const: SHOP_ITEMS ──
const SHOP_ITEMS = [
  { id: 'hprism', name: 'Harmonizer Prism', desc: 'Basic capture matrix. Increases catch rate to 35%.', price: 25, icon: '◆', effect: (p) => { p.items.push('prism'); } },
  { id: 'hprism2', name: 'Hyper-Prism', desc: 'Advanced geometric capture array. 60% catch rate.', price: 100, icon: '◆◆', effect: (p) => { p.items.push('hyperprism'); } },
  { id: 'restorer', name: 'Core Restorer', desc: 'Restores 50% of max HP to one Resonant.', price: 30, icon: '♥', effect: (p) => { p.items.push('restorer'); } },
  { id: 'cleanser', name: 'Resonance Elixir', desc: 'Cleanses all negative harmonic status effects.', price: 40, icon: '◈', effect: (p) => { p.items.push('cleanser'); } }
];

// ── function: defaultProfile ──
function defaultProfile() {
  return {
    zoneProgress: 1, unlockedZones: [1], completedBosses: [], shards: 50,
    party: [
      { id: 'seedling', level: 1, xp: 0, hp: 70, maxHP: 70, movesUnlocked: [1] }
    ],
    inventory: ['prism','restorer'],
    caught: ['seedling'],
    activePartyIndex: 0
  };
}

// ── function: saveGame ──
function saveGame() {
  try { localStorage.setItem('aethelgard_save', JSON.stringify(gameState)); } catch (e) {}
}

// ── function: loadSave ──
function loadSave() {
  try {
    const raw = localStorage.getItem('aethelgard_save');
    if (!raw) throw new Error('No save');
    const s = JSON.parse(raw);
    Object.assign(gameState, s);
    saveGame();
    initUI();
    showScreen('world');
    showToast('Save restored');
    synth.playSelect();
  } catch (e) {
    showToast('No save found');
    gameState = defaultProfile();
  }
}

// ── function: resetProgress ──
function resetProgress() {
  gameState = defaultProfile();
  saveGame();
  showToast('Progress reset');
  closeSaveOverlay();
  setTimeout(() => location.reload(), 400);
}
</script>
</body>
</html>
<!-- agent-meta {"model":"thinkingmachines/inkling","provider":"openrouter","persona":"composer","sessionId":"5f34cabe-d63c-41c3-9750-653368c32534","tokensIn":153217,"tokensOut":16949,"tokensTotal":170166,"turns":13,"toolCalls":12,"failedToolCalls":2,"timestamp":"2026-07-21T01:18:23.304Z"} -->