zakcode-python / index.html
Zakia's picture
Update index.html - initial commit
8e02946 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ZakCode: Python - Learn Python Through Play</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.23.9/babel.min.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&family=DM+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
*{margin:0;padding:0;box-sizing:border-box}
html,body,#root{width:100%;min-height:100vh;background:#06080F}
body{font-family:'DM Sans','Segoe UI',system-ui,sans-serif;-webkit-font-smoothing:antialiased}
input:focus{outline:none} button{font-family:inherit}
::selection{background:rgba(139,92,246,0.3)}
@keyframes shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-8px)}75%{transform:translateX(8px)}}
@keyframes fadeUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}
@keyframes float{0%{transform:translateY(0) translateX(0);opacity:0.1}50%{opacity:0.2}100%{transform:translateY(-40px) translateX(15px);opacity:0.05}}
@keyframes pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.05)}}
@keyframes slideIn{from{opacity:0;transform:translateX(20px)}to{opacity:1;transform:translateX(0)}}
@keyframes popIn{from{opacity:0;transform:scale(0.8)}to{opacity:1;transform:scale(1)}}
@keyframes starPop{0%{transform:scale(0) rotate(-20deg);opacity:0}60%{transform:scale(1.3) rotate(5deg);opacity:1}100%{transform:scale(1) rotate(0deg);opacity:1}}
::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:rgba(148,163,184,0.15);border-radius:3px}
</style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const {useState,useEffect,useCallback,useRef} = React;
const LEVELS = [
{id:1,name:"Variables & Types",icon:"πŸ“¦",color:"#38BDF8",questions:[
{type:"quiz",question:"What type does Python assign to: x = 3.14?",code:'x = 3.14\nprint(type(x))',options:["int","float","str","double"],correct:1,explanation:"3.14 has a decimal point, so Python assigns the float type."},
{type:"fillblank",question:'Complete the code to convert "25" to an integer:',codeBefore:'age_str = "25"\nage = ',codeAfter:'(age_str)',answer:"int",hint:"Which built-in function converts to a whole number?",explanation:"int() converts a string to an integer."},
{type:"debug",question:"This code has a TypeError. Which line?",code:'name = "Zakia"\nage = "30"\nresult = name + " is " + age + 1',options:["Line 1","Line 2","Line 3: can't add int to str","No error"],correct:2,explanation:'age is a string, so age + 1 tries to add int to string. Fix: str(1)'},
{type:"quiz",question:"What is type(True)?",code:'print(type(True))',options:["<class 'int'>","<class 'str'>","<class 'bool'>","<class 'true'>"],correct:2,explanation:"True is a boolean, so type(True) returns <class 'bool'>."},
{type:"fillblank",question:"Complete the code to check a variable's type:",codeBefore:'x = "hello"\nresult = ',codeAfter:'(x)',answer:"type",hint:"Which function tells you what kind of data you have?",explanation:"type() returns the class/type of any Python object."},
]},
{id:2,name:"Strings",icon:"✏️",color:"#A78BFA",questions:[
{type:"quiz",question:'What does "hello".upper() return?',code:'print("hello".upper())',options:['"Hello"','"HELLO"','"hello"',"Error"],correct:1,explanation:".upper() converts ALL characters to uppercase."},
{type:"fillblank",question:"Complete the f-string to include the variable:",codeBefore:'name = "Zakia"\nmsg = f"Hello, ',codeAfter:'!"',answer:"{name}",hint:"In f-strings, wrap variables in curly braces.",explanation:'f-strings use {variable_name} to embed values.'},
{type:"debug",question:'Expected output is "Pyt". Find the bug:',code:'text = "Python"\nfirst_three = text[1:3]\nprint(first_three)',options:["Should be text[0:3]","Should be text[1:4]","Should be text(1:3)","No error"],correct:0,explanation:'Indexing starts at 0. text[0:3] = "Pyt". text[1:3] = "yt".'},
{type:"quiz",question:'What does "Python"[-1] return?',code:'print("Python"[-1])',options:['"P"','"n"','"o"',"Error"],correct:1,explanation:"Negative indexing: -1 is the last character = 'n'."},
{type:"fillblank",question:"Complete the code to split into words:",codeBefore:'s = "I love Python"\nwords = s.',codeAfter:'()',answer:"split",hint:"Which method breaks a string into a list?",explanation:".split() breaks a string by whitespace into a list."},
]},
{id:3,name:"Lists",icon:"πŸ“‹",color:"#34D399",questions:[
{type:"quiz",question:"After this code, what is nums?",code:'nums = [1, 2, 3]\nnums.append(4)\nprint(nums)',options:["[1,2,3]","[4,1,2,3]","[1,2,3,4]","[1,2,4]"],correct:2,explanation:".append() adds to the END of the list."},
{type:"fillblank",question:"Complete the list comprehension:",codeBefore:'squares = [x**2 ',codeAfter:' range(6)]',answer:"for x in",hint:"'for variable in iterable'",explanation:"Syntax: [expression for variable in iterable]"},
{type:"debug",question:"This code crashes. Why?",code:'fruits = ["apple", "banana", "cherry"]\nprint(fruits[3])',options:["IndexError: out of range","Prints 'cherry'","Prints None","Use fruits.get(3)"],correct:0,explanation:"Indices are 0,1,2. Index 3 doesn't exist. Use [-1] for last."},
{type:"quiz",question:"What does len([10, 20, 30]) return?",code:'print(len([10, 20, 30]))',options:["30","3","60","2"],correct:1,explanation:"len() counts ELEMENTS, not their sum."},
{type:"fillblank",question:"Complete the code to sort the list:",codeBefore:'nums = [3, 1, 4, 1, 5]\nnums.',codeAfter:'()',answer:"sort",hint:"Which method arranges elements in order?",explanation:".sort() sorts ascending in place."},
]},
{id:4,name:"Dictionaries",icon:"πŸ”‘",color:"#FBBF24",questions:[
{type:"quiz",question:'How do you access the value for key "name"?',code:'person = {"name": "Zakia", "age": 30}',options:['person.name','person["name"]','person.get[name]','person(name)'],correct:1,explanation:'Square brackets: dict["key"] to access values.'},
{type:"fillblank",question:"Get a default value if key is missing:",codeBefore:'d = {"a": 1}\nresult = d.',codeAfter:'("b", 0)',answer:"get",hint:"Which method returns a default instead of error?",explanation:'.get(key, default) avoids KeyError.'},
{type:"debug",question:"This code throws an error. Why?",code:'person = {"name": "Zakia"}\nprint(person["age"])',options:["KeyError: 'age'","Prints None","Prints 'Zakia'","Syntax error"],correct:0,explanation:'Missing key with [] raises KeyError. Use .get() instead.'},
{type:"quiz",question:"What does .keys() return?",code:'person = {"name": "Zakia", "city": "Durban"}\nprint(person.keys())',options:["['Zakia','Durban']","['name','city']","{'name','city'}","[('name','Zakia')]"],correct:1,explanation:".keys() returns all keys (not values)."},
{type:"fillblank",question:"Loop through key-value pairs:",codeBefore:'d = {"a":1, "b":2}\nfor k, v in d.',codeAfter:'():\n print(k, v)',answer:"items",hint:"Which method gives both keys and values?",explanation:".items() returns (key, value) pairs."},
]},
{id:5,name:"Conditionals",icon:"πŸ”€",color:"#FB7185",questions:[
{type:"quiz",question:"What does this print?",code:'x = 15\nif x > 20:\n print("big")\nelif x > 10:\n print("medium")\nelse:\n print("small")',options:['"big"','"medium"','"small"','Both big and medium'],correct:1,explanation:"15 > 20 is False, 15 > 10 is True β†’ 'medium'."},
{type:"fillblank",question:"Complete the ternary conditional:",codeBefore:'age = 25\nstatus = "adult" ',codeAfter:' age >= 18 else "minor"',answer:"if",hint:"value_if_true IF condition ELSE value_if_false",explanation:'Ternary: result = value_a if condition else value_b'},
{type:"debug",question:"This code has a syntax error:",code:'x = 5\nif x > 3 or < 10:\n print("in range")',options:["Need: x > 3 or x < 10","Use 'and' not 'or'","Missing parentheses","No error"],correct:0,explanation:"Each side of 'or' needs a complete comparison."},
{type:"quiz",question:'What does "not True" evaluate to?',code:'print(not True)',options:["True","False","None","Error"],correct:1,explanation:"'not' inverts a boolean. not True = False."},
{type:"fillblank",question:"Check that BOTH conditions are true:",codeBefore:'age = 25\nhas_id = True\nif age >= 18 ',codeAfter:' has_id:\n print("allowed")',answer:"and",hint:"Which operator requires both to be True?",explanation:"'and' requires both sides to be True."},
]},
{id:6,name:"Loops",icon:"πŸ”„",color:"#2DD4BF",questions:[
{type:"quiz",question:"How many times does this print?",code:'for i in range(3):\n print(i)',options:["2","3","4","Infinite"],correct:1,explanation:"range(3) = 0, 1, 2 β†’ 3 iterations."},
{type:"fillblank",question:"Get index AND value in a loop:",codeBefore:'fruits = ["a", "b", "c"]\nfor i, f in ',codeAfter:'(fruits):\n print(i, f)',answer:"enumerate",hint:"Which function gives index + value?",explanation:"enumerate() yields (index, value) pairs."},
{type:"debug",question:"This while loop has a critical problem:",code:'count = 0\nwhile count < 5:\n print(count)',options:["Infinite loop (no count += 1)","Should be count <= 5","count starts wrong","No error"],correct:0,explanation:"Without incrementing count β†’ infinite loop!"},
{type:"quiz",question:"What does 'break' do in a loop?",code:'for i in range(10):\n if i == 5:\n break\n print(i)',options:["Skips iteration","Exits the loop","Restarts loop","Nothing"],correct:1,explanation:"break exits the entire loop. Prints 0,1,2,3,4."},
{type:"fillblank",question:"Skip odd numbers with:",codeBefore:'for x in range(10):\n if x % 2 != 0:\n ',codeAfter:'\n print(x)',answer:"continue",hint:"Which keyword skips to next iteration?",explanation:"continue skips the rest of current iteration."},
]},
{id:7,name:"Functions",icon:"⚑",color:"#818CF8",questions:[
{type:"quiz",question:"What does this return?",code:'def add(a, b=10):\n return a + b\n\nprint(add(5))',options:["5","10","15","Error"],correct:2,explanation:"b defaults to 10. add(5) = 5 + 10 = 15."},
{type:"fillblank",question:"Create a lambda that doubles:",codeBefore:'double = ',codeAfter:' x: x * 2',answer:"lambda",hint:"Keyword for anonymous functions?",explanation:"lambda creates small inline functions."},
{type:"debug",question:"Why does this return None?",code:'def greet(name):\n message = f"Hello, {name}!"\n print(message)\n\nresult = greet("Zakia")\nprint(result)',options:["Missing return","f-string wrong","Missing param","It returns the message"],correct:0,explanation:"print() displays but doesn't return. Add 'return message'."},
{type:"quiz",question:"What does *args allow?",code:'def total(*args):\n return sum(args)\n\nprint(total(1,2,3,4))',options:["Only 1 arg","Exactly 4","Any number","Only keywords"],correct:2,explanation:"*args collects any number of positional arguments."},
{type:"fillblank",question:"Complete the function keyword:",codeBefore:'',codeAfter:' multiply(a, b):\n return a * b',answer:"def",hint:"Which keyword defines a function?",explanation:"def defines functions in Python."},
]},
{id:8,name:"Files, Errors & More",icon:"🧰",color:"#F472B6",questions:[
{type:"quiz",question:"What does 'with' do for files?",code:'with open("data.txt", "r") as f:\n content = f.read()',options:["Opens faster","Auto-closes when done","Makes read-only","Encrypts"],correct:1,explanation:"'with' auto-closes the file, even if an error occurs."},
{type:"fillblank",question:"Complete the error handling:",codeBefore:'try:\n result = 10 / 0\n',codeAfter:' ZeroDivisionError:\n print("Can\'t divide by zero!")',answer:"except",hint:"Which keyword catches errors?",explanation:"except catches exceptions from the try block."},
{type:"debug",question:"What does this code output?",code:'try:\n num = int("hello")\nexcept:\n print("Error!")\nfinally:\n print("Done")',options:['"Error!" then "Done"','Only "Error!"','Crashes','Only "Done"'],correct:0,explanation:'int("hello") raises ValueError β†’ except runs. finally ALWAYS runs.'},
{type:"quiz",question:"Tuples differ from lists because:",code:'t = (1, 2, 3)\nt[0] = 99 # What happens?',options:["Faster","Immutable (can't change)","Unordered","Numbers only"],correct:1,explanation:"Tuples are immutable. t[0] = 99 raises TypeError."},
{type:"fillblank",question:"Import with a shorter name:",codeBefore:'',codeAfter:' pandas as pd',answer:"import",hint:"Which keyword brings in modules?",explanation:"import module as alias for shorter names."},
]},
];
const BADGES=["Newcomer","Beginner","Learner","Coder","Explorer","Hacker","Developer","Pythonista"];
const SC={HOME:"home",LEVELS:"levels",PLAY:"play",DONE:"done"};
function Particles({color="#A78BFA",count=15}){
const ps=React.useMemo(()=>Array.from({length:count},(_,i)=>({id:i,x:Math.random()*100,y:Math.random()*100,sz:Math.random()*3+1,dur:Math.random()*20+10,del:Math.random()*10})),[count]);
return React.createElement('div',{style:{position:'fixed',inset:0,overflow:'hidden',pointerEvents:'none',zIndex:0}},ps.map(p=>React.createElement('div',{key:p.id,style:{position:'absolute',left:p.x+'%',top:p.y+'%',width:p.sz,height:p.sz,borderRadius:'50%',background:color,opacity:0.12,animation:`float ${p.dur}s ease-in-out ${p.del}s infinite alternate`}})));
}
function CodeBlock({code,style:s}){
return React.createElement('div',{style:{background:'#0A0E1B',border:'1px solid rgba(148,163,184,0.1)',borderRadius:14,padding:'16px 20px',fontFamily:"'Fira Code','Courier New',monospace",fontSize:14.5,lineHeight:1.75,color:'#CBD5E1',whiteSpace:'pre-wrap',...s}},
React.createElement('div',{style:{display:'flex',gap:6,marginBottom:12}},
React.createElement('div',{style:{width:10,height:10,borderRadius:'50%',background:'#EF4444'}}),
React.createElement('div',{style:{width:10,height:10,borderRadius:'50%',background:'#FBBF24'}}),
React.createElement('div',{style:{width:10,height:10,borderRadius:'50%',background:'#22C55E'}})),
code);
}
function ZakCode(){
const[screen,setScreen]=useState(SC.HOME);
const[levels,setLevels]=useState(LEVELS.map((l,i)=>({...l,unlocked:i===0})));
const[cLvl,setCLvl]=useState(0);
const[cQ,setCQ]=useState(0);
const[score,setScore]=useState(0);
const[totalXP,setTotalXP]=useState(0);
const[streak,setStreak]=useState(0);
const[bestStreak,setBestStreak]=useState(0);
const[sel,setSel]=useState(null);
const[fill,setFill]=useState("");
const[showR,setShowR]=useState(false);
const[ok,setOk]=useState(false);
const[shk,setShk]=useState(false);
const[lvlS,setLvlS]=useState(0);
const[xpG,setXpG]=useState(0);
const[lvlOk,setLvlOk]=useState(0);
const[hint,setHint]=useState(false);
const iRef=useRef(null);
const lv=levels[cLvl], q=lv?.questions?.[cQ], tQ=lv?.questions?.length||0;
useEffect(()=>{
if(screen===SC.PLAY&&q?.type==='fillblank'&&iRef.current)setTimeout(()=>iRef.current?.focus(),100);
setHint(false);
},[cQ,screen]);
const doOk=(pts)=>{setScore(s=>s+pts);setLvlS(s=>s+pts);setXpG(pts);setLvlOk(c=>c+1);setStreak(s=>{const n=s+1;if(n>bestStreak)setBestStreak(n);return n;});};
const doFail=()=>{setStreak(0);setXpG(0);setShk(true);setTimeout(()=>setShk(false),500);};
const handleQuiz=useCallback((i)=>{
if(showR)return;setSel(i);const c=i===q.correct;setOk(c);setShowR(true);
c?doOk(10+streak*2):doFail();
},[showR,q,streak,bestStreak]);
const handleFill=useCallback(()=>{
if(showR)return;const c=fill.trim().toLowerCase()===q.answer.toLowerCase();
setOk(c);setShowR(true);c?doOk(10+streak*2):doFail();
},[showR,fill,q,streak,bestStreak]);
const nextQ=useCallback(()=>{
if(cQ+1>=tQ){
setTotalXP(s=>s+lvlS);
if(cLvl+1<levels.length)setLevels(p=>p.map((l,i)=>i===cLvl+1?{...l,unlocked:true}:l));
setScreen(SC.DONE);
}else{setCQ(n=>n+1);setSel(null);setFill("");setShowR(false);}
},[cQ,tQ,cLvl,levels.length,lvlS]);
const startLvl=useCallback((i)=>{setCLvl(i);setCQ(0);setSel(null);setFill("");setShowR(false);setLvlS(0);setLvlOk(0);setScreen(SC.PLAY);},[]);
const base={width:'100%',minHeight:'100vh',background:'#06080F',color:'#E2E8F0',fontFamily:"'DM Sans','Segoe UI',system-ui,sans-serif",position:'relative'};
const wrap={maxWidth:600,margin:'0 auto',padding:'40px 24px',position:'relative',zIndex:2};
const btn={border:'none',borderRadius:12,padding:'14px 28px',fontSize:16,fontWeight:700,cursor:'pointer',transition:'all 0.2s',fontFamily:'inherit'};
const msh=(c1,c2)=>({position:'fixed',inset:0,background:`radial-gradient(ellipse 600px 500px at 10% 20%,${c1}15 0%,transparent 70%),radial-gradient(ellipse 500px 500px at 90% 80%,${c2}10 0%,transparent 70%)`,pointerEvents:'none',zIndex:0});
// HOME
if(screen===SC.HOME){
const rank=BADGES[Math.min(Math.floor(totalXP/40),7)];
const done=levels.filter((l,i)=>i>0&&l.unlocked).length;
return React.createElement('div',{style:base},
React.createElement('div',{style:msh('#6366F1','#06B6D4')}),
React.createElement(Particles,{color:'#A78BFA'}),
React.createElement('div',{style:{...wrap,textAlign:'center',paddingTop:70}},
React.createElement('div',{style:{width:100,height:100,borderRadius:24,background:'linear-gradient(145deg,rgba(99,102,241,0.2),rgba(6,182,212,0.12))',border:'2px solid rgba(99,102,241,0.3)',display:'inline-flex',alignItems:'center',justifyContent:'center',marginBottom:28,position:'relative'}},
React.createElement('div',{style:{position:'absolute',inset:4,borderRadius:20,border:'1px solid rgba(251,191,36,0.2)'}}),
React.createElement('span',{style:{fontFamily:"'Fira Code',monospace",fontWeight:800,fontSize:42,background:'linear-gradient(135deg,#38BDF8,#818CF8)',WebkitBackgroundClip:'text',WebkitTextFillColor:'transparent'}},'Py')),
React.createElement('h1',{style:{fontSize:52,fontWeight:900,letterSpacing:-2,background:'linear-gradient(135deg,#FFF,#94A3B8)',WebkitBackgroundClip:'text',WebkitTextFillColor:'transparent',marginBottom:6,lineHeight:1.1}},'ZakCode'),
React.createElement('p',{style:{fontSize:20,fontWeight:600,background:'linear-gradient(135deg,#A78BFA,#38BDF8)',WebkitBackgroundClip:'text',WebkitTextFillColor:'transparent',marginBottom:10}},'Python Edition'),
React.createElement('p',{style:{color:'#64748B',fontSize:15,marginBottom:40,lineHeight:1.6}},'Quiz Β· Fill in the Code Β· Debug the Bugs',React.createElement('br'),'8 levels Β· 40 challenges Β· Master the basics!'),
totalXP>0&&React.createElement('div',{style:{display:'flex',gap:12,justifyContent:'center',marginBottom:36,flexWrap:'wrap'}},
[{l:'Total XP',v:totalXP,i:'⚑'},{l:'Best Streak',v:bestStreak,i:'πŸ”₯'},{l:'Rank',v:rank,i:'πŸ†'},{l:'Levels',v:`${done}/8`,i:'πŸ“Š'}].map((s,i)=>
React.createElement('div',{key:i,style:{background:'rgba(15,23,42,0.6)',border:'1px solid rgba(148,163,184,0.08)',borderRadius:14,padding:'14px 16px',textAlign:'center',flex:'1 1 100px',minWidth:80}},
React.createElement('div',{style:{fontSize:20,marginBottom:2}},s.i),
React.createElement('div',{style:{fontSize:20,fontWeight:800,color:'#E2E8F0'}},s.v),
React.createElement('div',{style:{fontSize:11,color:'#64748B',marginTop:2}},s.l)))),
React.createElement('button',{onClick:()=>setScreen(SC.LEVELS),style:{...btn,background:'linear-gradient(135deg,#6366F1,#8B5CF6)',color:'#FFF',fontSize:18,padding:'18px 52px',boxShadow:'0 8px 32px rgba(99,102,241,0.3)'},onMouseEnter:e=>e.target.style.transform='translateY(-2px)',onMouseLeave:e=>e.target.style.transform='translateY(0)'},totalXP>0?'Continue Learning β†’':'Start Learning β†’'),
React.createElement('div',{style:{marginTop:56,paddingTop:20,borderTop:'1px solid rgba(148,163,184,0.07)',color:'#4B5563',fontSize:13}},
'Created by ',React.createElement('span',{style:{color:'#A78BFA',fontWeight:600}},'Dr Zakia Salod'),React.createElement('br'),'Software Developer & AI Researcher')));
}
// LEVELS
if(screen===SC.LEVELS){
return React.createElement('div',{style:base},
React.createElement('div',{style:msh('#6366F1','#06B6D4')}),
React.createElement(Particles,{color:'#38BDF8'}),
React.createElement('div',{style:wrap},
React.createElement('button',{onClick:()=>setScreen(SC.HOME),style:{...btn,background:'transparent',color:'#64748B',padding:'8px 0',fontSize:14,marginBottom:20}},'← Back'),
React.createElement('h2',{style:{fontSize:32,fontWeight:800,letterSpacing:-1,marginBottom:6,color:'#FFF'}},'Choose Your Level'),
React.createElement('p',{style:{color:'#64748B',marginBottom:32,fontSize:14}},'Complete each level to unlock the next'),
React.createElement('div',{style:{display:'flex',flexDirection:'column',gap:12}},
levels.map((l,i)=>{const lk=!l.unlocked;return React.createElement('button',{key:l.id,onClick:()=>!lk&&startLvl(i),disabled:lk,
style:{...btn,background:lk?'rgba(15,23,42,0.4)':'rgba(15,23,42,0.7)',border:`1px solid ${lk?'rgba(148,163,184,0.05)':l.color+'30'}`,borderRadius:16,padding:'18px 22px',display:'flex',alignItems:'center',gap:16,textAlign:'left',opacity:lk?0.4:1,cursor:lk?'not-allowed':'pointer',width:'100%',position:'relative',overflow:'hidden',animation:`slideIn 0.3s ease ${i*0.05}s both`},
onMouseEnter:e=>{if(!lk)e.currentTarget.style.borderColor=l.color+'60'},onMouseLeave:e=>{if(!lk)e.currentTarget.style.borderColor=l.color+'30'}},
!lk&&React.createElement('div',{style:{position:'absolute',top:0,left:0,right:0,height:3,background:`linear-gradient(90deg,${l.color},${l.color}88)`}}),
React.createElement('div',{style:{width:46,height:46,borderRadius:12,background:lk?'rgba(148,163,184,0.05)':l.color+'15',display:'flex',alignItems:'center',justifyContent:'center',fontSize:22,flexShrink:0}},lk?'πŸ”’':l.icon),
React.createElement('div',{style:{flex:1}},
React.createElement('div',{style:{fontSize:16,fontWeight:700,color:lk?'#4B5563':'#E2E8F0'}},`Level ${l.id}: ${l.name}`),
React.createElement('div',{style:{fontSize:12,color:'#64748B',marginTop:2}},`${l.questions.length} challenges Β· ${lk?'Locked':'Ready'}`)),
!lk&&React.createElement('div',{style:{color:l.color,fontWeight:700,fontSize:20}},'β†’'));}))));
}
// COMPLETE
if(screen===SC.DONE){
const pct=Math.round((lvlOk/tQ)*100),stars=pct>=100?3:pct>=60?2:pct>=20?1:0,nx=cLvl+1<levels.length;
return React.createElement('div',{style:base},
React.createElement('div',{style:msh(lv.color,'#6366F1')}),
React.createElement(Particles,{color:lv.color,count:25}),
React.createElement('div',{style:{...wrap,textAlign:'center',paddingTop:70}},
React.createElement('div',{style:{fontSize:60,marginBottom:12,animation:'popIn 0.5s ease'}},stars>=3?'πŸ†':stars>=2?'⭐':stars>=1?'πŸ‘':'πŸ’ͺ'),
React.createElement('h2',{style:{fontSize:34,fontWeight:800,color:'#FFF',marginBottom:6,letterSpacing:-1}},stars>=3?'Perfect!':stars>=2?'Great Job!':'Level Complete!'),
React.createElement('p',{style:{color:lv.color,fontSize:17,fontWeight:600,marginBottom:28}},`${lv.icon} ${lv.name}`),
React.createElement('div',{style:{fontSize:38,marginBottom:28,letterSpacing:8}},[0,1,2].map(i=>React.createElement('span',{key:i,style:{opacity:i<stars?1:0.15,filter:i<stars?'none':'grayscale(1)',display:'inline-block',animation:i<stars?`starPop 0.4s ease ${i*0.2}s both`:'none'}},'⭐'))),
React.createElement('div',{style:{background:'rgba(15,23,42,0.7)',border:'1px solid rgba(148,163,184,0.08)',borderRadius:16,padding:24,marginBottom:28,display:'flex',justifyContent:'space-around'}},
[{v:lvlS,l:'XP Earned',c:lv.color},{v:`${lvlOk}/${tQ}`,l:'Correct',c:'#34D399'},{v:pct+'%',l:'Accuracy',c:'#FBBF24'}].map((s,i)=>React.createElement(React.Fragment,{key:i},i>0&&React.createElement('div',{style:{width:1,background:'rgba(148,163,184,0.1)'}}),React.createElement('div',null,React.createElement('div',{style:{fontSize:26,fontWeight:800,color:s.c}},s.v),React.createElement('div',{style:{fontSize:11,color:'#64748B',marginTop:4}},s.l))))),
React.createElement('div',{style:{display:'flex',gap:12,justifyContent:'center'}},
React.createElement('button',{onClick:()=>startLvl(cLvl),style:{...btn,background:'rgba(15,23,42,0.7)',border:'1px solid rgba(148,163,184,0.15)',color:'#94A3B8'}},'πŸ”„ Retry'),
nx?React.createElement('button',{onClick:()=>startLvl(cLvl+1),style:{...btn,background:`linear-gradient(135deg,${lv.color},${lv.color}CC)`,color:'#FFF',boxShadow:`0 8px 24px ${lv.color}30`}},'Next Level β†’'):
React.createElement('button',{onClick:()=>setScreen(SC.HOME),style:{...btn,background:'linear-gradient(135deg,#6366F1,#8B5CF6)',color:'#FFF'}},'πŸŽ‰ Quest Complete!')),
React.createElement('button',{onClick:()=>setScreen(SC.LEVELS),style:{...btn,background:'transparent',color:'#4B5563',marginTop:14,fontSize:14}},'All Levels')));
}
// PLAYING
if(screen===SC.PLAY&&q){
const prog=(cQ/tQ)*100;
const tb={quiz:{bg:'rgba(56,189,248,0.1)',bd:'rgba(56,189,248,0.2)',c:'#38BDF8',l:'🧠 Quiz'},fillblank:{bg:'rgba(52,211,153,0.1)',bd:'rgba(52,211,153,0.2)',c:'#34D399',l:'✍️ Fill the Blank'},debug:{bg:'rgba(251,113,133,0.1)',bd:'rgba(251,113,133,0.2)',c:'#FB7185',l:'πŸ› Debug'}}[q.type];
return React.createElement('div',{style:base},
React.createElement('div',{style:msh(lv.color,'#6366F1')}),
React.createElement('div',{style:wrap},
// Header
React.createElement('div',{style:{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:18}},
React.createElement('button',{onClick:()=>setScreen(SC.LEVELS),style:{...btn,background:'transparent',color:'#64748B',padding:'4px 0',fontSize:14}},'← Exit'),
React.createElement('div',{style:{display:'flex',gap:10,alignItems:'center'}},
streak>0&&React.createElement('div',{style:{background:'rgba(251,191,36,0.1)',border:'1px solid rgba(251,191,36,0.2)',borderRadius:20,padding:'3px 12px',fontSize:13,fontWeight:700,color:'#FBBF24',animation:streak>2?'pulse 1s infinite':'none'}},'πŸ”₯ '+streak),
React.createElement('div',{style:{background:'rgba(99,102,241,0.1)',border:'1px solid rgba(99,102,241,0.2)',borderRadius:20,padding:'3px 12px',fontSize:13,fontWeight:700,color:'#818CF8'}},'⚑ '+score))),
// Progress
React.createElement('div',{style:{background:'rgba(148,163,184,0.08)',borderRadius:8,height:5,marginBottom:6,overflow:'hidden'}},
React.createElement('div',{style:{height:'100%',borderRadius:8,background:`linear-gradient(90deg,${lv.color},${lv.color}AA)`,width:prog+'%',transition:'width 0.5s ease'}})),
React.createElement('div',{style:{display:'flex',justifyContent:'space-between',marginBottom:24}},
React.createElement('span',{style:{fontSize:12,color:'#4B5563'}},`${lv.icon} ${lv.name}`),
React.createElement('span',{style:{fontSize:12,color:'#4B5563'}},`${cQ+1} / ${tQ}`)),
// Badge
React.createElement('div',{style:{display:'inline-block',background:tb.bg,border:`1px solid ${tb.bd}`,borderRadius:20,padding:'4px 14px',fontSize:12,fontWeight:600,marginBottom:16,color:tb.c}},tb.l),
// Question
React.createElement('h3',{style:{fontSize:21,fontWeight:700,color:'#F1F5F9',lineHeight:1.45,marginBottom:18,animation:shk?'shake 0.5s ease':'fadeUp 0.3s ease'}},q.question),
q.code&&React.createElement(CodeBlock,{code:q.code,style:{marginBottom:22}}),
// Fill blank
q.type==='fillblank'?
React.createElement('div',{style:{marginBottom:22}},
React.createElement('div',{style:{background:'#0A0E1B',border:'1px solid rgba(148,163,184,0.1)',borderRadius:14,padding:'16px 20px',fontFamily:"'Fira Code','Courier New',monospace",fontSize:14.5,lineHeight:1.75,color:'#CBD5E1',whiteSpace:'pre-wrap'}},
React.createElement('div',{style:{display:'flex',gap:6,marginBottom:12}},
React.createElement('div',{style:{width:10,height:10,borderRadius:'50%',background:'#EF4444'}}),
React.createElement('div',{style:{width:10,height:10,borderRadius:'50%',background:'#FBBF24'}}),
React.createElement('div',{style:{width:10,height:10,borderRadius:'50%',background:'#22C55E'}})),
React.createElement('span',{style:{color:'#64748B'}},q.codeBefore),
React.createElement('input',{ref:iRef,type:'text',value:fill,onChange:e=>setFill(e.target.value),onKeyDown:e=>e.key==='Enter'&&!showR&&handleFill(),disabled:showR,placeholder:'type here...',
style:{background:showR?(ok?'rgba(52,211,153,0.15)':'rgba(251,113,133,0.15)'):'rgba(99,102,241,0.1)',border:`1px solid ${showR?(ok?'#34D399':'#FB7185'):'rgba(99,102,241,0.3)'}`,borderRadius:6,padding:'4px 10px',fontFamily:"'Fira Code','Courier New',monospace",fontSize:14.5,color:showR?(ok?'#34D399':'#FB7185'):'#E2E8F0',width:Math.max(120,fill.length*10+50)}}),
React.createElement('span',{style:{color:'#64748B'}},q.codeAfter)),
!showR&&React.createElement('div',{style:{display:'flex',gap:10,marginTop:14}},
React.createElement('button',{onClick:handleFill,style:{...btn,background:`linear-gradient(135deg,${lv.color},${lv.color}CC)`,color:'#FFF',padding:'12px 28px'}},'Submit'),
React.createElement('button',{onClick:()=>setHint(true),style:{...btn,background:'transparent',border:'1px solid rgba(148,163,184,0.12)',color:'#64748B',padding:'12px 18px',fontSize:14}},'πŸ’‘ Hint')),
hint&&!showR&&React.createElement('div',{style:{marginTop:10,padding:'10px 16px',background:'rgba(251,191,36,0.06)',border:'1px solid rgba(251,191,36,0.15)',borderRadius:10,fontSize:14,color:'#D4A843',animation:'fadeUp 0.2s ease'}},q.hint))
:
// Quiz/Debug options
React.createElement('div',{style:{display:'flex',flexDirection:'column',gap:10,marginBottom:22}},
q.options.map((opt,i)=>{
let bg='rgba(15,23,42,0.7)',bd='rgba(148,163,184,0.08)',cl='#CBD5E1';
if(showR){if(i===q.correct){bg='rgba(52,211,153,0.12)';bd='#34D399';cl='#34D399';}else if(i===sel&&!ok){bg='rgba(251,113,133,0.12)';bd='#FB7185';cl='#FB7185';}}
return React.createElement('button',{key:i,onClick:()=>handleQuiz(i),disabled:showR,
style:{...btn,background:bg,border:`1px solid ${bd}`,color:cl,padding:'15px 18px',textAlign:'left',fontSize:14.5,fontWeight:500,display:'flex',alignItems:'center',gap:14,cursor:showR?'default':'pointer',animation:`slideIn 0.3s ease ${i*0.06}s both`},
onMouseEnter:e=>{if(!showR)e.currentTarget.style.borderColor=lv.color+'50'},onMouseLeave:e=>{if(!showR)e.currentTarget.style.borderColor='rgba(148,163,184,0.08)'}},
React.createElement('span',{style:{width:28,height:28,borderRadius:8,background:showR&&i===q.correct?'rgba(52,211,153,0.2)':showR&&i===sel&&!ok?'rgba(251,113,133,0.2)':'rgba(148,163,184,0.06)',display:'flex',alignItems:'center',justifyContent:'center',fontSize:12,fontWeight:700,flexShrink:0,color:showR&&i===q.correct?'#34D399':showR&&i===sel&&!ok?'#FB7185':'#64748B'}},showR&&i===q.correct?'βœ“':showR&&i===sel&&!ok?'βœ—':String.fromCharCode(65+i)),
opt);})),
// Feedback
showR&&React.createElement('div',{style:{background:ok?'rgba(52,211,153,0.08)':'rgba(251,113,133,0.08)',border:`1px solid ${ok?'rgba(52,211,153,0.2)':'rgba(251,113,133,0.2)'}`,borderRadius:14,padding:'16px 20px',marginBottom:18,animation:'fadeUp 0.3s ease'}},
React.createElement('div',{style:{fontSize:15,fontWeight:700,marginBottom:5,color:ok?'#34D399':'#FB7185'}},ok?`βœ… Correct! +${xpG} XP`:'❌ Not quite!',ok&&streak>1?' πŸ”₯ '+streak+' streak!':''),
React.createElement('div',{style:{fontSize:13.5,color:'#94A3B8',lineHeight:1.55}},q.explanation,q.type==='fillblank'&&!ok?React.createElement('span',{style:{color:'#34D399',fontWeight:600}},' Answer: '+q.answer):null)),
// Next
showR&&React.createElement('button',{onClick:nextQ,style:{...btn,width:'100%',background:`linear-gradient(135deg,${lv.color},${lv.color}CC)`,color:'#FFF',fontSize:16,boxShadow:`0 8px 24px ${lv.color}25`,animation:'fadeUp 0.3s ease'}},cQ+1>=tQ?'See Results β†’':'Next Challenge β†’')));
}
return null;
}
ReactDOM.render(React.createElement(ZakCode),document.getElementById('root'));
</script>
</body>
</html>