ANAGRAMS - INTERACTIVE ARCADE GAME SOURCE CODE
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>Anagram Verse — Dark Edition | Pre‑filled Letters</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--bg-color: #000000;
--text-color: #f0f3f8;
--tile-bg: #11161f;
--tile-border: #2d3a4a;
--tile-hover-bg: #1f2a36;
--tile-hover-border: #4d7cb0;
--slot-bg: #0c0f15;
--slot-border: #3a4c62;
--slot-filled-bg: #111a24;
--slot-filled-border: #4c6a8a;
--slot-filled-hover-bg: #2a1c1c;
--slot-filled-hover-border: #e07a7a;
--msg-correct-bg: #102a1a;
--msg-correct-text: #9effb0;
--msg-wrong-bg: #2f1818;
--msg-wrong-text: #ffb0a8;
--pill-bg: #12161e;
--pill-border: #2b3543;
--pill-text: #cbdbe6;
--tag-bg: #172618;
--tag-border: #2d543a;
--tag-text: #b3f7c2;
--btn-bg: #12171f;
--btn-border: #2f4052;
--btn-text: #eef3fc;
--btn-hover-bg: #202a36;
--btn-hover-border: #5f7f9e;
--btn-primary-bg: #0f2b44;
--btn-primary-border: #2e628b;
--btn-primary-text: #cae3ff;
--btn-primary-hover-bg: #1a3f62;
--btn-primary-hover-border: #78b0e0;
--prog-bg: #181e26;
--hint-bg: #0f1a24;
--hint-border: #2c4968;
--hint-text: #bbd6ff;
--hr-border: #263340;
}
html:not(.dark) {
--bg-color: #f5f7fa;
--text-color: #1a202c;
--tile-bg: #ffffff;
--tile-border: #e2e8f0;
--tile-hover-bg: #edf2f7;
--tile-hover-border: #3182ce;
--slot-bg: #e2e8f0;
--slot-border: #cbd5e0;
--slot-filled-bg: #ffffff;
--slot-filled-border: #a0aec0;
--slot-filled-hover-bg: #fff5f5;
--slot-filled-hover-border: #f56565;
--msg-correct-bg: #f0fff4;
--msg-correct-text: #2f855a;
--msg-wrong-bg: #fff5f5;
--msg-wrong-text: #c53030;
--pill-bg: #ffffff;
--pill-border: #e2e8f0;
--pill-text: #4a5568;
--tag-bg: #f0fff4;
--tag-border: #9ae6b4;
--tag-text: #2f855a;
--btn-bg: #ffffff;
--btn-border: #e2e8f0;
--btn-text: #2d3748;
--btn-hover-bg: #edf2f7;
--btn-hover-border: #cbd5e0;
--btn-primary-bg: #3182ce;
--btn-primary-border: #2b6cb0;
--btn-primary-text: #ffffff;
--btn-primary-hover-bg: #2b6cb0;
--btn-primary-hover-border: #2c5282;
--prog-bg: #e2e8f0;
--hint-bg: #ebf8ff;
--hint-border: #bee3f8;
--hint-text: #2b6cb0;
--hr-border: #e2e8f0;
}
body {
background: var(--bg-color);
font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, sans-serif;
color: var(--text-color);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: 1rem;
margin: 0;
}
.game-full {
width: 100%;
max-width: 900px;
margin: 0 auto;
padding: 1.2rem 1rem;
}
/* letter tiles & answer slots (dark mode) */
.letter-tile {
display: inline-flex; align-items: center; justify-content: center;
width: 54px; height: 60px;
border-radius: 16px;
font-size: 24px; font-weight: 600;
cursor: pointer; user-select: none;
border: 1px solid var(--tile-border);
background: var(--tile-bg);
color: var(--text-color);
transition: transform 0.12s, background 0.1s, box-shadow 0.1s;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.letter-tile:hover {
background: var(--tile-hover-bg);
transform: translateY(-2px);
border-color: var(--tile-hover-border);
}
.letter-tile.used {
opacity: 0.28;
pointer-events: none;
filter: grayscale(0.4);
transform: none;
}
.answer-slot {
display: inline-flex; align-items: center; justify-content: center;
width: 54px; height: 60px;
border-radius: 16px;
font-size: 24px; font-weight: 600;
cursor: pointer;
border: 1.5px dashed var(--slot-border);
background: var(--slot-bg);
color: var(--text-color);
transition: all 0.12s;
}
.answer-slot.filled {
border-style: solid;
border-color: var(--slot-filled-border);
background: var(--slot-filled-bg);
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
.answer-slot.filled:hover {
background: var(--slot-filled-hover-bg);
border-color: var(--slot-filled-hover-border);
transform: scale(0.97);
}
.tiles-row {
display: flex;
gap: 12px;
justify-content: center;
flex-wrap: wrap;
margin: 0.25rem 0;
}
@media (max-width: 540px) {
.letter-tile, .answer-slot { width: 44px; height: 50px; font-size: 20px; }
.tiles-row { gap: 8px; }
}
/* Centered messages (no left-aligned warnings) */
.result-msg {
font-size: 15px;
font-weight: 550;
min-height: 2.7rem;
text-align: center;
padding: 0.4rem;
letter-spacing: -0.2px;
display: flex;
justify-content: center;
}
.correct-msg {
color: var(--msg-correct-text);
background: var(--msg-correct-bg);
display: inline-block;
padding: 0.3rem 1.2rem;
border-radius: 60px;
width: auto;
}
.wrong-msg {
color: var(--msg-wrong-text);
background: var(--msg-wrong-bg);
display: inline-block;
padding: 0.3rem 1.2rem;
border-radius: 60px;
}
.score-pill {
display: inline-block;
background: var(--pill-bg);
border-radius: 60px;
padding: 6px 18px;
font-size: 13px;
font-weight: 500;
color: var(--pill-text);
backdrop-filter: blur(2px);
border: 0.5px solid var(--pill-border);
}
.score-pill strong {
color: var(--text-color);
font-weight: 700;
}
.word-history {
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: center;
min-height: 38px;
margin-top: 8px;
}
.solved-tag {
font-size: 12px;
background: var(--tag-bg);
color: var(--tag-text);
padding: 5px 14px;
border-radius: 40px;
font-weight: 500;
border: 0.5px solid var(--tag-border);
letter-spacing: 0.3px;
}
.btn {
cursor: pointer;
padding: 8px 22px;
border-radius: 44px;
font-size: 14px;
font-weight: 530;
border: 0.5px solid var(--btn-border);
background: var(--btn-bg);
color: var(--btn-text);
transition: all 0.15s;
font-family: inherit;
display: inline-flex;
align-items: center;
gap: 6px;
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
}
.btn:hover {
background: var(--btn-hover-bg);
transform: translateY(-1px);
border-color: var(--btn-hover-border);
}
.btn-primary {
background: var(--btn-primary-bg);
color: var(--btn-primary-text);
border-color: var(--btn-primary-border);
}
.btn-primary:hover {
background: var(--btn-primary-hover-bg);
border-color: var(--btn-primary-hover-border);
}
.progress-bar-bg {
background: var(--prog-bg);
border-radius: 80px;
height: 6px;
overflow: hidden;
box-shadow: inset 0 1px 2px rgba(0,0,0,0.1);
}
.progress-bar-fill {
height: 100%;
background: #4f9eff;
border-radius: 80px;
transition: width 0.35s ease;
}
.hint-text {
font-size: 13px;
color: var(--hint-text);
background: var(--hint-bg);
padding: 8px 16px;
border-radius: 40px;
display: inline-block;
margin: 0 auto;
font-weight: 470;
border: 0.5px solid var(--hint-border);
}
hr {
border: none;
border-top: 1px solid var(--hr-border);
margin: 0.75rem 0;
}
</style>
</head>
<body>
<div class="game-full">
<h2 class="sr-only" style="position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;">Anagram word unscramble – 8‑letter challenge with pre‑filled hints</h2>
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:1.5rem; flex-wrap:wrap; gap:12px;">
<div style="display:flex; gap:10px;">
<span class="score-pill">🏆 SCORE: <strong id="score">0</strong></span>
<span class="score-pill">📖 WORD <strong id="word-num">1</strong> / <strong id="word-total">?</strong></span>
</div>
<button class="btn" id="skipButton">⏩ SKIP</button>
</div>
<div style="margin-bottom:1.2rem;">
<div class="progress-bar-bg"><div class="progress-bar-fill" id="progress-fill" style="width:0%"></div></div>
</div>
<div style="text-align:center; margin-bottom:1.8rem;">
<p style="font-size:13px; font-weight:500; color:var(--pill-text); margin:0 0 12px; letter-spacing:0.4px;">✍️ YOUR ANSWER</p>
<div class="tiles-row" id="answer-row"></div>
</div>
<div style="text-align:center; margin-bottom:1.8rem;">
<p style="font-size:13px; font-weight:500; color:var(--pill-text); margin:0 0 12px;">🔀 SCRAMBLED — tap to add</p>
<div class="tiles-row" id="source-row"></div>
</div>
<div class="result-msg" id="result-msg" style="margin-bottom:1rem;"></div>
<div style="text-align:center; margin-bottom:1.2rem;" id="hint-wrapper">
<div class="hint-text" id="hint-text"></div>
</div>
<div style="display:flex; gap:14px; justify-content:center; margin-bottom:2rem; flex-wrap:wrap;">
<button class="btn" id="clearBtn">🗑️ CLEAR</button>
<button class="btn btn-primary" id="checkBtn">✅ CHECK</button>
<button class="btn" id="hintBtn">💡 HINT (−1 pt)</button>
</div>
<div>
<p style="font-size:12px; color:var(--pill-text); text-align:center; margin:0 0 10px; font-weight:500;">✨ SOLVED WORDS</p>
<div class="word-history" id="word-history"></div>
</div>
</div>
<script>
(function() {
function syncTheme() {
try {
if (window.parent && window.parent.document) {
const isDark = window.parent.document.documentElement.classList.contains('dark');
if (isDark) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}
} catch (e) {}
}
syncTheme();
try {
if (window.parent && window.parent.document) {
const observer = new MutationObserver(syncTheme);
observer.observe(window.parent.document.documentElement, { attributes: true, attributeFilter: ['class'] });
}
} catch (e) {}
})();
// ======================= 8-LETTER WORD DATABASE =======================
const RAW_WORDS = [
"Absolute","Bachelor","Computer","Abstract","Bacteria","Conclude","Academic","Baseball","Concrete",
"Accepted","Bathroom","Conflict","Accident","Becoming","Confused","Accuracy","Birthday","Congress",
"Accurate","Boundary","Consider","Achieved","Breaking","Constant","Acquired","Breeding","Consumer",
"Activity","Building","Continue","Actually","Bulletin","Contract","Addition","Business","Contrary",
"Adequate","Calendar","Contrast","Adjacent","Campaign","Convince","Adjusted","Capacity","Corridor",
"Advanced","Cashmere","Casualty","Catching","Category","Catholic","Cautious","Cellular","Ceremony",
"Chairman","Champion","Chemical","Children","Circular","Civilian","Clearing","Clinical","Clothing",
"Collapse","Colonial","Colourful","Commence","Commerce","Complain","Complete","Composed","Compound",
"Comprise","Doubtful","Emerging","Directly","Dramatic","Emphasis","Director","Dressing","Employee",
"Disabled","Dropping","Endeavour","Disaster","Duration","Engaging","Disclose","Dynamics","Engineer",
"Discount","Earnings","Enormous","Discover","Economic","Entirely","Disorder","Educated","Entrance",
"Disposal","Efficacy","Envelope","Distance","Eighteen","Equality","Distinct","Election","Equation",
"District","Electric","Estimate","Dividend","Eligible","Evaluate","Division","External","Eventual",
"Doctrine","Facility","Everyday","Document","Familiar","Everyone","Domestic","Featured","Evidence",
"Dominant","Feedback","Exchange","Dominate","Festival","Exciting","Floating","Finished","Exercise",
"Football","Firewall","Explicit","Foothill","Flagship","Exposure","Forecast","Flexible","Extended",
"Foremost","Function","Guidance","Formerly","Generate","Handling","Fourteen","Generous","Hardware",
"Fraction","Genomics","Heritage","Fracture","Goodwill","Highland","Frequent","Governor","Historic",
"Friendly","Graduate","Homeless","Frontier","Graphics","Homepage","Imperial","Grateful","Hospital",
"Incident","Included","Initiate","Identify","Increase","Innocent","Identity","Indicate","Inspired",
"Ideology","Indirect","Instance","Intimate","Industry","Integral","Intranet","Informal","Intended",
"Invasion","Informed","Interact","Involved","Inherent","Interest","Isolated","Keyboard","Interior",
"Judgment","Landlord","Internal","Judicial","Language","Interval","Junction","Laughter","Material",
"Minority","Learning","Maturity","Mobility","Leverage","Maximise","Modelling","Moderate","Lifetime",
"Meantime","Momentum","Lighting","Measured","Monetary","Likewise","Medicine","Moreover","Literary",
"Medieval","Mortgage","Location","Merchant","Mountain","Magazine","Midnight","Mounting","Magnetic",
"Military","Movement","Maintain","Minimise","Multiple","Majority","Minister","National","Marginal",
"Ministry","Negative","Marriage","Original","Nineteen","Preserve","Overcome","Northern","Pressing",
"Overhead","Notebook","Pressure","Overseas","Numerous","Previous","Overview","Observer","Princess",
"Painting","Occasion","Printing","Parallel","Offering","Priority","Parental","Official","Probable",
"Patented","Offshore","Probably","Patience","Operator","Producer","Peaceful","Opponent","Profound",
"Periodic","Opposite","Progress","Personal","Optimism","Property","Persuade","Optional","Proposal",
"Petition","Organise","Prospect","Physical","Organised","Protocol","Pipeline","Relation","Provided",
"Platform","Relative","Provider","Pleasant","Relevant","Province","Pleasure","Reliable","Publicly",
"Politics","Reliance","Purchase","Portable","Religion","Pursuant","Portrait","Remember","Quantity",
"Position","Renowned","Question","Positive","Repeated","Rational","Possible","Reporter","Reaction",
"Powerful","Republic","Received","Practice","Required","Receiver","Precious","Research","Recovery",
"Pregnant","Reserved","Regional","Presence","Resident","Register","Scenario","Resigned","Revision",
"Schedule","Resource","Rigorous","Scrutiny","Response","Romantic","Seasonal","Restrict","Sampling",
"Secondly","Somebody","Struggle","Security","Somewhat","Stunning","Sensible","Southern","Suburban",
"Sentence","Speaking","Suitable","Separate","Specific","Superior","Sequence","Spectrum","Supposed",
"Sergeant","Sporting","Surgical","Shipping","Standard","Surprise","Shortage","Standing","Survival",
"Shoulder","Standout","Sweeping","Simplify","Sterling","Swimming","Situated","Straight","Symbolic",
"Slightly","Strategy","Sympathy","Software","Strength","Syndrome","Solution","Striking","Tactical",
"Terrible","Training","Tailored","Thinking","Transfer","Takeover","Thirteen","Tragical","Tangible",
"Thorough","Treasury","Taxation","Thousand","Triangle","Taxpayer","Together","Tropical","Teaching",
"Tomorrow","Turnover","Tendency","Touching","Ultimate","Terminal","Tracking","Umbrella","Universe",
"Weakness","Withdraw","Unlawful","Weighted","Woodland","Unlikely","Whatever","Workshop","Valuable",
"Whenever","Yourself","Variable","Wherever","Volatile","Vertical","Wildlife","Warranty","Victoria",
"Wireless","Violence"
];
const WORDS = [...new Set(RAW_WORDS.filter(w => w.length === 8))];
function shuffleArray(arr) {
const a = [...arr];
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
}
// pick two positions that are NOT adjacent (spaced apart)
function getTwoSpacedApartPositions() {
for (let tries = 0; tries < 50; tries++) {
const i1 = Math.floor(Math.random() * 8);
let i2 = Math.floor(Math.random() * 8);
while (i2 === i1) i2 = Math.floor(Math.random() * 8);
if (Math.abs(i1 - i2) > 1) return [i1, i2].sort((a,b)=>a-b);
}
return [0, 2]; // safe fallback
}
let gameQueue = shuffleArray([...WORDS]);
let currentIdx = 0;
let totalScore = 0;
let currentAnswer = []; // array of length 8, each { letter, srcIdx } or undefined
let sourceLetters = []; // full scrambled array (length 8)
let usedSourceIndices = new Set(); // indices into sourceLetters that are already placed
let hintCountForWord = 0;
let hintPenalty = 0;
let isTransitioning = false;
// DOM elements
const answerRowEl = document.getElementById('answer-row');
const sourceRowEl = document.getElementById('source-row');
const scoreSpan = document.getElementById('score');
const wordNumSpan = document.getElementById('word-num');
const wordTotalSpan = document.getElementById('word-total');
const progressFill = document.getElementById('progress-fill');
const resultMsgDiv = document.getElementById('result-msg');
const hintTextDiv = document.getElementById('hint-text');
const wordHistoryDiv = document.getElementById('word-history');
const skipBtn = document.getElementById('skipButton');
const clearBtn = document.getElementById('clearBtn');
const checkBtn = document.getElementById('checkBtn');
const hintBtn = document.getElementById('hintBtn');
function updateScoreUI() {
scoreSpan.innerText = totalScore;
}
// Reset current word to prefilled state (keep the same target word)
function resetToPrefilledState() {
const targetWord = gameQueue[currentIdx].toUpperCase();
// scramble letters fresh each reset (more dynamic)
let scrambledArr = shuffleArray(targetWord.split(''));
while (scrambledArr.join('') === targetWord) {
scrambledArr = shuffleArray(targetWord.split(''));
}
sourceLetters = scrambledArr;
// pick two spaced apart positions
const positions = getTwoSpacedApartPositions();
const newAnswer = new Array(8).fill(undefined);
const newUsed = new Set();
for (let pos of positions) {
const neededChar = targetWord[pos];
// find first occurrence in sourceLetters that matches neededChar and not already used
let foundIdx = -1;
for (let i = 0; i < sourceLetters.length; i++) {
if (!newUsed.has(i) && sourceLetters[i] === neededChar) {
foundIdx = i;
break;
}
}
if (foundIdx !== -1) {
newAnswer[pos] = { letter: neededChar, srcIdx: foundIdx };
newUsed.add(foundIdx);
}
}
currentAnswer = newAnswer;
usedSourceIndices = newUsed;
renderSource();
renderAnswer();
}
function loadWord() {
isTransitioning = false;
if (currentIdx >= gameQueue.length) {
document.querySelector('.game-full').innerHTML = `
<div style="text-align:center; padding:2rem 1.5rem; width:100%;">
<div style="font-size:64px; margin-bottom:1rem;">🏆✨</div>
<h2 style="font-size:28px; font-weight:600; margin:0 0 0.6rem; color:#fff;">Anagram Master!</h2>
<p style="color:#bfd6f0; font-size:1rem; margin-bottom:1.8rem;">Final score: <strong style="font-size:1.8rem;">${totalScore}</strong> out of ${gameQueue.length}</p>
<button class="btn btn-primary" onclick="location.reload()">🔄 PLAY AGAIN</button>
</div>`;
return;
}
const targetWord = gameQueue[currentIdx].toUpperCase();
// create scrambled full set (8 letters)
let scrambledArr = shuffleArray(targetWord.split(''));
while (scrambledArr.join('') === targetWord) {
scrambledArr = shuffleArray(targetWord.split(''));
}
sourceLetters = scrambledArr;
// pick two spaced apart positions
const positions = getTwoSpacedApartPositions();
const newAnswer = new Array(8).fill(undefined);
const newUsed = new Set();
for (let pos of positions) {
const neededChar = targetWord[pos];
let foundIdx = -1;
for (let i = 0; i < sourceLetters.length; i++) {
if (!newUsed.has(i) && sourceLetters[i] === neededChar) {
foundIdx = i;
break;
}
}
if (foundIdx !== -1) {
newAnswer[pos] = { letter: neededChar, srcIdx: foundIdx };
newUsed.add(foundIdx);
}
}
currentAnswer = newAnswer;
usedSourceIndices = newUsed;
// reset hint state
hintCountForWord = 0;
hintPenalty = 0;
resultMsgDiv.innerHTML = '';
hintTextDiv.textContent = '';
renderSource();
renderAnswer();
wordNumSpan.innerText = currentIdx + 1;
wordTotalSpan.innerText = gameQueue.length;
const progressPercent = (currentIdx / gameQueue.length) * 100;
progressFill.style.width = `${progressPercent}%`;
}
function renderSource() {
sourceRowEl.innerHTML = '';
sourceLetters.forEach((letter, idx) => {
const tile = document.createElement('span');
tile.className = 'letter-tile' + (usedSourceIndices.has(idx) ? ' used' : '');
tile.textContent = letter;
tile.onclick = () => pickLetter(idx);
sourceRowEl.appendChild(tile);
});
}
function renderAnswer() {
answerRowEl.innerHTML = '';
for (let i = 0; i < 8; i++) {
const slot = document.createElement('span');
const isFilled = currentAnswer[i] !== undefined;
slot.className = 'answer-slot' + (isFilled ? ' filled' : '');
slot.textContent = isFilled ? currentAnswer[i].letter : '';
if (isFilled) {
slot.onclick = (() => { if (!isTransitioning) removeLetter(i); });
} else {
slot.onclick = null;
}
answerRowEl.appendChild(slot);
}
}
function pickLetter(idx) {
if (isTransitioning) return;
if (usedSourceIndices.has(idx)) return;
// find first empty slot in answer
const emptyPos = currentAnswer.findIndex(slot => slot === undefined);
if (emptyPos === -1) {
resultMsgDiv.innerHTML = '<span class="wrong-msg">❌ Answer is full (8 letters). Clear or remove some.</span>';
return;
}
currentAnswer[emptyPos] = { letter: sourceLetters[idx], srcIdx: idx };
usedSourceIndices.add(idx);
renderSource();
renderAnswer();
resultMsgDiv.innerHTML = '';
}
function removeLetter(pos) {
if (isTransitioning) return;
const item = currentAnswer[pos];
if (!item) return;
usedSourceIndices.delete(item.srcIdx);
currentAnswer[pos] = undefined;
renderSource();
renderAnswer();
resultMsgDiv.innerHTML = '';
}
function clearAnswer() {
if (isTransitioning) return;
// Reset current word to original prefilled state (same target, fresh scramble)
resetToPrefilledState();
resultMsgDiv.innerHTML = '';
hintTextDiv.textContent = '';
hintCountForWord = 0;
hintPenalty = 0;
}
function submitAnswer() {
if (isTransitioning) return;
if (currentAnswer.some(slot => slot === undefined)) {
resultMsgDiv.innerHTML = '<span class="wrong-msg">⚠️ Fill all 8 letters before checking!</span>';
return;
}
const guess = currentAnswer.map(a => a.letter).join('').toUpperCase();
const target = gameQueue[currentIdx].toUpperCase();
if (guess === target) {
let pointsEarned = Math.max(1, 3 - hintPenalty);
totalScore += pointsEarned;
updateScoreUI();
resultMsgDiv.innerHTML = pointsEarned === 3
? '<span class="correct-msg">🎉 PERFECT! +3 points</span>'
: `<span class="correct-msg">✔ CORRECT! +${pointsEarned} point${pointsEarned !== 1 ? 's' : ''} (hint used)</span>`;
const solvedWord = gameQueue[currentIdx];
const tag = document.createElement('span');
tag.className = 'solved-tag';
tag.textContent = solvedWord;
wordHistoryDiv.appendChild(tag);
isTransitioning = true;
setTimeout(() => {
currentIdx++;
loadWord();
}, 820);
} else {
resultMsgDiv.innerHTML = '<span class="wrong-msg">✗ INCORRECT — keep trying!</span>';
const filledSlots = document.querySelectorAll('.answer-slot.filled');
filledSlots.forEach(slot => {
slot.style.transition = 'background 0.08s';
slot.style.background = '#361b1b';
slot.style.borderColor = '#d97a72';
setTimeout(() => {
if (slot) { slot.style.background = ''; slot.style.borderColor = ''; }
}, 480);
});
}
}
function showHint() {
if (isTransitioning) return;
if (currentIdx >= gameQueue.length) return;
const targetWord = gameQueue[currentIdx].toUpperCase();
hintCountForWord++;
if (hintPenalty < 2) hintPenalty = Math.min(2, hintCountForWord);
let hintMsg = '';
if (hintCountForWord === 1) {
hintMsg = `💡 STARTS WITH “${targetWord[0]}”`;
} else if (hintCountForWord === 2) {
hintMsg = `🔍 STARTS WITH “${targetWord.slice(0, 2)}” … ENDS WITH “${targetWord.slice(-1)}”`;
} else {
const firstThree = targetWord.slice(0, 3);
hintMsg = `📖 PATTERN: ${firstThree} _ _ _ _ _`;
}
hintTextDiv.textContent = hintMsg;
hintTextDiv.style.opacity = '0.8';
setTimeout(() => { if(hintTextDiv) hintTextDiv.style.opacity = '1'; }, 120);
}
function skipWord() {
if (isTransitioning) return;
if (currentIdx >= gameQueue.length) return;
isTransitioning = true;
const skippedWord = gameQueue[currentIdx];
resultMsgDiv.innerHTML = `<span class="wrong-msg">⏩ SKIPPED — the word was “${skippedWord}”</span>`;
setTimeout(() => {
currentIdx++;
loadWord();
}, 1050);
}
skipBtn.addEventListener('click', skipWord);
clearBtn.addEventListener('click', clearAnswer);
checkBtn.addEventListener('click', submitAnswer);
hintBtn.addEventListener('click', showHint);
loadWord();
</script>
</body>
</html>