🎮ArcadeLab

DUEL MASTERS

by FrostCobra30
2154 lines105.1 KB
▶ Play
import { useState, useEffect, useRef } from "react";

// ============================================================
// ELEMENT SYSTEM
// ============================================================
const ELEMENT_CYCLE = {
  fire:      { beats: "ice",       weakTo: "water",     icon: "🔥", color: "#e74c3c" },
  ice:       { beats: "water",     weakTo: "fire",      icon: "❄️", color: "#3498db" },
  water:     { beats: "lightning", weakTo: "ice",       icon: "💧", color: "#1abc9c" },
  lightning: { beats: "earth",     weakTo: "water",     icon: "⚡", color: "#f39c12" },
  earth:     { beats: "wind",      weakTo: "lightning", icon: "🌍", color: "#8b4513" },
  wind:      { beats: "fire",      weakTo: "earth",     icon: "🌪️", color: "#7f8c8d" },
  light:     { beats: "dark",      weakTo: "dark",      icon: "✨", color: "#f1c40f" },
  dark:      { beats: "light",     weakTo: "light",     icon: "🌑", color: "#8e44ad" }
};

// ============================================================
// GENERATE 1000 CARDS
// ============================================================
const CREATURE_TEMPLATES = {
  fire: ["Emberclaw", "Pyroclast", "Ashwing", "Flamebound", "Infernal", "Scorchwyrm", "Cinder", "Blaze", "Magmafist", "Burnheart", "Searing", "Flamebeast", "Lavaborn", "Pyreking", "Cinderhorn", "Charred", "Heatwave", "Molten", "Wildfire", "Firestorm"],
  ice: ["Frostbite", "Glacius", "Hoarfrost", "Icebound", "Permafrost", "Snowfall", "Crystalix", "Winterclaw", "Frostveil", "Coldsnap", "Icicle", "Blizzard", "Frostguard", "Glacial", "Rimefrost", "Chillborn", "Arcticus", "Snowdrift", "Frostfang", "Iceheart"],
  water: ["Tidecaller", "Deepwarden", "Coralborn", "Stormwake", "Abyssal", "Wavecrest", "Kelphook", "Maelstrom", "Aquarius", "Seafoam", "Torrent", "Whirlpool", "Oceanborn", "Depthstalker", "Riptide", "Seabeast", "Current", "Mariner", "Saltborn", "Deepsea"],
  lightning: ["Voltspine", "Stormborn", "Thunderclaw", "Shockwave", "Arclash", "Strikeborn", "Ionflux", "Staticbane", "Voltaic", "Tempest", "Boltborn", "Sparkfang", "Thunderborn", "Surgecoil", "Electrus", "Shockfist", "Stormchaser", "Ionborn", "Chargemaster", "Arcflash"],
  earth: ["Stoneheart", "Quartzback", "Terrabane", "Cliffborn", "Boulderfist", "Gravelord", "Ironveil", "Cragborn", "Rockfist", "Earthshaker", "Granite", "Gemborn", "Mountainborn", "Cliffjaw", "Stonewall", "Dirtborn", "Quakehoof", "Stoneborn", "Earthling", "Crystalback"],
  wind: ["Tempest", "Zephyrwing", "Galeforce", "Skydancer", "Cyclone", "Breezeborn", "Whirlwind", "Draftmaw", "Stormrider", "Airborn", "Gustwing", "Typhoon", "Skyborn", "Windrider", "Breezehowl", "Vortex", "Galebeast", "Windborn", "Hurricane", "Squall"],
  light: ["Radiant", "Dawnbringer", "Luminary", "Solaris", "Holyflame", "Starborn", "Prismatic", "Lightbane", "Celestial", "Sunborn", "Divineray", "Glowborn", "Lux", "Holylight", "Shimmer", "Brightborn", "Aurora", "Daylord", "Holybeam", "Starlight"],
  dark: ["Shadowmaw", "Voidcaller", "Duskborn", "Nightshade", "Abyssal", "Grimveil", "Eclipseborn", "Netherbane", "Darkborn", "Voidfang", "Nightborn", "Shadowclaw", "Duskfang", "Nightmaw", "Darkflux", "Obsidian", "Midnight", "Gloomborn", "Shadowborn", "Darkveil"]
};

const DESCRIPTORS = ["fearsome beast wielding", "ancient creature of pure", "powerful entity commanding", "mystical being born from", "legendary monster channeling", "fierce predator infused with"];

function generateMonsters() {
  const monsters = [];
  let id = 1;
  const elements = Object.keys(ELEMENT_CYCLE);
  
  for (let i = 0; i < 750; i++) {
    const element = elements[i % elements.length];
    const templates = CREATURE_TEMPLATES[element];
    const name = templates[Math.floor(Math.random() * templates.length)];
    const descriptor = DESCRIPTORS[Math.floor(Math.random() * DESCRIPTORS.length)];
    const stars = Math.floor(i / 75) + 1;
    
    monsters.push({
      id: id++,
      cardNumber: `SH-${String(id).padStart(3, '0')}`,
      name,
      type: "monster",
      stars,
      atk: 100 + stars * 200 + Math.floor(Math.random() * 300),
      def: 80 + stars * 150 + Math.floor(Math.random() * 250),
      hp: 300 + stars * 250 + Math.floor(Math.random() * 400),
      rarity: stars <= 2 ? "common" : stars <= 4 ? "uncommon" : stars <= 7 ? "rare" : "super_rare",
      element,
      desc: `${descriptor} ${element} energy`,
      effect: Math.random() < 0.25 ? { desc: `On summon: Deal ${stars * 50} damage to opponent`, trigger:"onSummon", type:"directDamage", value: stars * 50 } : null,
      sacrifices: stars >= 10 ? 2 : stars >= 5 ? 1 : 0
    });
  }
  return monsters;
}

function generateMagicCards() {
  const spells = [
    { name: "Soul Revival", desc: "Powerful resurrection spell", effect: "Special Summon 1 monster from your Graveyard" },
    { name: "Heavenstrike", desc: "Divine judgment from above", effect: "Deal 800 damage to target creature" },
    { name: "Battle Surge", desc: "Primal strength enhancement", effect: "Target creature gains +600 ATK this turn" },
    { name: "Iron Bastion", desc: "Impenetrable defenses", effect: "Target creature gains +700 DEF this turn" },
    { name: "Mending Draught", desc: "Healing elixir", effect: "Restore 1000 HP to yourself" },
    { name: "Scroll of Fortune", desc: "Ancient knowledge", effect: "Draw 2 cards from your deck" },
    { name: "Fireball", desc: "Explosive flame", effect: "Deal 600 damage to target" },
    { name: "Lightning Bolt", desc: "Crackling electricity", effect: "Deal 700 damage and stun target" }
  ];
  
  const magicCards = [];
  for (let i = 0; i < 200; i++) {
    const spell = spells[i % spells.length];
    magicCards.push({
      id: 1000 + i,
      cardNumber: `SH-M${String(i+1).padStart(3, '0')}`,
      name: spell.name,
      type: "magic",
      rarity: i < 50 ? "common" : i < 120 ? "uncommon" : i < 180 ? "rare" : "super_rare",
      desc: spell.desc,
      effectDesc: spell.effect
    });
  }
  return magicCards;
}

function generateTrapCards() {
  const traps = [
    { name: "Mirror Force", desc: "Reflective barrier", effect: "When attacked: Destroy all opponent's Attack Position monsters" },
    { name: "Trap Hole", desc: "Hidden pitfall", effect: "When opponent summons (1000+ ATK): Destroy that monster" },
    { name: "Magic Cylinder", desc: "Redirect damage", effect: "When attacked: Negate attack and deal attacker's ATK as damage" },
    { name: "Sakuretsu Armor", desc: "Explosive counter", effect: "When attacked: Destroy the attacking monster" }
  ];
  
  const trapCards = [];
  for (let i = 0; i < 50; i++) {
    const trap = traps[i % traps.length];
    trapCards.push({
      id: 2000 + i,
      cardNumber: `SH-T${String(i+1).padStart(3, '0')}`,
      name: trap.name,
      type: "trap",
      rarity: i < 20 ? "common" : i < 35 ? "uncommon" : i < 45 ? "rare" : "super_rare",
      desc: trap.desc,
      effectDesc: trap.effect
    });
  }
  return trapCards;
}

const MONSTERS = generateMonsters();
const MAGIC_CARDS = generateMagicCards();
const TRAP_CARDS = generateTrapCards();
const ALL_CARDS = [...MONSTERS, ...MAGIC_CARDS, ...TRAP_CARDS];

// ============================================================
// REFRESHED STORY EVENTS
// ============================================================
const STORY_EVENTS = [
  { id:"e1", text:"A mysterious merchant spreads his wares before you. 'These cards hold power beyond measure,' he whispers. 'But power always comes with a price...'", options:["Examine his cards →","Ask about his past →","Walk away suspicious →","Negotiate prices →"] },
  { id:"e2", text:"Thunder rumbles overhead as a cloaked figure challenges you. 'Your reputation precedes you, duelist. Let's see if you're worthy of it.'", options:["Accept the duel →","Question their motives →","Propose a wager →","Decline politely →"] },
  { id:"e3", text:"You discover an ancient shrine dedicated to forgotten duel monsters. Strange energy emanates from within, calling to you.", options:["Enter the shrine →","Study the inscriptions →","Leave offerings →","Turn back →"] },
  { id:"e4", text:"A grand tournament is announced! The Shadow Realm Championship promises glory, gold, and a legendary prize card to the victor.", options:["Register for tournament →","Scout other duelists →","Train your deck →","Gather information →"], triggerTournament: true },
  { id:"e5", text:"A wounded duelist stumbles toward you. 'Please... take my deck... don't let them fall into the wrong hands...' They collapse before you can ask more.", options:["Help them immediately →","Examine the deck →","Search for pursuers →","Call for healers →"] },
  { id:"e6", text:"You overhear rumors of a secret underground dueling ring where rare cards exchange hands. The entrance is hidden, but you know someone who knows the way.", options:["Seek the entrance →","Ask your contact →","Investigate cautiously →","Report to authorities →"] },
];

// ============================================================
// UTILITIES
// ============================================================
const RARITY_COLORS = { common:"#888", uncommon:"#4caf50", rare:"#2196f3", super_rare:"#ff9800", legendary:"#ff00ff" };
const SAVE_KEY = "duel_masters_v1";

function saveGame(s) { try { localStorage.setItem(SAVE_KEY, JSON.stringify(s)); } catch(e){} }
function loadGame() { try { const s = localStorage.getItem(SAVE_KEY); return s ? JSON.parse(s) : null; } catch(e){ return null; } }
function shuffle(arr) { const a=[...arr]; for(let i=a.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1));[a[i],a[j]]=[a[j],a[i]];} return a; }
function deepClone(o) { return JSON.parse(JSON.stringify(o)); }
function getCardKey(c) { return `${c.id}_${c.cardNumber}`; }

function getCardQuantities(collection) {
  const counts = {};
  collection.forEach(card => {
    const key = getCardKey(card);
    counts[key] = (counts[key] || 0) + 1;
  });
  return counts;
}

function countCardInDeck(deck, card) {
  const key = getCardKey(card);
  return deck.filter(c => getCardKey(c) === key).length;
}

function buildStarterDeck() {
  return [
    ...shuffle(MONSTERS.filter(m => m.stars <= 2 && m.rarity === "common")).slice(0,15),
    ...shuffle(MAGIC_CARDS.filter(m => m.rarity === "common")).slice(0,6),
    ...shuffle(TRAP_CARDS.filter(t => t.rarity === "common")).slice(0,4)
  ];
}

// ============================================================
// CARD DISPLAY WITH HOVER
// ============================================================
function CardDisplay({ card, onClick, selected, small, quantity, inDeckCount, notOwned, showHoverPreview, isNew }) {
  const [hovered, setHovered] = useState(false);
  if (!card) return null;
  
  const elInfo = card.element ? ELEMENT_CYCLE[card.element] : null;
  const w = small ? 80 : 120, h = small ? 112 : 168;
  const typeColor = card.type==="monster" ? (elInfo?.color||"#666") : card.type==="magic" ? "#4a90e2" : "#c0392b";
  
  return (
    <div 
      onMouseEnter={() => showHoverPreview && setHovered(true)}
      onMouseLeave={() => setHovered(false)}
      style={{ position: "relative", display: "inline-block" }}
    >
      <div onClick={onClick} style={{
        width:w, height:h, background: notOwned ? "#111" : "#1a1a1a",
        border:`2px solid ${selected?"#ffd700":typeColor}`, borderRadius:8,
        cursor:onClick?"pointer":"default", display:"flex",flexDirection:"column",
        position:"relative", opacity: notOwned ? 0.3 : 1,
        boxShadow: selected?`0 0 20px #ffd70099`:`0 2px 8px rgba(0,0,0,0.5)`,
        flexShrink:0,
        transition: "all 0.3s ease, transform 0.2s ease",
        transform: selected ? "translateY(-5px)" : "translateY(0)"
      }}>
        <div style={{ background:typeColor, padding:small?"3px 6px":"4px 8px", display:"flex", justifyContent:"space-between" }}>
          <span style={{ fontSize:small?5:7, color:"#fff", fontWeight:700, fontFamily:"monospace" }}>{card.cardNumber}</span>
          {card.type==="monster" && <span style={{ fontSize:small?7:9, color:"#ffd700" }}>{"★".repeat(Math.min(card.stars,5))}</span>}
        </div>
        
        <div style={{ padding:small?"4px 5px":"5px 8px", borderBottom:`1px solid ${typeColor}33` }}>
          <div style={{ fontSize:small?7:9, color:"#fff", fontWeight:700, textAlign:"center", lineHeight:1.2 }}>{card.name}</div>
        </div>
        
        <div style={{ fontSize:small?18:28, textAlign:"center", padding:small?"4px 0":"6px 0", lineHeight:1 }}>
          {card.type==="monster"?"🌙":card.type==="magic"?"✨":"⚡"}
        </div>
        
        {card.type==="monster" && (
          <div style={{ display:"flex", justifyContent:"space-around", padding:small?"2px":"3px 6px", background:"rgba(0,0,0,0.3)", borderTop:"1px solid rgba(255,255,255,0.1)" }}>
            {[["ATK",card.atk],["DEF",card.def],["HP",card.hp]].map(([lbl,val])=>(
              <div key={lbl} style={{ textAlign:"center" }}>
                <div style={{ fontSize:small?4:5, color:"#888" }}>{lbl}</div>
                <div style={{ fontSize:small?8:10, color:lbl==="HP"?"#2ecc71":"#fff", fontWeight:700 }}>{val}</div>
              </div>
            ))}
          </div>
        )}
        
        {!small && (
          <div style={{ padding:"4px 6px", fontSize:6, flex:1, overflow:"hidden", lineHeight:1.3 }}>
            {card.type==="monster" ? (
              <>
                {elInfo && <span style={{ fontSize:8, marginRight:3 }}>{elInfo.icon}</span>}
                {card.effect ? <span style={{ color:"#f1c40f" }}>{card.effect.desc}</span> : <span style={{ color:"#aaa" }}>{card.desc}</span>}
              </>
            ) : (
              <span style={{ color:"#aaa" }}>{card.effectDesc || card.desc}</span>
            )}
          </div>
        )}
        
        <div style={{ background:"rgba(0,0,0,0.5)", padding:small?"2px 4px":"3px 6px", display:"flex", justifyContent:"space-between", borderTop:"1px solid rgba(255,255,255,0.1)" }}>
          <span style={{ fontSize:small?4:6, color:RARITY_COLORS[card.rarity], fontWeight:700, textTransform:"uppercase" }}>{card.rarity?.replace("_"," ")}</span>
          {elInfo && <span style={{ fontSize:small?4:6, color:elInfo.color, fontWeight:700, textTransform:"uppercase" }}>{card.element}</span>}
        </div>
        
        {quantity > 1 && <div style={{ position:"absolute", top:4, left:4, background:"rgba(0,0,0,0.95)", border:"2px solid #f39c12", padding:"4px 8px", borderRadius:6, fontSize:small?9:12, color:"#f1c40f", fontWeight:700, boxShadow:"0 2px 8px rgba(0,0,0,0.6)", zIndex:10 }}>×{quantity}</div>}
        {inDeckCount > 0 && <div style={{ position:"absolute", top:4, right:4, background:"rgba(155,89,182,0.95)", border:"2px solid #9b59b6", padding:"4px 8px", borderRadius:6, fontSize:small?9:12, color:"#fff", fontWeight:700, boxShadow:"0 2px 8px rgba(0,0,0,0.6)", zIndex:10 }}>📋 {inDeckCount}</div>}
        {isNew && <div className="bounce" style={{ position:"absolute", top:small?-8:-12, right:small?-8:-12, background:"#f39c12", border:"2px solid #fff", padding:"4px 8px", borderRadius:12, fontSize:small?8:10, color:"#000", fontWeight:900, boxShadow:"0 3px 12px rgba(243,156,18,0.8)", zIndex:20, transform:"rotate(15deg)" }}>*NEW*</div>}
        {notOwned && <div style={{ position:"absolute", inset:0, background:"rgba(0,0,0,0.7)", borderRadius:8, display:"flex",alignItems:"center",justifyContent:"center", fontSize:small?16:24 }}>🔒</div>}
      </div>
      
      {hovered && showHoverPreview && !selected && (
        <div style={{ position: "fixed", left: "50%", top: "50%", transform: "translate(-50%, -50%)", zIndex: 10000, pointerEvents: "none" }}>
          <EnlargedCard card={card} />
        </div>
      )}
    </div>
  );
}

function EnlargedCard({ card }) {
  const elInfo = card.element ? ELEMENT_CYCLE[card.element] : null;
  const typeColor = card.type==="monster" ? (elInfo?.color||"#666") : card.type==="magic" ? "#4a90e2" : "#c0392b";
  
  return (
    <div style={{ width: 300, height: 420, background: "#1a1a1a", border: `4px solid ${typeColor}`, borderRadius: 16, boxShadow: "0 8px 32px rgba(0,0,0,0.8)", display: "flex", flexDirection: "column", overflow: "hidden" }}>
      <div style={{ background: typeColor, padding: "12px", display: "flex", justifyContent: "space-between" }}>
        <span style={{ fontSize: 14, color: "#fff", fontWeight: 700, fontFamily: "monospace" }}>{card.cardNumber}</span>
        {card.type === "monster" && <span style={{ fontSize: 18, color: "#ffd700" }}>{"★".repeat(Math.min(card.stars, 5))}</span>}
      </div>
      <div style={{ padding: "16px", borderBottom: `2px solid ${typeColor}` }}>
        <div style={{ fontSize: 20, color: "#fff", fontWeight: 700, textAlign: "center", marginBottom: 8 }}>{card.name}</div>
        <div style={{ fontSize: 12, color: "#aaa", textAlign: "center" }}>{card.type.toUpperCase()}</div>
      </div>
      <div style={{ fontSize: 60, textAlign: "center", padding: "20px 0" }}>
        {card.type === "monster" ? "🌙" : card.type === "magic" ? "✨" : "⚡"}
      </div>
      {card.type === "monster" && (
        <div style={{ display: "flex", justifyContent: "space-around", padding: "12px", background: "rgba(0,0,0,0.3)", borderTop: "1px solid rgba(255,255,255,0.1)", borderBottom: "1px solid rgba(255,255,255,0.1)" }}>
          {[["ATK", card.atk], ["DEF", card.def], ["HP", card.hp]].map(([lbl, val]) => (
            <div key={lbl} style={{ textAlign: "center" }}>
              <div style={{ fontSize: 11, color: "#888", marginBottom: 4 }}>{lbl}</div>
              <div style={{ fontSize: 20, color: lbl === "HP" ? "#2ecc71" : "#fff", fontWeight: 700 }}>{val}</div>
            </div>
          ))}
        </div>
      )}
      <div style={{ padding: "16px", flex: 1, overflow: "auto" }}>
        {card.effect ? (
          <>
            <div style={{ fontSize: 12, color: "#f1c40f", fontWeight: 600, padding: "8px", background: "rgba(241,196,15,0.1)", borderRadius: 6, lineHeight: 1.6, marginBottom: 12 }}>
              <div style={{ color: "#f39c12", fontSize: 10, marginBottom: 4, textTransform: "uppercase", letterSpacing: 1 }}>⚡ CARD EFFECT:</div>
              {card.effect.desc}
            </div>
            <div style={{ fontSize: 10, color: "#666", lineHeight: 1.6 }}>
              {elInfo && <span style={{ fontSize: 14, marginRight: 6 }}>{elInfo.icon}</span>}
              {card.desc}
            </div>
          </>
        ) : card.effectDesc && card.type !== "monster" ? (
          <>
            <div style={{ fontSize: 12, color: "#4a90e2", fontWeight: 600, padding: "8px", background: "rgba(74,144,226,0.1)", borderRadius: 6, lineHeight: 1.6, marginBottom: 12 }}>
              <div style={{ color: "#3498db", fontSize: 10, marginBottom: 4, textTransform: "uppercase", letterSpacing: 1 }}>⚡ CARD EFFECT:</div>
              {card.effectDesc}
            </div>
            <div style={{ fontSize: 10, color: "#666", lineHeight: 1.6 }}>
              {card.desc}
            </div>
          </>
        ) : (
          <div style={{ fontSize: 11, color: "#aaa", lineHeight: 1.6 }}>
            {elInfo && <span style={{ fontSize: 16, marginRight: 6 }}>{elInfo.icon}</span>}
            {card.desc}
          </div>
        )}
      </div>
      <div style={{ background: "rgba(0,0,0,0.5)", padding: "12px", display: "flex", justifyContent: "space-between", borderTop: "1px solid rgba(255,255,255,0.1)" }}>
        <span style={{ fontSize: 12, color: RARITY_COLORS[card.rarity], fontWeight: 700, textTransform: "uppercase" }}>{card.rarity?.replace("_", " ")}</span>
        {elInfo && <span style={{ fontSize: 12, color: elInfo.color, fontWeight: 700, textTransform: "uppercase" }}>{card.element}</span>}
      </div>
    </div>
  );
}

// ============================================================
// PINNED CARD PREVIEW (CLICK TO PIN)
// ============================================================
function PinnedCardPreview({ card, onAddToDeck, onClose }) {
  if (!card) return null;
  
  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.8)", zIndex: 10000, display: "flex", alignItems: "center", justifyContent: "center" }} onClick={onClose}>
      <div onClick={(e) => e.stopPropagation()} style={{ width: 300 }}>
        <EnlargedCard card={card} />
        <div style={{ padding: "16px", display: "flex", gap: 12, background: "#1a1a1a", borderRadius: "0 0 16px 16px" }}>
          <button onClick={onAddToDeck} style={{
            flex: 1, background: "#4caf50", border: "none", borderRadius: 8, padding: "12px",
            color: "#fff", fontWeight: 700, fontSize: 14, cursor: "pointer"
          }}>✓ Add to Deck</button>
          <button onClick={onClose} style={{
            flex: 1, background: "#e74c3c", border: "none", borderRadius: 8, padding: "12px",
            color: "#fff", fontWeight: 700, fontSize: 14, cursor: "pointer"
          }}>✕ Cancel</button>
        </div>
      </div>
    </div>
  );
}

// ============================================================
// STORY SCREEN
// ============================================================
function StoryScreen({ playerName, playerGold, onStartTournament, tournamentActive, inBattle, storyState, setStoryState, onStartBattle }) {
  const [inputText, setInputText] = useState("");
  const [loading, setLoading] = useState(false);
  const logRef = useRef(null);
  
  const storyLog = storyState.log;
  const currentEvent = storyState.currentEvent;
  const showTournamentButton = storyState.showTournamentButton;
  
  const setStoryLog = (updater) => {
    setStoryState(prev => ({...prev, log: typeof updater === 'function' ? updater(prev.log) : updater}));
  };
  
  const setCurrentEvent = (event) => {
    setStoryState(prev => ({...prev, currentEvent: event}));
  };
  
  const setShowTournamentButton = (val) => {
    setStoryState(prev => ({...prev, showTournamentButton: val}));
  };
  
  useEffect(() => {
    if (logRef.current) logRef.current.scrollTop = logRef.current.scrollHeight;
  }, [storyLog]);
  
  function addLog(role, text) {
    setStoryLog(l => [...l, { role, text, id: Date.now()+Math.random() }]);
  }
  
  async function handleOption(option) {
    addLog("player", option);
    
    // Check if accepting a duel - look at recent narrator messages
    const recentNarrator = storyLog.filter(l => l.role === "narrator").slice(-2);
    const hasDuelMention = recentNarrator.some(msg => 
      msg.text.toLowerCase().includes("duel") || 
      msg.text.toLowerCase().includes("challenge") ||
      msg.text.toLowerCase().includes("battle")
    );
    
    const acceptingDuel = option.toLowerCase().includes("accept") || 
                          option.toLowerCase().includes("bring it") ||
                          option.toLowerCase().includes("let") ||
                          option.toLowerCase().includes("begin");
    
    if (hasDuelMention && acceptingDuel) {
      addLog("narrator", "The challenger grins and draws their deck. 'Let's see what you've got!'");
      
      // Show duel popup after a brief delay
      setTimeout(() => {
        const confirmed = window.confirm("⚔️ BEGIN DUEL?\n\n🎴 Your opponent is ready!\n💰 Winner takes 50 gold\n\nClick OK to enter the Battle Arena.");
        
        if (confirmed) {
          onStartBattle({ type: "friendly", wager: 50 });
        } else {
          addLog("narrator", "You hesitate... the moment passes. Perhaps another time.");
        }
      }, 800);
      
      return; // Stop here, don't continue story
    }
    
    setLoading(true);
    
    if (currentEvent.triggerTournament && option.toLowerCase().includes("register")) {
      setShowTournamentButton(true);
      addLog("narrator", "Excellent! The tournament registration is complete. When you're ready, the tournament will begin. Prepare your deck and steel your resolve.");
      setLoading(false);
      return;
    }
    
    try {
      const context = storyLog.slice(-4).map(l => `${l.role==="player"?"Player":"Narrator"}: ${l.text}`).join("\n");
      const response = await fetch("https://api.anthropic.com/v1/messages", {
        method:"POST",
        headers:{ "Content-Type":"application/json" },
        body: JSON.stringify({
          model:"claude-sonnet-4-20250514",
          max_tokens:200,
          messages:[{
            role:"user",
            content:`You are narrator of dark fantasy card game DUEL MASTERS. Keep response to 2 sentences max, atmospheric. Recent:\n${context}\n\nPlayer: ${option}\n\nRespond as narrator:`
          }]
        })
      });
      const data = await response.json();
      const text = data.content?.find(b=>b.type==="text")?.text || "The shadows deepen around you.";
      addLog("narrator", text);
      
      const nextEvent = STORY_EVENTS[Math.floor(Math.random()*STORY_EVENTS.length)];
      setCurrentEvent(nextEvent);
      setTimeout(()=>addLog("narrator", nextEvent.text), 600);
    } catch(e) {
      addLog("narrator", "The shadows stir... your choice echoes through the Realm.");
      const nextEvent = STORY_EVENTS[Math.floor(Math.random()*STORY_EVENTS.length)];
      setCurrentEvent(nextEvent);
    }
    setLoading(false);
  }
  
  function handleFreeInput() {
    if (!inputText.trim() || inBattle) return;
    const text = inputText.trim();
    setInputText("");
    handleOption(text);
  }
  
  return (
    <div style={{ display:"flex", flexDirection:"column", height:"calc(100vh - 52px)", padding:"20px 30px", maxWidth:800, margin:"0 auto" }}>
      <h2 style={{ color:"#9b59b6", fontSize:28, marginBottom:16 }}>📖 Story Mode</h2>
      
      <div ref={logRef} style={{
        flex:1, overflowY:"auto",
        background:"rgba(0,0,0,0.4)", border:"1px solid rgba(255,255,255,0.08)",
        borderRadius:12, padding:20, marginBottom:16,
        display:"flex", flexDirection:"column", gap:12
      }}>
        {storyLog.map((entry,i) => (
          <div key={entry.id||i} className="fade-in" style={{
            background: entry.role==="player" ? "rgba(155,89,182,0.15)" : "rgba(255,255,255,0.03)",
            border: `1px solid ${entry.role==="player"?"rgba(155,89,182,0.3)":"rgba(255,255,255,0.06)"}`,
            borderRadius:8, padding:"10px 14px"
          }}>
            <span style={{ fontSize:10, color:entry.role==="player"?"#9b59b6":"#888", fontWeight:700, textTransform:"uppercase", marginRight:8 }}>
              {entry.role==="player"?playerName:"Narrator"}
            </span>
            <span style={{ color: entry.role==="player"?"#e0d0ff":"#ccc", fontSize:13, lineHeight:1.6 }}>{entry.text}</span>
          </div>
        ))}
        {loading && <div style={{ color:"#888", fontSize:12, fontStyle:"italic" }}>...</div>}
        {inBattle && (
          <div style={{ background:"rgba(231,76,60,0.2)", border:"2px solid #e74c3c", borderRadius:8, padding:12, textAlign:"center" }}>
            <div style={{ color:"#e74c3c", fontWeight:700 }}>⚔️ BATTLE IN PROGRESS</div>
            <div style={{ color:"#888", fontSize:11, marginTop:4 }}>Story input disabled until battle ends</div>
          </div>
        )}
      </div>
      
      {showTournamentButton && !tournamentActive && (
        <div style={{ marginBottom:12 }}>
          <button onClick={onStartTournament} style={{
            width:"100%", background:"#f39c12", border:"none", borderRadius:10, padding:"14px",
            color:"#000", fontSize:14, fontWeight:700, cursor:"pointer"
          }}>🏆 START TOURNAMENT</button>
        </div>
      )}
      
      {/* Show BEGIN DUEL button if recent narrator mentioned duel */}
      {!inBattle && storyLog.filter(l => l.role === "narrator").slice(-2).some(msg => 
        msg.text.toLowerCase().includes("duel") || 
        msg.text.toLowerCase().includes("challenge") ||
        msg.text.toLowerCase().includes("grin")
      ) && (
        <div style={{ marginBottom:12 }}>
          <button onClick={() => {
            if (window.confirm("⚔️ BEGIN DUEL?\n\n🎴 Your opponent is ready!\n💰 Winner takes 50 gold\n\nClick OK to enter the Battle Arena.")) {
              onStartBattle({ type: "friendly", wager: 50 });
            }
          }} style={{
            width:"100%", background:"#e74c3c", border:"none", borderRadius:10, padding:"14px",
            color:"#fff", fontSize:14, fontWeight:700, cursor:"pointer", animation:"pulse 2s infinite"
          }}>⚔️ BEGIN DUEL</button>
        </div>
      )}
      
      {!loading && !inBattle && currentEvent && (
        <div style={{ display:"flex", flexWrap:"wrap", gap:8, marginBottom:10 }}>
          {currentEvent.options.map((opt,i) => (
            <button key={i} onClick={()=>handleOption(opt)} style={{
              background:"rgba(155,89,182,0.15)", border:"2px solid rgba(155,89,182,0.4)",
              borderRadius:8, padding:"8px 14px", color:"#c39bd3",
              fontSize:12, cursor:"pointer", fontWeight:600
            }}>{opt}</button>
          ))}
        </div>
      )}
      
      <div style={{ display:"flex", gap:10 }}>
        <input
          value={inputText}
          onChange={e=>setInputText(e.target.value)}
          onKeyDown={e=>e.key==="Enter"&&handleFreeInput()}
          placeholder={inBattle ? "Battle in progress..." : "Type your own action..."}
          disabled={inBattle}
          style={{
            flex:1, background:"rgba(255,255,255,0.05)", border:"2px solid rgba(255,255,255,0.15)",
            borderRadius:10, padding:"10px 14px", color:inBattle?"#555":"#fff", fontSize:13, outline:"none",
            cursor: inBattle ? "not-allowed" : "text"
          }}
        />
        <button onClick={handleFreeInput} disabled={loading||!inputText.trim()||inBattle} style={{
          background:inBattle?"#333":"#9b59b6", border:"none", borderRadius:10, padding:"10px 20px",
          color:inBattle?"#555":"#fff", fontWeight:700, fontSize:13, cursor:inBattle?"not-allowed":"pointer"
        }}>Send</button>
      </div>
    </div>
  );
}

// ============================================================
// DECK BUILDER WITH PINNED PREVIEW
// ============================================================
function DeckScreen({ playerDeck, playerCollection, onSave }) {
  const [deck, setDeck] = useState(deepClone(playerDeck));
  const [filter, setFilter] = useState("all");
  const [search, setSearch] = useState("");
  const [pinnedCard, setPinnedCard] = useState(null);
  
  const collectionQty = getCardQuantities(playerCollection);
  const uniqueCards = [];
  const seen = new Set();
  playerCollection.forEach(card => {
    const key = getCardKey(card);
    if (!seen.has(key)) {
      seen.add(key);
      uniqueCards.push(card);
    }
  });
  
  const filtered = uniqueCards.filter(c => {
    const matchType = filter === "all" || c.type === filter;
    const matchSearch = !search || c.name.toLowerCase().includes(search.toLowerCase());
    return matchType && matchSearch;
  });
  
  function addToDeck(card) {
    const key = getCardKey(card);
    const ownedQty = collectionQty[key] || 0;
    const inDeckQty = countCardInDeck(deck, card);
    
    if (deck.length >= 30) {
      setPinnedCard(null);
      setTimeout(() => alert("❌ Deck is Full!\n\nMaximum 30 cards allowed in your deck."), 100);
      return;
    }
    
    if (ownedQty === 0) {
      setPinnedCard(null);
      setTimeout(() => alert(`❌ You Don't Own This Card!\n\n"${card.name}" is not in your collection.`), 100);
      return;
    }
    
    // Check 2-copy limit FIRST
    if (inDeckQty >= 2) {
      setPinnedCard(null);
      setTimeout(() => alert(`❌ Deck Limit Reached!\n\nYou can only have 2 copies of "${card.name}" in your deck.\n\nCurrent in deck: ${inDeckQty}/2`), 100);
      return;
    }
    
    // Then check if you have more copies to add
    if (inDeckQty >= ownedQty) {
      setPinnedCard(null);
      setTimeout(() => alert(`❌ Not Enough Copies!\n\nYou only own ${ownedQty} ${ownedQty === 1 ? 'copy' : 'copies'} of "${card.name}".\n\nAll ${ownedQty} ${ownedQty === 1 ? 'is' : 'are'} already in your deck.`), 100);
      return;
    }
    
    setDeck(d => [...d, card]);
    setPinnedCard(null);
  }
  
  return (
    <div style={{ display:"flex", height:"calc(100vh - 52px)", overflow:"hidden" }}>
      <div style={{ flex:1, padding:20, overflowY:"auto", borderRight:"1px solid rgba(255,255,255,0.08)" }}>
        <h3 style={{ color:"#9b59b6", marginBottom:12 }}>Collection ({playerCollection.length} cards)</h3>
        <div style={{ display:"flex", gap:8, marginBottom:12, flexWrap:"wrap" }}>
          {["all","monster","magic","trap"].map(f => (
            <button key={f} onClick={()=>setFilter(f)} style={{
              background:filter===f?"#9b59b6":"transparent",
              border:`1px solid ${filter===f?"#9b59b6":"#444"}`,
              borderRadius:6, padding:"4px 12px", color:filter===f?"#fff":"#888",
              fontSize:11, cursor:"pointer"
            }}>{f.charAt(0).toUpperCase()+f.slice(1)}</button>
          ))}
          <input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Search..." style={{
            background:"rgba(255,255,255,0.05)", border:"1px solid #444",
            borderRadius:6, padding:"4px 10px", color:"#fff", fontSize:11, outline:"none", flex:1, minWidth:80
          }} />
        </div>
        <div style={{ display:"grid", gridTemplateColumns:"repeat(auto-fill,minmax(90px,1fr))", gap:8, marginBottom:32 }}>
          {filtered.map((card,i) => {
            const key = getCardKey(card);
            const owned = collectionQty[key] || 0;
            const inDeck = countCardInDeck(deck, card);
            const isSelected = pinnedCard && getCardKey(pinnedCard) === key;
            
            return (
              <div key={i} onClick={() => setPinnedCard(card)} style={{ position: "relative" }}>
                <CardDisplay 
                  card={card} 
                  small 
                  inDeckCount={inDeck}
                  showHoverPreview={true}
                  selected={isSelected}
                />
                {owned > 1 && <div style={{ position:"absolute", bottom:-8, left:"50%", transform:"translateX(-50%)", background:"rgba(0,0,0,0.95)", border:"2px solid #f39c12", padding:"4px 10px", borderRadius:6, fontSize:11, color:"#f1c40f", fontWeight:700, boxShadow:"0 2px 8px rgba(0,0,0,0.6)", zIndex:10, whiteSpace:"nowrap" }}>×{owned}</div>}
              </div>
            );
          })}
        </div>
      </div>
      <div style={{ width:320, padding:20, overflowY:"auto", background:"rgba(0,0,0,0.3)" }}>
        <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center", marginBottom:16 }}>
          <h3 style={{ color:"#f1c40f", fontSize:18, margin:0 }}>Deck ({deck.length}/30)</h3>
          <button onClick={()=>onSave(deck)} style={{ background:"#9b59b6", border:"none", borderRadius:8, padding:"8px 16px", color:"#fff", fontWeight:700, cursor:"pointer" }}>SAVE</button>
        </div>
        {deck.length === 0 && <p style={{ color:"#555", fontSize:12 }}>Click cards to add</p>}
        <div style={{ display:"flex", flexDirection:"column", gap:4 }}>
          {deck.map((card,i) => (
            <div key={i} style={{ display:"flex", alignItems:"center", gap:8, background:"rgba(255,255,255,0.03)", borderRadius:6, padding:"8px 12px" }}>
              <span style={{ fontSize:18 }}>{card.type==="monster"?"🌙":card.type==="magic"?"✨":"⚡"}</span>
              <div style={{ flex:1 }}>
                <div style={{ color:"#fff", fontSize:12, fontWeight:600 }}>{card.name}</div>
                <div style={{ color:"#666", fontSize:9 }}>{card.cardNumber}</div>
              </div>
              {card.type==="monster" && <span style={{ color:"#888", fontSize:10 }}>{card.atk}A</span>}
              <button onClick={()=>setDeck(d=>d.filter((_,idx)=>idx!==i))} style={{ background:"transparent", border:"1px solid #e74c3c", borderRadius:4, padding:"2px 6px", color:"#e74c3c", fontSize:10, cursor:"pointer" }}>✕</button>
            </div>
          ))}
        </div>
      </div>
      
      {pinnedCard && (
        <PinnedCardPreview 
          card={pinnedCard} 
          onAddToDeck={() => addToDeck(pinnedCard)} 
          onClose={() => setPinnedCard(null)} 
        />
      )}
    </div>
  );
}

// ============================================================
// COLLECTION SCREEN
// ============================================================
function CollectionScreen({ collection }) {
  const collectionQty = getCardQuantities(collection);
  const uniqueCards = [];
  const seen = new Set();
  collection.forEach(card => {
    const key = getCardKey(card);
    if (!seen.has(key)) {
      seen.add(key);
      uniqueCards.push(card);
    }
  });
  
  return (
    <div style={{ padding:30 }}>
      <h2 style={{ color:"#9b59b6", marginBottom:20 }}>🎴 My Collection ({collection.length} cards)</h2>
      <div style={{ display:"grid", gridTemplateColumns:"repeat(auto-fill,minmax(125px,1fr))", gap:14 }}>
        {uniqueCards.map((card,i) => {
          const key = getCardKey(card);
          const qty = collectionQty[key] || 0;
          return <CardDisplay key={i} card={card} quantity={qty} showHoverPreview={true} />;
        })}
      </div>
    </div>
  );
}

// ============================================================
// CODEX SCREEN
// ============================================================
function CodexScreen({ playerCollection }) {
  const [filter, setFilter] = useState("all");
  const [search, setSearch] = useState("");
  
  const collectionKeys = new Set(playerCollection.map(c => getCardKey(c)));
  const filtered = ALL_CARDS.filter(c => {
    const matchType = filter === "all" || c.type === filter;
    const matchSearch = !search || c.name.toLowerCase().includes(search.toLowerCase());
    return matchType && matchSearch;
  });
  
  const ownedCount = ALL_CARDS.filter(c => collectionKeys.has(getCardKey(c))).length;
  const percent = Math.floor((ownedCount / ALL_CARDS.length) * 100);
  
  return (
    <div style={{ padding:30, maxWidth:1400, margin:"0 auto" }}>
      <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center", marginBottom:20 }}>
        <h2 style={{ color:"#9b59b6", fontSize:28, margin:0 }}>📚 Card Codex</h2>
        <div style={{ textAlign:"right" }}>
          <div style={{ color:"#f1c40f", fontSize:20, fontWeight:700 }}>{ownedCount} / {ALL_CARDS.length}</div>
          <div style={{ color:"#888", fontSize:12 }}>{percent}% Complete</div>
        </div>
      </div>
      
      <div style={{ background:"rgba(155,89,182,0.1)", border:"1px solid rgba(155,89,182,0.3)", borderRadius:12, padding:16, marginBottom:20 }}>
        <div style={{ display:"flex", gap:8, marginBottom:12 }}>
          {["all","monster","magic","trap"].map(f => (
            <button key={f} onClick={()=>setFilter(f)} style={{
              background:filter===f?"#9b59b6":"transparent", border:`1px solid ${filter===f?"#9b59b6":"#444"}`,
              borderRadius:6, padding:"4px 12px", color:filter===f?"#fff":"#888", fontSize:11, cursor:"pointer"
            }}>{f.toUpperCase()}</button>
          ))}
        </div>
        <input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Search..." style={{
          background:"rgba(255,255,255,0.05)", border:"1px solid #444", borderRadius:8, padding:"8px 12px",
          color:"#fff", fontSize:13, outline:"none", width:"100%"
        }} />
      </div>
      
      <div style={{ color:"#666", fontSize:13, marginBottom:12 }}>
        {filtered.length} cards — 🔒 = Not collected
      </div>
      
      <div style={{ display:"grid", gridTemplateColumns:"repeat(auto-fill,minmax(125px,1fr))", gap:14 }}>
        {filtered.map((card,i) => (
          <CardDisplay key={i} card={card} notOwned={!collectionKeys.has(getCardKey(card))} showHoverPreview={true} />
        ))}
      </div>
    </div>
  );
}

// ============================================================
// SHOP SCREEN WITH LIVE TIMER
// ============================================================
function ShopScreen({ playerGold, playerCollection, playerDeck, onBuy, onSell }) {
  const [tab, setTab] = useState("packs");
  const [packResult, setPackResult] = useState(null);
  const [shopSingles, setShopSingles] = useState([]);
  const [refreshTime, setRefreshTime] = useState(Date.now() + 3600000);
  const [currentTime, setCurrentTime] = useState(Date.now());
  const [sellFilter, setSellFilter] = useState("not_equipped");
  
  useEffect(() => {
    const saved = localStorage.getItem('shop_singles');
    const savedTime = localStorage.getItem('shop_refresh_time');
    if (saved && savedTime && parseInt(savedTime) > Date.now()) {
      setShopSingles(JSON.parse(saved));
      setRefreshTime(parseInt(savedTime));
    } else {
      refreshShop();
    }
    
    // Live timer update every second
    const interval = setInterval(() => {
      const now = Date.now();
      setCurrentTime(now);
      if (now >= refreshTime) {
        refreshShop();
      }
    }, 1000);
    
    return () => clearInterval(interval);
  }, [refreshTime]);
  
  function refreshShop() {
    const newSingles = shuffle(ALL_CARDS).slice(0, 5).map(card => {
      const price = card.rarity === "common" ? 20 : card.rarity === "uncommon" ? 40 : card.rarity === "rare" ? 80 : 150;
      return { ...card, price };
    });
    setShopSingles(newSingles);
    const newRefresh = Date.now() + 3600000;
    setRefreshTime(newRefresh);
    localStorage.setItem('shop_singles', JSON.stringify(newSingles));
    localStorage.setItem('shop_refresh_time', newRefresh.toString());
  }
  
  const timeLeft = Math.max(0, Math.floor((refreshTime - currentTime) / 1000));
  const minutes = Math.floor(timeLeft / 60);
  const seconds = timeLeft % 60;
  
  const PACKS = [
    { id:"basic", name:"Basic Pack", cost:50, desc:"10 random cards", icon:"📦" },
    { id:"rare", name:"Rare Pack", cost:120, desc:"6 cards, higher rare chance", icon:"💎" },
    ...Object.keys(ELEMENT_CYCLE).map(el => ({
      id: el,
      name: `${el.charAt(0).toUpperCase() + el.slice(1)} Pack`,
      cost: 80,
      desc: `5 ${el} element cards`,
      icon: ELEMENT_CYCLE[el].icon
    }))
  ];
  
  function openPack(pack) {
    if (playerGold < pack.cost) return;
    let cards = [];
    if (pack.id === "basic") {
      cards = shuffle(ALL_CARDS).slice(0, 10);
    } else if (pack.id === "rare") {
      const pool = ALL_CARDS.filter(c => c.rarity !== "common" || Math.random() < 0.3);
      cards = shuffle(pool).slice(0, 6);
    } else {
      cards = shuffle(MONSTERS.filter(c => c.element === pack.id)).slice(0, 5);
    }
    onBuy(pack.cost, cards);
    setPackResult(cards);
  }
  
  function buySingle(card) {
    if (playerGold < card.price) return;
    onBuy(card.price, [card]);
    const newSingles = shopSingles.filter(c => c !== card);
    setShopSingles(newSingles);
    localStorage.setItem('shop_singles', JSON.stringify(newSingles));
  }
  
  return (
    <div style={{ padding:30, maxWidth:1200, margin:"0 auto" }}>
      <h2 style={{ color:"#f39c12", fontSize:28, marginBottom:24 }}>🏪 Card Shop</h2>
      
      <div style={{ display:"flex", gap:8, marginBottom:24 }}>
        {["packs","singles","sell"].map(t => (
          <button key={t} onClick={()=>setTab(t)} style={{
            background:tab===t?"#f39c12":"transparent",
            border:`2px solid ${tab===t?"#f39c12":"#555"}`,
            borderRadius:8, padding:"8px 20px",
            color:tab===t?"#000":"#888", fontWeight:700, cursor:"pointer"
          }}>{t==="packs"?"Card Packs":t==="singles"?"Single Cards":"Sell Cards"}</button>
        ))}
      </div>
      
      {packResult && (
        <div style={{ background:"rgba(241,196,15,0.1)", border:"2px solid #f1c40f", borderRadius:12, padding:20, marginBottom:24 }}>
          <div style={{ color:"#f1c40f", fontWeight:700, marginBottom:12 }}>Pack Opened! ({packResult.length} cards)</div>
          <div style={{ display:"flex", gap:10, flexWrap:"wrap" }}>
            {packResult.map((c,i) => <CardDisplay key={i} card={c} small showHoverPreview={true} />)}
          </div>
          <button onClick={()=>setPackResult(null)} style={{ marginTop:12, background:"#333", border:"none", borderRadius:6, padding:"6px 16px", color:"#fff", cursor:"pointer" }}>Close</button>
        </div>
      )}
      
      {tab === "packs" && (
        <div style={{ display:"grid", gridTemplateColumns:"repeat(auto-fit,minmax(180px,1fr))", gap:16 }}>
          {PACKS.map(pack => (
            <div key={pack.id} style={{ background:"rgba(255,255,255,0.03)", border:`2px solid ${playerGold>=pack.cost?"#f39c12":"#333"}`, borderRadius:12, padding:16, textAlign:"center" }}>
              <div style={{ fontSize:36, marginBottom:8 }}>{pack.icon}</div>
              <div style={{ color:"#fff", fontWeight:700, fontSize:14, marginBottom:4 }}>{pack.name}</div>
              <div style={{ color:"#888", fontSize:11, marginBottom:12 }}>{pack.desc}</div>
              <button onClick={()=>openPack(pack)} disabled={playerGold<pack.cost} style={{
                width:"100%", background:playerGold>=pack.cost?"#f39c12":"#333",
                border:"none", borderRadius:6, padding:"8px", color:playerGold>=pack.cost?"#000":"#666",
                fontWeight:700, cursor:playerGold>=pack.cost?"pointer":"not-allowed"
              }}>{pack.cost}g</button>
            </div>
          ))}
        </div>
      )}
      
      {tab === "singles" && (
        <div>
          <div style={{ background:"rgba(241,196,15,0.1)", border:"1px solid #f39c12", borderRadius:8, padding:12, marginBottom:20, textAlign:"center" }}>
            <div style={{ color:"#f1c40f", fontSize:14, fontWeight:700 }}>⏰ Refreshes in: {String(minutes).padStart(2,'0')}:{String(seconds).padStart(2,'0')}</div>
          </div>
          <div style={{ display:"grid", gridTemplateColumns:"repeat(auto-fill,minmax(140px,1fr))", gap:16 }}>
            {shopSingles.map((card,i) => (
              <div key={i} style={{ display:"flex", flexDirection:"column", alignItems:"center", gap:8 }}>
                <CardDisplay card={card} showHoverPreview={true} />
                <button onClick={()=>buySingle(card)} disabled={playerGold<card.price} style={{
                  width:"100%", background:playerGold>=card.price?"#2ecc71":"#333",
                  border:"none", borderRadius:6, padding:"8px", color:playerGold>=card.price?"#fff":"#666",
                  fontWeight:700, cursor:playerGold>=card.price?"pointer":"not-allowed"
                }}>{card.price}g</button>
              </div>
            ))}
          </div>
        </div>
      )}
      
      {tab === "sell" && (
        <div>
          <div style={{ display:"flex", gap:8, marginBottom:16 }}>
            {["not_equipped","equipped"].map(filter => (
              <button key={filter} onClick={()=>setSellFilter(filter)} style={{
                background:sellFilter===filter?"#9b59b6":"transparent",
                border:`2px solid ${sellFilter===filter?"#9b59b6":"#555"}`,
                borderRadius:8, padding:"6px 16px", fontSize:12,
                color:sellFilter===filter?"#fff":"#888", fontWeight:700, cursor:"pointer"
              }}>{filter==="equipped"?"In Deck":"Not in Deck"}</button>
            ))}
          </div>
          
          <div style={{ display:"grid", gridTemplateColumns:"repeat(auto-fill,minmax(140px,1fr))", gap:16 }}>
            {(() => {
              const deckKeys = new Set(playerDeck.map(c => getCardKey(c)));
              const collectionQty = getCardQuantities(playerCollection);
              const uniqueCards = [];
              const seen = new Set();
              
              playerCollection.forEach(card => {
                const key = getCardKey(card);
                if (!seen.has(key)) {
                  seen.add(key);
                  const inDeck = countCardInDeck(playerDeck, card);
                  const owned = collectionQty[key] || 0;
                  const canSell = owned > inDeck;
                  const isEquipped = deckKeys.has(key);
                  
                  if ((sellFilter === "equipped" && isEquipped) || (sellFilter === "not_equipped" && canSell)) {
                    uniqueCards.push({card, owned, inDeck, canSell});
                  }
                }
              });
              
              return uniqueCards.map(({card, owned, inDeck, canSell},i) => {
                const sellPrice = Math.floor((card.rarity === "common" ? 10 : card.rarity === "uncommon" ? 20 : card.rarity === "rare" ? 40 : 75));
                
                return (
                  <div key={i} style={{ display:"flex", flexDirection:"column", alignItems:"center", gap:8 }}>
                    <CardDisplay card={card} showHoverPreview={true} quantity={owned} inDeckCount={inDeck} />
                    <button onClick={()=>{if(canSell) onSell(card, sellPrice);}} disabled={!canSell} style={{
                      width:"100%", background:canSell?"#e74c3c":"#333",
                      border:"none", borderRadius:6, padding:"8px", color:canSell?"#fff":"#666",
                      fontWeight:700, cursor:canSell?"pointer":"not-allowed", fontSize:11
                    }}>{canSell?`Sell for ${sellPrice}g`:"All in Deck"}</button>
                  </div>
                );
              });
            })()}
          </div>
        </div>
      )}
    </div>
  );
}

// ============================================================
// ELEMENTS SCREEN
// ============================================================
function ElementsScreen() {
  return (
    <div style={{ padding:30, maxWidth:900, margin:"0 auto" }}>
      <h2 style={{ color:"#2ecc71", fontSize:24, marginBottom:24 }}>⚡ Element System</h2>
      <div style={{ background:"rgba(255,255,255,0.03)", border:"1px solid rgba(255,255,255,0.08)", borderRadius:12, padding:20, marginBottom:24 }}>
        <p style={{ color:"#aaa", fontSize:14, lineHeight:1.8, margin:0 }}>
          Element advantage grants <strong style={{ color:"#4caf50" }}>+15% damage</strong>. 
          Disadvantage applies <strong style={{ color:"#e74c3c" }}>-15% damage</strong>.
          All card stats reset to normal after battle ends.
        </p>
      </div>
      <div style={{ display:"grid", gridTemplateColumns:"repeat(auto-fit,minmax(200px,1fr))", gap:16 }}>
        {Object.entries(ELEMENT_CYCLE).map(([el,data]) => (
          <div key={el} style={{ background:data.color+"11", border:`1px solid ${data.color}44`, borderRadius:10, padding:16, textAlign:"center" }}>
            <div style={{ fontSize:40, marginBottom:8 }}>{data.icon}</div>
            <div style={{ color:data.color, fontWeight:700, textTransform:"uppercase", fontSize:16, marginBottom:10 }}>{el}</div>
            <div style={{ fontSize:13, color:"#aaa" }}>
              <div style={{ color:"#4caf50", marginBottom:4 }}>✓ Beats {data.beats}</div>
              <div style={{ color:"#e74c3c" }}>✗ Weak to {data.weakTo}</div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ============================================================
// TOURNAMENT SCREEN
// ============================================================
// ============================================================
// TOURNAMENT DATA - 20 TOURNAMENTS WITH UNIQUE DUELISTS
// ============================================================
const TOURNAMENTS = [
  { id: 1, name: "Rookie Arena", difficulty: "Beginner", entryFee: 0, prizeGold: 100, prizeCards: 1, participants: 4 },
  { id: 2, name: "Street Duel Circuit", difficulty: "Beginner", entryFee: 50, prizeGold: 200, prizeCards: 2, participants: 4 },
  { id: 3, name: "City Championship", difficulty: "Easy", entryFee: 100, prizeGold: 400, prizeCards: 3, participants: 8 },
  { id: 4, name: "Regional Qualifiers", difficulty: "Easy", entryFee: 150, prizeGold: 600, prizeCards: 0, participants: 8 },
  { id: 5, name: "Academy Tournament", difficulty: "Medium", entryFee: 200, prizeGold: 800, prizeCards: 4, participants: 8 },
  { id: 6, name: "Guild Masters Cup", difficulty: "Medium", entryFee: 250, prizeGold: 1000, prizeCards: 5, participants: 8 },
  { id: 7, name: "Elemental Showdown", difficulty: "Medium", entryFee: 300, prizeGold: 0, prizeCards: 8, participants: 8 },
  { id: 8, name: "Shadow League", difficulty: "Hard", entryFee: 400, prizeGold: 1500, prizeCards: 6, participants: 16 },
  { id: 9, name: "Imperial Grand Prix", difficulty: "Hard", entryFee: 500, prizeGold: 2000, prizeCards: 8, participants: 16 },
  { id: 10, name: "Twilight Invitational", difficulty: "Hard", entryFee: 600, prizeGold: 2500, prizeCards: 10, participants: 16 },
  { id: 11, name: "Masters Championship", difficulty: "Expert", entryFee: 800, prizeGold: 3500, prizeCards: 12, participants: 16 },
  { id: 12, name: "Legends Arena", difficulty: "Expert", entryFee: 1000, prizeGold: 5000, prizeCards: 15, participants: 16 },
  { id: 13, name: "Platinum Series", difficulty: "Expert", entryFee: 1200, prizeGold: 0, prizeCards: 20, participants: 16 },
  { id: 14, name: "Diamond League", difficulty: "Elite", entryFee: 1500, prizeGold: 8000, prizeCards: 18, participants: 32 },
  { id: 15, name: "World Championship", difficulty: "Elite", entryFee: 2000, prizeGold: 12000, prizeCards: 25, participants: 32 },
  { id: 16, name: "Grand Festival", difficulty: "Elite", entryFee: 2500, prizeGold: 15000, prizeCards: 30, participants: 32 },
  { id: 17, name: "Mythic Gauntlet", difficulty: "Legendary", entryFee: 3000, prizeGold: 20000, prizeCards: 40, participants: 32 },
  { id: 18, name: "Cosmic Clash", difficulty: "Legendary", entryFee: 4000, prizeGold: 30000, prizeCards: 50, participants: 32 },
  { id: 19, name: "Ultimate Showdown", difficulty: "Legendary", entryFee: 5000, prizeGold: 50000, prizeCards: 75, participants: 64 },
  { id: 20, name: "Infinity Cup", difficulty: "Legendary", entryFee: 10000, prizeGold: 100000, prizeCards: 100, participants: 64 }
];

const DUELISTS = [
  // Beginner tier
  { name: "Rookie Ryan", deck: "basic_fire", skill: 1, bio: "Just started dueling last week" },
  { name: "Timid Tina", deck: "basic_water", skill: 1, bio: "Nervous but determined" },
  { name: "Eager Eddie", deck: "basic_earth", skill: 2, bio: "Lots of enthusiasm, little experience" },
  { name: "Casual Casey", deck: "basic_wind", skill: 2, bio: "Plays for fun" },
  
  // Easy tier
  { name: "Street Fighter Sam", deck: "improved_fire", skill: 3, bio: "Veteran of local card shops" },
  { name: "Tactical Terry", deck: "improved_lightning", skill: 3, bio: "Studies every matchup" },
  { name: "Quick Quinn", deck: "improved_wind", skill: 4, bio: "Fast-paced aggressive duelist" },
  { name: "Steady Sarah", deck: "improved_earth", skill: 4, bio: "Defensive playstyle expert" },
  
  // Medium tier
  { name: "Academy Ace Alex", deck: "advanced_mixed", skill: 5, bio: "Top of their dueling class" },
  { name: "Guild Master Morgan", deck: "advanced_dark", skill: 5, bio: "Leader of the Shadow Guild" },
  { name: "Elemental Elena", deck: "advanced_light", skill: 6, bio: "Masters all eight elements" },
  { name: "Professor Pierce", deck: "advanced_lightning", skill: 6, bio: "Teaches advanced strategies" },
  
  // Hard tier
  { name: "Shadow Knight Kane", deck: "expert_dark", skill: 7, bio: "Mysterious masked duelist" },
  { name: "Imperial Guard Iris", deck: "expert_light", skill: 7, bio: "Protects the royal family" },
  { name: "Twilight Sage Silas", deck: "expert_mixed", skill: 8, bio: "Ancient wisdom meets modern tactics" },
  { name: "Crimson Duelist Drake", deck: "expert_fire", skill: 8, bio: "Never lost a fire mirror match" },
  
  // Expert tier
  { name: "Master Zephyr", deck: "master_wind", skill: 9, bio: "Can predict your every move" },
  { name: "Legend Luna", deck: "master_light", skill: 9, bio: "Three-time world champion" },
  { name: "Platinum Prince Victor", deck: "master_mixed", skill: 10, bio: "Royalty with unmatched skill" },
  { name: "Diamond Duchess Diana", deck: "master_ice", skill: 10, bio: "Cold precision in every duel" },
  
  // Elite tier
  { name: "World Champion Renji", deck: "elite_fire", skill: 11, bio: "Current reigning world champion" },
  { name: "Grand Master Yuki", deck: "elite_water", skill: 11, bio: "Founded the modern dueling system" },
  { name: "Festival King Malik", deck: "elite_lightning", skill: 12, bio: "Undefeated in major tournaments" },
  
  // Legendary tier
  { name: "Mythic Warrior Astrid", deck: "legendary_mixed", skill: 13, bio: "Wields cards from the ancient era" },
  { name: "Cosmic Emperor Vex", deck: "legendary_dark", skill: 14, bio: "Rumored to have supernatural powers" },
  { name: "Ultimate Dragon Kai", deck: "legendary_supreme", skill: 15, bio: "The strongest duelist alive" },
  { name: "Infinity Master Zen", deck: "legendary_infinite", skill: 16, bio: "Has never lost a single duel" }
];

function generateDuelistDeck(deckType, skillLevel) {
  const starRange = Math.min(10, Math.floor(skillLevel / 2) + 1);
  const elementTypes = Object.keys(ELEMENT_CYCLE);
  
  let deckCards = [];
  
  if (deckType.includes("basic")) {
    const element = deckType.split("_")[1];
    deckCards = [
      ...shuffle(MONSTERS.filter(m => m.element === element && m.stars <= 3)).slice(0, 15),
      ...shuffle(MAGIC_CARDS.filter(c => c.rarity === "common")).slice(0, 8),
      ...shuffle(TRAP_CARDS.filter(c => c.rarity === "common")).slice(0, 7)
    ];
  } else if (deckType.includes("improved")) {
    const element = deckType.split("_")[1];
    deckCards = [
      ...shuffle(MONSTERS.filter(m => m.element === element && m.stars <= 5)).slice(0, 18),
      ...shuffle(MAGIC_CARDS.filter(c => c.rarity !== "super_rare")).slice(0, 7),
      ...shuffle(TRAP_CARDS.filter(c => c.rarity !== "super_rare")).slice(0, 5)
    ];
  } else if (deckType.includes("advanced")) {
    const element = deckType === "advanced_mixed" ? elementTypes[Math.floor(Math.random() * elementTypes.length)] : deckType.split("_")[1];
    deckCards = [
      ...shuffle(MONSTERS.filter(m => m.stars <= 7 && (deckType === "advanced_mixed" || m.element === element))).slice(0, 20),
      ...shuffle(MAGIC_CARDS.filter(c => c.rarity !== "common")).slice(0, 6),
      ...shuffle(TRAP_CARDS).slice(0, 4)
    ];
  } else if (deckType.includes("expert")) {
    deckCards = [
      ...shuffle(MONSTERS.filter(m => m.stars >= 5 && m.stars <= 9)).slice(0, 20),
      ...shuffle(MAGIC_CARDS.filter(c => c.rarity === "rare" || c.rarity === "super_rare")).slice(0, 6),
      ...shuffle(TRAP_CARDS.filter(c => c.rarity !== "common")).slice(0, 4)
    ];
  } else if (deckType.includes("master")) {
    deckCards = [
      ...shuffle(MONSTERS.filter(m => m.stars >= 6)).slice(0, 22),
      ...shuffle(MAGIC_CARDS.filter(c => c.rarity === "super_rare")).slice(0, 5),
      ...shuffle(TRAP_CARDS.filter(c => c.rarity === "rare" || c.rarity === "super_rare")).slice(0, 3)
    ];
  } else if (deckType.includes("elite")) {
    deckCards = [
      ...shuffle(MONSTERS.filter(m => m.stars >= 7)).slice(0, 23),
      ...shuffle(MAGIC_CARDS.filter(c => c.rarity === "super_rare")).slice(0, 5),
      ...shuffle(TRAP_CARDS.filter(c => c.rarity === "super_rare")).slice(0, 2)
    ];
  } else {
    // legendary
    deckCards = [
      ...shuffle(MONSTERS.filter(m => m.stars >= 8)).slice(0, 25),
      ...shuffle(MAGIC_CARDS.filter(c => c.rarity === "super_rare")).slice(0, 3),
      ...shuffle(TRAP_CARDS.filter(c => c.rarity === "super_rare")).slice(0, 2)
    ];
  }
  
  return shuffle(deckCards).slice(0, 30);
}

function TournamentScreen({ playerGold, onRegister, activeTournamentData, onStartMatch }) {
  const [selectedTournament, setSelectedTournament] = useState(null);
  
  const difficultyColors = {
    "Beginner": "#4caf50",
    "Easy": "#8bc34a",
    "Medium": "#ffc107",
    "Hard": "#ff9800",
    "Expert": "#ff5722",
    "Elite": "#e91e63",
    "Legendary": "#9c27b0"
  };
  
  if (activeTournamentData) {
    // Show bracket
    const bracket = activeTournamentData.bracket;
    const currentMatch = activeTournamentData.currentMatch;
    
    return (
      <div style={{ padding: 30, maxWidth: 1400, margin: "0 auto" }}>
        <h2 style={{ color: "#f39c12", fontSize: 28, marginBottom: 8 }}>🏆 {activeTournamentData.tournament.name}</h2>
        <div style={{ color: "#888", marginBottom: 20 }}>Round {activeTournamentData.currentRound} / {Math.log2(activeTournamentData.tournament.participants)}</div>
        
        <div style={{ display: "flex", gap: 20, marginBottom: 30 }}>
          <div style={{ background: "rgba(241,196,15,0.1)", border: "2px solid #f1c40f", borderRadius: 12, padding: 16, flex: 1 }}>
            <div style={{ color: "#888", fontSize: 11, marginBottom: 4 }}>PRIZE GOLD</div>
            <div style={{ color: "#f1c40f", fontSize: 24, fontWeight: 700 }}>💰 {activeTournamentData.tournament.prizeGold}g</div>
          </div>
          {activeTournamentData.tournament.prizeCards > 0 && (
            <div style={{ background: "rgba(155,89,182,0.1)", border: "2px solid #9b59b6", borderRadius: 12, padding: 16, flex: 1 }}>
              <div style={{ color: "#888", fontSize: 11, marginBottom: 4 }}>PRIZE CARDS</div>
              <div style={{ color: "#9b59b6", fontSize: 24, fontWeight: 700 }}>🎴 {activeTournamentData.tournament.prizeCards} cards</div>
            </div>
          )}
        </div>
        
        {/* Tournament Bracket */}
        <div style={{ background: "rgba(0,0,0,0.3)", border: "1px solid rgba(255,255,255,0.1)", borderRadius: 12, padding: 20, marginBottom: 20 }}>
          <h3 style={{ color: "#9b59b6", marginBottom: 16 }}>Full Tournament Bracket</h3>
          <div style={{ overflowX: "auto", paddingBottom: 16 }}>
            <div style={{ display: "flex", gap: 40, minWidth: "max-content", paddingBottom: 20 }}>
              {(() => {
                const totalRounds = Math.log2(activeTournamentData.tournament.participants);
                const allRounds = [];
                
                // Build all rounds structure
                let participants = activeTournamentData.tournament.participants;
                for (let round = 1; round <= totalRounds; round++) {
                  const matchesInRound = participants / 2;
                  allRounds.push({ round, matches: matchesInRound });
                  participants = matchesInRound;
                }
                
                return allRounds.map((roundInfo, roundIdx) => (
                  <div key={roundIdx} style={{ display: "flex", flexDirection: "column", gap: 16, justifyContent: "space-around", minWidth: 180 }}>
                    <div style={{ color: "#f39c12", fontWeight: 700, fontSize: 14, textAlign: "center", marginBottom: 8 }}>
                      {roundInfo.round === totalRounds ? "FINAL" : roundInfo.round === totalRounds - 1 ? "SEMI-FINAL" : `ROUND ${roundInfo.round}`}
                    </div>
                    {Array.from({ length: roundInfo.matches }).map((_, matchIdx) => {
                      const isCurrentRound = roundInfo.round === activeTournamentData.currentRound;
                      const match = isCurrentRound && bracket[matchIdx] ? bracket[matchIdx] : null;
                      const isCompleted = match?.completed;
                      const isActive = isCurrentRound && matchIdx === currentMatch;
                      
                      return (
                        <div key={matchIdx} style={{
                          background: isActive ? "rgba(241,196,15,0.2)" : isCompleted ? "rgba(76,175,80,0.1)" : "rgba(255,255,255,0.05)",
                          border: `2px solid ${isActive ? "#f39c12" : isCompleted ? "#4caf50" : "#444"}`,
                          borderRadius: 8,
                          padding: 12,
                          minHeight: 80,
                          display: "flex",
                          flexDirection: "column",
                          justifyContent: "center",
                          transition: "all 0.3s ease"
                        }}>
                          {match ? (
                            <>
                              <div style={{ color: match.player1 === "YOU" ? "#f1c40f" : "#fff", fontSize: 11, marginBottom: 4, fontWeight: match.player1 === "YOU" ? 700 : 400 }}>
                                {match.player1 === "YOU" ? "👤 YOU" : match.player1?.substring(0, 15) || "TBD"}
                              </div>
                              <div style={{ color: match.player2 === "YOU" ? "#f1c40f" : "#fff", fontSize: 11, fontWeight: match.player2 === "YOU" ? 700 : 400 }}>
                                {match.player2 === "YOU" ? "👤 YOU" : match.player2?.substring(0, 15) || "TBD"}
                              </div>
                              {isCompleted && (
                                <div style={{ color: "#4caf50", fontSize: 10, marginTop: 6, fontWeight: 700 }}>
                                  Winner: {match.winner === "YOU" ? "YOU" : match.winner?.substring(0, 12)}
                                </div>
                              )}
                            </>
                          ) : (
                            <div style={{ color: "#666", fontSize: 11, textAlign: "center" }}>TBD</div>
                          )}
                        </div>
                      );
                    })}
                  </div>
                ));
              })()}
            </div>
          </div>
          
          <h3 style={{ color: "#9b59b6", marginBottom: 16, marginTop: 24 }}>Current Round Details - Round {activeTournamentData.currentRound}</h3>
          <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
            {bracket.map((match, i) => {
              const isCurrentMatch = currentMatch === i;
              const isCompleted = match.winner !== null;
              const isInProgress = match.inProgress === true;
              
              return (
                <div key={i} className={isCurrentMatch && !isInProgress ? "glow" : ""} style={{
                  background: isInProgress ? "rgba(231,76,60,0.15)" : isCurrentMatch ? "rgba(241,196,15,0.1)" : isCompleted ? "rgba(0,255,0,0.05)" : "rgba(255,255,255,0.03)",
                  border: `2px solid ${isInProgress ? "#e74c3c" : isCurrentMatch ? "#f39c12" : isCompleted ? "#4caf50" : "#333"}`,
                  borderRadius: 8,
                  padding: 16,
                  transition: "all 0.3s ease",
                  position: "relative"
                }}>
                  {i === currentMatch && !isCompleted && !isInProgress && (
                    <div style={{ position: "absolute", top: -10, right: -10, background: "#f39c12", color: "#000", padding: "4px 12px", borderRadius: 6, fontSize: 11, fontWeight: 900, boxShadow: "0 2px 8px rgba(0,0,0,0.5)" }}>*NEW*</div>
                  )}
                  <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                    <div style={{ flex: 1 }}>
                      <div style={{ color: match.player1 === "YOU" ? "#f1c40f" : "#fff", fontWeight: match.player1 === "YOU" ? 700 : 400, marginBottom: 4 }}>
                        {match.player1 === "YOU" ? "👤 YOU" : `🎴 ${match.player1}`}
                      </div>
                      <div style={{ color: match.player2 === "YOU" ? "#f1c40f" : "#fff", fontWeight: match.player2 === "YOU" ? 700 : 400 }}>
                        {match.player2 === "YOU" ? "👤 YOU" : `🎴 ${match.player2}`}
                      </div>
                    </div>
                    <div style={{ textAlign: "right" }}>
                      {isCompleted ? (
                        <div style={{ color: "#4caf50", fontWeight: 700 }}>
                          ✓ {match.winner === "YOU" ? "YOU WON" : `${match.winner} WON`}
                        </div>
                      ) : isInProgress ? (
                        <div style={{ color: "#e74c3c", fontWeight: 700, animation: "pulse 2s infinite" }}>
                          ⚔️ IN PROGRESS
                        </div>
                      ) : isCurrentMatch ? (
                        <button onClick={() => onStartMatch(match, i)} className="bounce" style={{
                          background: "#e74c3c",
                          border: "none",
                          borderRadius: 8,
                          padding: "12px 24px",
                          color: "#fff",
                          fontWeight: 700,
                          fontSize: 14,
                          cursor: "pointer"
                        }}>⚔️ START MATCH</button>
                      ) : (
                        <div style={{ color: "#666" }}>Waiting...</div>
                      )}
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      </div>
    );
  }
  
  return (
    <div style={{ padding: 30, maxWidth: 1400, margin: "0 auto" }}>
      <h2 style={{ color: "#f39c12", fontSize: 32, marginBottom: 8 }}>🏆 Tournaments</h2>
      <p style={{ color: "#888", marginBottom: 24 }}>Choose a tournament and test your skills against unique duelists!</p>
      
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(320px, 1fr))", gap: 16 }}>
        {TOURNAMENTS.map(tournament => {
          const canAfford = playerGold >= tournament.entryFee;
          const diffColor = difficultyColors[tournament.difficulty];
          
          return (
            <div key={tournament.id} className="fade-in" style={{
              background: selectedTournament?.id === tournament.id ? "rgba(155,89,182,0.15)" : "rgba(255,255,255,0.03)",
              border: `2px solid ${selectedTournament?.id === tournament.id ? "#9b59b6" : canAfford ? "#444" : "#222"}`,
              borderRadius: 12,
              padding: 20,
              cursor: canAfford ? "pointer" : "not-allowed",
              opacity: canAfford ? 1 : 0.5,
              transition: "all 0.3s ease"
            }} onClick={() => canAfford && setSelectedTournament(tournament)}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "start", marginBottom: 12 }}>
                <h3 style={{ color: "#fff", fontSize: 18, margin: 0 }}>{tournament.name}</h3>
                <div style={{
                  background: diffColor + "33",
                  border: `1px solid ${diffColor}`,
                  borderRadius: 6,
                  padding: "4px 10px",
                  fontSize: 10,
                  color: diffColor,
                  fontWeight: 700
                }}>{tournament.difficulty}</div>
              </div>
              
              <div style={{ display: "flex", gap: 12, marginBottom: 12 }}>
                <div style={{ flex: 1 }}>
                  <div style={{ color: "#888", fontSize: 10, marginBottom: 4 }}>ENTRY FEE</div>
                  <div style={{ color: tournament.entryFee === 0 ? "#4caf50" : "#f39c12", fontSize: 16, fontWeight: 700 }}>
                    {tournament.entryFee === 0 ? "FREE" : `${tournament.entryFee}g`}
                  </div>
                </div>
                <div style={{ flex: 1 }}>
                  <div style={{ color: "#888", fontSize: 10, marginBottom: 4 }}>PARTICIPANTS</div>
                  <div style={{ color: "#fff", fontSize: 16, fontWeight: 700 }}>{tournament.participants}</div>
                </div>
              </div>
              
              <div style={{ background: "rgba(0,0,0,0.3)", borderRadius: 8, padding: 12, marginBottom: 12 }}>
                <div style={{ color: "#888", fontSize: 10, marginBottom: 8 }}>PRIZES</div>
                {tournament.prizeGold > 0 && (
                  <div style={{ color: "#f1c40f", fontSize: 14, marginBottom: 4 }}>💰 {tournament.prizeGold} gold</div>
                )}
                {tournament.prizeCards > 0 && (
                  <div style={{ color: "#9b59b6", fontSize: 14 }}>🎴 {tournament.prizeCards} random cards</div>
                )}
              </div>
              
              {!canAfford && (
                <div style={{ color: "#e74c3c", fontSize: 11, textAlign: "center", marginTop: 8 }}>
                  ❌ Need {tournament.entryFee - playerGold} more gold
                </div>
              )}
            </div>
          );
        })}
      </div>
      
      {selectedTournament && (
        <div style={{
          position: "fixed",
          bottom: 20,
          left: "50%",
          transform: "translateX(-50%)",
          background: "#9b59b6",
          border: "none",
          borderRadius: 12,
          padding: 20,
          boxShadow: "0 8px 32px rgba(0,0,0,0.6)",
          zIndex: 1000
        }} className="bounce">
          <button onClick={() => onRegister(selectedTournament)} style={{
            background: "#4caf50",
            border: "none",
            borderRadius: 8,
            padding: "16px 48px",
            color: "#fff",
            fontSize: 18,
            fontWeight: 700,
            cursor: "pointer"
          }}>
            🎫 REGISTER FOR {selectedTournament.name.toUpperCase()}
          </button>
        </div>
      )}
    </div>
  );
}

// ============================================================
// BATTLE SCREEN WITH PLAYABLE FIELD
// ============================================================
function BattleScreen({ inBattle, playerDeck, playerName, onBattleEnd, currentBattleInfo }) {
  const [battleState, setBattleState] = useState(null);
  const [selectedCard, setSelectedCard] = useState(null);
  const [selectedTarget, setSelectedTarget] = useState(null);
  const [battleLog, setBattleLog] = useState([]);
  const [viewingGraveyard, setViewingGraveyard] = useState(null);
  const battleLogRef = useRef(null);
  const battleLogRef = useRef(null);
  
  useEffect(() => {
    if (inBattle && !battleState) {
      initBattle();
    }
  }, [inBattle]);
  
  useEffect(() => {
    if (battleLogRef.current) {
      battleLogRef.current.scrollTop = battleLogRef.current.scrollHeight;
    }
  }, [battleLog]);
  
  function initBattle() {
    const shuffledDeck = shuffle([...playerDeck]);
    const playerHand = shuffledDeck.slice(0, 5);
    const playerDrawPile = shuffledDeck.slice(5);
    
    const opponentDeck = currentBattleInfo?.opponentDeck || buildStarterDeck();
    const shuffledOppDeck = shuffle([...opponentDeck]);
    const opponentHand = shuffledOppDeck.slice(0, 5);
    const opponentDrawPile = shuffledOppDeck.slice(5);
    
    setBattleState({
      player: {
        hp: 8000,
        hand: playerHand,
        monsterField: [],
        spellTrapField: [],
        graveyard: [],
        drawPile: playerDrawPile
      },
      opponent: {
        hp: 8000,
        hand: opponentHand,
        monsterField: [],
        spellTrapField: [],
        graveyard: [],
        drawPile: opponentDrawPile,
        name: currentBattleInfo?.opponent?.name || "Opponent"
      },
      turn: "player",
      turnCount: 1,
      phase: "draw"
    });
    
    addBattleLog("⚔️ DUEL START! Draw your opening hand!");
  }
  
  function addBattleLog(msg) {
    setBattleLog(prev => [...prev, { text: msg, id: Date.now() + Math.random() }]);
  }
  
  function drawCard(side) {
    setBattleState(prev => {
      const newState = {...prev};
      const sideData = newState[side];
      
      if (sideData.drawPile.length === 0) {
        addBattleLog(`${side === 'player' ? playerName : 'Opponent'} has no cards left to draw!`);
        return prev;
      }
      
      const drawnCard = sideData.drawPile[0];
      sideData.hand.push(drawnCard);
      sideData.drawPile = sideData.drawPile.slice(1);
      
      addBattleLog(`${side === 'player' ? playerName : 'Opponent'} draws a card.`);
      return newState;
    });
  }
  
  function playCard(card, side) {
    setBattleState(prev => {
      const newState = {...prev};
      const sideData = newState[side];
      
      // Check field limits
      if (card.type === "monster") {
        if (sideData.monsterField.length >= 5) {
          addBattleLog(`Monster field is full! (5 card limit)`);
          return prev;
        }
        
        // Check if can play (monster needs sacrifices)
        if (card.sacrifices > 0 && sideData.monsterField.length < card.sacrifices) {
          addBattleLog(`Need ${card.sacrifices} sacrifice(s) to summon ${card.name}!`);
          return prev;
        }
        
        // Handle sacrifices
        if (card.sacrifices > 0) {
          const sacrificed = sideData.monsterField.slice(0, card.sacrifices);
          sideData.monsterField = sideData.monsterField.slice(card.sacrifices);
          sideData.graveyard.push(...sacrificed);
          addBattleLog(`Sacrificed ${sacrificed.map(c => c.name).join(", ")} to summon ${card.name}!`);
        }
        
        // Remove from hand
        sideData.hand = sideData.hand.filter(c => c !== card);
        
        sideData.monsterField.push({...card, currentHp: card.hp, canAttack: false});
        addBattleLog(`${side === 'player' ? playerName : newState.opponent.name} summons ${card.name}!`);
      } else {
        // Magic/Trap
        if (sideData.spellTrapField.length >= 5) {
          addBattleLog(`Spell/Trap field is full! (5 card limit)`);
          return prev;
        }
        
        // Remove from hand
        sideData.hand = sideData.hand.filter(c => c !== card);
        
        // Set face-down
        sideData.spellTrapField.push({...card, faceDown: true});
        addBattleLog(`${side === 'player' ? playerName : newState.opponent.name} sets a ${card.type} card face-down.`);
      }
      
      return newState;
    });
    
    setSelectedCard(null);
  }
  
  function attack(attackerIndex) {
    if (!selectedTarget && selectedTarget !== 0) {
      addBattleLog("Select a target to attack!");
      return;
    }
    
    setBattleState(prev => {
      const newState = {...prev};
      
      // Prevent first turn attacks
      if (newState.turnCount === 1 && newState.turn === "player") {
        addBattleLog(`Cannot attack on the first turn!`);
        return prev;
      }
      
      const attacker = newState.player.monsterField[attackerIndex];
      
      if (!attacker.canAttack) {
        addBattleLog(`${attacker.name} cannot attack this turn!`);
        return prev;
      }
      
      if (selectedTarget === "direct") {
        // Direct attack
        const damage = attacker.atk;
        newState.opponent.hp -= damage;
        addBattleLog(`${attacker.name} attacks directly for ${damage} damage!`);
      } else {
        // Attack monster
        const defender = newState.opponent.monsterField[selectedTarget];
        const atkDamage = attacker.atk;
        const defDamage = defender.atk;
        
        defender.currentHp -= atkDamage;
        attacker.currentHp -= defDamage;
        
        addBattleLog(`${attacker.name} (${attacker.atk} ATK) battles ${defender.name} (${defender.atk} ATK)!`);
        
        // Check destruction
        if (defender.currentHp <= 0) {
          newState.opponent.monsterField = newState.opponent.monsterField.filter((_, i) => i !== selectedTarget);
          newState.opponent.graveyard.push(defender);
          addBattleLog(`${defender.name} is destroyed!`);
        }
        
        if (attacker.currentHp <= 0) {
          newState.player.monsterField = newState.player.monsterField.filter((_, i) => i !== attackerIndex);
          newState.player.graveyard.push(attacker);
          addBattleLog(`${attacker.name} is destroyed!`);
        }
      }
      
      attacker.canAttack = false;
      setSelectedTarget(null);
      
      return newState;
    });
  }
  
  function endTurn() {
    setBattleState(prev => {
      const newState = {...prev};
      
      if (newState.turn === "player") {
        // Refresh monsters
        newState.player.monsterField.forEach(m => m.canAttack = true);
        newState.turn = "opponent";
        newState.turnCount++;
        addBattleLog("🔄 Opponent's turn!");
        
        // Simple AI
        setTimeout(() => aiTurn(newState), 1000);
      } else {
        newState.opponent.monsterField.forEach(m => m.canAttack = true);
        newState.turn = "player";
        newState.turnCount++;
        addBattleLog("🔄 Your turn! Draw a card.");
        drawCard("player");
      }
      
      return newState;
    });
  }
  
  function aiTurn(state) {
    // Simple AI
    if (state.opponent.hand.length > 0) {
      const card = state.opponent.hand[0];
      playCard(card, "opponent");
    }
    
    setTimeout(() => {
      setBattleState(prev => {
        const newState = {...prev};
        
        // Attack with first monster if available and not first turn
        if (newState.opponent.monsterField.length > 0 && newState.turnCount > 1) {
          const attacker = newState.opponent.monsterField[0];
          
          if (newState.player.monsterField.length > 0) {
            // Attack player's first monster
            const defender = newState.player.monsterField[0];
            defender.currentHp -= attacker.atk;
            attacker.currentHp -= defender.atk;
            
            addBattleLog(`${newState.opponent.name}'s ${attacker.name} attacks ${defender.name}!`);
            
            if (defender.currentHp <= 0) {
              newState.player.monsterField.shift();
              newState.player.graveyard.push(defender);
              addBattleLog(`${defender.name} destroyed!`);
            }
            if (attacker.currentHp <= 0) {
              newState.opponent.monsterField.shift();
              newState.opponent.graveyard.push(attacker);
              addBattleLog(`${attacker.name} destroyed!`);
            }
          } else {
            // Direct attack
            newState.player.hp -= attacker.atk;
            addBattleLog(`${newState.opponent.name}'s ${attacker.name} attacks directly for ${attacker.atk} damage!`);
          }
        }
        
        return newState;
      });
      
      setTimeout(() => endTurn(), 1000);
    }, 1500);
  }
  
  if (!inBattle || !battleState) {
    return (
      <div style={{ padding:30, display:"flex", alignItems:"center", justifyContent:"center", height:"calc(100vh - 52px)" }}>
        <div style={{ textAlign:"center", opacity:0.3 }}>
          <div style={{ fontSize:80, marginBottom:16 }}>⚔️</div>
          <h2 style={{ color:"#666", fontSize:24 }}>No Active Battle</h2>
          <p style={{ color:"#444", fontSize:14 }}>Accept a duel in Story mode to begin!</p>
        </div>
      </div>
    );
  }
  
  // Check win conditions
  if (battleState.player.hp <= 0) {
    return (
      <div style={{ padding:30, textAlign:"center" }}>
        <h2 style={{ color:"#e74c3c", fontSize:32 }}>💀 DEFEAT</h2>
        <p style={{ color:"#aaa" }}>You lost the duel...</p>
        <button onClick={() => onBattleEnd(false)} style={{ background:"#e74c3c", border:"none", borderRadius:8, padding:"12px 24px", color:"#fff", fontWeight:700, cursor:"pointer", marginTop:20 }}>Return to Story</button>
      </div>
    );
  }
  
  if (battleState.opponent.hp <= 0) {
    return (
      <div style={{ padding:30, textAlign:"center" }}>
        <h2 style={{ color:"#4caf50", fontSize:32 }}>🏆 VICTORY!</h2>
        <p style={{ color:"#aaa" }}>You won the duel and earned 50 gold!</p>
        <button onClick={() => onBattleEnd(true)} style={{ background:"#4caf50", border:"none", borderRadius:8, padding:"12px 24px", color:"#fff", fontWeight:700, cursor:"pointer", marginTop:20 }}>Return to Story</button>
      </div>
    );
  }
  
  return (
    <div style={{ padding:20, height:"calc(100vh - 52px)", display:"flex", flexDirection:"column", gap:12 }}>
      {/* HP Bars and Counters */}
      <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center" }}>
        <div style={{ display:"flex", gap:16, alignItems:"center" }}>
          <div>
            <div style={{ color:"#888", fontSize:11 }}>OPPONENT</div>
            <div style={{ color:"#e74c3c", fontSize:20, fontWeight:700 }}>❤️ {battleState.opponent.hp}</div>
          </div>
          <div onClick={() => setViewingGraveyard({side:"opponent", cards:battleState.opponent.graveyard})} style={{ cursor:"pointer", textAlign:"center", background:"rgba(155,89,182,0.2)", padding:"8px 12px", borderRadius:6, border:"1px solid #9b59b6" }}>
            <div style={{ color:"#9b59b6", fontSize:10 }}>GRAVEYARD</div>
            <div style={{ color:"#fff", fontSize:16, fontWeight:700 }}>💀 {battleState.opponent.graveyard.length}</div>
          </div>
          <div style={{ textAlign:"center", background:"rgba(74,144,226,0.2)", padding:"8px 12px", borderRadius:6, border:"1px solid #4a90e2" }}>
            <div style={{ color:"#4a90e2", fontSize:10 }}>DECK</div>
            <div style={{ color:"#fff", fontSize:16, fontWeight:700 }}>🎴 {battleState.opponent.drawPile.length}</div>
          </div>
        </div>
        <div style={{ color:"#f39c12", fontSize:14, fontWeight:700, textTransform:"uppercase", textAlign:"center" }}>
          {battleState.turn === "player" ? "YOUR TURN" : "OPPONENT'S TURN"}
          <div style={{ color:"#666", fontSize:10, marginTop:4 }}>Turn {battleState.turnCount}</div>
        </div>
        <div style={{ display:"flex", gap:16, alignItems:"center" }}>
          <div style={{ textAlign:"center", background:"rgba(74,144,226,0.2)", padding:"8px 12px", borderRadius:6, border:"1px solid #4a90e2" }}>
            <div style={{ color:"#4a90e2", fontSize:10 }}>DECK</div>
            <div style={{ color:"#fff", fontSize:16, fontWeight:700 }}>🎴 {battleState.player.drawPile.length}</div>
          </div>
          <div onClick={() => setViewingGraveyard({side:"player", cards:battleState.player.graveyard})} style={{ cursor:"pointer", textAlign:"center", background:"rgba(155,89,182,0.2)", padding:"8px 12px", borderRadius:6, border:"1px solid #9b59b6" }}>
            <div style={{ color:"#9b59b6", fontSize:10 }}>GRAVEYARD</div>
            <div style={{ color:"#fff", fontSize:16, fontWeight:700 }}>💀 {battleState.player.graveyard.length}</div>
          </div>
          <div>
            <div style={{ color:"#888", fontSize:11 }}>{playerName.toUpperCase()}</div>
            <div style={{ color:"#4caf50", fontSize:20, fontWeight:700 }}>❤️ {battleState.player.hp}</div>
          </div>
        </div>
      </div>
      
      {/* Opponent Monster Field */}
      <div style={{ background:"rgba(231,76,60,0.1)", border:"1px solid #e74c3c", borderRadius:8, padding:12, minHeight:100 }}>
        <div style={{ color:"#e74c3c", fontSize:11, marginBottom:8 }}>OPPONENT MONSTERS ({battleState.opponent.monsterField.length}/5)</div>
        <div style={{ display:"flex", gap:8, flexWrap:"wrap" }}>
          {battleState.opponent.monsterField.map((card, i) => (
            <div key={i} onClick={() => battleState.turn === "player" && setSelectedTarget(i)} 
                 style={{ cursor: battleState.turn === "player" ? "pointer" : "default", opacity: selectedTarget === i ? 1 : 0.8 }}>
              <CardDisplay card={card} small selected={selectedTarget === i} />
              <div style={{ textAlign:"center", color:"#2ecc71", fontSize:9, marginTop:2 }}>{card.currentHp} HP</div>
            </div>
          ))}
          {battleState.turn === "player" && battleState.opponent.monsterField.length === 0 && (
            <div onClick={() => setSelectedTarget("direct")} style={{ padding:"20px 40px", background:"rgba(255,255,255,0.05)", border:"2px dashed #666", borderRadius:8, cursor:"pointer", display:"flex", alignItems:"center", justifyContent:"center" }}>
              <span style={{ color:"#888", fontSize:11 }}>DIRECT ATTACK</span>
            </div>
          )}
        </div>
      </div>
      
      {/* Opponent Spell/Trap Field */}
      <div style={{ background:"rgba(74,144,226,0.05)", border:"1px solid rgba(74,144,226,0.3)", borderRadius:8, padding:8, minHeight:60 }}>
        <div style={{ color:"#4a90e2", fontSize:10, marginBottom:6 }}>OPPONENT SPELL/TRAP ({battleState.opponent.spellTrapField.length}/5)</div>
        <div style={{ display:"flex", gap:6, flexWrap:"wrap" }}>
          {battleState.opponent.spellTrapField.map((card, i) => (
            <div key={i} style={{ width:60, height:84, background:"#1a1a1a", border:"2px solid #4a90e2", borderRadius:6, display:"flex", alignItems:"center", justifyContent:"center", fontSize:24 }}>
              {card.faceDown ? "🂠" : card.type === "magic" ? "✨" : "⚡"}
            </div>
          ))}
        </div>
      </div>
      
      {/* Battle Log */}
      <div ref={battleLogRef} style={{ background:"rgba(0,0,0,0.3)", border:"1px solid rgba(255,255,255,0.1)", borderRadius:8, padding:8, height:80, overflowY:"auto" }}>
        {battleLog.slice(-5).map(log => (
          <div key={log.id} className="slide-in" style={{ color:"#aaa", fontSize:11, marginBottom:4 }}>{log.text}</div>
        ))}
      </div>
      
      {/* Player Spell/Trap Field */}
      <div style={{ background:"rgba(74,144,226,0.05)", border:"1px solid rgba(74,144,226,0.3)", borderRadius:8, padding:8, minHeight:60 }}>
        <div style={{ color:"#4a90e2", fontSize:10, marginBottom:6 }}>YOUR SPELL/TRAP ({battleState.player.spellTrapField.length}/5)</div>
        <div style={{ display:"flex", gap:6, flexWrap:"wrap" }}>
          {battleState.player.spellTrapField.map((card, i) => (
            <div key={i} style={{ width:60, height:84, background:"#1a1a1a", border:"2px solid #4a90e2", borderRadius:6, display:"flex", flexDirection:"column", alignItems:"center", justifyContent:"center", fontSize:card.faceDown?24:10, color:"#4a90e2", padding:4 }}>
              {card.faceDown ? "🂠" : (
                <>
                  <span style={{ fontSize:20, marginBottom:4 }}>{card.type === "magic" ? "✨" : "⚡"}</span>
                  <span style={{ fontSize:8, textAlign:"center" }}>{card.name.substring(0,8)}</span>
                </>
              )}
            </div>
          ))}
        </div>
      </div>
      
      {/* Player Monster Field */}
      <div style={{ background:"rgba(76,175,80,0.1)", border:"1px solid #4caf50", borderRadius:8, padding:12, minHeight:100 }}>
        <div style={{ color:"#4caf50", fontSize:11, marginBottom:8 }}>YOUR MONSTERS ({battleState.player.monsterField.length}/5)</div>
        <div style={{ display:"flex", gap:8, flexWrap:"wrap" }}>
          {battleState.player.monsterField.map((card, i) => (
            <div key={i}>
              <CardDisplay card={card} small />
              <div style={{ textAlign:"center", color:"#2ecc71", fontSize:9, marginTop:2 }}>{card.currentHp} HP</div>
              {battleState.turn === "player" && card.canAttack && battleState.turnCount > 1 && (
                <button onClick={() => attack(i)} style={{ width:"100%", background:"#e74c3c", border:"none", borderRadius:4, padding:"4px", color:"#fff", fontSize:9, marginTop:4, cursor:"pointer" }}>ATTACK</button>
              )}
              {battleState.turn === "player" && battleState.turnCount === 1 && (
                <div style={{ width:"100%", background:"#666", border:"none", borderRadius:4, padding:"4px", color:"#333", fontSize:8, marginTop:4, textAlign:"center" }}>Turn 1</div>
              )}
            </div>
          ))}
        </div>
      </div>
      
      {/* Player Hand */}
      <div style={{ background:"rgba(0,0,0,0.5)", border:"1px solid rgba(255,255,255,0.2)", borderRadius:8, padding:12 }}>
        <div style={{ display:"flex", justifyContent:"space-between", marginBottom:8 }}>
          <div style={{ color:"#f39c12", fontSize:11 }}>YOUR HAND ({battleState.player.hand.length})</div>
          {battleState.turn === "player" && (
            <button onClick={endTurn} style={{ background:"#f39c12", border:"none", borderRadius:6, padding:"4px 12px", color:"#000", fontSize:11, fontWeight:700, cursor:"pointer" }}>END TURN</button>
          )}
        </div>
        <div style={{ display:"flex", gap:8, flexWrap:"wrap" }}>
          {battleState.player.hand.map((card, i) => (
            <div key={i} onClick={() => battleState.turn === "player" && playCard(card, "player")} 
                 style={{ cursor: battleState.turn === "player" ? "pointer" : "not-allowed" }}>
              <CardDisplay card={card} small selected={selectedCard === card} showHoverPreview={true} />
            </div>
          ))}
        </div>
      </div>
      
      {/* Graveyard Viewer Modal */}
      {viewingGraveyard && (
        <div style={{ position:"fixed", inset:0, background:"rgba(0,0,0,0.9)", zIndex:1000, display:"flex", alignItems:"center", justifyContent:"center", padding:20 }} onClick={() => setViewingGraveyard(null)}>
          <div onClick={(e) => e.stopPropagation()} style={{ background:"#1a1a1a", border:"2px solid #9b59b6", borderRadius:12, padding:24, maxWidth:800, maxHeight:"80vh", overflowY:"auto" }}>
            <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center", marginBottom:16 }}>
              <h3 style={{ color:"#9b59b6", margin:0 }}>
                💀 {viewingGraveyard.side === "player" ? "Your" : "Opponent's"} Graveyard ({viewingGraveyard.cards.length} cards)
              </h3>
              <button onClick={() => setViewingGraveyard(null)} style={{ background:"#e74c3c", border:"none", borderRadius:6, padding:"8px 16px", color:"#fff", fontWeight:700, cursor:"pointer" }}>✕ Close</button>
            </div>
            {viewingGraveyard.cards.length === 0 ? (
              <div style={{ color:"#666", textAlign:"center", padding:40 }}>No cards in graveyard</div>
            ) : (
              <div style={{ display:"grid", gridTemplateColumns:"repeat(auto-fill, minmax(90px, 1fr))", gap:12 }}>
                {viewingGraveyard.cards.map((card, i) => (
                  <CardDisplay key={i} card={card} small showHoverPreview={true} />
                ))}
              </div>
            )}
          </div>
        </div>
      )}
    </div>
  );
}

// ============================================================
// MAIN APP
// ============================================================
export default function ShadowRealmApp() {
  const [screen, setScreen] = useState("title");
  const [playerName, setPlayerName] = useState("");
  const [nameInput, setNameInput] = useState("");
  const [playerDeck, setPlayerDeck] = useState([]);
  const [playerCollection, setPlayerCollection] = useState([]);
  const [playerGold, setPlayerGold] = useState(100);
  const [activeTab, setActiveTab] = useState("tournament");
  const [inBattle, setInBattle] = useState(false);
  const [activeTournamentData, setActiveTournamentData] = useState(null);
  const [currentBattleInfo, setCurrentBattleInfo] = useState(null);
  
  useEffect(() => {
    const saved = loadGame();
    if (saved?.playerName) {
      setPlayerName(saved.playerName);
      setPlayerDeck(saved.playerDeck||[]);
      setPlayerCollection(saved.playerCollection||[]);
      setPlayerGold(saved.playerGold||100);
      setActiveTournamentData(saved.activeTournamentData||null);
      setScreen("main");
    }
  }, []);
  
  useEffect(() => {
    if (playerName) saveGame({ playerName, playerDeck, playerCollection, playerGold, activeTournamentData });
  }, [playerName, playerGold, playerDeck, playerCollection, activeTournamentData]);
  
  function startGame() {
    if (!nameInput.trim()) return;
    setPlayerName(nameInput.trim());
    const deck = buildStarterDeck();
    setPlayerDeck(deck);
    setPlayerCollection(deepClone(deck));
    setStoryState({
      log: [{ role:"narrator", text:`You step into the dimly lit card shop, the scent of old paper and ink filling your nostrils. A challenger approaches with a confident smirk. "Hey, you look like you know your way around a deck. How about a friendly duel? Winner takes 50 gold."` }],
      currentEvent: STORY_EVENTS[0],
      showTournamentButton: false
    });
    setScreen("main");
  }
  
  function handleShopBuy(cost, cards) {
    setPlayerGold(g => g - cost);
    setPlayerCollection(c => [...c, ...cards]);
  }
  
  function handleSell(card, sellPrice) {
    const key = getCardKey(card);
    let removed = false;
    const newCollection = [];
    
    for (const c of playerCollection) {
      if (!removed && getCardKey(c) === key) {
        removed = true;
        continue;
      }
      newCollection.push(c);
    }
    
    setPlayerCollection(newCollection);
    setPlayerGold(g => g + sellPrice);
  }
  
  function handleStartTournament() {
    setTournamentActive(true);
    setActiveTab("tournament");
  }
  
  function handleStartBattle(battleInfo) {
    console.log("🎮 Starting battle...");
    setCurrentBattleInfo(battleInfo);
    setInBattle(true);
    setTimeout(() => {
      console.log("⚔️ Switching to battle tab");
      setActiveTab("battle");
    }, 100);
  }
  
  function handleBattleEnd(won) {
    setInBattle(false);
    
    if (activeTournamentData && currentBattleInfo) {
      const newTournamentData = {...activeTournamentData};
      const match = newTournamentData.bracket[newTournamentData.currentMatch];
      
      match.winner = won ? "YOU" : (match.player1 === "YOU" ? match.player2 : match.player1);
      match.completed = true;
      match.inProgress = false; // Clear in progress flag
      
      const allMatchesCompleted = newTournamentData.bracket.every(m => m.completed);
      
      if (allMatchesCompleted) {
        if (match.winner === "YOU") {
          const prize = newTournamentData.tournament;
          setPlayerGold(g => g + prize.prizeGold);
          
          if (prize.prizeCards > 0) {
            const prizeCards = shuffle(ALL_CARDS).slice(0, prize.prizeCards);
            setPlayerCollection(c => [...c, ...prizeCards]);
          }
          
          alert(`🏆 TOURNAMENT VICTORY!\n\n💰 Won ${prize.prizeGold} gold!\n🎴 Won ${prize.prizeCards} cards!`);
        } else {
          alert(`💀 Tournament Eliminated\n\nBetter luck next time!`);
        }
        
        setActiveTournamentData(null);
        setActiveTab("tournament");
      } else {
        newTournamentData.currentMatch++;
        
        if (newTournamentData.currentMatch >= newTournamentData.bracket.length) {
          const winners = newTournamentData.bracket.filter(m => m.completed).map(m => m.winner);
          if (winners.length > 1) {
            const nextRoundBracket = [];
            for (let i = 0; i < winners.length; i += 2) {
              nextRoundBracket.push({
                player1: winners[i],
                player2: winners[i + 1] || winners[i],
                winner: null,
                completed: false
              });
            }
            newTournamentData.bracket = nextRoundBracket;
            newTournamentData.currentMatch = 0;
            newTournamentData.currentRound++;
          }
        }
        
        setActiveTournamentData(newTournamentData);
        setActiveTab("tournament");
      }
    } else {
      if (won) {
        setPlayerGold(g => g + 50);
      }
      setActiveTab("tournament");
    }
    
    setCurrentBattleInfo(null);
  }
  
  function handleTournamentRegister(tournament) {
    if (playerGold < tournament.entryFee) {
      alert("Not enough gold!");
      return;
    }
    
    setPlayerGold(g => g - tournament.entryFee);
    
    const duelists = shuffle(DUELISTS).slice(0, tournament.participants - 1);
    const participants = ["YOU", ...duelists.map(d => d.name)];
    const shuffledParticipants = shuffle(participants);
    
    const bracket = [];
    for (let i = 0; i < shuffledParticipants.length; i += 2) {
      bracket.push({
        player1: shuffledParticipants[i],
        player2: shuffledParticipants[i + 1],
        winner: null,
        completed: false
      });
    }
    
    setActiveTournamentData({
      tournament,
      bracket,
      duelists,
      currentMatch: 0,
      currentRound: 1
    });
  }
  
  function handleStartMatch(match, matchIndex) {
    // Mark match as in progress
    const newTournamentData = {...activeTournamentData};
    newTournamentData.bracket[matchIndex].inProgress = true;
    setActiveTournamentData(newTournamentData);
    
    const opponent = match.player1 === "YOU" ? match.player2 : match.player1;
    const duelistData = DUELISTS.find(d => d.name === opponent);
    
    handleStartBattle({
      type: "tournament",
      opponent: duelistData,
      opponentDeck: generateDuelistDeck(duelistData.deck, duelistData.skill),
      matchIndex
    });
  }
  
  const TABS = [
    { id:"deck", label:"Deck", icon:"🃏" },
    { id:"collection", label:"Collection", icon:"🎴" },
    { id:"codex", label:"Codex", icon:"📚" },
    { id:"shop", label:"Shop", icon:"🏪" },
    { id:"elements", label:"Elements", icon:"⚡" },
    { id:"tournament", label:"Tournaments", icon:"🏆" },
    { id:"battle", label:"Battle", icon:"⚔️", disabled: !inBattle },
  ];
  
  if (screen === "title") {
    return (
      <div style={{ minHeight:"100vh", background:"#07070f", display:"flex",alignItems:"center",justifyContent:"center", fontFamily:"'Lato',sans-serif" }}>
        <style>{`@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@900&family=Lato:wght@400;700&display=swap');`}</style>
        <div style={{ textAlign:"center", maxWidth:500, padding:40 }}>
          <div style={{ fontSize:80, marginBottom:12 }}>🌙</div>
          <h1 style={{ fontSize:52,fontWeight:900,color:"#9b59b6",letterSpacing:6,fontFamily:"'Cinzel',serif" }}>DUEL MASTERS</h1>
          <p style={{ color:"#555",fontSize:13,letterSpacing:4,marginBottom:48 }}>1000 CARDS • 8 ELEMENTS</p>
          <div style={{ background:"rgba(155,89,182,0.08)", border:"1px solid rgba(155,89,182,0.2)", borderRadius:12,padding:30 }}>
            <p style={{ color:"#888",marginBottom:16 }}>Enter your name, Duelist</p>
            <input value={nameInput} onChange={e=>setNameInput(e.target.value)} onKeyDown={e=>e.key==="Enter"&&startGame()}
              placeholder="Your name..." style={{
                background:"rgba(255,255,255,0.05)", border:"2px solid #9b59b6",
                borderRadius:10, padding:"12px 16px", color:"#fff", width:"100%",
                fontSize:16, marginBottom:16, outline:"none"
              }} />
            <button onClick={startGame} style={{
              background:"#9b59b6", border:"none", borderRadius:10, padding:"14px",
              color:"#fff", fontSize:16, fontWeight:700, cursor:"pointer", width:"100%"
            }}>BEGIN DUEL →</button>
          </div>
        </div>
      </div>
    );
  }
  
  return (
    <div style={{ minHeight:"100vh", background:"#07070f", color:"#e0e0e0", fontFamily:"'Lato',sans-serif" }}>
      <style>{`
        @import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@700&family=Lato:wght@400;700&display=swap'); 
        * { box-sizing:border-box; } 
        
        @keyframes pulse { 
          0%, 100% { transform: scale(1); } 
          50% { transform: scale(1.05); } 
        }
        
        @keyframes fadeIn {
          from { opacity: 0; transform: translateY(20px); }
          to { opacity: 1; transform: translateY(0); }
        }
        
        @keyframes slideIn {
          from { transform: translateX(-100%); opacity: 0; }
          to { transform: translateX(0); opacity: 1; }
        }
        
        @keyframes glow {
          0%, 100% { box-shadow: 0 0 5px rgba(155,89,182,0.5); }
          50% { box-shadow: 0 0 20px rgba(155,89,182,0.8), 0 0 30px rgba(155,89,182,0.4); }
        }
        
        @keyframes shake {
          0%, 100% { transform: translateX(0); }
          25% { transform: translateX(-5px); }
          75% { transform: translateX(5px); }
        }
        
        @keyframes cardFlip {
          0% { transform: rotateY(0deg); }
          100% { transform: rotateY(180deg); }
        }
        
        @keyframes bounce {
          0%, 100% { transform: translateY(0); }
          50% { transform: translateY(-10px); }
        }
        
        .fade-in { animation: fadeIn 0.5s ease-out; }
        .slide-in { animation: slideIn 0.4s ease-out; }
        .glow { animation: glow 2s ease-in-out infinite; }
        .shake { animation: shake 0.5s ease-in-out; }
        .bounce { animation: bounce 1s ease-in-out infinite; }
        
        button { transition: all 0.3s ease; }
        button:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.4); }
        button:active:not(:disabled) { transform: translateY(0); }
      `}</style>
      
      <div style={{ background:"rgba(0,0,0,0.8)", borderBottom:"1px solid rgba(155,89,182,0.2)", padding:"0 20px", display:"flex", justifyContent:"space-between", alignItems:"center", position:"sticky", top:0, zIndex:50, height:52 }}>
        <div style={{ display:"flex",alignItems:"center",gap:16 }}>
          <span style={{ color:"#9b59b6", fontWeight:900, fontSize:16, fontFamily:"'Cinzel',serif" }}>🌙 DUEL MASTERS</span>
          <div style={{ display:"flex", gap:2 }}>
            {TABS.map(tab => (
              <button key={tab.id} onClick={()=>!tab.disabled && setActiveTab(tab.id)} className={activeTab===tab.id?"glow":""} style={{
                background:activeTab===tab.id?"rgba(155,89,182,0.2)":"transparent",
                border:"none", borderBottom:activeTab===tab.id?"2px solid #9b59b6":"2px solid transparent",
                padding:"14px 10px", color:tab.disabled?"#333":activeTab===tab.id?"#9b59b6":"#666",
                fontWeight:700, fontSize:10, cursor:tab.disabled?"not-allowed":"pointer",
                opacity:tab.disabled?0.4:1, transition:"all 0.3s ease"
              }}>
                {tab.icon} {tab.label}
              </button>
            ))}
          </div>
        </div>
        <div style={{ display:"flex", gap:16, alignItems:"center" }}>
          <span style={{ color:"#f1c40f", fontWeight:700, fontSize:16 }}>💰 {playerGold}g</span>
          <span style={{ color:"#9b59b6", fontSize:14 }}>👤 {playerName}</span>
        </div>
      </div>
      
      <div style={{ minHeight:"calc(100vh - 52px)" }}>
        {activeTab === "deck" && <DeckScreen playerDeck={playerDeck} playerCollection={playerCollection} onSave={setPlayerDeck} />}
        {activeTab === "collection" && <CollectionScreen collection={playerCollection} />}
        {activeTab === "codex" && <CodexScreen playerCollection={playerCollection} />}
        {activeTab === "shop" && <ShopScreen playerGold={playerGold} playerCollection={playerCollection} playerDeck={playerDeck} onBuy={handleShopBuy} onSell={handleSell} />}
        {activeTab === "elements" && <ElementsScreen />}
        {activeTab === "tournament" && <TournamentScreen playerGold={playerGold} onRegister={handleTournamentRegister} activeTournamentData={activeTournamentData} onStartMatch={handleStartMatch} />}
        {activeTab === "battle" && <BattleScreen inBattle={inBattle} playerDeck={playerDeck} playerName={playerName} onBattleEnd={handleBattleEnd} currentBattleInfo={currentBattleInfo} />}
      </div>
    </div>
  );
}

Game Source: DUEL MASTERS

Creator: FrostCobra30

Libraries: none

Complexity: complex (2154 lines, 105.1 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: duel-masters-frostcobra30" to link back to the original. Then publish at arcadelab.ai/publish.