Upload 3 files
Browse files- index.html +51 -19
- script.js +213 -0
- style.css +139 -17
index.html
CHANGED
@@ -1,19 +1,51 @@
|
|
1 |
-
<!
|
2 |
-
<html>
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>Multiplication Farm! 🧑🌾</title>
|
7 |
+
<link rel="stylesheet" href="style.css">
|
8 |
+
<link href="https://fonts.googleapis.com/css2?family=Lilita+One&display=swap" rel="stylesheet">
|
9 |
+
</head>
|
10 |
+
<body>
|
11 |
+
|
12 |
+
<div id="game-wrapper">
|
13 |
+
|
14 |
+
<h1>Multiplication Farm!</h1>
|
15 |
+
|
16 |
+
<div id="score-area">
|
17 |
+
Score: <span id="score">0</span> / <span id="total-questions">10</span>
|
18 |
+
</div>
|
19 |
+
|
20 |
+
<div id="problem-area">
|
21 |
+
<h2>Time to Plant/Gather!</h2>
|
22 |
+
<p>Show me this multiplication:</p>
|
23 |
+
<div id="multiplication-problem">
|
24 |
+
<span id="num1">?</span> x <span id="num2">?</span> = ?
|
25 |
+
</div>
|
26 |
+
</div>
|
27 |
+
|
28 |
+
<div id="feedback-area">
|
29 |
+
Click the farm plot that matches the problem!
|
30 |
+
</div>
|
31 |
+
|
32 |
+
<div id="farm-options-area">
|
33 |
+
<h2>Choose the Correct Farm Plot:</h2>
|
34 |
+
<div id="field-choices">
|
35 |
+
<!-- Farm plot options will be dynamically added here by JS -->
|
36 |
+
<!-- Example of one plot option structure (repeated by JS) -->
|
37 |
+
<!--
|
38 |
+
<div class="field-option" data-rows="3" data-cols="4">
|
39 |
+
<div class="item">🍎</div> <div class="item">🍎</div> <div class="item">🍎</div> <div class="item">🍎</div>
|
40 |
+
<div class="item">🍎</div> <div class="item">🍎</div> <div class="item">🍎</div> <div class="item">🍎</div>
|
41 |
+
<div class="item">🍎</div> <div class="item">🍎</div> <div class="item">🍎</div> <div class="item">🍎</div>
|
42 |
+
</div>
|
43 |
+
-->
|
44 |
+
</div>
|
45 |
+
</div>
|
46 |
+
|
47 |
+
</div> <!-- End of game-wrapper -->
|
48 |
+
|
49 |
+
<script src="script.js"></script>
|
50 |
+
</body>
|
51 |
+
</html>
|
script.js
ADDED
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
document.addEventListener('DOMContentLoaded', () => {
|
2 |
+
const scoreDisplay = document.getElementById('score');
|
3 |
+
const totalQuestionsDisplay = document.getElementById('total-questions');
|
4 |
+
const num1Display = document.getElementById('num1');
|
5 |
+
const num2Display = document.getElementById('num2');
|
6 |
+
const feedbackArea = document.getElementById('feedback-area');
|
7 |
+
const fieldChoicesContainer = document.getElementById('field-choices');
|
8 |
+
|
9 |
+
const OPTIONS_COUNT = 3; // Number of plot choices (1 correct, 2 incorrect)
|
10 |
+
const MAX_FACTOR = 6; // Maximum number for factors (e.g., up to 6x6)
|
11 |
+
const TOTAL_ROUNDS = 10; // Number of questions in a game
|
12 |
+
|
13 |
+
// --- Items for the Farm ---
|
14 |
+
const farmItems = ['🍎', '🥕', '🐔', '🐑', '🌻', '🌽'];
|
15 |
+
|
16 |
+
// --- Generate Multiplication Problems ---
|
17 |
+
let possibleProblems = [];
|
18 |
+
function generateProblems() {
|
19 |
+
possibleProblems = [];
|
20 |
+
for (let i = 1; i <= MAX_FACTOR; i++) {
|
21 |
+
// Start j from 1 to include squares and both orders (e.g., 2x3 and 3x2 are distinct visual arrays)
|
22 |
+
for (let j = 1; j <= MAX_FACTOR; j++) {
|
23 |
+
possibleProblems.push({ num1: i, num2: j, answer: i * j });
|
24 |
+
}
|
25 |
+
}
|
26 |
+
// Remove duplicates might be needed if we consider A*B same as B*A later
|
27 |
+
}
|
28 |
+
|
29 |
+
// --- Game State ---
|
30 |
+
let score = 0;
|
31 |
+
let currentProblem = null;
|
32 |
+
let currentRound = 0;
|
33 |
+
let waitingForNext = false;
|
34 |
+
|
35 |
+
// --- Utility: Get Random Int ---
|
36 |
+
function getRandomInt(max) {
|
37 |
+
return Math.floor(Math.random() * max);
|
38 |
+
}
|
39 |
+
|
40 |
+
// --- Utility: Shuffle Array ---
|
41 |
+
function shuffleArray(array) {
|
42 |
+
for (let i = array.length - 1; i > 0; i--) {
|
43 |
+
const j = getRandomInt(i + 1);
|
44 |
+
[array[i], array[j]] = [array[j], array[i]];
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
// --- Setup a New Round ---
|
49 |
+
function setupNewRound() {
|
50 |
+
if (currentRound >= TOTAL_ROUNDS) {
|
51 |
+
endGame();
|
52 |
+
return;
|
53 |
+
}
|
54 |
+
|
55 |
+
waitingForNext = false;
|
56 |
+
fieldChoicesContainer.innerHTML = '';
|
57 |
+
feedbackArea.textContent = "Click the farm plot that matches the problem!";
|
58 |
+
feedbackArea.className = '';
|
59 |
+
|
60 |
+
currentRound++;
|
61 |
+
|
62 |
+
// 1. Choose a target problem
|
63 |
+
if (!possibleProblems || possibleProblems.length === 0) generateProblems(); // Regenerate if empty
|
64 |
+
const problemIndex = getRandomInt(possibleProblems.length);
|
65 |
+
currentProblem = possibleProblems.splice(problemIndex, 1)[0]; // Pick and remove
|
66 |
+
|
67 |
+
num1Display.textContent = currentProblem.num1;
|
68 |
+
num2Display.textContent = currentProblem.num2;
|
69 |
+
|
70 |
+
// 2. Create options array (as {rows, cols})
|
71 |
+
// Allow commutative property visually (3x4 can be 3 rows of 4 OR 4 rows of 3)
|
72 |
+
const correctOption = { rows: currentProblem.num1, cols: currentProblem.num2 };
|
73 |
+
const options = [correctOption];
|
74 |
+
|
75 |
+
// 3. Generate incorrect options
|
76 |
+
while (options.length < OPTIONS_COUNT) {
|
77 |
+
let wrongRows, wrongCols;
|
78 |
+
let isDuplicate = true;
|
79 |
+
let attempts = 0; // Prevent infinite loop
|
80 |
+
|
81 |
+
while(isDuplicate && attempts < 20) {
|
82 |
+
// Generate wrong dimensions, make sure at least one is different
|
83 |
+
const changeRows = Math.random() > 0.5;
|
84 |
+
wrongRows = changeRows ? getRandomInt(MAX_FACTOR) + 1 : correctOption.rows;
|
85 |
+
wrongCols = !changeRows ? getRandomInt(MAX_FACTOR) + 1 : correctOption.cols;
|
86 |
+
|
87 |
+
// Ensure it's actually wrong AND not zero product AND different from target
|
88 |
+
if((wrongRows !== correctOption.rows || wrongCols !== correctOption.cols) &&
|
89 |
+
(wrongRows * wrongCols > 0) ) {
|
90 |
+
|
91 |
+
// Check if this combination (or its commutative pair) is already in options
|
92 |
+
isDuplicate = options.some(opt =>
|
93 |
+
(opt.rows === wrongRows && opt.cols === wrongCols) ||
|
94 |
+
(opt.rows === wrongCols && opt.cols === wrongRows)
|
95 |
+
);
|
96 |
+
} else {
|
97 |
+
isDuplicate = true; // Force retry if generated same as correct or zero product
|
98 |
+
}
|
99 |
+
attempts++;
|
100 |
+
}
|
101 |
+
// If stuck finding unique, just create a simple wrong one
|
102 |
+
if (attempts >= 20) {
|
103 |
+
wrongRows = correctOption.rows === 1 ? 2 : correctOption.rows -1;
|
104 |
+
wrongCols = correctOption.cols;
|
105 |
+
isDuplicate = options.some(opt =>
|
106 |
+
(opt.rows === wrongRows && opt.cols === wrongCols) ||
|
107 |
+
(opt.rows === wrongCols && opt.cols === wrongRows)
|
108 |
+
); // Final check
|
109 |
+
}
|
110 |
+
|
111 |
+
|
112 |
+
if (!isDuplicate) {
|
113 |
+
options.push({ rows: wrongRows, cols: wrongCols });
|
114 |
+
}
|
115 |
+
}
|
116 |
+
|
117 |
+
// 4. Shuffle options
|
118 |
+
shuffleArray(options);
|
119 |
+
|
120 |
+
// 5. Create and display field elements
|
121 |
+
options.forEach(plot => {
|
122 |
+
const fieldDiv = document.createElement('div');
|
123 |
+
fieldDiv.classList.add('field-option');
|
124 |
+
fieldDiv.dataset.rows = plot.rows;
|
125 |
+
fieldDiv.dataset.cols = plot.cols;
|
126 |
+
|
127 |
+
// Style the grid layout for items *inside* this field
|
128 |
+
fieldDiv.style.gridTemplateColumns = `repeat(${plot.cols}, auto)`; // auto size columns
|
129 |
+
fieldDiv.style.gridTemplateRows = `repeat(${plot.rows}, auto)`; // auto size rows
|
130 |
+
// Set a max-width to prevent huge single rows/columns
|
131 |
+
fieldDiv.style.maxWidth = `${plot.cols * 35}px`; // Approx item size + gap
|
132 |
+
|
133 |
+
|
134 |
+
// Add items (emoji)
|
135 |
+
const itemEmoji = farmItems[getRandomInt(farmItems.length)];
|
136 |
+
for (let i = 0; i < plot.rows * plot.cols; i++) {
|
137 |
+
const itemSpan = document.createElement('span');
|
138 |
+
itemSpan.classList.add('item');
|
139 |
+
itemSpan.textContent = itemEmoji;
|
140 |
+
fieldDiv.appendChild(itemSpan);
|
141 |
+
}
|
142 |
+
|
143 |
+
fieldDiv.addEventListener('click', handleChoiceClick);
|
144 |
+
fieldChoicesContainer.appendChild(fieldDiv);
|
145 |
+
});
|
146 |
+
|
147 |
+
console.log("New round setup. Target:", currentProblem);
|
148 |
+
}
|
149 |
+
|
150 |
+
// --- Handle Field Choice Click ---
|
151 |
+
function handleChoiceClick(event) {
|
152 |
+
if (waitingForNext) return;
|
153 |
+
|
154 |
+
const clickedField = event.currentTarget;
|
155 |
+
const clickedRows = parseInt(clickedField.dataset.rows);
|
156 |
+
const clickedCols = parseInt(clickedField.dataset.cols);
|
157 |
+
|
158 |
+
waitingForNext = true;
|
159 |
+
|
160 |
+
// Remove listeners
|
161 |
+
document.querySelectorAll('.field-option').forEach(opt => {
|
162 |
+
const clone = opt.cloneNode(true);
|
163 |
+
opt.parentNode.replaceChild(clone, opt);
|
164 |
+
});
|
165 |
+
|
166 |
+
// Check if correct (allow commutative: A x B or B x A)
|
167 |
+
const isCorrect = (clickedRows === currentProblem.num1 && clickedCols === currentProblem.num2) ||
|
168 |
+
(clickedRows === currentProblem.num2 && clickedCols === currentProblem.num1);
|
169 |
+
|
170 |
+
if (isCorrect) {
|
171 |
+
score++;
|
172 |
+
scoreDisplay.textContent = score;
|
173 |
+
feedbackArea.textContent = `Yes! ${currentProblem.num1} x ${currentProblem.num2} = ${currentProblem.answer}! 🎉`;
|
174 |
+
feedbackArea.className = 'correct-feedback';
|
175 |
+
|
176 |
+
const newClickedElement = fieldChoicesContainer.querySelector(`.field-option[data-rows="${clickedRows}"][data-cols="${clickedCols}"]`);
|
177 |
+
if (newClickedElement) newClickedElement.classList.add('correct-choice');
|
178 |
+
|
179 |
+
} else {
|
180 |
+
feedbackArea.textContent = `Oops! That shows ${clickedRows} x ${clickedCols}. The answer was ${currentProblem.answer}. 🤔`;
|
181 |
+
feedbackArea.className = 'incorrect-feedback';
|
182 |
+
|
183 |
+
const newClickedElement = fieldChoicesContainer.querySelector(`.field-option[data-rows="${clickedRows}"][data-cols="${clickedCols}"]`);
|
184 |
+
if (newClickedElement) newClickedElement.classList.add('incorrect-choice');
|
185 |
+
|
186 |
+
// Highlight the correct answer(s)
|
187 |
+
setTimeout(() => {
|
188 |
+
const correctElement1 = fieldChoicesContainer.querySelector(`.field-option[data-rows="${currentProblem.num1}"][data-cols="${currentProblem.num2}"]`);
|
189 |
+
if (correctElement1) correctElement1.classList.add('correct-choice');
|
190 |
+
// Also highlight commutative pair if it exists and is different
|
191 |
+
const correctElement2 = fieldChoicesContainer.querySelector(`.field-option[data-rows="${currentProblem.num2}"][data-cols="${currentProblem.num1}"]`);
|
192 |
+
if (correctElement2 && correctElement1 !== correctElement2) correctElement2.classList.add('correct-choice');
|
193 |
+
}, 300);
|
194 |
+
}
|
195 |
+
|
196 |
+
// Load next round
|
197 |
+
setTimeout(setupNewRound, 2500); // Longer delay to see feedback/answer
|
198 |
+
}
|
199 |
+
|
200 |
+
// --- End Game ---
|
201 |
+
function endGame() {
|
202 |
+
feedbackArea.textContent = `Game Over! Your final score: ${score} / ${TOTAL_ROUNDS}! Great work! 🥳`;
|
203 |
+
feedbackArea.className = 'correct-feedback'; // Use correct style for positive end
|
204 |
+
fieldChoicesContainer.innerHTML = '<p style="font-size:1.2em; color: #795548;">Refresh the page to play again!</p>'; // Clear options
|
205 |
+
// Optionally disable further interaction if needed
|
206 |
+
}
|
207 |
+
|
208 |
+
// --- Initial Game Start ---
|
209 |
+
totalQuestionsDisplay.textContent = TOTAL_ROUNDS; // Set total rounds display
|
210 |
+
generateProblems(); // Create the initial list of problems
|
211 |
+
setupNewRound();
|
212 |
+
|
213 |
+
}); // End DOMContentLoaded
|
style.css
CHANGED
@@ -1,28 +1,150 @@
|
|
1 |
body {
|
2 |
-
|
3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
}
|
5 |
|
6 |
h1 {
|
7 |
-
|
8 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
}
|
10 |
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
margin-top: 5px;
|
16 |
}
|
17 |
|
18 |
-
.
|
19 |
-
|
20 |
-
|
21 |
-
padding: 16px;
|
22 |
-
border: 1px solid lightgray;
|
23 |
-
border-radius: 16px;
|
24 |
}
|
25 |
|
26 |
-
|
27 |
-
|
|
|
|
|
28 |
}
|
|
|
|
|
|
|
|
|
|
|
|
1 |
body {
|
2 |
+
font-family: 'Lilita One', cursive;
|
3 |
+
display: flex;
|
4 |
+
justify-content: center;
|
5 |
+
align-items: flex-start;
|
6 |
+
background-color: #c8e6c9; /* Light green background */
|
7 |
+
color: #388e3c; /* Darker green */
|
8 |
+
padding: 20px;
|
9 |
+
margin: 0;
|
10 |
+
min-height: 100vh;
|
11 |
+
}
|
12 |
+
|
13 |
+
#game-wrapper {
|
14 |
+
background-color: #fffde7; /* Light yellow */
|
15 |
+
padding: 20px 30px;
|
16 |
+
border-radius: 20px;
|
17 |
+
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15);
|
18 |
+
border: 5px solid #795548; /* Brown border */
|
19 |
+
max-width: 700px;
|
20 |
+
width: 95%;
|
21 |
+
text-align: center;
|
22 |
}
|
23 |
|
24 |
h1 {
|
25 |
+
color: #fb8c00; /* Orange */
|
26 |
+
text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.1);
|
27 |
+
margin-bottom: 15px;
|
28 |
+
}
|
29 |
+
|
30 |
+
#score-area {
|
31 |
+
font-size: 1.2em;
|
32 |
+
font-weight: bold;
|
33 |
+
color: #1e88e5; /* Blue */
|
34 |
+
background-color: #e3f2fd; /* Light blue */
|
35 |
+
padding: 5px 15px;
|
36 |
+
border-radius: 10px;
|
37 |
+
display: inline-block;
|
38 |
+
margin-bottom: 20px;
|
39 |
+
border: 2px solid #90caf9; /* Lighter blue border */
|
40 |
+
}
|
41 |
+
|
42 |
+
#problem-area {
|
43 |
+
background-color: #ffecb3; /* Light amber */
|
44 |
+
border: 3px dashed #ff8f00; /* Amber dashed border */
|
45 |
+
padding: 15px;
|
46 |
+
border-radius: 15px;
|
47 |
+
margin-bottom: 20px;
|
48 |
+
}
|
49 |
+
|
50 |
+
#problem-area h2 {
|
51 |
+
margin-top: 0;
|
52 |
+
margin-bottom: 5px;
|
53 |
+
color: #795548; /* Brown */
|
54 |
+
}
|
55 |
+
#problem-area p {
|
56 |
+
margin-top: 0;
|
57 |
+
margin-bottom: 10px;
|
58 |
+
font-size: 1.1em;
|
59 |
+
}
|
60 |
+
|
61 |
+
|
62 |
+
#multiplication-problem {
|
63 |
+
font-size: 2.8em; /* Large problem display */
|
64 |
+
font-weight: bold;
|
65 |
+
color: #e53935; /* Red */
|
66 |
+
}
|
67 |
+
|
68 |
+
#feedback-area {
|
69 |
+
margin-bottom: 25px;
|
70 |
+
font-size: 1.1em;
|
71 |
+
font-weight: bold;
|
72 |
+
color: #5d4037; /* Brown */
|
73 |
+
min-height: 30px;
|
74 |
+
padding: 10px;
|
75 |
+
border-radius: 8px;
|
76 |
+
background-color: #efebe9; /* Light brown/grey */
|
77 |
+
}
|
78 |
+
|
79 |
+
#feedback-area.correct-feedback {
|
80 |
+
color: #2e7d32; /* Dark Green */
|
81 |
+
background-color: #c8e6c9; /* Light Green */
|
82 |
+
}
|
83 |
+
|
84 |
+
#feedback-area.incorrect-feedback {
|
85 |
+
color: #c62828; /* Dark Red */
|
86 |
+
background-color: #ffcdd2; /* Light Red */
|
87 |
+
}
|
88 |
+
|
89 |
+
#farm-options-area h2 {
|
90 |
+
color: #795548; /* Brown */
|
91 |
+
margin-bottom: 15px;
|
92 |
+
}
|
93 |
+
|
94 |
+
#field-choices {
|
95 |
+
display: flex;
|
96 |
+
justify-content: space-around;
|
97 |
+
align-items: flex-start; /* Align tops of potentially diff height grids */
|
98 |
+
flex-wrap: wrap;
|
99 |
+
gap: 25px; /* Space between plot options */
|
100 |
+
}
|
101 |
+
|
102 |
+
.field-option {
|
103 |
+
cursor: pointer;
|
104 |
+
border: 4px solid #a1887f; /* Brownish border */
|
105 |
+
background-color: #d7ccc8; /* Light background for field */
|
106 |
+
padding: 10px;
|
107 |
+
border-radius: 8px;
|
108 |
+
transition: border-color 0.2s ease, transform 0.2s ease;
|
109 |
+
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
110 |
+
|
111 |
+
/* CSS Grid for items inside */
|
112 |
+
display: grid;
|
113 |
+
gap: 4px; /* Space between items */
|
114 |
+
/* grid-template-columns/rows set by JS */
|
115 |
+
}
|
116 |
+
|
117 |
+
.field-option:hover {
|
118 |
+
border-color: #fb8c00; /* Orange hover border */
|
119 |
+
transform: translateY(-3px);
|
120 |
+
}
|
121 |
+
|
122 |
+
.field-option .item {
|
123 |
+
font-size: 1.8em; /* Size of the emoji/item */
|
124 |
+
line-height: 1; /* Prevent extra vertical space */
|
125 |
+
display: flex;
|
126 |
+
justify-content: center;
|
127 |
+
align-items: center;
|
128 |
}
|
129 |
|
130 |
+
/* Feedback Animations */
|
131 |
+
.field-option.correct-choice {
|
132 |
+
border-color: #4caf50 !important; /* Green border */
|
133 |
+
animation: pulse 0.6s;
|
|
|
134 |
}
|
135 |
|
136 |
+
.field-option.incorrect-choice {
|
137 |
+
border-color: #f44336 !important; /* Red border */
|
138 |
+
animation: shake 0.5s;
|
|
|
|
|
|
|
139 |
}
|
140 |
|
141 |
+
@keyframes shake {
|
142 |
+
0%, 100% { transform: translateX(0); }
|
143 |
+
25% { transform: translateX(-6px); }
|
144 |
+
75% { transform: translateX(6px); }
|
145 |
}
|
146 |
+
@keyframes pulse {
|
147 |
+
0% { transform: scale(1); }
|
148 |
+
50% { transform: scale(1.05); }
|
149 |
+
100% { transform: scale(1); }
|
150 |
+
}
|