<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>Mr Mauro's Phonics: The Case of the Missing 'A'!</title>
<link href="https://fonts.googleapis.com/css2?family=Fredoka+One&family=Quicksand:wght=500;700&display=swap" rel="stylesheet">
<style>
:root {
--primary: #FF5E97;
--primary-dark: #D84373;
--secondary: #4BC0C0;
--accent: #FFE266;
--background: #E8F5E9;
--card-bg: #FFFFFF;
--font-family: 'Quicksand', sans-serif;
--title-family: 'Fredoka One', cursive;
}
* {
box-sizing: border-box;
user-select: none;
-webkit-user-select: none;
}
body {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
font-family: var(--font-family);
background: linear-gradient(135deg, #FFF5F5 0%, #E8F5E9 100%);
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}
#game-container {
width: 100%;
max-width: 1024px;
height: 100%;
max-height: 768px;
background: #FFF;
border: 10px solid #FFCDD2;
border-radius: 40px;
box-shadow: 0 16px 32px rgba(0,0,0,0.15);
position: relative;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* Full screen color flashes */
.flash-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 99;
opacity: 0;
transition: background-color 0.1s, opacity 0.1s;
}
.flash-green {
animation: flashGAnim 0.8s forwards;
}
.flash-red {
animation: flashRAnim 0.8s forwards;
}
@keyframes flashGAnim {
0% { background-color: rgba(76, 175, 80, 0.5); opacity: 1; }
40% { background-color: rgba(76, 175, 80, 0.3); opacity: 0.7; }
100% { background-color: transparent; opacity: 0; }
}
@keyframes flashRAnim {
0% { background-color: rgba(244, 67, 54, 0.5); opacity: 1; }
40% { background-color: rgba(244, 67, 54, 0.3); opacity: 0.7; }
100% { background-color: transparent; opacity: 0; }
}
/* Screen Management */
.screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
flex-direction: column;
align-items: center;
padding: 25px;
text-align: center;
}
.screen.active {
display: flex;
}
/* Typography */
h1 {
font-family: var(--title-family);
color: var(--primary);
font-size: 3rem;
margin: 15px 0;
text-shadow: 3px 3px 0px #FFF, 5px 5px 0px rgba(0,0,0,0.05);
}
h2 {
font-family: var(--title-family);
color: #333;
font-size: 2.2rem;
margin: 5px 0;
}
p {
font-size: 1.4rem;
color: #555;
margin: 5px 0 15px 0;
font-weight: 700;
}
/* Buttons */
.btn {
font-family: var(--title-family);
font-size: 1.8rem;
padding: 15px 45px;
border: none;
border-radius: 60px;
cursor: pointer;
box-shadow: 0 8px 0px rgba(0,0,0,0.15);
transition: transform 0.1s, box-shadow 0.1s;
outline: none;
}
.btn-pink {
background-color: var(--primary);
color: white;
}
.btn-pink:hover {
background-color: var(--primary-dark);
}
.btn:active {
transform: translateY(4px);
box-shadow: 0 4px 0px rgba(0,0,0,0.15);
}
/* START SCREEN */
#start-screen {
justify-content: space-around;
background: radial-gradient(circle, #FFF9C4 0%, #FFF59D 100%);
}
.mascot-container {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 15px;
min-height: 280px;
}
.superhero-mascot-vector {
height: 280px;
width: 280px;
background: radial-gradient(circle, #E3F2FD 0%, #BBDEFB 100%);
border-radius: 35px;
border: 8px solid #FFF;
box-shadow: 0 12px 24px rgba(0,0,0,0.15);
display: flex;
align-items: center;
justify-content: center;
font-size: 9.5rem;
line-height: 1;
animation: bounce 1.5s infinite alternate ease-in-out;
}
/* GAME SCREEN */
#game-screen {
justify-content: space-between;
background: #E0F2F1;
padding-top: 15px;
}
#progress-bar-container {
width: 85%;
background: #B2DFDB;
height: 20px;
border-radius: 15px;
overflow: hidden;
margin-bottom: 10px;
box-shadow: inset 0 3px 6px rgba(0,0,0,0.1);
}
#progress-fill {
width: 0%;
height: 100%;
background: var(--secondary);
border-radius: 15px;
transition: width 0.3s ease;
}
.score-stars {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 8px;
margin: 5px 0;
min-height: 35px;
max-width: 90%;
}
.star {
width: 25px;
height: 25px;
fill: #CCC;
transition: fill 0.3s, stroke 0.3s, transform 0.3s;
}
.star.earned {
fill: #FFD700;
transform: scale(1.3);
}
.star.missed {
fill: #E0E0E0;
stroke: #EF5350;
stroke-width: 2px;
transform: scale(0.9);
}
/* Game Area Layout */
.game-area {
display: flex;
width: 100%;
flex: 1;
justify-content: space-around;
align-items: center;
position: relative;
}
/* Drop Zones */
.drop-zone {
width: 220px;
height: 240px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.7);
border: 5px dashed #80CBC4;
border-radius: 25px;
transition: transform 0.2s, background-color 0.2s, border-color 0.2s;
position: relative;
}
.drop-zone.hover {
background: rgba(255, 255, 255, 0.95);
border-color: var(--primary);
transform: scale(1.08);
}
.zone-image {
width: 160px;
height: 160px;
object-fit: contain;
pointer-events: none;
}
.zone-label {
font-family: var(--title-family);
font-size: 1.8rem;
color: #00796B;
margin-top: 10px;
}
/* Draggable Item Card with Transitions */
#draggable-card {
width: 220px;
height: 280px;
background: var(--card-bg);
border: 6px solid #4BC0C0;
border-radius: 25px;
box-shadow: 0 12px 24px rgba(0,0,0,0.15);
cursor: grab;
position: absolute;
left: calc(50% - 110px);
top: calc(50% - 140px);
z-index: 10;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
padding: 15px;
touch-action: none;
}
#draggable-card:active {
cursor: grabbing;
}
/* Transition Keyframes for Smooth Gameplay Flow */
@keyframes cardSlideIn {
0% { transform: translate(0, -250px) scale(0.5); opacity: 0; }
70% { transform: translate(0, 10px) scale(1.05); opacity: 1; }
100% { transform: translate(0, 0) scale(1); opacity: 1; }
}
@keyframes cardSlideOutLeft {
0% { transform: translate(0, 0) rotate(0deg); opacity: 1; }
100% { transform: translate(-300px, 80px) rotate(-35deg) scale(0.6); opacity: 0; }
}
@keyframes cardSlideOutRight {
0% { transform: translate(0, 0) rotate(0deg); opacity: 1; }
100% { transform: translate(300px, 80px) rotate(35deg) scale(0.6); opacity: 0; }
}
@keyframes cardFadeOutFail {
0% { transform: scale(1); opacity: 1; }
100% { transform: scale(0.7) translateY(50px); opacity: 0; }
}
.card-enter {
animation: cardSlideIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.2) forwards;
}
.card-exit-left {
animation: cardSlideOutLeft 0.5s cubic-bezier(0.25, 1, 0.5, 1) forwards;
}
.card-exit-right {
animation: cardSlideOutRight 0.5s cubic-bezier(0.25, 1, 0.5, 1) forwards;
}
.card-exit-fail {
animation: cardFadeOutFail 0.55s cubic-bezier(0.25, 1, 0.5, 1) forwards;
}
.card-svg-container {
width: 160px;
height: 160px;
display: flex;
align-items: center;
justify-content: center;
}
.card-svg-container svg {
width: 100%;
height: 100%;
}
.card-word {
font-family: var(--title-family);
font-size: 2rem;
color: #333;
margin: 0;
text-transform: capitalize;
}
/* Wrong Overlay (Fading red X) */
#wrong-overlay {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.92);
border-radius: 19px;
justify-content: center;
align-items: center;
z-index: 15;
flex-direction: column;
animation: fadeIn 0.25s forwards;
}
@keyframes fadeIn {
from { opacity: 0; transform: scale(0.9); }
to { opacity: 1; transform: scale(1); }
}
/* Accessibility/Mobile Touch Helper Buttons */
.mobile-buttons {
display: flex;
gap: 40px;
margin-bottom: 15px;
}
.mob-btn {
font-family: var(--title-family);
font-size: 1.5rem;
padding: 12px 35px;
border-radius: 20px;
border: none;
background: #FFF;
box-shadow: 0 6px 0 rgba(0,0,0,0.1);
cursor: pointer;
}
.mob-btn:active {
transform: translateY(3px);
box-shadow: 0 3px 0 rgba(0,0,0,0.1);
}
/* Hint Button at bottom left */
.hint-btn {
position: absolute;
bottom: 25px;
left: 25px;
background: #FFF;
border: 4px solid var(--secondary);
width: 65px;
height: 65px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 2.3rem;
cursor: pointer;
box-shadow: 0 6px 0 rgba(0,0,0,0.15);
z-index: 20;
transition: transform 0.1s, box-shadow 0.1s;
}
.hint-btn:active {
transform: translateY(3px);
box-shadow: 0 3px 0 rgba(0,0,0,0.15);
}
/* Hint Modal Popup */
.hint-modal {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 100;
justify-content: center;
align-items: center;
opacity: 0;
transition: opacity 0.3s ease;
}
.hint-modal.active {
display: flex;
opacity: 1;
}
.hint-content {
background: #FFF;
width: 85%;
max-width: 520px;
border-radius: 35px;
border: 6px solid var(--secondary);
padding: 30px;
position: relative;
transform: scale(0.8);
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
text-align: center;
box-shadow: 0 15px 30px rgba(0,0,0,0.25);
}
.hint-modal.active .hint-content {
transform: scale(1);
}
.hint-close {
position: absolute;
top: 15px;
right: 22px;
font-size: 2.2rem;
font-weight: bold;
color: #888;
cursor: pointer;
}
.hint-close:hover {
color: #333;
}
.hint-title {
font-family: var(--title-family);
color: var(--primary);
font-size: 2.1rem;
margin-bottom: 20px;
}
.hint-box {
background: #F0FBFB;
border: 3px solid #B2DFDB;
border-radius: 18px;
padding: 15px;
margin-bottom: 15px;
text-align: left;
}
.hint-box p {
font-size: 1.15rem;
margin: 8px 0 0 0;
color: #444;
line-height: 1.45;
}
.hint-badge {
font-family: var(--title-family);
background: var(--primary);
color: white;
padding: 4px 15px;
border-radius: 12px;
font-size: 1.1rem;
display: inline-block;
}
.badge-an {
background: var(--secondary);
}
/* COMPLETION SCREEN */
#completion-screen {
justify-content: center;
background: radial-gradient(circle, #FFFDE7 0%, #FFF9C4 100%);
overflow-y: auto;
}
.certificate {
width: 95%;
max-width: 800px;
border: 12px double #FFB74D;
background: #FFF;
border-radius: 25px;
padding: 35px;
box-shadow: 0 15px 30px rgba(0,0,0,0.1);
position: relative;
margin-bottom: 15px;
}
.cert-title {
font-family: var(--title-family);
color: #FF8F00;
font-size: 2.8rem;
margin: 0 0 10px 0;
}
.cert-sub {
font-size: 1.4rem;
color: #666;
margin-bottom: 25px;
}
.name-input-box {
margin: 20px 0;
}
.name-input-box label {
font-weight: bold;
font-size: 1.3rem;
display: block;
margin-bottom: 8px;
color: #E65100;
}
.student-name-input {
font-family: var(--title-family);
font-size: 2rem;
padding: 10px 20px;
border: 4px solid #FFB74D;
border-radius: 20px;
width: 80%;
text-align: center;
color: var(--primary-dark);
outline: none;
}
.cert-score {
font-family: var(--title-family);
font-size: 2.2rem;
color: var(--primary);
margin: 20px 0;
}
.cert-instructions {
font-size: 1.1rem;
color: #777;
background: #FFF9C4;
padding: 15px;
border-radius: 12px;
display: inline-block;
margin-top: 15px;
border: 2px dashed #FBC02D;
}
.no-replay-warning {
color: #C62828;
font-size: 1.1rem;
font-weight: bold;
margin-top: 15px;
}
/* Animations */
@keyframes bounce {
from { transform: translateY(0) scale(1); }
to { transform: translateY(-12px) scale(1.03); }
}
.correct-pop {
animation: pop 0.4s ease-out;
}
.wrong-shake {
animation: shake 0.4s ease-in-out;
}
@keyframes pop {
0% { transform: scale(1); }
50% { transform: scale(1.15) rotate(4deg); }
100% { transform: scale(1); }
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
20%, 60% { transform: translateX(-15px); }
40%, 80% { transform: translateX(15px); }
}
/* Confetti Canvas overlay */
#confetti-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 98;
}
/* SVG Library Definitions (hidden) */
.svg-library {
display: none;
}
</style>
</head>
<body>
<div id="game-container">
<div id="flash-overlay" class="flash-overlay"></div>
<canvas id="confetti-canvas"></canvas>
<!-- 1. START SCREEN -->
<div id="start-screen" class="screen active">
<div>
<h1>The Case of the Missing "A"!</h1>
<h2>Help Mr Mauro!</h2>
<p>A fun sorting adventure for Grammar Superstars!</p>
</div>
<div class="mascot-container">
<div class="superhero-mascot-vector">
🧔
</div>
</div>
<button class="btn btn-pink" onclick="startGame()">Start Game! ➔</button>
</div>
<!-- 2. GAME SCREEN -->
<div id="game-screen" class="screen">
<div id="progress-bar-container">
<div id="progress-fill"></div>
</div>
<div class="score-stars" id="stars-row">
<!-- Stars populated by script -->
</div>
<p style="margin: 0; color: #00796B;">Drag the card to A or An, or tap the buttons below!</p>
<div class="game-area">
<!-- Left Zone (A) -->
<div class="drop-zone" id="zone-a">
<img class="zone-image" src="article A.png" alt="Article A" onerror="this.onerror=null; this.src='data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 100 100\'><text x=\'50\' y=\'75\' font-size=\'75\' font-family=\'Fredoka One\' fill=\'%23FF3B30\' text-anchor=\'middle\'>A</text></svg>';">
<div class="zone-label">A</div>
</div>
<!-- Center Draggable Card -->
<div id="draggable-card" class="card-enter">
<!-- Red X Overlay for wrong answers -->
<div id="wrong-overlay">
<svg width="85" height="85" viewBox="0 0 24 24" fill="none" stroke="#D32F2F" stroke-width="4.5" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
<span style="color: #D32F2F; font-family: 'Fredoka One', cursive; font-size: 1.8rem; margin-top: 10px;">Play Again!</span>
</div>
<div class="card-svg-container" id="card-graphic">
<!-- Dynamic SVG loaded here -->
</div>
<p class="card-word" id="card-word">Word</p>
</div>
<!-- Right Zone (An) -->
<div class="drop-zone" id="zone-an">
<img class="zone-image" src="article AN.png" alt="Article AN" onerror="this.onerror=null; this.src='data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 100 100\'><text x=\'50\' y=\'75\' font-size=\'65\' font-family=\'Fredoka One\' fill=\'%23FF3B30\' text-anchor=\'middle\'>AN</text></svg>';">
<div class="zone-label">An</div>
</div>
</div>
<!-- Accessible click options for tablets/mice -->
<div class="mobile-buttons">
<button class="mob-btn" style="border: 3px solid #FF5E97; color: #FF5E97;" id="btn-choice-a" onclick="submitAnswer('a')">Put in A</button>
<button class="mob-btn" style="border: 3px solid #4BC0C0; color: #4BC0C0;" id="btn-choice-an" onclick="submitAnswer('an')">Put in An</button>
</div>
<!-- Floating Magnifying Glass Hint Button -->
<button class="hint-btn" onclick="openHint()" title="Get a Hint!">🔍</button>
</div>
<!-- HINT MODAL -->
<div id="hint-modal" class="hint-modal">
<div class="hint-content">
<span class="hint-close" onclick="closeHint()">×</span>
<div class="hint-title">💡 Mr Mauro's Golden Phonics Rule!</div>
<div class="hint-body">
<div class="hint-box">
<span class="hint-badge">Use A</span>
<p>If the word starts with a <strong>consonant sound</strong> (like <strong>C</strong>at, <strong>D</strong>og, <strong>P</strong>encil, <strong>T</strong>oilet).</p>
</div>
<div class="hint-box">
<span class="hint-badge badge-an">Use An</span>
<p>If the word starts with a <strong>vowel sound</strong>: <strong>A</strong>, <strong>E</strong>, <strong>I</strong>, <strong>O</strong>, <strong>U</strong> (like <strong>A</strong>pple, <strong>E</strong>lephant, <strong>I</strong>ce cream).</p>
</div>
</div>
<button class="btn btn-pink" onclick="closeHint()" style="font-size: 1.4rem; padding: 10px 30px; margin-top: 15px;">Got it! ➔</button>
</div>
</div>
<!-- 3. COMPLETION SCREEN -->
<div id="completion-screen" class="screen">
<div class="certificate">
<div class="cert-title">Grammar Superstar!</div>
<div class="cert-sub">Kowloon True Light School (Primary Section)</div>
<div class="name-input-box">
<label for="student-name">Type Your Name Here:</label>
<input type="text" id="student-name" class="student-name-input" placeholder="Your Name" oninput="updateCertName()">
</div>
<p style="font-size: 1.5rem; margin: 10px 0;">Has successfully completed</p>
<h2 style="color: #4BC0C0; font-family: var(--title-family); font-size: 2.2rem;">"The Case of the Missing 'A'!" Game</h2>
<div class="cert-score" id="final-score-display">
Score: 15 / 15 Stars! ⭐
</div>
<div class="cert-instructions">
📸 <strong>Parents:</strong> Please type your child's name above, take a picture or screenshot of this certificate, and send it to your teacher!
</div>
</div>
<div class="no-replay-warning">
To play again, please refresh this page!
</div>
</div>
</div>
<!-- SVG Graphics Library Definitions (Upgraded for high visual quality) -->
<div class="svg-library">
<!-- CAT -->
<div id="svg-cat">
<svg viewBox="0 0 120 120">
<defs>
<radialGradient id="catBody" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="#FFB374" />
<stop offset="100%" stop-color="#E67E22" />
</radialGradient>
</defs>
<path d="M 85 85 C 105 85, 105 50, 95 50 C 90 50, 93 65, 85 70 Z" fill="#E67E22" />
<polygon points="25,45 15,10 45,30" fill="#E67E22" stroke="#D35400" stroke-width="2" />
<polygon points="28,40 20,18 40,28" fill="#FFADAD" />
<polygon points="95,45 105,10 75,30" fill="#E67E22" stroke="#D35400" stroke-width="2" />
<polygon points="92,40 100,18 80,28" fill="#FFADAD" />
<ellipse cx="60" cy="78" rx="35" ry="30" fill="url(#catBody)" stroke="#D35400" stroke-width="2" />
<circle cx="60" cy="55" r="32" fill="url(#catBody)" stroke="#D35400" stroke-width="2" />
<circle cx="48" cy="48" r="7" fill="#2C3E50" />
<circle cx="46" cy="46" r="2.5" fill="#FFF" />
<circle cx="50" cy="50" r="1" fill="#FFF" />
<circle cx="72" cy="48" r="7" fill="#2C3E50" />
<circle cx="70" cy="46" r="2.5" fill="#FFF" />
<circle cx="74" cy="50" r="1" fill="#FFF" />
<ellipse cx="40" cy="58" rx="5" ry="3" fill="#FF8A80" opacity="0.8" />
<ellipse cx="80" cy="58" rx="5" ry="3" fill="#FF8A80" opacity="0.8" />
<polygon points="56,56 64,56 60,60" fill="#FF8A80" />
<path d="M 54,64 Q 60,68 60,64 Q 60,68 66,64" stroke="#2C3E50" stroke-width="2.5" fill="none" stroke-linecap="round" />
<line x1="30" y1="58" x2="10" y2="56" stroke="#2C3E50" stroke-width="2" />
<line x1="30" y1="63" x2="12" y2="66" stroke="#2C3E50" stroke-width="2" />
<line x1="90" y1="58" x2="110" y2="56" stroke="#2C3E50" stroke-width="2" />
<line x1="90" y1="63" x2="108" y2="66" stroke="#2C3E50" stroke-width="2" />
<rect x="42" y="80" width="36" height="6" rx="3" fill="#E74C3C" />
<circle cx="60" cy="86" r="6" fill="#F1C40F" />
<circle cx="60" cy="86" r="2" fill="#D35400" />
</svg>
</div>
<!-- DOG -->
<div id="svg-dog">
<svg viewBox="0 0 120 120">
<defs>
<linearGradient id="dogBrown" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#C0392B" />
<stop offset="100%" stop-color="#962D22" />
</linearGradient>
<radialGradient id="dogBody" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="#E5A93C" />
<stop offset="100%" stop-color="#C68B15" />
</radialGradient>
</defs>
<ellipse cx="60" cy="80" rx="32" ry="26" fill="url(#dogBody)" stroke="#9E6F0B" stroke-width="2" />
<circle cx="45" cy="100" r="10" fill="#C68B15" stroke="#9E6F0B" stroke-width="2" />
<circle cx="75" cy="100" r="10" fill="#C68B15" stroke="#9E6F0B" stroke-width="2" />
<path d="M 22,42 C 10,50 12,82 24,80 C 32,78 30,52 28,42 Z" fill="url(#dogBrown)" stroke="#78241C" stroke-width="2" />
<path d="M 98,42 C 110,50 108,82 96,80 C 88,78 90,52 92,42 Z" fill="url(#dogBrown)" stroke="#78241C" stroke-width="2" />
<circle cx="60" cy="52" r="32" fill="url(#dogBody)" stroke="#9E6F0B" stroke-width="2" />
<ellipse cx="44" cy="48" rx="14" ry="16" fill="url(#dogBrown)" opacity="0.9" />
<circle cx="44" cy="48" r="6" fill="#FFF" />
<circle cx="44" cy="48" r="3.5" fill="#2C3E50" />
<circle cx="42.5" cy="46.5" r="1.5" fill="#FFF" />
<circle cx="74" cy="48" r="6" fill="#FFF" />
<circle cx="74" cy="48" r="3.5" fill="#2C3E50" />
<circle cx="72.5" cy="46.5" r="1.5" fill="#FFF" />
<ellipse cx="60" cy="62" rx="14" ry="10" fill="#FFF" />
<ellipse cx="60" cy="56" rx="5" ry="3" fill="#2C3E50" />
<path d="M 57,66 C 57,75 63,75 63,66 Z" fill="#FF4757" />
<path d="M 54,63 Q 60,67 66,63" stroke="#2C3E50" stroke-width="2" fill="none" />
</svg>
</div>
<!-- PENCIL -->
<div id="svg-pencil">
<svg viewBox="0 0 120 120">
<defs>
<linearGradient id="pencilGrad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#FFDD59" />
<stop offset="50%" stop-color="#FFD32A" />
<stop offset="100%" stop-color="#FFA801" />
</linearGradient>
</defs>
<g transform="rotate(45 60 60)">
<rect x="42" y="10" width="36" height="15" rx="4" fill="#FF8A80" stroke="#C0392B" stroke-width="2" />
<rect x="42" y="23" width="36" height="8" fill="#D2D7D9" stroke="#7F8C8D" stroke-width="1.5" />
<line x1="48" y1="23" x2="48" y2="31" stroke="#BDC3C7" stroke-width="2" />
<line x1="60" y1="23" x2="60" y2="31" stroke="#BDC3C7" stroke-width="2" />
<line x1="72" y1="23" x2="72" y2="31" stroke="#BDC3C7" stroke-width="2" />
<rect x="42" y="31" width="36" height="50" fill="url(#pencilGrad)" stroke="#D35400" stroke-width="2" />
<circle cx="50" cy="50" r="3" fill="#2C3E50" />
<circle cx="70" cy="50" r="3" fill="#2C3E50" />
<path d="M 56,56 Q 60,60 64,56" stroke="#2C3E50" stroke-width="2" fill="none" stroke-linecap="round" />
<circle cx="46" cy="53" r="1.5" fill="#FF8A80" />
<circle cx="74" cy="53" r="1.5" fill="#FF8A80" />
<polygon points="42,81 60,105 78,81" fill="#FFEAA7" stroke="#D35400" stroke-width="2" />
<polygon points="53,95 60,105 67,95" fill="#2C3E50" />
</g>
</svg>
</div>
<!-- RULER -->
<div id="svg-ruler">
<svg viewBox="0 0 120 120">
<defs>
<linearGradient id="rulerGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#00D2D3" />
<stop offset="100%" stop-color="#00A8FF" />
</linearGradient>
</defs>
<g transform="rotate(-15 60 60)">
<rect x="15" y="42" width="90" height="36" rx="6" fill="url(#rulerGrad)" stroke="#0097E6" stroke-width="3" />
<line x1="25" y1="42" x2="25" y2="52" stroke="#FFF" stroke-width="2.5" stroke-linecap="round" />
<line x1="35" y1="42" x2="35" y2="48" stroke="#FFF" stroke-width="2" stroke-linecap="round" />
<line x1="45" y1="42" x2="45" y2="52" stroke="#FFF" stroke-width="2.5" stroke-linecap="round" />
<line x1="55" y1="42" x2="55" y2="48" stroke="#FFF" stroke-width="2" stroke-linecap="round" />
<line x1="65" y1="42" x2="65" y2="52" stroke="#FFF" stroke-width="2.5" stroke-linecap="round" />
<line x1="75" y1="42" x2="75" y2="48" stroke="#FFF" stroke-width="2" stroke-linecap="round" />
<line x1="85" y1="42" x2="85" y2="52" stroke="#FFF" stroke-width="2.5" stroke-linecap="round" />
<line x1="95" y1="42" x2="95" y2="48" stroke="#FFF" stroke-width="2" stroke-linecap="round" />
<circle cx="52" cy="62" r="3" fill="#FFF" />
<circle cx="68" cy="62" r="3" fill="#FFF" />
<path d="M 57,66 Q 60,70 63,66" stroke="#FFF" stroke-width="2" fill="none" stroke-linecap="round" />
</g>
</svg>
</div>
<!-- APPLE -->
<div id="svg-apple">
<svg viewBox="0 0 120 120">
<defs>
<radialGradient id="appleGrad" cx="35%" cy="35%" r="65%">
<stop offset="0%" stop-color="#FF7675" />
<stop offset="40%" stop-color="#D63031" />
<stop offset="100%" stop-color="#AE1C1C" />
</radialGradient>
</defs>
<path d="M 60,35 C 45,22 20,28 16,55 C 10,85 40,105 60,94 C 80,105 110,85 104,55 C 100,28 75,22 60,35 Z" fill="url(#appleGrad)" stroke="#8A0F0F" stroke-width="3" />
<path d="M 60,35 Q 63,16 72,12" stroke="#5C3818" stroke-width="5" fill="none" stroke-linecap="round" />
<path d="M 64,24 Q 85,15 80,2 C 65,5 62,20 64,24 Z" fill="#2ED573" stroke="#26AF58" stroke-width="1.5" />
<ellipse cx="36" cy="48" rx="6" ry="12" transform="rotate(-30 36 48)" fill="#FFF" opacity="0.6" />
</svg>
</div>
<!-- BANANA -->
<div id="svg-banana">
<svg viewBox="0 0 120 120">
<defs>
<linearGradient id="bananaGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#FFF200" />
<stop offset="80%" stop-color="#FFC400" />
<stop offset="100%" stop-color="#D4A000" />
</linearGradient>
</defs>
<path d="M 25,25 C 60,25 95,55 95,95 C 78,95 45,65 25,25 Z" fill="url(#bananaGrad)" stroke="#B38600" stroke-width="3" />
<path d="M 22,22 L 28,29" stroke="#4A3000" stroke-width="6" stroke-linecap="round" />
<path d="M 93,93 L 97,97" stroke="#4A3000" stroke-width="6" stroke-linecap="round" />
<path d="M 27,29 Q 55,42 84,77" stroke="#FFF" stroke-width="2" fill="none" opacity="0.5" />
<g transform="rotate(30 60 60)">
<circle cx="54" cy="45" r="3" fill="#2C3E50" />
<circle cx="66" cy="45" r="3" fill="#2C3E50" />
<path d="M 58,49 Q 60,53 62,49" stroke="#2C3E50" stroke-width="2" fill="none" stroke-linecap="round" />
</g>
</svg>
</div>
<!-- MONKEY -->
<div id="svg-monkey">
<svg viewBox="0 0 120 120">
<defs>
<radialGradient id="monkeyHead" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="#A0522D" />
<stop offset="100%" stop-color="#8B4513" />
</radialGradient>
</defs>
<circle cx="25" cy="60" r="16" fill="#8B4513" stroke="#5C2E0B" stroke-width="2" />
<circle cx="25" cy="60" r="10" fill="#FFD2A1" />
<circle cx="95" cy="60" r="16" fill="#8B4513" stroke="#5C2E0B" stroke-width="2" />
<circle cx="95" cy="60" r="10" fill="#FFD2A1" />
<circle cx="60" cy="60" r="34" fill="url(#monkeyHead)" stroke="#5C2E0B" stroke-width="2" />
<path d="M 60,40 C 46,40 38,48 40,64 C 42,78 50,86 60,86 C 70,86 78,78 80,64 C 82,48 74,40 60,40 Z" fill="#FFD2A1" />
<circle cx="48" cy="54" r="4.5" fill="#2C3E50" />
<circle cx="46.5" cy="52" r="1.5" fill="#FFF" />
<circle cx="72" cy="54" r="4.5" fill="#2C3E50" />
<circle cx="70.5" cy="52" r="1.5" fill="#FFF" />
<circle cx="40" cy="64" r="4" fill="#FF8A80" opacity="0.6" />
<circle cx="80" cy="64" r="4" fill="#FF8A80" opacity="0.6" />
<ellipse cx="60" cy="63" rx="4" ry="2" fill="#8B4513" />
<path d="M 52,69 Q 60,76 68,69" stroke="#8B4513" stroke-width="2.5" fill="none" stroke-linecap="round" />
</svg>
</div>
<!-- PEN -->
<div id="svg-pen">
<svg viewBox="0 0 120 120">
<defs>
<linearGradient id="penBlue" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#3498DB" />
<stop offset="50%" stop-color="#2980B9" />
<stop offset="100%" stop-color="#1F618D" />
</linearGradient>
</defs>
<g transform="rotate(45 60 60)">
<rect x="49" y="10" width="22" height="12" fill="#BDC3C7" stroke="#7F8C8D" stroke-width="1.5" />
<path d="M 64,28 L 74,28 L 74,50 L 64,50" fill="none" stroke="#7F8C8D" stroke-width="3" stroke-linecap="round" />
<rect x="47" y="22" width="26" height="65" rx="4" fill="url(#penBlue)" stroke="#1B4F72" stroke-width="2" />
<rect x="54" y="32" width="12" height="25" fill="#FFF" opacity="0.3" rx="2" />
<polygon points="47,87 60,110 73,87" fill="#BDC3C7" stroke="#7F8C8D" stroke-width="2" />
<polygon points="56,100 60,110 64,100" fill="#2C3E50" />
</g>
</svg>
</div>
<!-- ELEPHANT -->
<div id="svg-elephant">
<svg viewBox="0 0 120 120">
<defs>
<radialGradient id="elephantBody" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="#CED6E0" />
<stop offset="100%" stop-color="#747D8C" />
</radialGradient>
</defs>
<ellipse cx="28" cy="55" rx="22" ry="26" fill="#747D8C" stroke="#57606F" stroke-width="2" />
<ellipse cx="28" cy="55" rx="14" ry="18" fill="#FFADAD" opacity="0.6" />
<ellipse cx="92" cy="55" rx="22" ry="26" fill="#747D8C" stroke="#57606F" stroke-width="2" />
<ellipse cx="92" cy="55" rx="14" ry="18" fill="#FFADAD" opacity="0.6" />
<circle cx="60" cy="60" r="32" fill="url(#elephantBody)" stroke="#57606F" stroke-width="2" />
<circle cx="48" cy="52" r="5" fill="#2C3E50" />
<circle cx="46.5" cy="50" r="1.5" fill="#FFF" />
<circle cx="72" cy="52" r="5" fill="#2C3E50" />
<circle cx="70.5" cy="50" r="1.5" fill="#FFF" />
<path d="M 60,65 Q 60,86 74,84 Q 82,82 82,76" stroke="#CED6E0" stroke-width="10" fill="none" stroke-linecap="round" />
<path d="M 60,65 Q 60,86 74,84 Q 82,82 82,76" stroke="#747D8C" stroke-width="10" fill="none" stroke-linecap="round" opacity="0.3" />
<circle cx="86" cy="68" r="3.5" fill="#54A0FF" />
<circle cx="94" cy="72" r="2.5" fill="#54A0FF" />
<circle cx="90" cy="62" r="1.5" fill="#54A0FF" />
<ellipse cx="40" cy="60" rx="4" ry="2" fill="#FF8A80" opacity="0.6" />
<ellipse cx="80" cy="60" rx="4" ry="2" fill="#FF8A80" opacity="0.6" />
</svg>
</div>
<!-- OCTOPUS -->
<div id="svg-octopus">
<svg viewBox="0 0 120 120">
<defs>
<radialGradient id="octoGrad" cx="45%" cy="40%" r="60%">
<stop offset="0%" stop-color="#D6A2E8" />
<stop offset="100%" stop-color="#82589F" />
</radialGradient>
</defs>
<path d="M 35,70 Q 15,95 30,105 Q 40,110 45,95" stroke="#82589F" stroke-width="10" fill="none" stroke-linecap="round" />
<path d="M 50,75 Q 45,105 55,112 Q 65,112 60,95" stroke="#82589F" stroke-width="10" fill="none" stroke-linecap="round" />
<path d="M 70,75 Q 75,105 75,112 Q 85,112 80,95" stroke="#82589F" stroke-width="10" fill="none" stroke-linecap="round" />
<path d="M 85,70 Q 105,95 90,105 Q 80,110 75,95" stroke="#82589F" stroke-width="10" fill="none" stroke-linecap="round" />
<ellipse cx="60" cy="52" rx="34" ry="30" fill="url(#octoGrad)" stroke="#5B2C6F" stroke-width="2.5" />
<circle cx="22" cy="94" r="2.5" fill="#F8EFBA" />
<circle cx="28" cy="100" r="2.5" fill="#F8EFBA" />
<circle cx="50" cy="104" r="2.5" fill="#F8EFBA" />
<circle cx="70" cy="104" r="2.5" fill="#F8EFBA" />
<circle cx="92" cy="94" r="2.5" fill="#F8EFBA" />
<circle cx="88" cy="100" r="2.5" fill="#F8EFBA" />
<circle cx="48" cy="48" r="7" fill="#FFF" stroke="#5B2C6F" stroke-width="1.5" />
<circle cx="48" cy="48" r="4.5" fill="#2C3E50" />
<circle cx="46" cy="46" r="1.5" fill="#FFF" />
<circle cx="72" cy="48" r="7" fill="#FFF" stroke="#5B2C6F" stroke-width="1.5" />
<circle cx="72" cy="48" r="4.5" fill="#2C3E50" />
<circle cx="70" cy="46" r="1.5" fill="#FFF" />
<circle cx="38" cy="56" r="4" fill="#FF8A80" opacity="0.8" />
<circle cx="82" cy="56" r="4" fill="#FF8A80" opacity="0.8" />
<circle cx="60" cy="58" r="4" fill="#FF5E97" stroke="#5B2C6F" stroke-width="2" />
<circle cx="26" cy="30" r="4" fill="none" stroke="#D6A2E8" stroke-width="1.5" opacity="0.6" />
<circle cx="34" cy="22" r="2" fill="none" stroke="#D6A2E8" stroke-width="1" opacity="0.6" />
</svg>
</div>
<!-- UMBRELLA -->
<div id="svg-umbrella">
<svg viewBox="0 0 120 120">
<defs>
<linearGradient id="umbRed" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#FF4757" />
<stop offset="100%" stop-color="#FF6B81" />
</linearGradient>
<linearGradient id="umbYellow" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#FFA502" />
<stop offset="100%" stop-color="#FFD200" />
</linearGradient>
</defs>
<path d="M 20,60 Q 60,15 100,60 C 90,52 75,52 65,60 C 55,52 40,52 30,60 Z" fill="url(#umbRed)" stroke="#2C3E50" stroke-width="3" />
<path d="M 38,59 C 48,51 53,51 60,60 C 67,51 72,51 82,59 C 72,42 48,42 38,59 Z" fill="url(#umbYellow)" />
<polygon points="56,22 60,10 64,22" fill="#BDC3C7" stroke="#2C3E50" stroke-width="2" />
<line x1="60" y1="60" x2="60" y2="92" stroke="#747D8C" stroke-width="5" stroke-linecap="round" />
<path d="M 60,92 Q 60,102 50,102 Q 40,102 40,92" stroke="#747D8C" stroke-width="5" fill="none" stroke-linecap="round" />
<path d="M 18,30 Q 14,38 18,38 Q 22,38 18,30" fill="#54A0FF" />
<path d="M 102,25 Q 98,33 102,33 Q 106,33 102,25" fill="#54A0FF" />
</svg>
</div>
<!-- ORANGE -->
<div id="svg-orange">
<svg viewBox="0 0 120 120">
<defs>
<radialGradient id="orangeGrad" cx="35%" cy="35%" r="65%">
<stop offset="0%" stop-color="#FFA502" />
<stop offset="70%" stop-color="#FF7F50" />
<stop offset="100%" stop-color="#FF6B81" />
</radialGradient>
</defs>
<circle cx="60" cy="62" r="32" fill="url(#orangeGrad)" stroke="#E056FD" stroke-width="3" />
<circle cx="60" cy="30" r="3" fill="#5C3818" />
<path d="M 60,30 Q 64,18 72,16" stroke="#5C3818" stroke-width="3" fill="none" />
<path d="M 64,24 Q 85,15 80,4 C 66,7 62,20 64,24 Z" fill="#2ED573" stroke="#26AF58" stroke-width="1.5" />
<circle cx="42" cy="50" r="1.5" fill="#D35400" opacity="0.7" />
<circle cx="78" cy="55" r="1.5" fill="#D35400" opacity="0.7" />
<circle cx="48" cy="80" r="1.5" fill="#D35400" opacity="0.7" />
<circle cx="74" cy="78" r="1.5" fill="#D35400" opacity="0.7" />
<ellipse cx="48" cy="46" rx="4" ry="8" transform="rotate(-30 48 46)" fill="#FFF" opacity="0.5" />
</svg>
</div>
<!-- EGG -->
<div id="svg-egg">
<svg viewBox="0 0 120 120">
<defs>
<radialGradient id="eggYolk" cx="35%" cy="35%" r="65%">
<stop offset="0%" stop-color="#FFEA00" />
<stop offset="100%" stop-color="#FF9100" />
</radialGradient>
</defs>
<path d="M 15,75 Q 35,50 60,65 Q 85,50 105,75" fill="none" stroke="#BDC3C7" stroke-width="2" />
<path d="M 60,18 C 25,18 10,48 10,74 C 10,102 38,110 60,110 C 82,110 110,102 110,74 C 110,48 95,18 60,18 Z" fill="#F5F6FA" stroke="#DCDDE1" stroke-width="3" />
<path d="M 28,52 C 22,65 24,85 24,94" stroke="#FFF" stroke-width="5" fill="none" stroke-linecap="round" opacity="0.6" />
<circle cx="60" cy="65" r="24" fill="url(#eggYolk)" stroke="#E67E22" stroke-width="2.5" />
<circle cx="52" cy="58" r="3" fill="#2C3E50" />
<circle cx="68" cy="58" r="3" fill="#2C3E50" />
<path d="M 56,66 Q 60,72 64,66" stroke="#2C3E50" stroke-width="2.5" fill="none" stroke-linecap="round" />
<circle cx="46" cy="62" r="2.5" fill="#FF8A80" opacity="0.8" />
<circle cx="74" cy="62" r="2.5" fill="#FF8A80" opacity="0.8" />
<ellipse cx="48" cy="52" rx="2" ry="4" transform="rotate(-20 48 52)" fill="#FFF" opacity="0.6" />
<path d="M 37,64 Q 30,55 32,50" stroke="#FF9100" stroke-width="4" stroke-linecap="round" fill="none" />
</svg>
</div>
<!-- NOSE (Funny Groucho Marx Disguise Emoji) -->
<div id="svg-nose">
<svg viewBox="0 0 120 120">
<defs>
<linearGradient id="noseGrad" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#FFD2A1" />
<stop offset="100%" stop-color="#FFB374" />
</linearGradient>
</defs>
<path d="M 22,25 C 28,15 48,18 48,26" stroke="#2C3E50" stroke-width="8" stroke-linecap="round" fill="none" />
<path d="M 98,25 C 92,15 72,18 72,26" stroke="#2C3E50" stroke-width="8" stroke-linecap="round" fill="none" />
<rect x="20" y="28" width="80" height="8" rx="4" fill="#2C3E50" />
<circle cx="38" cy="46" r="16" fill="none" stroke="#2C3E50" stroke-width="6" />
<circle cx="82" cy="46" r="16" fill="none" stroke="#2C3E50" stroke-width="6" />
<path d="M 46,38 C 42,65 32,85 45,92 C 55,98 65,98 75,92 C 88,85 78,65 74,38 Z" fill="url(#noseGrad)" stroke="#D35400" stroke-width="3" />
<ellipse cx="60" cy="80" rx="14" ry="10" fill="#FF8A80" opacity="0.4" />
<path d="M 60,94 C 40,94 30,104 22,98 C 15,92 25,86 42,92 C 55,96 60,94 60,94 C 60,94 65,96 78,92 C 95,86 105,92 98,98 C 90,104 80,94 60,94 Z" fill="#2C3E50" />
</svg>
</div>
<!-- EAR (Funny lop-eared boy) -->
<div id="svg-ear">
<svg viewBox="0 0 120 120">
<defs>
<linearGradient id="skinGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#FFE0BD" />
<stop offset="100%" stop-color="#FFC48C" />
</linearGradient>
</defs>
<path d="M 28,45 Q 60,10 92,45 C 80,25 40,25 28,45 Z" fill="#5C3818" stroke="#3D2510" stroke-width="2" />
<circle cx="60" cy="62" r="32" fill="url(#skinGrad)" stroke="#D35400" stroke-width="2" />
<path d="M 28,45 Q 60,28 92,45 Q 75,38 60,42 Q 45,38 28,45 Z" fill="#5C3818" />
<circle cx="27" cy="62" r="4" fill="#FFC48C" stroke="#D35400" stroke-width="1.5" />
<path d="M 92,62 C 102,40 125,44 120,68 C 115,94 95,88 92,72 Z" fill="#FFC48C" stroke="#D35400" stroke-width="3" />
<path d="M 98,64 Q 112,56 112,68 Q 112,78 102,74" stroke="#D35400" stroke-width="2.5" fill="none" stroke-linecap="round" />
<path d="M 104,70 Q 108,72 108,74" stroke="#D35400" stroke-width="2" fill="none" />
<circle cx="48" cy="58" r="3.5" fill="#2C3E50" />
<circle cx="72" cy="58" r="3.5" fill="#2C3E50" />
<circle cx="42" cy="66" r="3.5" fill="#FF8A80" opacity="0.6" />
<circle cx="78" cy="66" r="3.5" fill="#FF8A80" opacity="0.6" />
<path d="M 52,72 Q 60,82 68,72" stroke="#2C3E50" stroke-width="2.5" fill="none" stroke-linecap="round" />
</svg>
</div>
<!-- TOILET (Safe, friendly, cartoon styled) -->
<div id="svg-toilet">
<svg viewBox="0 0 120 120">
<defs>
<linearGradient id="toiletGrad" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#FFFFFF" />
<stop offset="100%" stop-color="#E2E8F0" />
</linearGradient>
</defs>
<!-- Tank -->
<rect x="35" y="20" width="50" height="42" rx="8" fill="url(#toiletGrad)" stroke="#A0AEC0" stroke-width="3" />
<!-- Flush Handle -->
<rect x="42" y="28" width="12" height="6" rx="2" fill="#CBD5E0" stroke="#718096" stroke-width="1.5" />
<!-- Tank Connection Neck -->
<rect x="52" y="62" width="16" height="12" fill="#CBD5E0" stroke="#A0AEC0" stroke-width="2" />
<!-- Bowl Rim -->
<ellipse cx="60" cy="74" rx="28" ry="12" fill="url(#toiletGrad)" stroke="#A0AEC0" stroke-width="3" />
<!-- Inside Water -->
<ellipse cx="60" cy="74" rx="20" ry="7" fill="#EBF8FF" stroke="#90CDF4" stroke-width="1" />
<!-- Base Pillar -->
<path d="M 38,72 Q 38,102 48,108 L 72,108 Q 82,102 82,72 Z" fill="url(#toiletGrad)" stroke="#A0AEC0" stroke-width="3" />
<!-- Foot/Base Rim -->
<rect x="44" y="104" width="32" height="6" rx="2" fill="#CBD5E0" stroke="#A0AEC0" stroke-width="2" />
<!-- Happy Face on Base -->
<circle cx="50" cy="88" r="3.5" fill="#2D3748" />
<circle cx="70" cy="88" r="3.5" fill="#2D3748" />
<path d="M 56,94 Q 60,98 64,94" stroke="#2D3748" stroke-width="2.5" fill="none" stroke-linecap="round" />
<circle cx="44" cy="90" r="2.5" fill="#FEB2B2" />
<circle cx="76" cy="90" r="2.5" fill="#FEB2B2" />
</svg>
</div>
<!-- ALIEN -->
<div id="svg-alien">
<svg viewBox="0 0 120 120">
<defs>
<radialGradient id="alienGrad" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="#A8E6CF" />
<stop offset="100%" stop-color="#1B5E20" />
</radialGradient>
</defs>
<line x1="45" y1="35" x2="35" y2="15" stroke="#81C784" stroke-width="4" stroke-linecap="round" />
<circle cx="34" cy="12" r="6" fill="#FFD54F" />
<line x1="75" y1="35" x2="85" y2="15" stroke="#81C784" stroke-width="4" stroke-linecap="round" />
<circle cx="86" cy="12" r="6" fill="#FFD54F" />
<ellipse cx="60" cy="60" rx="38" ry="28" fill="url(#alienGrad)" stroke="#1B5E20" stroke-width="3" />
<circle cx="42" cy="50" r="7" fill="#FFF" />
<circle cx="42" cy="50" r="4" fill="#311B92" />
<circle cx="40.5" cy="48.5" r="1.5" fill="#FFF" />
<circle cx="60" cy="46" r="9" fill="#FFF" />
<circle cx="60" cy="46" r="5" fill="#311B92" />
<circle cx="58.5" cy="44.5" r="2" fill="#FFF" />
<circle cx="78" cy="50" r="7" fill="#FFF" />
<circle cx="78" cy="50" r="4" fill="#311B92" />
<circle cx="76.5" cy="48.5" r="1.5" fill="#FFF" />
<path d="M 46,70 Q 60,85 74,70" stroke="#1B5E20" stroke-width="3" fill="none" stroke-linecap="round" />
<rect x="57" y="70" width="6" height="5" fill="#FFF" stroke="#1B5E20" stroke-width="1.5" />
</svg>
</div>
<!-- ICECREAM -->
<div id="svg-icecream">
<svg viewBox="0 0 120 120">
<defs>
<linearGradient id="coneGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#FFEAA7" />
<stop offset="100%" stop-color="#D5A6BD" />
</linearGradient>
</defs>
<polygon points="60,112 35,65 85,65" fill="#E5C290" stroke="#8D6E63" stroke-width="3" />
<line x1="45" y1="65" x2="68" y2="112" stroke="#8D6E63" stroke-width="1.5" />
<line x1="55" y1="65" x2="76" y2="104" stroke="#8D6E63" stroke-width="1.5" />
<line x1="65" y1="65" x2="82" y2="95" stroke="#8D6E63" stroke-width="1.5" />
<line x1="75" y1="65" x2="52" y2="112" stroke="#8D6E63" stroke-width="1.5" />
<line x1="65" y1="65" x2="44" y2="104" stroke="#8D6E63" stroke-width="1.5" />
<line x1="55" y1="65" x2="38" y2="95" stroke="#8D6E63" stroke-width="1.5" />
<circle cx="60" cy="62" r="22" fill="#55EFC4" stroke="#00B894" stroke-width="2" />
<circle cx="60" cy="46" r="18" fill="#FF7675" stroke="#D63031" stroke-width="2" />
<path d="M 42,46 C 42,32 78,32 78,46 C 78,54 72,50 68,54 C 64,50 56,50 52,54 C 48,50 42,54 42,46 Z" fill="#6D4C41" />
<line x1="52" y1="42" x2="56" y2="40" stroke="#FFEAA7" stroke-width="3" stroke-linecap="round" />
<line x1="64" y1="45" x2="68" y2="43" stroke="#74B9FF" stroke-width="3" stroke-linecap="round" />
<line x1="58" y1="36" x2="62" y2="38" stroke="#55EFC4" stroke-width="3" stroke-linecap="round" />
<circle cx="60" cy="26" r="8" fill="#D63031" />
<path d="M 60,20 Q 64,8 72,10" stroke="#2C3E50" stroke-width="2.5" fill="none" stroke-linecap="round" />
</svg>
</div>
</div>
<script>
// Audio Synthesizer Engine
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
function playSound(type) {
if (audioCtx.state === 'suspended') {
audioCtx.resume();
}
const osc = audioCtx.createOscillator();
const gainNode = audioCtx.createGain();
osc.connect(gainNode);
gainNode.connect(audioCtx.destination);
if (type === 'success') {
osc.type = 'sine';
osc.frequency.setValueAtTime(523.25, audioCtx.currentTime);
osc.frequency.setValueAtTime(659.25, audioCtx.currentTime + 0.1);
osc.frequency.setValueAtTime(783.99, audioCtx.currentTime + 0.2);
gainNode.gain.setValueAtTime(0.15, audioCtx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.4);
osc.start();
osc.stop(audioCtx.currentTime + 0.4);
} else if (type === 'error') {
osc.type = 'triangle';
osc.frequency.setValueAtTime(220, audioCtx.currentTime);
osc.frequency.exponentialRampToValueAtTime(110, audioCtx.currentTime + 0.35);
gainNode.gain.setValueAtTime(0.2, audioCtx.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.4);
osc.start();
osc.stop(audioCtx.currentTime + 0.4);
} else if (type === 'fanfare') {
const notes = [261.63, 329.63, 392.00, 523.25, 659.25, 783.99, 1046.50];
notes.forEach((freq, idx) => {
const o = audioCtx.createOscillator();
const g = audioCtx.createGain();
o.connect(g);
g.connect(audioCtx.destination);
o.frequency.setValueAtTime(freq, audioCtx.currentTime + idx * 0.08);
g.gain.setValueAtTime(0.1, audioCtx.currentTime + idx * 0.08);
g.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + idx * 0.08 + 0.3);
o.start(audioCtx.currentTime + idx * 0.08);
o.stop(audioCtx.currentTime + idx * 0.08 + 0.3);
});
}
}
// Comprehensive Vowel & Consonant Word Pools (18 items total)
// Swapped "unicorn" out and "toilet" in.
const wordPool = [
{ word: 'cat', type: 'a', svg: 'cat' },
{ word: 'dog', type: 'a', svg: 'dog' },
{ word: 'pencil', type: 'a', svg: 'pencil' },
{ word: 'ruler', type: 'a', svg: 'ruler' },
{ word: 'banana', type: 'a', svg: 'banana' },
{ word: 'monkey', type: 'a', svg: 'monkey' },
{ word: 'pen', type: 'a', svg: 'pen' },
{ word: 'nose', type: 'a', svg: 'nose' },
{ word: 'toilet', type: 'a', svg: 'toilet' },
{ word: 'apple', type: 'an', svg: 'apple' },
{ word: 'elephant', type: 'an', svg: 'elephant' },
{ word: 'octopus', type: 'an', svg: 'octopus' },
{ word: 'umbrella', type: 'an', svg: 'umbrella' },
{ word: 'orange', type: 'an', svg: 'orange' },
{ word: 'egg', type: 'an', svg: 'egg' },
{ word: 'ear', type: 'an', svg: 'ear' },
{ word: 'alien', type: 'an', svg: 'alien' },
{ word: 'ice cream', type: 'an', svg: 'icecream' }
];
let gameWords = [];
let currentIdx = 0;
let score = 0;
let isActionLocked = false;
const maxItems = 15; // EXACTLY 15 rounds
// Initialize/Shuffle Game Items
function initGameWords() {
const shuffled = [...wordPool].sort(() => 0.5 - Math.random());
gameWords = shuffled.slice(0, maxItems);
}
function startGame() {
if (audioCtx.state === 'suspended') {
audioCtx.resume();
}
initGameWords();
currentIdx = 0;
score = 0;
isActionLocked = false;
// Populate stars
const starsRow = document.getElementById('stars-row');
starsRow.innerHTML = '';
for (let i = 0; i < maxItems; i++) {
starsRow.innerHTML += `
<svg class="star" id="star-${i}" viewBox="0 0 24 24">
<path d="M12,17.27L18.18,21L16.54,13.97L22,9.24L14.81,8.62L12,2L9.19,8.62L2,9.24L7.45,13.97L5.82,21L12,17.27Z"/>
</svg>
`;
}
showScreen('game-screen');
loadCard();
}
function showScreen(screenId) {
document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
document.getElementById(screenId).classList.add('active');
}
function loadCard() {
if (currentIdx >= maxItems) {
endGame();
return;
}
isActionLocked = false;
const currentItem = gameWords[currentIdx];
// Update Progress Bar
const progress = (currentIdx / maxItems) * 100;
document.getElementById('progress-fill').style.width = `${progress}%`;
// Update Card Visual & Label
document.getElementById('card-word').textContent = currentItem.word;
const targetGraphic = document.getElementById(`svg-${currentItem.svg}`);
const cardContainer = document.getElementById('card-graphic');
if (targetGraphic) {
cardContainer.innerHTML = targetGraphic.innerHTML;
} else {
cardContainer.innerHTML = '';
}
// Reset Card overlays and styles with beautiful introduction animation
document.getElementById('wrong-overlay').style.display = 'none';
const card = document.getElementById('draggable-card');
card.removeAttribute('style'); // Clear inline styles completely
card.className = 'card-enter';
}
function submitAnswer(chosenType) {
if (isActionLocked) return;
isActionLocked = true;
const currentItem = gameWords[currentIdx];
const card = document.getElementById('draggable-card');
const flash = document.getElementById('flash-overlay');
// Clear inline manual transforms so CSS animation transitions smoothly from the center
card.style.transform = '';
if (chosenType === currentItem.type) {
// Correct Answer -> Green Flash + Earned Star
playSound('success');
flash.className = 'flash-overlay';
void flash.offsetWidth; // Force CSS reflow to re-trigger overlay animation
flash.className = 'flash-overlay flash-green';
// Beautiful side-exit transition
if (chosenType === 'a') {
card.className = 'card-exit-left';
} else {
card.className = 'card-exit-right';
}
triggerVisualConfetti();
score++;
document.getElementById(`star-${currentIdx}`).classList.add('earned');
currentIdx++;
setTimeout(() => {
flash.className = 'flash-overlay';
loadCard();
}, 550); // Matches sliding transition
} else {
// Incorrect Answer -> Red Flash + Red X Overlay + Missed Star
playSound('error');
flash.className = 'flash-overlay';
void flash.offsetWidth; // Force CSS reflow
flash.className = 'flash-overlay flash-red';
card.className = 'wrong-shake';
// Show fading "X" block immediately inside the card
document.getElementById('wrong-overlay').style.display = 'flex';
document.getElementById(`star-${currentIdx}`).classList.add('missed');
currentIdx++;
// Smoother exit sequence for errors
setTimeout(() => {
card.className = 'card-exit-fail';
}, 650);
setTimeout(() => {
flash.className = 'flash-overlay';
loadCard();
}, 1150);
}
}
// Modal Hint System
function openHint() {
document.getElementById('hint-modal').classList.add('active');
}
function closeHint() {
document.getElementById('hint-modal').classList.remove('active');
}
// Touch and Drag Mechanism for Cards
const cardElement = document.getElementById('draggable-card');
let startX = 0, startY = 0;
let currentX = 0, currentY = 0;
let isDragging = false;
cardElement.addEventListener('pointerdown', dragStart);
document.addEventListener('pointermove', dragMove);
document.addEventListener('pointerup', dragEnd);
function dragStart(e) {
if (isActionLocked) return;
isDragging = true;
startX = e.clientX;
startY = e.clientY;
cardElement.className = ''; // Disable entrance animation during dragging
cardElement.style.transition = 'none';
}
function dragMove(e) {
if (!isDragging || isActionLocked) return;
currentX = e.clientX - startX;
currentY = e.clientY - startY;
cardElement.style.transform = `translate(${currentX}px, ${currentY}px) rotate(${currentX * 0.05}deg)`;
const zoneA = document.getElementById('zone-a');
const zoneAn = document.getElementById('zone-an');
const cardRect = cardElement.getBoundingClientRect();
const aRect = zoneA.getBoundingClientRect();
const anRect = zoneAn.getBoundingClientRect();
if (isOverlapping(cardRect, aRect)) {
zoneA.classList.add('hover');
} else {
zoneA.classList.remove('hover');
}
if (isOverlapping(cardRect, anRect)) {
zoneAn.classList.add('hover');
} else {
zoneAn.classList.remove('hover');
}
}
function dragEnd() {
if (!isDragging) return;
isDragging = false;
cardElement.style.transition = 'transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275)';
const zoneA = document.getElementById('zone-a');
const zoneAn = document.getElementById('zone-an');
const cardRect = cardElement.getBoundingClientRect();
const aRect = zoneA.getBoundingClientRect();
const anRect = zoneAn.getBoundingClientRect();
zoneA.classList.remove('hover');
zoneAn.classList.remove('hover');
if (isOverlapping(cardRect, aRect)) {
submitAnswer('a');
} else if (isOverlapping(cardRect, anRect)) {
submitAnswer('an');
} else {
cardElement.style.transform = 'translate(0px, 0px) rotate(0deg)';
}
}
function isOverlapping(rect1, rect2) {
return !(rect1.right < rect2.left ||
rect1.left > rect2.right ||
rect1.bottom < rect2.top ||
rect1.top > rect2.bottom);
}
// End Game Handler
function endGame() {
playSound('fanfare');
document.getElementById('final-score-display').textContent = `Score: ${score} / ${maxItems} Stars! ⭐`;
showScreen('completion-screen');
startPersistentConfetti();
}
function updateCertName() {
const input = document.getElementById('student-name');
if (input.value.trim() !== "") {
input.style.border = "4px solid #4BC0C0";
} else {
input.style.border = "4px solid #FFB74D";
}
}
// Interactive Confetti Engine
const canvas = document.getElementById('confetti-canvas');
const ctx = canvas.getContext('2d');
let confettiActive = false;
let particles = [];
function resizeCanvas() {
canvas.width = document.getElementById('game-container').clientWidth;
canvas.height = document.getElementById('game-container').clientHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
function triggerVisualConfetti() {
resizeCanvas();
for (let i = 0; i < 30; i++) {
particles.push({
x: canvas.width / 2,
y: canvas.height / 2,
vx: (Math.random() - 0.5) * 10,
vy: (Math.random() - 0.5) * 10 - 5,
color: ['#FF5E97', '#4BC0C0', '#FFE266', '#FF9F43', '#10AC84'][Math.floor(Math.random() * 5)],
radius: Math.random() * 5 + 4,
alpha: 1,
decay: Math.random() * 0.03 + 0.02
});
}
if (!confettiActive) {
confettiActive = true;
animateParticles();
}
}
function startPersistentConfetti() {
resizeCanvas();
for (let i = 0; i < 80; i++) {
particles.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height - canvas.height,
vx: (Math.random() - 0.5) * 3,
vy: Math.random() * 3 + 2,
color: ['#FF5E97', '#4BC0C0', '#FFE266', '#FF9F43', '#10AC84'][Math.floor(Math.random() * 5)],
radius: Math.random() * 5 + 4,
alpha: 1,
decay: 0
});
}
if (!confettiActive) {
confettiActive = true;
animateParticles();
}
}
function animateParticles() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
let alive = false;
particles.forEach((p, idx) => {
p.x += p.vx;
p.y += p.vy;
if (p.decay > 0) {
p.alpha -= p.decay;
}
if (p.alpha > 0 && p.y < canvas.height) {
alive = true;
ctx.beginPath();
ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
ctx.fillStyle = p.color;
ctx.globalAlpha = p.alpha;
ctx.fill();
} else if (p.decay === 0) {
p.y = -10;
p.x = Math.random() * canvas.width;
}
});
if (alive) {
requestAnimationFrame(animateParticles);
} else {
confettiActive = false;
particles = [];
}
}
</script>
</body>
</html>