Machine_Speed_Defense / index.html
eaglelandsonce's picture
Update index.html
03a7bdd verified
Raw History Blame Contribute Delete
26.9 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Machine Speed Defense</title>
<style>
*{box-sizing:border-box}body{margin:0;font-family:Arial,Helvetica,sans-serif;color:#1f2937;background:#f8fafc;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:16px}button{font:inherit;cursor:pointer}button:disabled{cursor:default}button:focus-visible,a:focus-visible{outline:3px solid #4285f4;outline-offset:3px}a{text-decoration:none}a:hover{text-decoration:underline}h1,h2,p{margin:0}ul{padding:0;list-style:none}main{width:100%;max-width:1152px;background:white;border:1px solid #e2e8f0;border-radius:16px;padding:24px;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a}h1{font-size:36px;font-weight:800;letter-spacing:-.025em}.text-center{text-align:center}.text-sm{font-size:14px}.text-xs{font-size:12px}.text-lg{font-size:18px}.text-xl{font-size:20px}.text-gray-500{color:#6b7280}.text-gray-600{color:#4b5563}.font-semibold{font-weight:600}.font-bold{font-weight:700}.font-medium{font-weight:500}.mb-2{margin-bottom:8px}.mb-3{margin-bottom:12px}.mb-4{margin-bottom:16px}.mb-5{margin-bottom:20px}.mt-3{margin-top:12px}.mt-4{margin-top:16px}.mt-6{margin-top:24px}.flex{display:flex}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-2{gap:8px}.gap-3{gap:12px}.gap-6{gap:24px}.grid{display:grid}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.rounded-lg{border-radius:8px}.rounded-xl{border-radius:12px}.rounded-2xl{border-radius:16px}.rounded-full{border-radius:999px}.border{border-width:1px;border-style:solid}.border-slate-200{border-color:#e2e8f0}.border-green-200{border-color:#bbf7d0}.border-red-200{border-color:#fecaca}.border-amber-100{border-color:#fef3c7}.bg-slate-100{background:#f1f5f9}.bg-slate-50{background:#f8fafc}.bg-white{background:white}.bg-blue-50{background:#eff6ff}.bg-red-50{background:#fef2f2}.bg-green-50{background:#f0fdf4}.bg-amber-50{background:#fffbeb}.text-blue-600,.text-blue-700{color:#1967d2}.text-red-600,.text-red-700{color:#c5221f}.text-green-800{color:#166534}.text-red-800{color:#991b1b}.text-slate-400{color:#94a3b8}.text-slate-600,.text-slate-700{color:#475569}.text-white{color:#fff}.p-3{padding:12px}.p-5{padding:20px}.px-3{padding-left:12px;padding-right:12px}.px-4{padding-left:16px;padding-right:16px}.py-1{padding-top:4px;padding-bottom:4px}.py-2{padding-top:8px;padding-bottom:8px}.py-3{padding-top:12px;padding-bottom:12px}.uppercase{text-transform:uppercase}.tracking-wide{letter-spacing:.025em}.w-full{width:100%}.text-left{text-align:left}.shadow-sm{box-shadow:0 1px 2px #0000000d}.transition{transition:all .15s}.hidden{display:none!important}#board button{height:112px;width:112px;font-size:36px;font-weight:800}#board button:not(:disabled):hover{background:#f8fafc;transform:translateY(-2px)}#questionPanel{min-height:320px}#panelChoices{margin-bottom:0}#panelChoices li+li{margin-top:8px}#panelChoices button:hover{background:#eff6ff;border-color:#bfdbfe}#hintBtn,#restartBtn{border:0}#hintBtn:disabled{opacity:.4;cursor:not-allowed}#hintBtn:hover:enabled{background:#e2e8f0}#squareBadge,#turnBadge{padding-left:10px;padding-right:10px}#banner{line-height:1.5;padding-left:12px;padding-right:12px}#restartBtn:hover{opacity:.9}@media(min-width:640px){main>div:last-child{flex-direction:row}}@media(min-width:1024px){main>.gap-6{flex-direction:row;align-items:flex-start}#questionPanel{width:50%}}@media(max-width:420px){body{padding:8px}main{padding:16px}h1{font-size:30px}#board button{width:80px;height:80px}#questionPanel{padding:16px}}
</style>
<style>
:root { --ms-blue:#4285f4; --ms-red:#ea4335; --ms-yellow:#fbbc05; --ms-green:#34a853; }
.ms-title span:nth-child(4n+1){color:var(--ms-blue)} .ms-title span:nth-child(4n+2){color:var(--ms-red)}
.ms-title span:nth-child(4n+3){color:var(--ms-yellow)} .ms-title span:nth-child(4n+4){color:var(--ms-green)}
.cell-number{color:#5f6368}.selected-cell{background:#e8f3fb}
</style>
</head>
<body class="bg-slate-50 min-h-screen flex items-center justify-center p-4">
<main class="max-w-6xl w-full bg-white rounded-2xl shadow-xl border border-slate-200 p-6">
<h1 id="appTitle" class="ms-title text-3xl sm:text-4xl font-extrabold mb-3 text-center tracking-tight" aria-label="Machine Speed Defense"></h1>
<div class="text-center mb-2 text-sm text-gray-600">
<span class="font-semibold">Reference:</span> <a href="https://services.google.com/fh/files/misc/white_paper_combating_ai_driven_threats_google_machine_speed_defense.pdf" target="_blank" rel="noopener noreferrer" style="color:#1967d2">White Paper: Combating AI-Driven Threats – Google Machine-Speed Defense</a>
</div>
<p class="text-center text-sm text-gray-500 mb-3">Tic-Tac-Toe · 35 questions from M2S1 Foundations of AI Threat Defense</p>
<p class="text-center mb-5 text-sm text-gray-500">Select a numbered square and answer correctly to claim it. A missed question returns the square to its number and passes the turn.</p>
<div role="status" aria-live="polite" id="banner" class="hidden bg-green-50 border border-green-200 text-green-800 font-bold text-center py-2 rounded-lg mb-4"></div>
<div class="flex flex-col lg:flex-row items-center lg:items-start justify-center gap-6">
<section>
<div id="board" class="grid grid-cols-3 gap-2 rounded-2xl p-3 bg-slate-100 border border-slate-200"></div>
<div class="grid grid-cols-2 gap-2 mt-3 text-sm"><div class="rounded-lg px-3 py-2 bg-blue-50 text-blue-700 font-semibold text-center">X = Player 1</div><div class="rounded-lg px-3 py-2 bg-red-50 text-red-700 font-semibold text-center">O = Player 2</div></div>
</section>
<section id="questionPanel" class="w-full lg:w-1/2 bg-white rounded-2xl border border-slate-200 shadow-sm p-5 min-h-80">
<div class="flex items-center justify-between gap-3 mb-2"><span id="squareBadge" class="hidden text-xs font-bold uppercase tracking-wide px-2.5 py-1 rounded-full bg-blue-50 text-blue-700"></span><span id="turnBadge" class="text-xs font-bold uppercase tracking-wide px-2.5 py-1 rounded-full bg-slate-100 text-slate-600"></span></div>
<h2 id="panelQuestion" class="text-xl font-semibold text-gray-800">Select a numbered square to view the question</h2>
<ul id="panelChoices" class="mt-4 space-y-2"></ul>
<p id="panelHint" class="mt-3 text-sm text-gray-600 hidden rounded-lg bg-amber-50 border border-amber-100 px-3 py-2"></p>
<button id="hintBtn" class="mt-4 px-3 py-2 bg-slate-100 text-slate-700 rounded-lg hover:bg-slate-200 font-medium disabled:opacity-40 disabled:cursor-not-allowed">Show Hint</button>
</section>
</div>
<div class="flex flex-col sm:flex-row justify-between items-center gap-3 mt-6"><p id="status" class="text-lg font-medium text-gray-800"></p><button id="restartBtn" class="px-4 py-2 text-white rounded-lg font-semibold hover:opacity-90" style="background:var(--ms-blue)">Restart Game</button></div>
</main>
<script>
const questions=[
{
"question": "What distinguishes machine-speed defense from scheduled security scanning?",
"choices": [
"Continuous analysis and rapid feedback across the SDLC",
"Running the same batch scan once per quarter",
"Waiting for every issue to enter a manual queue",
"Removing security checks from developer workflows"
],
"answer": 1,
"hint": "Security signals are consumed and acted on continuously.",
"slide": 10
},
{
"question": "Why can long intervals between security scans create risk?",
"choices": [
"They leave windows of exposure between scans",
"They automatically reduce the attack surface",
"They make every finding exploitable",
"They prevent deployment changes"
],
"answer": 1,
"hint": "A newly introduced vulnerability can remain undetected until the next scan.",
"slide": 11
},
{
"question": "What is a major problem with findings that lack runtime context?",
"choices": [
"Teams cannot easily judge real-world exploitability",
"Every finding becomes a confirmed incident",
"The source code cannot be compiled",
"The application automatically loses its logs"
],
"answer": 1,
"hint": "Context helps distinguish theoretical issues from reachable risks.",
"slide": 11
},
{
"question": "Where does IDE-level security feedback act?",
"choices": [
"While developers write code, before committing it",
"Only after an incident reaches production",
"Only during annual audits",
"Only when a customer reports an outage"
],
"answer": 1,
"hint": "The feedback appears inside the developer’s coding workflow.",
"slide": 12
},
{
"question": "What is the purpose of a CI/CD security gate?",
"choices": [
"Block high-severity findings from reaching production",
"Replace every runtime monitoring tool",
"Approve all code changes without checks",
"Delay scanning until after release"
],
"answer": 1,
"hint": "The pipeline can enforce security criteria before deployment.",
"slide": 12
},
{
"question": "What causes alert fatigue in the deck’s examples?",
"choices": [
"Large volumes of findings without exploitability context",
"A small number of verified actionable findings",
"Clear remediation guidance in developer tools",
"Prioritization based on runtime exposure"
],
"answer": 1,
"hint": "Noise makes it harder to identify the issues that matter.",
"slide": 13
},
{
"question": "Why can several low-severity findings become a critical risk?",
"choices": [
"An attacker can combine them into a multi-stage exploit chain",
"Their individual scores always add up arithmetically",
"Low-severity findings are always harmless in combination",
"Each finding must independently grant administrator access"
],
"answer": 1,
"hint": "Relationships between weaknesses can create an exploitable path.",
"slide": 17
},
{
"question": "Which sequence describes the exploit-chain stages shown in the slides?",
"choices": [
"Enumerate, Correlate, Escalate, Exfiltrate",
"Compile, Deploy, Archive, Delete",
"Authenticate, Invoice, Approve, Publish",
"Scan, Ignore, Report, Close"
],
"answer": 1,
"hint": "First map assets, then connect weaknesses and exploit the combined path.",
"slide": 17
},
{
"question": "What is the dual-use concern with open-weight models?",
"choices": [
"They support innovation but can also be adapted for offensive tasks",
"They can only be used for defensive scanning",
"They eliminate the need for threat modeling",
"They automatically prevent malicious fine-tuning"
],
"answer": 1,
"hint": "The same foundational technology can serve defenders and attackers.",
"slide": 19
},
{
"question": "How can AI-generated test cases contribute to vulnerability discovery?",
"choices": [
"Explore novel edge conditions and application logic flaws",
"Guarantee all vulnerabilities are found",
"Replace execution with formatting checks",
"Prove every warning is a real attack"
],
"answer": 1,
"hint": "The deck describes augmenting fuzzing with generated test cases.",
"slide": 20
},
{
"question": "What is the defender’s dilemma described in the deck?",
"choices": [
"Attackers need one exploitable path while defenders protect the whole attack surface",
"Attackers must fix every vulnerability before acting",
"Defenders only need to protect the login page",
"Attackers and defenders always have identical workloads"
],
"answer": 1,
"hint": "The asymmetry becomes more difficult at machine speed.",
"slide": 22
},
{
"question": "What is an example of shift-left security?",
"choices": [
"Reviewing insecure patterns inside the IDE before commit",
"Investigating anomalous production processes",
"Containing an active runtime intrusion",
"Detecting configuration drift after deployment"
],
"answer": 1,
"hint": "Shift-left brings security into earlier development stages.",
"slide": 25
},
{
"question": "What makes an AI-assisted pull request security review context-aware?",
"choices": [
"It relates code changes to threat models and vulnerability history",
"It considers only the number of changed lines",
"It ignores the rest of the codebase",
"It approves code based on the author’s job title"
],
"answer": 1,
"hint": "Reviewing a change in isolation can miss relevant risk.",
"slide": 25
},
{
"question": "Which feedback is most useful to developers?",
"choices": [
"Precise contextual findings with clear remediation guidance",
"Vague warnings without suggested fixes",
"Thousands of unprioritized alerts in a separate portal",
"A compliance score with no link to code"
],
"answer": 1,
"hint": "Useful security assistance reduces cognitive load.",
"slide": 26
},
{
"question": "Which metric approach does the developer-experience slide encourage?",
"choices": [
"Track security debt trends over time",
"Count all alerts as equally important",
"Measure only the number of installed scanners",
"Use code line count as the sole risk indicator"
],
"answer": 1,
"hint": "The goal is a quantified trend in risk reduction.",
"slide": 26
},
{
"question": "Why is runtime defense still needed when pre-production checks exist?",
"choices": [
"Pre-production processes cannot catch every issue",
"A successful build guarantees production security",
"Runtime configuration never changes",
"Shift-left tools prevent every unknown attack"
],
"answer": 1,
"hint": "Live behavior can reveal risks that were not apparent before deployment.",
"slide": 27
},
{
"question": "What does human-in-the-loop governance add to auto-remediation?",
"choices": [
"Configurable confidence thresholds and control over autonomy",
"Automatic approval of every proposed production action",
"Removal of all audit records",
"A requirement to disable runtime monitoring"
],
"answer": 1,
"hint": "Teams decide how much authority automation receives.",
"slide": 27
},
{
"question": "How does behavioral analysis help detect unfamiliar attacks?",
"choices": [
"It identifies deviations from normal service execution patterns",
"It checks only exact signatures of known malware",
"It assumes every new API call is safe",
"It looks only at the age of source files"
],
"answer": 1,
"hint": "Unexpected API calls, data access, or process trees can provide signals.",
"slide": 28
},
{
"question": "Which issue is a continuous posture assessment designed to detect?",
"choices": [
"Runtime configuration drift and misconfigured IAM roles",
"Only spelling errors in comments",
"Only missing presentation images",
"Only expired meeting invitations"
],
"answer": 1,
"hint": "Production posture can change after a successful deployment.",
"slide": 28
},
{
"question": "How should shift-left and shift-right security work together?",
"choices": [
"As a continuous feedback loop from development to runtime",
"As mutually exclusive strategies",
"As two disconnected reporting systems",
"By replacing runtime defense after the first code scan"
],
"answer": 1,
"hint": "Prevention and live detection strengthen each other.",
"slide": 29
},
{
"question": "Which posture combines development and runtime security capabilities?",
"choices": [
"Full-spectrum defense",
"Reactive-only security",
"Shift-left-only investment",
"Annual audit-only coverage"
],
"answer": 1,
"hint": "The slide describes integrated feedback across the entire SDLC.",
"slide": 30
},
{
"question": "In the exploit-window discussion, what does time-to-exploit describe?",
"choices": [
"The interval from vulnerability disclosure to exploitation",
"The time required to compile an application",
"The length of a developer’s code review",
"The time between two scheduled team meetings"
],
"answer": 1,
"hint": "A shorter interval leaves defenders less time to respond.",
"slide": 40
},
{
"question": "Why does rapid vulnerability discovery create a remediation gap?",
"choices": [
"Patch development, testing, and approval can take longer than discovery",
"Discovering an issue automatically deploys a safe fix",
"Every discovered issue is immediately exploited",
"Faster scans remove the need to prioritize"
],
"answer": 1,
"hint": "Finding issues and safely fixing them are different workloads.",
"slide": 41
},
{
"question": "What are the four phases of the AI Threat Defense framework shown?",
"choices": [
"Prepare, Scan and prioritize, Remediate, Monitor",
"Design, Market, Sell, Invoice",
"Register, Discover, Govern, Orchestrate",
"Compile, Package, Archive, Delete"
],
"answer": 1,
"hint": "The framework spans readiness, assessment, fixes, and ongoing defense.",
"slide": 42
},
{
"question": "What is the goal of the Prepare phase?",
"choices": [
"Harden the foundation and operationalize readiness for rapid response",
"Skip prioritization and patch randomly",
"Disable controls before scanning",
"Wait until an active incident begins"
],
"answer": 1,
"hint": "Preparation establishes the foundation for machine-speed remediation.",
"slide": 42
},
{
"question": "What role does CodeMender play in the deck?",
"choices": [
"An AI code security agent that finds, verifies, and fixes vulnerabilities",
"A tool used only to create slide presentations",
"A replacement for every source code repository",
"A service that only counts security alerts"
],
"answer": 1,
"hint": "Its workflow goes beyond reporting potential vulnerabilities.",
"slide": 44
},
{
"question": "Why prioritize fixes by exploitability?",
"choices": [
"To focus effort on vulnerabilities that can be exercised in context",
"To ignore all vulnerabilities with a low file count",
"To patch only the newest source files",
"To treat every scanner warning as equally urgent"
],
"answer": 1,
"hint": "Verification helps identify actionable risk.",
"slide": 44
},
{
"question": "What does the security-tuned harness add around a model?",
"choices": [
"Tools, skills, and prompts for executing the security workflow",
"A guarantee that no human review is ever needed",
"A replacement for all application tests",
"A requirement to use only one model forever"
],
"answer": 1,
"hint": "The deck distinguishes an agentic system from a model alone.",
"slide": 45
},
{
"question": "Where does the deck place CodeMender’s verification execution?",
"choices": [
"Inside a secure, customer-managed sandbox",
"Directly on every production server without isolation",
"Inside a public document shared with everyone",
"In the model response without running tests"
],
"answer": 1,
"hint": "Isolation supports controlled testing of suspected vulnerabilities.",
"slide": 47
},
{
"question": "What is the workflow shown for CodeMender remediation?",
"choices": [
"Scan, Verify, Fix, Test, Commit",
"Commit, Ignore, Scan, Delete, Notify",
"Deploy, Invoice, Archive, Scan, Publish",
"Scan, Commit, Skip tests, Close, Forget"
],
"answer": 1,
"hint": "Verification precedes repairs, and tests precede the final commit.",
"slide": 48
},
{
"question": "Who retains final approval to commit a CodeMender patch in the deck?",
"choices": [
"The developer",
"Any external scanner automatically",
"An anonymous user",
"The model with no review option"
],
"answer": 1,
"hint": "Automation proposes and validates fixes while engineers retain control.",
"slide": 48
},
{
"question": "Why run proof-of-concept exploit simulations in an isolated sandbox?",
"choices": [
"To gather execution-based evidence of exploitability",
"To attack unrelated public systems",
"To avoid documenting verification steps",
"To prove that every static warning is correct"
],
"answer": 1,
"hint": "Controlled execution helps separate actionable findings from theoretical concerns.",
"slide": 50
},
{
"question": "What should patch testing verify?",
"choices": [
"The vulnerability is fixed without introducing functional regressions",
"Only that the patch file exists",
"Only that fewer lines of code remain",
"Only that the model prefers the new wording"
],
"answer": 1,
"hint": "Both security and application behavior matter.",
"slide": 51
},
{
"question": "How does Wiz Security Graph context help remediation in the deck?",
"choices": [
"It adds runtime reachability and deployment context for prioritization",
"It removes the need to inspect application behavior",
"It grants every agent unrestricted access",
"It replaces code fixes with a diagram only"
],
"answer": 1,
"hint": "Context connects code findings to the deployed attack surface.",
"slide": 53
},
{
"question": "How does the deck describe using findings from third-party scanners?",
"choices": [
"Import them for verification and targeted remediation",
"Discard them and replace every existing scanner",
"Treat all imported findings as automatically confirmed",
"Store them without allowing developer review"
],
"answer": 1,
"hint": "The workflow can augment existing scanning investments.",
"slide": 54
}
];
const $=id=>document.getElementById(id),boardEl=$("board"),statusEl=$("status"),panelQuestion=$("panelQuestion"),panelChoices=$("panelChoices"),panelHint=$("panelHint"),hintBtn=$("hintBtn"),squareBadge=$("squareBadge"),turnBadge=$("turnBadge"),bannerEl=$("banner");
let currentPlayer,boardState,selectedCell,gameOver,cellQuestions;
$("appTitle").innerHTML=[..."Machine Speed Defense"].map(c=>c===' '?'&nbsp;':`<span>${c}</span>`).join('');
function shuffle(a){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 prepareQuestions(){return shuffle([...questions]).slice(0,9).map(q=>{const correct=q.choices[q.answer-1],choices=shuffle([...q.choices]);return{...q,choices,answer:choices.indexOf(correct)+1}})}
function initGame(){currentPlayer='X';boardState=Array(9).fill('');selectedCell=null;gameOver=false;cellQuestions=prepareQuestions();bannerEl.classList.add('hidden');panelQuestion.textContent='Select a numbered square to view the question';panelChoices.innerHTML='';panelHint.classList.add('hidden');squareBadge.classList.add('hidden');hintBtn.disabled=true;renderBoard()}
function renderBoard(){boardEl.innerHTML='';boardState.forEach((mark,idx)=>{const b=document.createElement('button'),sel=selectedCell===idx&&!mark,locked=gameOver||!!mark||selectedCell!==null;b.className='h-24 w-24 sm:h-28 sm:w-28 flex items-center justify-center text-4xl font-extrabold rounded-xl shadow-sm border border-slate-200 transition focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-300 '+(mark==='X'?'bg-blue-50 text-blue-600 ':mark==='O'?'bg-red-50 text-red-600 ':sel?'selected-cell text-slate-400 ':'bg-white cell-number hover:bg-slate-50 hover:-translate-y-0.5 ');b.textContent=mark||(sel?'':idx+1);b.disabled=locked;b.setAttribute('aria-label',mark?`Square ${idx+1}: ${mark}`:`Square ${idx+1}`);b.onclick=()=>openQuestion(idx);boardEl.appendChild(b)});statusEl.textContent=gameOver?'Game complete':`Current player: ${currentPlayer}`;turnBadge.textContent=`Turn: ${currentPlayer}`;turnBadge.className='text-xs font-bold uppercase tracking-wide px-2.5 py-1 rounded-full '+(currentPlayer==='X'?'bg-blue-50 text-blue-700':'bg-red-50 text-red-700')}
function openQuestion(idx){if(gameOver||boardState[idx]||selectedCell!==null)return;selectedCell=idx;bannerEl.classList.add('hidden');const q=cellQuestions[idx];renderBoard();squareBadge.textContent=`Square ${idx+1} · Slide ${q.slide}`;squareBadge.classList.remove('hidden');panelQuestion.textContent=q.question;panelChoices.innerHTML='';panelHint.classList.add('hidden');panelHint.textContent=q.hint;hintBtn.disabled=false;q.choices.forEach((choice,i)=>{const li=document.createElement('li'),b=document.createElement('button');b.textContent=choice;b.className='w-full text-left px-4 py-3 bg-slate-50 rounded-xl hover:bg-blue-50 border border-slate-200 hover:border-blue-200 transition';b.onclick=()=>handleAnswer(i+1);li.appendChild(b);panelChoices.appendChild(li)})}
function handleAnswer(choice){if(selectedCell===null||gameOver)return;const idx=selectedCell,q=cellQuestions[idx],correct=choice===q.answer;if(correct){boardState[idx]=currentPlayer;flash('Correct! Square claimed.','green');selectedCell=null;if(checkWin()){gameOver=true;bannerEl.textContent=`Player ${currentPlayer} wins!`;bannerEl.classList.remove('hidden')}else if(boardState.every(Boolean)){gameOver=true;bannerEl.textContent="It's a draw!";bannerEl.classList.remove('hidden')}else currentPlayer=currentPlayer==='X'?'O':'X'}else{flash(`Not quite. Correct answer: ${q.choices[q.answer-1]}`,'red');selectedCell=null;currentPlayer=currentPlayer==='X'?'O':'X'}panelQuestion.textContent=gameOver?'Game complete':'Select a numbered square to view the question';panelChoices.innerHTML='';panelHint.classList.add('hidden');squareBadge.classList.add('hidden');hintBtn.disabled=true;renderBoard()}
function flash(message,color){bannerEl.textContent=message;bannerEl.className=`${color==='green'?'bg-green-50 border-green-200 text-green-800':'bg-red-50 border-red-200 text-red-800'} border font-bold text-center py-2 rounded-lg mb-4`;bannerEl.classList.remove('hidden')}
function checkWin(){return[[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]].some(line=>line.every(i=>boardState[i]===currentPlayer))}
hintBtn.onclick=()=>panelHint.classList.toggle('hidden');$("restartBtn").onclick=initGame;initGame();
</script>
</body>
</html>