Grok Build 0.1

xAIAugust 2025

What it wrote

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>AETHER • Incremental</title>
  <style>
    @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&amp;family=Space+Grotesk:wght@500;600&amp;display=swap');

    :root {
      --bg: #0a0b14;
      --bg-elev: #12131f;
      --bg-glass: rgba(18, 19, 31, 0.85);
      --accent: #7c3aed;
      --accent-2: #22d3ee;
      --accent-3: #a78bfa;
      --text: #e2e8f0;
      --text-muted: #94a3b8;
      --border: rgba(148, 163, 184, 0.15);
      --success: #34d399;
    }

    * {
      box-sizing: border-box;
    }

    body {
      margin: 0;
      padding: 0;
      background: var(--bg);
      color: var(--text);
      font-family: 'Inter', system_ui, sans-serif;
      min-height: 100vh;
      overflow-x: hidden;
    }

    .stars {
      position: fixed;
      inset: 0;
      z-index: -1;
      background: 
        radial-gradient(circle at 20% 30%, rgba(124, 58, 237, 0.08) 0%, transparent 50%),
        radial-gradient(circle at 80% 70%, rgba(34, 211, 238, 0.06) 0%, transparent 50%),
        var(--bg);
    }

    .container {
      max-width: 1180px;
      margin: 0 auto;
      padding: 24px;
    }

    header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin-bottom: 32px;
    }

    .logo {
      display: flex;
      align-items: center;
      gap: 14px;
    }

    .logo-icon {
      width: 42px;
      height: 42px;
      background: linear-gradient(135deg, var(--accent), var(--accent-2));
      border-radius: 12px;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 22px;
      box-shadow: 0 0 40px rgba(124, 58, 237, 0.4);
    }

    .logo-text {
      font-family: 'Space Grotesk', sans-serif;
      font-size: 28px;
      font-weight: 600;
      letter-spacing: -1px;
      background: linear-gradient(90deg, #e2e8f0, #cbd5e1);
      -webkit-background-clip: text;
      background-clip: text;
      -webkit-text-fill-color: transparent;
    }

    .header-stats {
      display: flex;
      gap: 32px;
      font-size: 13px;
    }

    .header-stat {
      text-align: right;
    }

    .header-stat-label {
      color: var(--text-muted);
      font-size: 11px;
      text-transform: uppercase;
      letter-spacing: 0.5px;
    }

    .header-stat-value {
      font-weight: 600;
      font-size: 15px;
      font-variant-numeric: tabular-nums;
    }

    .main-grid {
      display: grid;
      grid-template-columns: 420px 1fr;
      gap: 28px;
      align-items: start;
    }

    @media (max-width: 900px) {
      .main-grid {
        grid-template-columns: 1fr;
      }
    }

    .core-panel {
      position: sticky;
      top: 24px;
    }

    .resources {
      text-align: center;
      margin-bottom: 24px;
    }

    .aether-amount {
      font-family: 'Space Grotesk', sans-serif;
      font-size: 64px;
      font-weight: 600;
      line-height: 1;
      letter-spacing: -3px;
      background: linear-gradient(180deg, #f1f5f9 0%, #cbd5e1 100%);
      -webkit-background-clip: text;
      background-clip: text;
      -webkit-text-fill-color: transparent;
      font-variant-numeric: tabular-nums;
      min-height: 68px;
    }

    .aether-label {
      color: var(--accent-2);
      font-size: 13px;
      letter-spacing: 3px;
      text-transform: uppercase;
      font-weight: 500;
      margin-top: 4px;
    }

    .aps {
      margin-top: 8px;
      font-size: 15px;
      color: var(--text-muted);
      font-variant-numeric: tabular-nums;
    }

    .aps span {
      color: var(--accent-2);
      font-weight: 600;
    }

    .orb-wrapper {
      position: relative;
      width: 320px;
      height: 320px;
      margin: 0 auto 28px;
      cursor: pointer;
      user-select: none;
      -webkit-user-select: none;
    }

    .orb {
      position: absolute;
      inset: 0;
      border-radius: 9999px;
      background: 
        radial-gradient(circle at 38% 32%, #f0abfc 0%, transparent 45%),
        radial-gradient(circle at 62% 68%, #67e8f9 0%, transparent 50%),
        linear-gradient(145deg, #7c3aed 0%, #312e81 45%, #1e1b4b 100%);
      box-shadow: 
        0 0 0 12px rgba(124, 58, 237, 0.15),
        0 0 0 28px rgba(124, 58, 237, 0.08),
        0 25px 70px -15px rgba(0, 0, 0, 0.6),
        inset 0 4px 20px rgba(255,255,255,0.35),
        inset 40px 40px 60px rgba(255,255,255,0.12),
        inset -30px -30px 50px rgba(0,0,0,0.5);
      transition: transform 0.08s cubic-bezier(0.23, 1, 0.32, 1), 
                  box-shadow 0.2s ease;
      display: flex;
      align-items: center;
      justify-content: center;
      overflow: hidden;
    }

    .orb::before {
      content: '';
      position: absolute;
      inset: 0;
      border-radius: 9999px;
      background: linear-gradient(
        120deg,
        transparent 30%,
        rgba(255,255,255,0.45) 48%,
        transparent 65%
      );
      background-size: 200% 200%;
      animation: orb-shimmer 4s linear infinite;
      pointer-events: none;
    }

    .orb::after {
      content: '';
      position: absolute;
      inset: 18px;
      border-radius: 9999px;
      background: radial-gradient(circle at 35% 30%, rgba(255,255,255,0.5), transparent 70%);
      pointer-events: none;
    }

    .orb:active {
      transform: scale(0.94);
      box-shadow: 
        0 0 0 8px rgba(124, 58, 237, 0.2),
        0 0 0 18px rgba(124, 58, 237, 0.1),
        0 15px 40px -10px rgba(0, 0, 0, 0.5),
        inset 0 2px 12px rgba(255,255,255,0.3),
        inset -20px -20px 35px rgba(0,0,0,0.55);
    }

    .orb-label {
      position: relative;
      z-index: 2;
      font-family: 'Space Grotesk', sans-serif;
      font-size: 17px;
      font-weight: 600;
      letter-spacing: 4px;
      color: rgba(255,255,255,0.95);
      text-shadow: 0 2px 12px rgba(0,0,0,0.4);
    }

    .orb-glow {
      position: absolute;
      inset: -60px;
      border-radius: 9999px;
      background: radial-gradient(circle, rgba(124, 58, 237, 0.25) 0%, transparent 70%);
      pointer-events: none;
      transition: opacity 0.3s ease;
      z-index: -1;
    }

    .orb-wrapper:hover .orb-glow {
      opacity: 1;
    }

    @keyframes orb-shimmer {
      0% { background-position: 200% 50%; }
      100% { background-position: -200% 50%; }
    }

    .canvas-particles {
      position: absolute;
      inset: -40px;
      border-radius: 50%;
      pointer-events: none;
      z-index: 3;
    }

    .floating-text {
      position: absolute;
      color: #c0a7ff;
      font-weight: 600;
      font-size: 15px;
      pointer-events: none;
      text-shadow: 0 0 8px rgba(124, 58, 237, 0.6);
      z-index: 10;
      animation: float-up 0.9s ease-out forwards;
      font-variant-numeric: tabular-nums;
    }

    @keyframes float-up {
      0% {
        transform: translateY(0) scale(1);
        opacity: 1;
      }
      100% {
        transform: translateY(-70px) scale(0.85);
        opacity: 0;
      }
    }

    .panel {
      background: var(--bg-glass);
      border: 1px solid var(--border);
      border-radius: 20px;
      padding: 24px;
      backdrop-filter: blur(20px);
    }

    .panel-title {
      font-size: 11px;
      letter-spacing: 2px;
      text-transform: uppercase;
      color: var(--text-muted);
      font-weight: 600;
      margin-bottom: 16px;
      display: flex;
      align-items: center;
      gap: 8px;
    }

    .panel-title::after {
      content: '';
      flex: 1;
      height: 1px;
      background: linear-gradient(to right, var(--border), transparent);
    }

    .generators {
      display: flex;
      flex-direction: column;
      gap: 10px;
    }

    .generator {
      display: grid;
      grid-template-columns: auto 1fr auto;
      align-items: center;
      gap: 16px;
      padding: 14px 18px;
      background: rgba(255,255,255,0.025);
      border: 1px solid var(--border);
      border-radius: 14px;
      transition: all 0.15s ease;
      cursor: pointer;
      position: relative;
      overflow: hidden;
    }

    .generator:hover {
      background: rgba(124, 58, 237, 0.08);
      border-color: rgba(124, 58, 237, 0.3);
      transform: translateY(-1px);
    }

    .generator.cant-afford {
      opacity: 0.55;
      cursor: not-allowed;
    }

    .generator.cant-afford:hover {
      transform: none;
      background: rgba(255,255,255,0.025);
      border-color: var(--border);
    }

    .gen-icon {
      width: 42px;
      height: 42px;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 22px;
      background: linear-gradient(135deg, rgba(124,58,237,0.2), rgba(34,211,238,0.1));
      border-radius: 11px;
      flex-shrink: 0;
    }

    .gen-info {
      min-width: 0;
    }

    .gen-name {
      font-weight: 600;
      font-size: 15px;
      margin-bottom: 2px;
    }

    .gen-desc {
      font-size: 12px;
      color: var(--text-muted);
    }

    .gen-stats {
      text-align: right;
      font-variant-numeric: tabular-nums;
    }

    .gen-owned {
      font-size: 18px;
      font-weight: 600;
      line-height: 1;
      color: var(--accent-2);
    }

    .gen-cost {
      font-size: 13px;
      color: #a5b4fc;
      margin-top: 2px;
    }

    .gen-rate {
      font-size: 11px;
      color: var(--text-muted);
      margin-top: 1px;
    }

    .buy-controls {
      display: flex;
      gap: 6px;
      margin-top: 16px;
      flex-wrap: wrap;
    }

    .buy-btn {
      flex: 1;
      min-width: 58px;
      padding: 8px 10px;
      background: rgba(255,255,255,0.06);
      border: 1px solid var(--border);
      color: var(--text);
      border-radius: 9px;
      font-size: 12px;
      font-weight: 600;
      cursor: pointer;
      transition: all 0.1s ease;
    }

    .buy-btn:hover {
      background: rgba(124, 58, 237, 0.15);
      border-color: var(--accent);
    }

    .buy-btn:active {
      transform: scale(0.96);
    }

    .buy-btn.active {
      background: var(--accent);
      border-color: var(--accent);
      color: white;
    }

    .upgrades-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
      gap: 10px;
    }

    .upgrade {
      padding: 14px 16px;
      background: rgba(255,255,255,0.025);
      border: 1px solid var(--border);
      border-radius: 12px;
      font-size: 13px;
      transition: all 0.15s ease;
      cursor: pointer;
      display: flex;
      flex-direction: column;
      gap: 6px;
    }

    .upgrade:hover:not(.owned) {
      border-color: rgba(124, 58, 237, 0.4);
      background: rgba(124, 58, 237, 0.06);
    }

    .upgrade.owned {
      border-color: rgba(52, 211, 153, 0.3);
      background: rgba(52, 211, 153, 0.06);
      cursor: default;
      opacity: 0.75;
    }

    .upgrade-name {
      font-weight: 600;
      font-size: 13.5px;
    }

    .upgrade-effect {
      font-size: 11.5px;
      color: var(--text-muted);
      line-height: 1.3;
    }

    .upgrade-cost {
      font-size: 12px;
      color: #a5b4fc;
      font-weight: 500;
      margin-top: 4px;
    }

    .prestige-section {
      margin-top: 28px;
    }

    .prestige-card {
      background: linear-gradient(145deg, rgba(124, 58, 237, 0.12), rgba(34, 211, 238, 0.06));
      border: 1px solid rgba(124, 58, 237, 0.25);
      border-radius: 18px;
      padding: 22px;
      position: relative;
      overflow: hidden;
    }

    .prestige-card::before {
      content: '';
      position: absolute;
      top: -50%;
      right: -20%;
      width: 200px;
      height: 200px;
      background: radial-gradient(circle, rgba(124,58,237,0.3) 0%, transparent 70%);
      pointer-events: none;
    }

    .prestige-header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin-bottom: 12px;
    }

    .prestige-title {
      font-weight: 600;
      font-size: 15px;
      display: flex;
      align-items: center;
      gap: 8px;
    }

    .prestige-multi {
      font-family: 'Space Grotesk', sans-serif;
      font-size: 22px;
      font-weight: 600;
      color: #c0a7ff;
    }

    .prestige-info {
      font-size: 13px;
      color: var(--text-muted);
      margin-bottom: 16px;
      line-height: 1.4;
    }

    .prestige-btn {
      width: 100%;
      padding: 14px;
      background: linear-gradient(135deg, var(--accent), #5b21b6);
      color: white;
      border: none;
      border-radius: 12px;
      font-size: 14px;
      font-weight: 700;
      letter-spacing: 0.3px;
      cursor: pointer;
      transition: all 0.2s ease;
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
      box-shadow: 0 10px 30px -10px rgba(124, 58, 237, 0.5);
    }

    .prestige-btn:hover:not(:disabled) {
      transform: translateY(-2px);
      box-shadow: 0 20px 40px -12px rgba(124, 58, 237, 0.6);
    }

    .prestige-btn:disabled {
      opacity: 0.4;
      cursor: not-allowed;
      background: #312e81;
    }

    .prestige-gain {
      text-align: center;
      font-size: 12px;
      margin-top: 10px;
      color: #c0a7ff;
    }

    .stats {
      display: grid;
      grid-template-columns: repeat(2, 1fr);
      gap: 10px;
      margin-top: 22px;
      font-size: 12px;
    }

    .stat {
      background: rgba(255,255,255,0.025);
      border: 1px solid var(--border);
      border-radius: 10px;
      padding: 10px 12px;
    }

    .stat-label {
      color: var(--text-muted);
      font-size: 10.5px;
      text-transform: uppercase;
      letter-spacing: 0.5px;
    }

    .stat-value {
      font-weight: 600;
      font-variant-numeric: tabular-nums;
      margin-top: 1px;
    }

    .achievements {
      margin-top: 28px;
    }

    .achievements-grid {
      display: flex;
      flex-wrap: wrap;
      gap: 8px;
    }

    .achievement {
      font-size: 12px;
      padding: 6px 12px;
      background: rgba(52, 211, 153, 0.1);
      border: 1px solid rgba(52, 211, 153, 0.25);
      border-radius: 9999px;
      color: #34d399;
      display: flex;
      align-items: center;
      gap: 6px;
      white-space: nowrap;
    }

    .toast-container {
      position: fixed;
      bottom: 24px;
      right: 24px;
      z-index: 9999;
      display: flex;
      flex-direction: column;
      gap: 10px;
      pointer-events: none;
    }

    .toast {
      background: var(--bg-elev);
      border: 1px solid var(--border);
      border-left: 4px solid var(--success);
      padding: 12px 18px;
      border-radius: 10px;
      box-shadow: 0 10px 30px -10px rgba(0,0,0,0.5);
      max-width: 280px;
      pointer-events: all;
      animation: toast-in 0.2s ease forwards;
    }

    .toast-title {
      font-weight: 600;
      font-size: 13px;
      color: #34d399;
    }

    .toast-desc {
      font-size: 12.5px;
      color: var(--text-muted);
      margin-top: 2px;
    }

    @keyframes toast-in {
      from { opacity: 0; transform: translateY(10px); }
      to { opacity: 1; transform: translateY(0); }
    }

    .offline-banner {
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      background: linear-gradient(to right, #312e81, #1e1b4b);
      color: #c0a7ff;
      text-align: center;
      padding: 9px 20px;
      font-size: 13px;
      z-index: 100;
      display: none;
      border-bottom: 1px solid rgba(124, 58, 237, 0.3);
    }

    .offline-banner.show {
      display: block;
    }

    .section-divider {
      height: 1px;
      background: linear-gradient(to right, transparent, var(--border), transparent);
      margin: 28px 0;
    }

    .empty-state {
      font-size: 12px;
      color: var(--text-muted);
      text-align: center;
      padding: 18px;
      background: rgba(255,255,255,0.015);
      border-radius: 12px;
      border: 1px dashed var(--border);
    }
  </style>
</head>
<body>
  <div class="stars" id="stars"></div>

  <div class="offline-banner" id="offline-banner"></div>

  <div class="container">
    <header>
      <div class="logo">
        <div class="logo-icon">✧</div>
        <div>
          <div class="logo-text">AETHER</div>
        </div>
      </div>
      <div class="header-stats">
        <div class="header-stat">
          <div class="header-stat-label">Total Harvested</div>
          <div class="header-stat-value" id="total-harvested">0</div>
        </div>
        <div class="header-stat">
          <div class="header-stat-label">Transcendences</div>
          <div class="header-stat-value" id="transcendences">0</div>
        </div>
      </div>
    </header>

    <div class="main-grid">
      <!-- CORE -->
      <div class="core-panel">
        <div class="resources">
          <div class="aether-amount" id="aether">0</div>
          <div class="aether-label">Aether</div>
          <div class="aps">
            <span id="aps">0</span> per second
          </div>
        </div>

        <div class="orb-wrapper" id="orb-wrapper">
          <canvas class="canvas-particles" id="particle-canvas" width="400" height="400"></canvas>
          <div class="orb" id="orb">
            <div class="orb-label">THE CORE</div>
          </div>
          <div class="orb-glow" style="opacity: 0.6;"></div>
        </div>

        <div class="prestige-card">
          <div class="prestige-header">
            <div class="prestige-title">
              <span>✧</span>
              <span>Transcendence</span>
            </div>
            <div class="prestige-multi" id="prestige-multi">1.00×</div>
          </div>
          <div class="prestige-info">
            Transcend to reset your progress and gain permanent <strong>Astral Power</strong>. 
            The more Aether you've ever collected, the stronger your next life becomes.
          </div>
          <button class="prestige-btn" id="prestige-btn" disabled>
            Transcend
          </button>
          <div class="prestige-gain" id="prestige-gain">Need 1.00M total Aether to transcend</div>
        </div>

        <div class="stats">
          <div class="stat">
            <div class="stat-label">Total Clicks</div>
            <div class="stat-value" id="total-clicks">0</div>
          </div>
          <div class="stat">
            <div class="stat-label">Peak APS</div>
            <div class="stat-value" id="peak-aps">0</div>
          </div>
          <div class="stat">
            <div class="stat-label">Astral Power</div>
            <div class="stat-value" id="astral-power">+0%</div>
          </div>
          <div class="stat">
            <div class="stat-label">Time Played</div>
            <div class="stat-value" id="time-played">0m</div>
          </div>
        </div>
      </div>

      <!-- RIGHT COLUMN -->
      <div>
        <!-- GENERATORS -->
        <div class="panel">
          <div class="panel-title">Generators</div>
          
          <div class="buy-controls">
            <button class="buy-btn active" data-multi="1">1</button>
            <button class="buy-btn" data-multi="10">10</button>
            <button class="buy-btn" data-multi="100">100</button>
            <button class="buy-btn" data-multi="max">MAX</button>
          </div>

          <div class="generators" id="generators"></div>
        </div>

        <div class="section-divider"></div>

        <!-- UPGRADES -->
        <div class="panel">
          <div class="panel-title">Upgrades</div>
          <div class="upgrades-grid" id="upgrades"></div>
        </div>

        <div class="achievements">
          <div class="panel-title">Achievements</div>
          <div class="achievements-grid" id="achievements"></div>
        </div>
      </div>
    </div>
  </div>

  <div class="toast-container" id="toast-container"></div>

  <script>
    // ==================== GAME STATE ====================
    const state = {
      aether: 0,
      totalAetherEarned: 0,
      totalClicks: 0,
      peakAps: 0,
      startTime: Date.now(),
      lastSave: Date.now(),
      lastTick: Date.now(),
      
      // Prestige
      transcendences: 0,
      astralShards: 0,
      
      // Generators: id -> { owned, ... }
      generators: {},
      
      // Upgrades purchased (set of ids)
      upgrades: new Set(),
      
      // Unlocked achievements
      achievements: new Set(),
    };

    // ==================== GENERATOR DEFINITIONS ====================
    const generators = [
      {
        id: 'shard',
        name: 'Aether Shard',
        icon: '◆',
        baseCost: 12,
        baseProduction: 0.1,
        desc: 'Tiny fragments humming with potential',
      },
      {
        id: 'condenser',
        name: 'Flux Condenser',
        icon: '◈',
        baseCost: 110,
        baseProduction: 1.1,
        desc: 'Compresses raw void into usable essence',
      },
      {
        id: 'voidtap',
        name: 'Void Tap',
        icon: '◉',
        baseCost: 1400,
        baseProduction: 13,
        desc: 'Draws directly from the space between stars',
      },
      {
        id: 'crucible',
        name: 'Star Crucible',
        icon: '✧',
        baseCost: 18500,
        baseProduction: 92,
        desc: 'Forges newborn stars into pure Aether',
      },
      {
        id: 'nebula',
        name: 'Nebula Loom',
        icon: '❋',
        baseCost: 260000,
        baseProduction: 780,
        desc: 'Weaves entire nebulae into threads of power',
      },
      {
        id: 'singularity',
        name: 'Singularity Anchor',
        icon: '◌',
        baseCost: 4200000,
        baseProduction: 9200,
        desc: 'Binds the impossible. Reality bends to your will',
      },
    ];

    // ==================== UPGRADE DEFINITIONS ====================
    const upgrades = [
      { id: 'tap1', name: 'Keen Resonance', cost: 85, effect: '+1 click power', type: 'click', value: 1 },
      { id: 'tap2', name: 'Amplified Tap', cost: 620, effect: 'Click power ×2', type: 'clickMulti', value: 2 },
      { id: 'tap3', name: 'Essence Overdrive', cost: 12500, effect: 'Click power ×3', type: 'clickMulti', value: 3 },
      { id: 'tap4', name: 'Quantum Touch', cost: 185000, effect: 'Click power ×4', type: 'clickMulti', value: 4 },
      
      { id: 'prod1', name: 'Harmonic Tuning', cost: 340, effect: 'All production +25%', type: 'global', value: 1.25 },
      { id: 'prod2', name: 'Astral Efficiency', cost: 5200, effect: 'All production +40%', type: 'global', value: 1.40 },
      { id: 'prod3', name: 'Celestial Cascade', cost: 78000, effect: 'All production +60%', type: 'global', value: 1.60 },
      { id: 'prod4', name: 'Infinite Bloom', cost: 1450000, effect: 'All production +100%', type: 'global', value: 2.0 },
      
      { id: 'shard1', name: 'Purer Shards', cost: 280, effect: 'Shards ×2.2', type: 'gen', target: 'shard', value: 2.2 },
      { id: 'cond1', name: 'Resonant Flux', cost: 1650, effect: 'Condensers ×2.4', type: 'gen', target: 'condenser', value: 2.4 },
      { id: 'void1', name: 'Deeper Wells', cost: 18500, effect: 'Void Taps ×2.5', type: 'gen', target: 'voidtap', value: 2.5 },
      { id: 'cruc1', name: 'Stellar Fury', cost: 260000, effect: 'Star Crucibles ×2.6', type: 'gen', target: 'crucible', value: 2.6 },
      { id: 'neb1', name: 'Loom Mastery', cost: 3100000, effect: 'Nebula Looms ×3.0', type: 'gen', target: 'nebula', value: 3.0 },
      { id: 'sing1', name: 'Event Horizon', cost: 72000000, effect: 'Singularity Anchors ×3.5', type: 'gen', target: 'singularity', value: 3.5 },
      
      { id: 'final1', name: 'Breath of the Infinite', cost: 880000, effect: 'All production +80%', type: 'global', value: 1.8 },
      { id: 'final2', name: 'One With The Void', cost: 12500000, effect: 'All production +120%', type: 'global', value: 2.2 },
    ];

    // ==================== ACHIEVEMENTS ====================
    const achievementsList = [
      { id: 'first', name: 'First Touch', desc: 'Click the Core once', check: () => state.totalClicks >= 1 },
      { id: 'hundred', name: 'Hundredfold', desc: 'Click the Core 100 times', check: () => state.totalClicks >= 100 },
      { id: 'thousand', name: 'Thousand Echoes', desc: 'Click the Core 1,000 times', check: () => state.totalClicks >= 1000 },
      { id: 'a1k', name: 'A Thousand Sparks', desc: 'Earn 1,000 total Aether', check: () => state.totalAetherEarned >= 1000 },
      { id: 'a1m', name: 'A Million Breaths', desc: 'Earn 1 million total Aether', check: () => state.totalAetherEarned >= 1e6 },
      { id: 'a1b', name: 'Cosmic Scale', desc: 'Earn 1 billion total Aether', check: () => state.totalAetherEarned >= 1e9 },
      { id: 'shard10', name: 'Shard Collector', desc: 'Own 10 Aether Shards', check: () => (state.generators.shard?.owned || 0) >= 10 },
      { id: 'sing1', name: 'Reality Anchor', desc: 'Build your first Singularity Anchor', check: () => (state.generators.singularity?.owned || 0) >= 1 },
      { id: 'trans1', name: 'First Transcendence', desc: 'Transcend once', check: () => state.transcendences >= 1 },
      { id: 'trans5', name: 'Eternal Walker', desc: 'Transcend 5 times', check: () => state.transcendences >= 5 },
    ];

    // ==================== UTILITIES ====================
    function formatNumber(n) {
      if (n < 1000) return n.toFixed(n < 10 ? 2 : 1).replace(/\.?0+$/, '');
      
      const suffixes = ['', 'K', 'M', 'B', 'T', 'Qa', 'Qi', 'Sx', 'Sp', 'Oc', 'No', 'Dc'];
      let tier = 0;
      let value = n;
      
      while (value >= 1000 && tier < suffixes.length - 1) {
        value /= 1000;
        tier++;
      }
      
      if (tier === 0) return Math.floor(n).toString();
      
      const fixed = value < 10 ? 2 : value < 100 ? 1 : 0;
      return value.toFixed(fixed).replace(/\.?0+$/, '') + suffixes[tier];
    }

    function getClickPower() {
      let power = 1;
      
      // Flat bonuses
      for (const upg of upgrades) {
        if (state.upgrades.has(upg.id) && upg.type === 'click') {
          power += upg.value;
        }
      }
      
      // Multipliers
      for (const upg of upgrades) {
        if (state.upgrades.has(upg.id) && upg.type === 'clickMulti') {
          power *= upg.value;
        }
      }
      
      return Math.floor(power);
    }

    function getGlobalMultiplier() {
      let multi = 1;
      
      // From upgrades
      for (const upg of upgrades) {
        if (state.upgrades.has(upg.id) && upg.type === 'global') {
          multi *= upg.value;
        }
      }
      
      // From astral shards (prestige)
      multi *= (1 + state.astralShards * 0.08); // 8% per shard
      
      return multi;
    }

    function getGeneratorProduction(genId) {
      const genDef = generators.find(g => g.id === genId);
      if (!genDef) return 0;
      
      const owned = state.generators[genId]?.owned || 0;
      if (owned === 0) return 0;
      
      let prod = genDef.baseProduction * owned;
      
      // Generator-specific upgrades
      for (const upg of upgrades) {
        if (state.upgrades.has(upg.id) && upg.type === 'gen' && upg.target === genId) {
          prod *= upg.value;
        }
      }
      
      prod *= getGlobalMultiplier();
      
      return prod;
    }

    function getTotalAps() {
      let total = 0;
      for (const g of generators) {
        total += getGeneratorProduction(g.id);
      }
      return total;
    }

    function getGeneratorCost(genId, count = 1) {
      const genDef = generators.find(g => g.id === genId);
      const currentOwned = state.generators[genId]?.owned || 0;
      
      let totalCost = 0;
      let nextCost = genDef.baseCost * Math.pow(1.14, currentOwned);
      
      for (let i = 0; i < count; i++) {
        totalCost += nextCost;
        nextCost *= 1.14;
      }
      
      return totalCost;
    }

    function getMaxAffordable(genId) {
      const genDef = generators.find(g => g.id === genId);
      let owned = state.generators[genId]?.owned || 0;
      let money = state.aether;
      let cost = genDef.baseCost * Math.pow(1.14, owned);
      let canBuy = 0;
      
      while (money >= cost && canBuy < 1000) {
        money -= cost;
        cost *= 1.14;
        canBuy++;
      }
      return canBuy;
    }

    function calculateAstralShards(totalEarned) {
      if (totalEarned < 1e6) return 0;
      // Logarithmic but satisfying: ~ every order of magnitude after 1M
      return Math.floor(Math.pow(totalEarned / 1e6, 0.42));
    }

    function getCurrentPrestigeBonus() {
      return 1 + state.astralShards * 0.08;
    }

    // ==================== PARTICLES & VISUALS ====================
    let particleCanvas, particleCtx;
    let particles = [];

    function initParticles() {
      particleCanvas = document.getElementById('particle-canvas');
      particleCtx = particleCanvas.getContext('2d', { alpha: true });
      
      // Make canvas cover the orb nicely
      particleCanvas.width = 400;
      particleCanvas.height = 400;
      
      // Click particles
      function createClickParticles(x, y, amount) {
        const count = Math.min(28, 8 + Math.floor(Math.log10(amount + 1) * 3));
        
        for (let i = 0; i < count; i++) {
          const angle = (Math.random() * Math.PI * 2) - Math.PI / 2 - 0.2;
          const speed = 1.8 + Math.random() * 3.4;
          
          particles.push({
            x: x + (Math.random() - 0.5) * 28,
            y: y + (Math.random() - 0.5) * 18,
            vx: Math.cos(angle) * speed,
            vy: Math.sin(angle) * speed - 1.6,
            life: 38 + Math.random() * 24,
            size: 2.5 + Math.random() * 3.2,
            hue: 260 + Math.random() * 60,
          });
        }
        
        // Bonus big central burst
        for (let i = 0; i < 5; i++) {
          particles.push({
            x: x + (Math.random() - 0.5) * 14,
            y: y + (Math.random() - 0.5) * 8,
            vx: (Math.random() - 0.5) * 1.6,
            vy: -2.8 - Math.random() * 2.5,
            life: 52,
            size: 4.5 + Math.random() * 1.8,
            hue: 265,
          });
        }
      }
      
      // Expose for click handler
      window.createClickParticles = createClickParticles;
      
      // Animation loop
      function animateParticles() {
        particleCtx.clearRect(0, 0, particleCanvas.width, particleCanvas.height);
        
        for (let i = particles.length - 1; i >= 0; i--) {
          const p = particles[i];
          p.x += p.vx;
          p.y += p.vy;
          p.vy += 0.055; // gentle gravity
          p.life -= 1;
          p.vx *= 0.985;
          
          if (p.life <= 0) {
            particles.splice(i, 1);
            continue;
          }
          
          const alpha = Math.max(0.05, p.life / 62);
          particleCtx.fillStyle = `hsla(${p.hue}, 92%, 86%, ${alpha})`;
          particleCtx.beginPath();
          particleCtx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
          particleCtx.fill();
          
          // soft glow
          if (p.size > 3) {
            particleCtx.fillStyle = `hsla(${p.hue}, 92%, 92%, ${alpha * 0.35})`;
            particleCtx.beginPath();
            particleCtx.arc(p.x, p.y, p.size * 1.9, 0, Math.PI * 2);
            particleCtx.fill();
          }
        }
        
        requestAnimationFrame(animateParticles);
      }
      
      animateParticles();
    }

    function spawnFloatingText(text, x, y) {
      const container = document.getElementById('orb-wrapper');
      const el = document.createElement('div');
      el.className = 'floating-text';
      el.textContent = text;
      
      // Position relative to orb wrapper
      const rect = container.getBoundingClientRect();
      el.style.left = `${x - rect.left + (Math.random() - 0.5) * 18}px`;
      el.style.top = `${y - rect.top}px`;
      
      container.appendChild(el);
      
      setTimeout(() => {
        el.remove();
      }, 950);
    }

    // Background starfield
    function initStarfield() {
      const starsEl = document.getElementById('stars');
      const canvas = document.createElement('canvas');
      canvas.style.position = 'absolute';
      canvas.style.inset = '0';
      canvas.style.width = '100%';
      canvas.style.height = '100%';
      starsEl.appendChild(canvas);
      
      const ctx = canvas.getContext('2d');
      let w, h, stars = [];
      
      function resize() {
        w = canvas.width = window.innerWidth;
        h = canvas.height = window.innerHeight;
        
        stars = [];
        const count = Math.floor((w * h) / 4200);
        for (let i = 0; i < count; i++) {
          stars.push({
            x: Math.random() * w,
            y: Math.random() * h,
            size: Math.random() * 1.6 + 0.3,
            speed: Math.random() * 0.018 + 0.004,
            alpha: Math.random() * 0.6 + 0.35,
          });
        }
      }
      
      window.addEventListener('resize', resize);
      resize();
      
      function draw() {
        ctx.clearRect(0, 0, w, h);
        
        for (const s of stars) {
          s.y += s.speed;
          if (s.y > h) {
            s.y = 0;
            s.x = Math.random() * w;
          }
          
          ctx.fillStyle = `rgba(226, 232, 240, ${s.alpha})`;
          ctx.fillRect(s.x, s.y, s.size, s.size);
          
          // occasional brighter stars
          if (s.size > 1.3) {
            ctx.fillStyle = `rgba(192, 167, 255, ${s.alpha * 0.4})`;
            ctx.fillRect(s.x - 0.5, s.y - 0.5, s.size + 1, s.size + 1);
          }
        }
        requestAnimationFrame(draw);
      }
      draw();
    }

    // ==================== RENDERING ====================
    let currentBuyMulti = 1;

    function renderAether() {
      document.getElementById('aether').textContent = formatNumber(state.aether);
      document.getElementById('total-harvested').textContent = formatNumber(state.totalAetherEarned);
    }

    function renderAps() {
      const aps = getTotalAps();
      document.getElementById('aps').textContent = formatNumber(aps);
      
      if (aps > state.peakAps) {
        state.peakAps = aps;
        document.getElementById('peak-aps').textContent = formatNumber(aps);
      }
      
      // Dynamic orb energy based on production rate (feels alive)
      const glow = document.querySelector('.orb-glow');
      if (glow) {
        const intensity = Math.min(1.6, Math.log10(aps + 1) * 0.32 + 0.35);
        glow.style.opacity = intensity.toFixed(2);
        glow.style.transform = `scale(${1 + Math.min(0.35, Math.log10(aps + 2) * 0.06)})`;
      }
    }

    function renderStats() {
      document.getElementById('total-clicks').textContent = state.totalClicks.toLocaleString();
      document.getElementById('peak-aps').textContent = formatNumber(state.peakAps);
      document.getElementById('transcendences').textContent = state.transcendences;
      
      const multi = getCurrentPrestigeBonus();
      document.getElementById('prestige-multi').textContent = multi.toFixed(2) + '×';
      document.getElementById('astral-power').textContent = '+' + Math.round((multi - 1) * 100) + '%';
      
      const minutes = Math.floor((Date.now() - state.startTime) / 60000);
      document.getElementById('time-played').textContent = minutes + 'm';
    }

    function renderGenerators() {
      const container = document.getElementById('generators');
      container.innerHTML = '';
      
      for (const def of generators) {
        const owned = state.generators[def.id]?.owned || 0;
        const production = getGeneratorProduction(def.id);
        const cost1 = getGeneratorCost(def.id, 1);
        
        let costText = formatNumber(cost1);
        let buyCount = currentBuyMulti;
        
        if (currentBuyMulti === 'max') {
          buyCount = getMaxAffordable(def.id);
          if (buyCount > 0) {
            costText = formatNumber(getGeneratorCost(def.id, buyCount));
          }
        } else {
          costText = formatNumber(getGeneratorCost(def.id, currentBuyMulti));
        }
        
        const canAfford = state.aether >= (currentBuyMulti === 'max' ? getGeneratorCost(def.id, buyCount || 1) : getGeneratorCost(def.id, currentBuyMulti));
        
        const el = document.createElement('div');
        el.className = `generator ${canAfford ? '' : 'cant-afford'}`;
        
        el.innerHTML = `
          <div class="gen-icon">${def.icon}</div>
          <div class="gen-info">
            <div class="gen-name">${def.name}</div>
            <div class="gen-desc">${def.desc}</div>
            <div class="gen-rate">+${formatNumber(production)}/s</div>
          </div>
          <div class="gen-stats">
            <div class="gen-owned">${owned}</div>
            <div class="gen-cost">${costText}</div>
          </div>
        `;
        
        el.addEventListener('click', () => {
          buyGenerator(def.id, currentBuyMulti);
        });
        
        container.appendChild(el);
      }
    }

    function renderUpgrades() {
      const container = document.getElementById('upgrades');
      container.innerHTML = '';
      
      let hasAny = false;
      
      for (const upg of upgrades) {
        if (state.upgrades.has(upg.id)) continue;
        
        // Only show upgrades the player can reasonably reach
        const canSee = state.totalAetherEarned >= upg.cost * 0.35;
        if (!canSee) continue;
        
        hasAny = true;
        
        const canAfford = state.aether >= upg.cost;
        
        const el = document.createElement('div');
        el.className = `upgrade ${canAfford ? '' : 'cant-afford'}`;
        
        el.innerHTML = `
          <div class="upgrade-name">${upg.name}</div>
          <div class="upgrade-effect">${upg.effect}</div>
          <div class="upgrade-cost">${formatNumber(upg.cost)}</div>
        `;
        
        if (canAfford) {
          el.addEventListener('click', () => buyUpgrade(upg.id));
        }
        
        container.appendChild(el);
      }
      
      if (!hasAny) {
        const empty = document.createElement('div');
        empty.className = 'empty-state';
        empty.textContent = 'New upgrades will appear as you grow stronger.';
        container.appendChild(empty);
      }
    }

    function renderAchievements() {
      const container = document.getElementById('achievements');
      container.innerHTML = '';
      
      for (const ach of achievementsList) {
        if (!state.achievements.has(ach.id)) continue;
        
        const el = document.createElement('div');
        el.className = 'achievement';
        el.innerHTML = `
          <span>★</span>
          <span>${ach.name}</span>
        `;
        el.title = ach.desc;
        container.appendChild(el);
      }
    }

    function renderPrestigeButton() {
      const btn = document.getElementById('prestige-btn');
      const gainEl = document.getElementById('prestige-gain');
      
      const shardsToGain = calculateAstralShards(state.totalAetherEarned);
      const nextShards = shardsToGain - state.astralShards;
      
      if (nextShards > 0) {
        btn.disabled = false;
        gainEl.textContent = `Transcend to gain +${nextShards} Astral Shard${nextShards > 1 ? 's' : ''}`;
        gainEl.style.color = '#c0a7ff';
      } else {
        btn.disabled = true;
        const needed = Math.ceil(Math.pow((state.astralShards + 1) / 0.42, 1 / 0.42) * 1e6);
        gainEl.textContent = `Need ${formatNumber(needed)} total Aether to gain another shard`;
        gainEl.style.color = 'var(--text-muted)';
      }
    }

    function renderAll() {
      renderAether();
      renderAps();
      renderStats();
      renderGenerators();
      renderUpgrades();
      renderAchievements();
      renderPrestigeButton();
    }

    // ==================== GAME ACTIONS ====================
    function addAether(amount, fromClick = false) {
      state.aether += amount;
      state.totalAetherEarned += amount;
      
      // Floating text on the orb
      if (fromClick && amount > 0) {
        const wrapper = document.getElementById('orb-wrapper');
        const rect = wrapper.getBoundingClientRect();
        const centerX = rect.left + rect.width / 2;
        const centerY = rect.top + rect.height / 2;
        
        spawnFloatingText('+' + formatNumber(amount), centerX, centerY);
        
        // Trigger particles
        if (window.createClickParticles) {
          window.createClickParticles(200, 200, amount);
        }
      }
      
      checkAchievements();
      renderAll();
    }

    function buyGenerator(genId, multi) {
      const def = generators.find(g => g.id === genId);
      if (!def) return;
      
      const currentOwned = state.generators[genId]?.owned || 0;
      let buyAmount = multi;
      
      if (multi === 'max') {
        buyAmount = getMaxAffordable(genId);
      }
      
      if (buyAmount < 1) return;
      
      const cost = getGeneratorCost(genId, buyAmount);
      if (state.aether < cost) return;
      
      state.aether -= cost;
      
      if (!state.generators[genId]) {
        state.generators[genId] = { owned: 0 };
      }
      state.generators[genId].owned += buyAmount;
      
      // Small satisfying particle pop on generator
      const genEls = document.querySelectorAll('#generators .generator');
      // We could do more advanced targeting but this is fine for now
      
      checkAchievements();
      renderAll();
    }

    function buyUpgrade(upgId) {
      const upg = upgrades.find(u => u.id === upgId);
      if (!upg || state.upgrades.has(upgId)) return;
      if (state.aether < upg.cost) return;
      
      state.aether -= upg.cost;
      state.upgrades.add(upgId);
      
      // Nice visual feedback
      const toast = createToast('Upgrade Acquired', upg.name + ' — ' + upg.effect);
      
      checkAchievements();
      renderAll();
    }

    function transcend() {
      const shardsToGain = calculateAstralShards(state.totalAetherEarned);
      if (shardsToGain <= state.astralShards) return;
      
      const gained = shardsToGain - state.astralShards;
      
      // Perform the prestige
      state.astralShards = shardsToGain;
      state.transcendences += 1;
      
      // Reset most progress
      state.aether = 0;
      state.generators = {};
      for (const g of generators) {
        state.generators[g.id] = { owned: 0 };
      }
      state.upgrades = new Set();
      
      // Keep totalAetherEarned and totalClicks for achievements and history
      // (this feels good — your legacy remains visible)
      
      createToast('Transcended', `You gained ${gained} Astral Shard${gained > 1 ? 's' : ''}. Reality is yours to reshape.`, true);
      
      renderAll();
      saveGame();
    }

    // ==================== ACHIEVEMENTS ====================
    function checkAchievements() {
      let unlocked = false;
      
      for (const ach of achievementsList) {
        if (state.achievements.has(ach.id)) continue;
        
        if (ach.check()) {
          state.achievements.add(ach.id);
          unlocked = true;
          createToast('Achievement Unlocked', ach.name + ' — ' + ach.desc);
        }
      }
      
      if (unlocked) {
        renderAchievements();
      }
    }

    // ==================== TOASTS ====================
    function createToast(title, desc, isBig = false) {
      const container = document.getElementById('toast-container');
      const toast = document.createElement('div');
      toast.className = 'toast';
      if (isBig) toast.style.borderLeftColor = '#c0a7ff';
      
      toast.innerHTML = `
        <div class="toast-title">${title}</div>
        <div class="toast-desc">${desc}</div>
      `;
      
      container.appendChild(toast);
      
      setTimeout(() => {
        toast.style.transition = 'all 0.25s ease';
        toast.style.opacity = '0';
        toast.style.transform = 'translateY(8px)';
        
        setTimeout(() => toast.remove(), 200);
      }, isBig ? 5200 : 3400);
      
      return toast;
    }

    // ==================== GAME LOOP ====================
    let gameLoopInterval = null;

    function gameTick() {
      const now = Date.now();
      const delta = (now - state.lastTick) / 1000;
      state.lastTick = now;
      
      // Production
      const production = getTotalAps() * delta;
      if (production > 0) {
        state.aether += production;
        state.totalAetherEarned += production;
      }
      
      // Update UI at a reasonable rate (not every single frame)
      if (Math.random() < 0.4) {
        renderAether();
        renderAps();
        renderGenerators();
        renderUpgrades();
        renderPrestigeButton();
      }
      
      // Occasional full render + save
      if (Math.random() < 0.035) {
        renderStats();
        saveGame();
      }
      
      // Auto-check achievements
      checkAchievements();
    }

    function startGameLoop() {
      if (gameLoopInterval) clearInterval(gameLoopInterval);
      gameLoopInterval = setInterval(gameTick, 110);
    }

    // ==================== CLICK HANDLING ====================
    let audioCtx;
    function playClickSound(power) {
      try {
        if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();
        const osc = audioCtx.createOscillator();
        const gain = audioCtx.createGain();
        const filter = audioCtx.createBiquadFilter();
        
        osc.type = 'sine';
        osc.frequency.value = 680 + Math.min(420, power * 1.6);
        
        filter.type = 'lowpass';
        filter.frequency.value = 1400;
        
        gain.gain.value = Math.min(0.22, 0.07 + power * 0.0015);
        
        const decay = audioCtx.createGain();
        decay.gain.value = 1;
        
        const now = audioCtx.currentTime;
        decay.gain.setValueAtTime(1, now);
        decay.gain.linearRampToValueAtTime(0.0001, now + 0.38);
        
        osc.connect(filter);
        filter.connect(gain);
        gain.connect(decay);
        decay.connect(audioCtx.destination);
        
        osc.start(now);
        osc.stop(now + 0.45);
      } catch (_) {}
    }

    function setupClicking() {
      const orb = document.getElementById('orb');
      const wrapper = document.getElementById('orb-wrapper');
      
      function handleClick(e) {
        const power = getClickPower();
        addAether(power, true);
        
        playClickSound(power);
        
        state.totalClicks += 1;
        
        // Click feedback
        orb.style.transform = 'scale(0.92)';
        setTimeout(() => {
          if (orb) orb.style.transform = '';
        }, 70);
        
        // Floating text at click position
        const rect = wrapper.getBoundingClientRect();
        spawnFloatingText('+' + formatNumber(power), e.clientX, e.clientY);
        
        // Particles at orb center
        if (window.createClickParticles) {
          window.createClickParticles(200, 200, power);
        }
        
        // Update stats occasionally
        if (state.totalClicks % 7 === 0) {
          renderStats();
        }
        
        checkAchievements();
      }
      
      orb.addEventListener('click', handleClick);
      orb.addEventListener('mousedown', () => {
        orb.style.boxShadow = `
          0 0 0 8px rgba(124, 58, 237, 0.2),
          0 0 0 18px rgba(124, 58, 237, 0.1),
          0 10px 30px -8px rgba(0, 0, 0, 0.4),
          inset 0 2px 10px rgba(255,255,255,0.25),
          inset -20px -20px 30px rgba(0,0,0,0.55)
        `;
      });
      window.addEventListener('mouseup', () => {
        if (orb) {
          orb.style.boxShadow = `
            0 0 0 12px rgba(124, 58, 237, 0.15),
            0 0 0 28px rgba(124, 58, 237, 0.08),
            0 25px 70px -15px rgba(0, 0, 0, 0.6),
            inset 0 4px 20px rgba(255,255,255,0.35),
            inset 40px 40px 60px rgba(255,255,255,0.12),
            inset -30px -30px 50px rgba(0,0,0,0.5)
          `;
        }
      });
      
      // Keyboard support (space or enter while focused)
      orb.setAttribute('tabindex', '0');
      orb.addEventListener('keydown', (e) => {
        if (e.key === ' ' || e.key === 'Enter') {
          e.preventDefault();
          const rect = orb.getBoundingClientRect();
          handleClick({ clientX: rect.left + rect.width / 2, clientY: rect.top + rect.height / 2 });
        }
      });
    }

    // ==================== BUY MULTIPLIER ====================
    function setupBuyMultipliers() {
      const buttons = document.querySelectorAll('.buy-btn');
      
      buttons.forEach(btn => {
        btn.addEventListener('click', () => {
          buttons.forEach(b => b.classList.remove('active'));
          btn.classList.add('active');
          
          const val = btn.dataset.multi;
          currentBuyMulti = val === 'max' ? 'max' : parseInt(val, 10);
          
          renderGenerators();
        });
      });
    }

    // ==================== PRESTIGE ====================
    function setupPrestige() {
      const btn = document.getElementById('prestige-btn');
      btn.addEventListener('click', () => {
        if (!btn.disabled) {
          if (confirm('Transcend now? All generators and upgrades will reset, but you will gain permanent Astral Power.')) {
            transcend();
          }
        }
      });
    }

    // ==================== SAVE / LOAD ====================
    const SAVE_KEY = 'aether_save_v1';

    function saveGame() {
      const saveData = {
        ...state,
        upgrades: Array.from(state.upgrades),
        achievements: Array.from(state.achievements),
        lastSave: Date.now(),
      };
      localStorage.setItem(SAVE_KEY, JSON.stringify(saveData));
    }

    function loadGame() {
      const raw = localStorage.getItem(SAVE_KEY);
      if (!raw) return false;
      
      try {
        const saved = JSON.parse(raw);
        
        // Merge into state
        Object.assign(state, saved);
        
        // Reconstruct sets
        state.upgrades = new Set(saved.upgrades || []);
        state.achievements = new Set(saved.achievements || []);
        
        // Restore generators properly
        state.generators = saved.generators || {};
        
        // Handle offline progress
        const now = Date.now();
        const offlineSeconds = Math.min(60 * 60 * 6, Math.floor((now - (saved.lastSave || now)) / 1000));
        
        if (offlineSeconds > 8) {
          const offlineProduction = getTotalAps() * offlineSeconds * 0.35; // 35% offline efficiency
          if (offlineProduction > 1) {
            state.aether += offlineProduction;
            state.totalAetherEarned += offlineProduction;
            
            // Show offline banner
            const banner = document.getElementById('offline-banner');
            banner.textContent = `While you were away, you harvested ${formatNumber(offlineProduction)} Aether`;
            banner.classList.add('show');
            
            setTimeout(() => {
              banner.classList.remove('show');
            }, 6200);
          }
        }
        
        // Make sure startTime makes sense
        if (!state.startTime || state.startTime > now) {
          state.startTime = now - 1000 * 60 * 12;
        }
        
        state.lastTick = now;
        return true;
      } catch (e) {
        console.warn('Failed to load save:', e);
        return false;
      }
    }

    function setupAutoSave() {
      setInterval(() => {
        saveGame();
      }, 1000 * 22);
      
      // Save on page hide / before unload
      window.addEventListener('beforeunload', saveGame);
      document.addEventListener('visibilitychange', () => {
        if (document.visibilityState === 'hidden') {
          saveGame();
        }
      });
    }

    // ==================== INITIALIZATION ====================
    function init() {
      // Load previous save if exists
      const hadSave = loadGame();
      
      // Initialize particle system
      initParticles();
      initStarfield();
      
      // Initial generators state if new game
      for (const g of generators) {
        if (!state.generators[g.id]) {
          state.generators[g.id] = { owned: 0 };
        }
      }
      
      // If it's a brand new game, give a nice little starting gift
      if (!hadSave) {
        state.aether = 24;
        state.totalAetherEarned = 24;
        state.startTime = Date.now();
      }
      
      // Wire up interactions
      setupClicking();
      setupBuyMultipliers();
      setupPrestige();
      setupAutoSave();
      
      // First render
      renderAll();
      
      // Start production
      startGameLoop();
      
      // Gentle initial hint
      if (!hadSave) {
        setTimeout(() => {
          const hint = document.createElement('div');
          hint.style.cssText = 'position:absolute; bottom:-34px; left:50%; transform:translateX(-50%); font-size:11px; color:#64748b; white-space:nowrap; pointer-events:none;';
          hint.textContent = 'Click the glowing core';
          document.getElementById('orb-wrapper').appendChild(hint);
          
          setTimeout(() => hint.remove(), 2600);
        }, 1800);
      }
      
      // Easter egg: konami code gives a burst of aether
      let konami = '';
      const code = 'ArrowUpArrowUpArrowDownArrowDownArrowLeftArrowRightArrowLeftArrowRightba';
      document.addEventListener('keydown', (e) => {
        konami += e.key;
        if (konami.length > code.length) konami = konami.slice(-code.length);
        if (konami === code) {
          konami = '';
          const burst = Math.max(500, state.aether * 0.07);
          addAether(burst, true);
          createToast('Secret', 'The universe smiles upon you.');
        }
      });
      
      // Dev helper: type "aetherdebug" to give big resources
      let debugBuffer = '';
      document.addEventListener('keypress', (e) => {
        debugBuffer += e.key;
        if (debugBuffer.length > 12) debugBuffer = debugBuffer.slice(-12);
        if (debugBuffer.includes('aetherdebug')) {
          debugBuffer = '';
          state.aether += 1e7;
          state.totalAetherEarned += 1e7;
          renderAll();
          createToast('Debug', 'Added 10 million Aether');
        }
      });
      
      // Make it feel alive — subtle random glow pulses on the orb
      const orb = document.getElementById('orb');
      setInterval(() => {
        if (!orb || document.hidden) return;
        const intensity = 0.6 + Math.random() * 0.7;
        orb.style.boxShadow = `
          0 0 0 12px rgba(124, 58, 237, ${0.12 * intensity}),
          0 0 0 28px rgba(124, 58, 237, ${0.06 * intensity}),
          0 25px 70px -15px rgba(0, 0, 0, 0.6),
          inset 0 4px 20px rgba(255,255,255,0.35),
          inset 40px 40px 60px rgba(255,255,255,0.12),
          inset -30px -30px 50px rgba(0,0,0,0.5)
        `;
        setTimeout(() => {
          if (orb) {
            orb.style.boxShadow = `
              0 0 0 12px rgba(124, 58, 237, 0.15),
              0 0 0 28px rgba(124, 58, 237, 0.08),
              0 25px 70px -15px rgba(0, 0, 0, 0.6),
              inset 0 4px 20px rgba(255,255,255,0.35),
              inset 40px 40px 60px rgba(255,255,255,0.12),
              inset -30px -30px 50px rgba(0,0,0,0.5)
            `;
          }
        }, 420);
      }, 12500);
      
      // Welcome message for new players
      if (!hadSave) {
        setTimeout(() => {
          // No intrusive toast on first load — the game speaks for itself
        }, 800);
      } else {
        // Returning player
        setTimeout(() => {
          if (state.transcendences > 0) {
            // subtle welcome back
          }
        }, 1200);
      }
      
      // Expose a tiny bit for fun / debugging in console (not necessary for players)
      window.AETHER = { state, save: saveGame, transcend: () => transcend() };
    }

    // Boot the game
    init();
  </script>
</body>
</html>