<meta name="viewport" content="width=device-width, initial-scale=1.0"/> 
    <title>Kupu Rapu - Te Reo Māori Word Game (10 Levels)</title> 
    <script src="https://cdn.tailwindcss.com"></script> 
        @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap'); 
        :root{ --tile-bg: rgba(255,255,255,0.2); } 
            font-family: 'Inter', sans-serif; 
            background: linear-gradient(135deg, #f74ff7 0%, #f53da8 100%); 
            transition: background 600ms ease; 
            background-color: rgba(255, 255, 255, 0.09); 
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); 
            backdrop-filter: blur(10px); 
            text-shadow: 2px 2px 6px rgba(0, 0, 0, 0.35); 
        .level-controls { display:flex; gap:8px; align-items:center; margin-bottom:8px; } 
        .level-indicator { font-weight:700; padding:6px 10px; border-radius:9999px; background: rgba(255,255,255,0.12); } 
        .main-content { display:flex; width:100%; gap:18px; flex-direction:column; } 
        @media(min-width:768px){ .main-content{ flex-direction:row; align-items:flex-start; } } 
        .game-section{ flex:1; display:flex; flex-direction:column; align-items:center; } 
        .word-builder{ display:flex; justify-content:center; min-height:48px; gap:6px; margin-bottom:12px; background-color: rgba(255, 255, 255, 0.14); border-radius:12px; padding:8px; width:100%; text-transform:uppercase; } 
        .built-letter{ width:34px; height:34px; display:flex; justify-content:center; align-items:center; background:#fff; color:#000; font-weight:700; border-radius:8px; box-shadow:0 2px 6px rgba(0,0,0,0.12); animation:popIn 0.18s ease; } 
        @keyframes popIn{ 0%{ transform:scale(0); opacity:0 } 100%{ transform:scale(1); opacity:1 } } 
        .grid{ display:grid; grid-template-columns: repeat(6, 1fr); gap:8px; width:100%; max-width:520px; aspect-ratio: 6 / 5; margin-bottom:12px; position:relative; } 
        .tile{ position:relative; background-color:var(--tile-bg); color:black; font-size:clamp(0.9rem,3.5vw,1.6rem); font-weight:700; border-radius:12px; cursor:pointer; user-select:none; display:flex; justify-content:center; align-items:center; transition: transform 0.18s, box-shadow 0.18s, opacity 0.25s, top 0.35s ease-out; text-transform:uppercase; box-shadow:0 4px 8px rgba(0,0,0,0.12); } 
        .tile.hidden-tile{ opacity:0 } 
        .tile:hover{ transform: translateY(-2px); box-shadow:0 6px 12px rgba(0,0,0,0.16); } 
        .selected{ transform:scale(1.06); outline:3px solid white; outline-offset:-4px; } 
        .message-box{ background-color: rgba(0,0,0,0.32); color:white; padding:10px; border-radius:10px; margin-bottom:10px; font-weight:700; width:100%; } 
        .win-overlay{ position:absolute; top:0; left:0; width:100%; height:100%; display:flex; flex-direction:column; justify-content:center; align-items:center; background-color:rgba(0,0,0,0.3); z-index:10; } 
        .win-star{ width:60%; height:60%; background-color:rgba(255,255,255,0.2); clip-path: polygon(50% 0%,61% 35%,98% 35%,68% 57%,79% 91%,50% 70%,21% 91%,32% 57%,2% 35%,39% 35%); display:flex; justify-content:center; align-items:center; } 
        .win-star-text{ font-size:2.5rem; font-weight:700; color:#fff; text-shadow:2px 2px 6px rgba(0,0,0,0.5); } 
        .win-buttons{ display:flex; gap:8px; margin-top:16px; } 
        .win-button{ background-color: rgba(0,0,0,0.28); color:white; padding:8px 16px; border-radius:9999px; font-weight:700; transition:transform 0.15s; border:none; } 
        .win-button:hover{ transform: translateY(-3px); } 
        .word-list-section{ width:320px; min-width:240px; max-width:340px; background-color: rgba(0,0,0,0.14); border-radius:12px; padding:12px; display:flex; flex-direction:column; align-items:stretch; } 
        .word-list-heading{ font-size:1.05rem; font-weight:700; margin-bottom:8px; } 
        .word-list{ display:flex; flex-direction:column; gap:8px; } 
        .word-item{ border-radius:8px; padding:6px 8px; font-weight:700; display:flex; justify-content:space-between; align-items:center; } 
        .word-item-text{ font-size:1.05rem; font-weight:800; color:black; } 
        .word-item-count{ font-size:1rem; font-weight:700; color:black; } 
        .tick{ font-size:1.2rem; margin-left:6px; color:black; } 
        .star-container{ display:grid; grid-template-columns: repeat(5, 1fr); grid-template-rows: repeat(2, 1fr); gap:8px; margin-top:12px; width:100%; max-width:240px; justify-content:center; margin-left:auto; margin-right:auto; } 
        .star{ width:32px; height:32px; background-color:#a78bfa; clip-path: polygon(50% 0%,61% 35%,98% 35%,68% 57%,79% 91%,50% 70%,21% 91%,32% 57%,2% 35%,39% 35%); cursor:pointer; transition: transform 0.18s, background-color 0.18s; } 
        .star.selected{ background-color:#ffffff !important; transform:scale(2); } 
        .star.used{ background-color:#000000; cursor:default; } 
        /* Hardcoded tile colors */ 
        .bg-red-400{ background-color:#f87171 !important; } 
        .bg-orange-400{ background-color:#fb923c !important; } 
        .bg-yellow-400{ background-color:#facc15 !important; } 
        .bg-green-400{ background-color:#4ade80 !important; } 
        .bg-blue-400{ background-color:#60a5fa !important; } 
        .bg-purple-400{ background-color:#a78bfa !important; } 
        .bg-pink-400{ background-color:#f472b6 !important; } 
        .bg-teal-400{ background-color:#2dd4bf !important; } 
        .bg-brown-400{ background-color:#f472b6 !important; } 
        .bg-black-400{ background-color:#2dd4bf !important; } 
        .text-black{ color:black !important; } 
        .controls-row{ display:flex; gap:8px; align-items:center; justify-content:center; margin-bottom:8px; } 
        button{ background-color: rgba(0,0,0,0.28); color:white; padding:8px 14px; border-radius:9999px; font-weight:700; transition:transform 0.15s; border:none; } 
        button:hover{ transform: translateY(-3px); } 
        <h1 class="title">Kupu Rapu</h1> 
        <p class="subtitle">Drag to connect adjacent letters to find words. Complete the level to reveal translations!</p> 
        <div class="level-controls"> 
            <div class="controls-row"> 
                <button id="prev-level">◀ Prev</button> 
                <div class="level-indicator" id="level-indicator">Level 1 / 10</div> 
                <button id="next-level">Next ▶</button> 
        <div class="main-content"> 
            <div id="game-container" class="game-section"> 
                <div id="word-builder" class="word-builder"></div> 
                <div id="grid-container" class="grid"></div> 
                <div id="message-box" class="message-box opacity-0 transition-opacity duration-300"></div> 
                <div id="win-screen" class="hidden"></div> 
            <div class="word-list-section"> 
                <div class="word-list-heading">Words to find</div> 
                <div id="word-list" class="word-list"></div> 
                <div class="star-container" id="star-container"></div> 
        document.addEventListener('DOMContentLoaded', () => { 
            const gridContainer = document.getElementById('grid-container'); 
            const messageBox = document.getElementById('message-box'); 
            const winScreen = document.getElementById('win-screen'); 
            const gameContainer = document.getElementById('game-container'); 
            const wordListEl = document.getElementById('word-list'); 
            const wordBuilderEl = document.getElementById('word-builder'); 
            const starContainer = document.getElementById('star-container'); 
            const prevLevelBtn = document.getElementById('prev-level'); 
            const nextLevelBtn = document.getElementById('next-level'); 
            const levelIndicator = document.getElementById('level-indicator'); 
            const FIND_COUNT_PER_WORD = 1; 
            let foundWordCounts = {}; 
            let wordPlacementCounts = {}; 
            let isStarSelected = false; 
            const letters = ['a','e','h','i','k','m','n','o','p','r','t','u','w']; 
    bg: 'linear-gradient(135deg, #FF6B6B 0%, #FFE66D 100%)', 
      { w: 'ākonga', t: 'student', c: 'bg-green-400' },   // same 
      { w: 'akomanga', t: 'classroom', c: 'bg-pink-400' }, // same 
      { w: 'akōranga', t: 'learning', c: 'bg-orange-400' }, // same 
      { w: 'kaiako', t: 'teacher', c: 'bg-blue-400' },    // same 
      { w: 'tamariki', t: 'children', c: 'bg-yellow-400' } // replaced from Whakapapa 
    bg: 'linear-gradient(135deg, #4ECDC4 0%, #1A535C 100%)', 
      { w: 'whānau', t: 'family', c: 'bg-yellow-400' },   // same 
      { w: 'tūpuna', t: 'ancestors', c: 'bg-teal-400' },  // same 
      { w: 'māmā', t: 'mother', c: 'bg-red-400' },        // same 
      { w: 'pāpā', t: 'father', c: 'bg-orange-400' },     // same 
      { w: 'kuia', t: 'elderly woman', c: 'bg-blue-400' } // same 
    bg: 'linear-gradient(135deg, #2A6041 0%, #A8D5BA 100%)', 
      { w: 'manu', t: 'bird', c: 'bg-green-400' },        // same 
      { w: 'iwi', t: 'tribe', c: 'bg-yellow-400' },       // same 
      { w: 'rākau', t: 'tree', c: 'bg-green-400' },       // same 
      { w: 'pipi', t: 'shellfish', c: 'bg-teal-400' },    // same 
      { w: 'moana', t: 'sea', c: 'bg-blue-400' }          // same 
    bg: 'linear-gradient(135deg, #FF9F43 0%, #EE6352 100%)', 
      { w: 'kākahu', t: 'clothes', c: 'bg-teal-400' },   // same 
      { w: 'panekoti', t: 'skirt', c: 'bg-yellow-400' }, // revised 
      { w: 'tarau', t: 'trousers', c: 'bg-orange-400' }, // revised 
      { w: 'pōtae', t: 'hat', c: 'bg-green-400' },      // revised 
      { w: 'poraka', t: 'jumper', c: 'bg-blue-400' }    // revised 
    bg: 'linear-gradient(135deg, #483D8B 0%, #B0C4DE 100%)', 
      { w: 'papatuanuku', t: 'Earth Mother', c: 'bg-green-400' }, // checked macrons 
      { w: 'ranginui', t: 'Sky Father', c: 'bg-blue-400' },      // same 
      { w: 'tāne', t: 'Forest God', c: 'bg-yellow-400' },       // same 
      { w: 'tangaroa', t: 'Sea God', c: 'bg-teal-400' },        // same 
      { w: 'rongo', t: 'God of Peace', c: 'bg-orange-400' }     // revised from Tūmatauenga 
    bg: 'linear-gradient(135deg, #FF6F61 0%, #D4A5A5 100%)', 
      { w: 'kōwhai', t: 'yellow', c: 'bg-yellow-400' }, // same 
      { w: 'parauri', t: 'brown', c: 'bg-brown-400' },   // same 
      { w: 'karaka', t: 'orange', c: 'bg-orange-400' },  // same 
      { w: 'kākāriki', t: 'green', c: 'bg-green-400' },  // same 
      { w: 'pango', t: 'black', c: 'bg-black-400' }      // same 
    bg: 'linear-gradient(135deg, #1B4332 0%, #74C69D 100%)', 
      { w: 'tokohia', t: 'many', c: 'bg-green-400' },  // same 
      { w: 'tuatahi', t: 'first', c: 'bg-blue-400' },  // same 
      { w: 'tuarua', t: 'second', c: 'bg-yellow-400' }, // same 
      { w: 'tuawhā', t: 'fourth', c: 'bg-orange-400' }, // same 
      { w: 'tokorima', t: 'five', c: 'bg-red-400' }     // same 
    name: 'Taonga & Pounamu', 
    bg: 'linear-gradient(135deg, #74C69D 0%, #B5EAD7 100%)', 
      { w: 'taonga', t: 'treasure', c: 'bg-yellow-400' },     // same 
      { w: 'pounamu', t: 'greenstone', c: 'bg-teal-400' },    // same 
      { w: 'ngākau', t: 'heart', c: 'bg-red-400' },           // same 
      { w: 'mārama', t: 'clarity', c: 'bg-blue-400' },       // same 
      { w: 'pakiwaitara', t: 'story', c: 'bg-orange-400' }    // new 
    bg: 'linear-gradient(135deg, #1B4332 0%, #74C69D 100%)', 
      { w: 'tupuānuku', t: 'star 1', c: 'bg-pink-400' },    // same 
      { w: 'tupuārangi', t: 'star 2', c: 'bg-blue-400' },   // same 
      { w: 'waitī', t: 'star 3', c: 'bg-yellow-400' },       // same 
      { w: 'waitā', t: 'star 4', c: 'bg-green-400' },       // same 
      { w: 'pōhutukawa', t: 'star 5', c: 'bg-orange-400' } // same 
            function shuffle(array) { 
                for (let i = array.length - 1; i > 0; i--) { 
                    const j = Math.floor(Math.random() * (i + 1)); 
                    [array[i], array[j]] = [array[j], array[i]]; 
            function createTile(row, col, letter, colorClass) { 
                const tile = document.createElement('div'); 
                tile.classList.add('tile'); 
                if (colorClass) tile.classList.add(colorClass); 
                tile.classList.add('text-black'); 
                tile.dataset.letter = letter; 
                tile.innerHTML = `<span>${letter.toUpperCase()}</span>`; 
            function createStar(index) { 
                const star = document.createElement('div'); 
                star.classList.add('star'); 
                star.dataset.index = index; 
                star.style.backgroundColor = '#a78bfa'; // Match non-word tiles 
                star.addEventListener('click', () => handleStarClick(index)); 
                starContainer.appendChild(star); 
                starContainer.innerHTML = ''; 
                for (let i = 0; i < 10; i++) { 
                    const star = createStar(i); 
                    stars.push({ element: star, used: false }); 
            function displayWordList() { 
                wordListEl.innerHTML = ''; 
                wordsToFind.forEach(word => { 
                    const count = foundWordCounts[word] || 0; 
                    const info = wordInfo[word]; 
                    const wordItem = document.createElement('div'); 
                    wordItem.classList.add('word-item'); 
                    if (info && info.color) wordItem.classList.add(info.color); 
                    const left = document.createElement('div'); 
                    left.style.display = 'flex'; 
                    left.style.flexDirection = 'column'; 
                    left.style.alignItems = 'flex-start'; 
                    const wordText = document.createElement('span'); 
                    wordText.classList.add('word-item-text'); 
                    wordText.textContent = word.toUpperCase(); 
                    const translation = document.createElement('small'); 
                    translation.style.fontWeight = '600'; 
                    translation.style.marginTop = '4px'; 
                    translation.style.opacity = count > 0 ? '1' : '0.0'; 
                    translation.textContent = count > 0 ? `(${info ? info.translation : ''})` : ''; 
                    left.appendChild(wordText); 
                    left.appendChild(translation); 
                    const wordCount = document.createElement('span'); 
                    wordCount.classList.add('word-item-count'); 
                    wordCount.innerHTML = count > 0 ? '<span class="tick">✓</span>' : ''; 
                    wordItem.appendChild(left); 
                    wordItem.appendChild(wordCount); 
                    wordListEl.appendChild(wordItem); 
function placeWord(wordObj, board) { 
    const directions = [[0,1],[0,-1],[1,0],[-1,0],[1,1],[1,-1],[-1,1],[-1,-1]]; 
    while (!placed && attempts < maxAttempts) { 
        const startR = Math.floor(Math.random() * GRID_SIZE); 
        const startC = Math.floor(Math.random() * GRID_SIZE); 
        const path = [{r:startR,c:startC}]; 
        const visited = new Set([`${startR},${startC}`]); 
        const findPath = (r,c,wordIndex) => { 
            if (wordIndex === word.length) return true; 
            for (const [dr,dc] of directions) { 
                const key = `${newR},${newC}`; 
                if (newR>=0 && newR<GRID_SIZE && newC>=0 && newC<GRID_SIZE && !visited.has(key)) { 
                    const cell = board[newR][newC]; 
                    // 🔴 FIX: only allow empty cells (no overlaps allowed) 
                    if (cell === null || cell === undefined || cell.word === null) { 
                        path.push({r:newR,c:newC}); 
                        if (findPath(newR,newC,wordIndex+1)) return true; 
        const startCell = board[startR][startC]; 
        // 🔴 FIX: starting cell also must be empty 
        if (startCell === null || startCell === undefined || startCell.word === null) { 
            if (findPath(startR,startC,1)) { 
                if (path.length === word.length) { 
                    for (let i=0;i<word.length;i++){ 
                        board[r][c] = { letter: word[i], word: word, color: wordObj.c }; 
                    wordPlacementCounts[word] = (wordPlacementCounts[word] || 0) + 1; 
            function validateBoard(board) { 
                const wordsOnGrid = new Set(); 
                const directions = [[0,1],[0,-1],[1,0],[-1,0],[1,1],[1,-1],[-1,1],[-1,-1]]; 
                function checkPath(r, c, word, wordIndex, path, visited) { 
                    if (wordIndex === word.length) return true; 
                    for (const [dr, dc] of directions) { 
                        const newR = r + dr; const newC = c + dc; 
                        const key = `${newR},${newC}`; 
                        if (newR >= 0 && newR < GRID_SIZE && newC >= 0 && newC < GRID_SIZE && !visited.has(key)) { 
                            if (board[newR][newC] && board[newR][newC].letter === word[wordIndex]) { 
                                visited.add(key); path.push({r:newR,c:newC}); 
                                if (checkPath(newR, newC, word, wordIndex + 1, path, visited)) return true; 
                                path.pop(); visited.delete(key); 
                for (const word of wordsToFind) { 
                    for (let r = 0; r < GRID_SIZE && !found; r++) { 
                        for (let c = 0; c < GRID_SIZE && !found; c++) { 
                            if (board[r][c] && board[r][c].letter === word[0]) { 
                                const visited = new Set([`${r},${c}`]); 
                                if (checkPath(r, c, word, 1, path, visited) && path.length === word.length) { 
                return wordsOnGrid.size === wordsToFind.length; 
            function refreshBoard() { 
                const MAX_OVERALL_ATTEMPTS = 100; 
                let words = wordsToFind.map(w=>wordInfo[w].obj); 
                words.sort((a, b) => b.w.length - a.w.length); // Place longer words first 
                while (!success && overallAttempt < MAX_OVERALL_ATTEMPTS) { 
                    const localBoard = Array.from({length:GRID_SIZE},()=>Array(GRID_SIZE).fill(null)); 
                    for (const wobj of words) { 
                        const placed = placeWord(wobj, localBoard); 
                        if (!placed) { allPlaced = false; break; } 
                    if (allPlaced && validateBoard(localBoard)) { 
                        for (let r=0;r<GRID_SIZE;r++){ 
                            for (let c=0;c<GRID_SIZE;c++){ 
                                if (localBoard[r][c] === null) localBoard[r][c] = { letter: getRandomLetter(), word: null, color: 'bg-purple-400' }; 
                    gameBoard = Array.from({length:GRID_SIZE},()=>Array(GRID_SIZE).fill(null)); 
                    for (const w of words) placeWord(w, gameBoard); 
                    for (let r=0;r<GRID_SIZE;r++) for (let c=0;c<GRID_SIZE;c++) if (gameBoard[r][c]===null) gameBoard[r][c] = { letter: getRandomLetter(), word:null, color:'bg-purple-400' }; 
                    if (!validateBoard(gameBoard)) refreshBoard(); 
                wordPlacementCounts = {}; 
                const level = LEVELS[currentLevel]; 
                wordsToFind = level.words.map(o => o.w); 
                level.words.forEach(o => { 
                    wordInfo[o.w] = { translation: o.t, color: o.c, obj: o }; 
                    foundWordCounts[o.w] = 0; 
                    wordPlacementCounts[o.w] = 0; 
                document.body.style.background = level.bg; 
                levelIndicator.textContent = `Level ${currentLevel+1} / ${LEVELS.length} — ${level.name}`; 
                for (let r=0;r<GRID_SIZE;r++){ 
                    if (!gameBoard[r]) gameBoard[r] = Array(GRID_SIZE).fill(null); 
                    for (let c=0;c<GRID_SIZE;c++) if (!gameBoard[r][c]) gameBoard[r][c] = { letter: getRandomLetter(), word:null, color:'bg-purple-400' }; 
                gridContainer.innerHTML = ''; 
                gameBoard.forEach((row,r)=>{ 
                        const tile = createTile(r,c,cell.letter, cell.color); 
                        tile.addEventListener('click', ()=>handleTileClick(r,c)); 
                        gridContainer.appendChild(tile); 
            function getRandomLetter(){ return letters[Math.floor(Math.random()*letters.length)]; } 
            function getSelectedWord(){ return selectedTiles.map(t=>gameBoard[t.row][t.col].letter).join(''); } 
            function isValidAdjacency(newTile){ if (selectedTiles.length===0) return true; const last = selectedTiles[selectedTiles.length-1]; const dx=Math.abs(newTile.row-last.row); const dy=Math.abs(newTile.col-last.col); return (dx<=1 && dy<=1 && (dx>0||dy>0)); } 
            function showMessage(text, duration=1400){ messageBox.textContent = text; messageBox.style.opacity = '1'; setTimeout(()=>{ messageBox.style.opacity='0'; }, duration); } 
            function clearHighlights(){ document.querySelectorAll('.tile.selected').forEach(t=>t.classList.remove('selected')); selectedTiles=[]; wordBuilderEl.innerHTML=''; } 
            function handleStarClick(index) { 
                if (stars[index].used || isDragging) return; 
                const thisStar = stars[index].element; 
                if (thisStar.classList.contains('selected')) { 
                    thisStar.classList.remove('selected'); 
                    thisStar.style.backgroundColor = '#a78bfa'; // Restore default color 
                        s.element.classList.remove('selected'); 
                        s.element.style.backgroundColor = '#a78bfa'; // Ensure default color 
                    thisStar.classList.add('selected'); 
                    thisStar.style.backgroundColor = '#ffffff'; // Force white color 
            function getAdjacentTiles(row,col){ const tiles=[]; const dirs=[[0,0],[0,1],[0,-1],[1,0],[-1,0],[1,1],[1,-1],[-1,1],[-1,-1]]; for(const [dr,dc] of dirs){ const nr=row+dr, nc=col+dc; if(nr>=0 && nr<GRID_SIZE && nc>=0 && nc<GRID_SIZE) tiles.push({row:nr,col:nc}); } return tiles; } 
            function handleTileClick(row,col) { 
                    const selectedStarIdx = stars.findIndex(s => s.element.classList.contains('selected')); 
                    if (selectedStarIdx >= 0) { 
                        stars[selectedStarIdx].used = true; 
                        stars[selectedStarIdx].element.classList.remove('selected'); 
                        stars[selectedStarIdx].element.classList.add('used'); 
                        stars[selectedStarIdx].element.style.backgroundColor = '#000000'; // Ensure used color 
                        showMessage('Board refreshed!'); 
            function handleStart(e){ if (isStarSelected) return; isDragging=true; handleMove(e); } 
                const clientX = e.clientX !== undefined ? e.clientX : (e.touches && e.touches[0] && e.touches[0].clientX); 
                const clientY = e.clientY !== undefined ? e.clientY : (e.touches && e.touches[0] && e.touches[0].clientY); 
                const target = document.elementFromPoint(clientX, clientY); 
                const tile = target && target.closest('.tile'); 
                if (tile && tile !== lastTile){ 
                    const row=parseInt(tile.dataset.row); 
                    const col=parseInt(tile.dataset.col); 
                    const isAlready = selectedTiles.some(t=>t.row===row && t.col===col); 
                    if (!isAlready && isValidAdjacency(newTile)){ 
                        selectedTiles.push(newTile); 
                        tile.classList.add('selected'); 
                        const built=document.createElement('div'); 
                        built.classList.add('built-letter'); 
                        built.textContent = gameBoard[row][col].letter.toUpperCase(); 
                        wordBuilderEl.appendChild(built); 
                const word = getSelectedWord().toLowerCase(); 
                const foundWord = wordsToFind.find(w=>w===word); 
                if (foundWord && word.length >= 2) { 
                    foundWordCounts[foundWord] = (foundWordCounts[foundWord]||0) + 1; 
                    showMessage('Mīharo - you got it!'); 
                    dropLettersAndRefill(selectedTiles); 
                } else if (word.length > 1) { 
                    showMessage('That is not a valid word.'); 
            function tryToPlaceNewWord(){ 
                let wordsNotOnGrid = wordsToFind.filter(w=>foundWordCounts[w] < FIND_COUNT_PER_WORD); 
                const wordsOnGrid = new Set(); 
                for (let r=0;r<GRID_SIZE;r++) for (let c=0;c<GRID_SIZE;c++) if (gameBoard[r][c] && gameBoard[r][c].word) wordsOnGrid.add(gameBoard[r][c].word); 
                wordsNotOnGrid = wordsNotOnGrid.filter(w=>!wordsOnGrid.has(w)); 
                wordsNotOnGrid.sort((a, b) => b.length - a.length); // Place longer words first 
                if (wordsNotOnGrid.length>0){ 
                    for (const w of wordsNotOnGrid){ 
                        if (placeWord(wordInfo[w].obj, gameBoard)) return true; 
            function replaceRandomLetters(){ 
                for (let r=0;r<GRID_SIZE;r++) for (let c=0;c<GRID_SIZE;c++) if (!gameBoard[r][c] || !gameBoard[r][c].word) nonWordTiles.push({r,c}); 
                const tilesToReplace = nonWordTiles.slice(0, Math.min(20, nonWordTiles.length)); 
                tilesToReplace.forEach(({r,c})=> gameBoard[r][c]=null); 
                const wordsOnGrid = new Set(); 
                for (let r=0;r<GRID_SIZE;r++) for (let c=0;c<GRID_SIZE;c++) if (gameBoard[r][c] && gameBoard[r][c].word) wordsOnGrid.add(gameBoard[r][c].word); 
                let wordsNotOnGrid = wordsToFind.filter(w=>foundWordCounts[w] < FIND_COUNT_PER_WORD).filter(w=>!wordsOnGrid.has(w)); 
                wordsNotOnGrid.sort((a, b) => b.length - a.length); // Place longer words first 
                for (const word of wordsNotOnGrid) { 
                    placeWord(wordInfo[word].obj, gameBoard); 
                for (let r=0;r<GRID_SIZE;r++) for (let c=0;c<GRID_SIZE;c++) if (gameBoard[r][c]===null) gameBoard[r][c] = { letter: getRandomLetter(), word:null, color:'bg-purple-400' }; 
            function dropLettersAndRefill(tilesToRemove){ 
                const newGameBoard = Array.from({length:GRID_SIZE},()=>Array(GRID_SIZE).fill(null)); 
                const removeSet = new Set(tilesToRemove.map(t=>`${t.row},${t.col}`)); 
                for (let c=0;c<GRID_SIZE;c++){ 
                    for (let r=GRID_SIZE-1;r>=0;r--){ 
                        if (!removeSet.has(coord) && gameBoard[r][c]) columnStack.push(gameBoard[r][c]); 
                    let fillRow = GRID_SIZE-1; 
                    for (let i=0;i<columnStack.length;i++){ 
                        newGameBoard[fillRow][c] = columnStack[i]; 
                gameBoard = newGameBoard; 
                // Fill empty spaces with random letters first 
                for (let r=0;r<GRID_SIZE;r++) for (let c=0;c<GRID_SIZE;c++) if (gameBoard[r][c]===null) gameBoard[r][c] = { letter: getRandomLetter(), word:null, color:'bg-purple-400' }; 
                // Try to place remaining words 
                const wordsOnGrid = new Set(); 
                for (let r=0;r<GRID_SIZE;r++) for (let c=0;c<GRID_SIZE;c++) if (gameBoard[r][c] && gameBoard[r][c].word) wordsOnGrid.add(gameBoard[r][c].word); 
                const wordsToFindStillRemaining = wordsToFind.filter(w=>foundWordCounts[w] < FIND_COUNT_PER_WORD); 
                if (wordsToFindStillRemaining.length > 0 && wordsOnGrid.size < wordsToFindStillRemaining.length){ 
                    const maxAttempts = 300; // Increased to improve placement success 
                    while (wordsOnGrid.size < wordsToFindStillRemaining.length && attempts < maxAttempts){ 
                        const placed = tryToPlaceNewWord(); 
                        if (!placed) replaceRandomLetters(); 
                        for (let r=0;r<GRID_SIZE;r++) for (let c=0;c<GRID_SIZE;c++) if (gameBoard[r][c] && gameBoard[r][c].word) wordsOnGrid.add(gameBoard[r][c].word); 
                    // If still missing, show message but do not reset to avoid every move reset 
                    if (wordsOnGrid.size < wordsToFindStillRemaining.length) { 
                        showMessage('Some words could not be placed. Use a star to refresh if needed.'); 
            function checkWinCondition(){ 
                const allFound = wordsToFind.every(word=> foundWordCounts[word] >= FIND_COUNT_PER_WORD ); 
                    gameContainer.querySelectorAll('*').forEach(n=>n.style.display=''); 
                    winScreen.classList.remove('hidden'); 
                        <div class="win-overlay"> 
                                <span class="win-star-text">Ka Pai!</span> 
                            <div class="win-buttons"> 
                                <button class="win-button" id="replay-level-btn">Replay</button> 
                                <button class="win-button" id="next-level-btn">Next</button> 
                    document.getElementById('replay-level-btn').addEventListener('click', () => resetGame()); 
                    document.getElementById('next-level-btn').addEventListener('click', () => nextLevel()); 
                winScreen.classList.add('hidden'); 
                winScreen.innerHTML = ''; 
                if (currentLevel < LEVELS.length -1) { 
                    showMessage('You completed all levels! Ka rawe!'); 
            function attachEventListeners(){ 
                gridContainer.addEventListener('mousedown', handleStart); 
                gridContainer.addEventListener('mousemove', handleMove); 
                gridContainer.addEventListener('mouseup', handleEnd); 
                gridContainer.addEventListener('mouseleave', handleEnd); 
                gridContainer.addEventListener('touchstart', (e)=>handleStart(e.touches[0])); 
                gridContainer.addEventListener('touchmove', (e)=>handleMove(e.touches[0])); 
                gridContainer.addEventListener('touchend', handleEnd); 
                prevLevelBtn.addEventListener('click', ()=>{ prevLevel(); }); 
                nextLevelBtn.addEventListener('click', ()=>{ nextLevel(); }); 
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/> 
    <title>Kupu Rapu - Te Reo Māori Word Game (10 Levels)</title> 
    <script src="https://cdn.tailwindcss.com"></script> 
        @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap'); 
        :root{ --tile-bg: rgba(255,255,255,0.2); } 
            font-family: 'Inter', sans-serif; 
            background: linear-gradient(135deg, #f74ff7 0%, #f53da8 100%); 
            transition: background 600ms ease; 
            background-color: rgba(255, 255, 255, 0.09); 
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); 
            backdrop-filter: blur(10px); 
            text-shadow: 2px 2px 6px rgba(0, 0, 0, 0.35); 
        .level-controls { display:flex; gap:8px; align-items:center; margin-bottom:8px; } 
        .level-indicator { font-weight:700; padding:6px 10px; border-radius:9999px; background: rgba(255,255,255,0.12); } 
        .main-content { display:flex; width:100%; gap:18px; flex-direction:column; } 
        @media(min-width:768px){ .main-content{ flex-direction:row; align-items:flex-start; } } 
        .game-section{ flex:1; display:flex; flex-direction:column; align-items:center; } 
        .word-builder{ display:flex; justify-content:center; min-height:48px; gap:6px; margin-bottom:12px; background-color: rgba(255, 255, 255, 0.14); border-radius:12px; padding:8px; width:100%; text-transform:uppercase; } 
        .built-letter{ width:34px; height:34px; display:flex; justify-content:center; align-items:center; background:#fff; color:#000; font-weight:700; border-radius:8px; box-shadow:0 2px 6px rgba(0,0,0,0.12); animation:popIn 0.18s ease; } 
        @keyframes popIn{ 0%{ transform:scale(0); opacity:0 } 100%{ transform:scale(1); opacity:1 } } 
        .grid{ display:grid; grid-template-columns: repeat(6, 1fr); gap:8px; width:100%; max-width:520px; aspect-ratio: 6 / 5; margin-bottom:12px; position:relative; } 
        .tile{ position:relative; background-color:var(--tile-bg); color:black; font-size:clamp(0.9rem,3.5vw,1.6rem); font-weight:700; border-radius:12px; cursor:pointer; user-select:none; display:flex; justify-content:center; align-items:center; transition: transform 0.18s, box-shadow 0.18s, opacity 0.25s, top 0.35s ease-out; text-transform:uppercase; box-shadow:0 4px 8px rgba(0,0,0,0.12); } 
        .tile.hidden-tile{ opacity:0 } 
        .tile:hover{ transform: translateY(-2px); box-shadow:0 6px 12px rgba(0,0,0,0.16); } 
        .selected{ transform:scale(1.06); outline:3px solid white; outline-offset:-4px; } 
        .message-box{ background-color: rgba(0,0,0,0.32); color:white; padding:10px; border-radius:10px; margin-bottom:10px; font-weight:700; width:100%; } 
        .win-overlay{ position:absolute; top:0; left:0; width:100%; height:100%; display:flex; flex-direction:column; justify-content:center; align-items:center; background-color:rgba(0,0,0,0.3); z-index:10; } 
        .win-star{ width:60%; height:60%; background-color:rgba(255,255,255,0.2); clip-path: polygon(50% 0%,61% 35%,98% 35%,68% 57%,79% 91%,50% 70%,21% 91%,32% 57%,2% 35%,39% 35%); display:flex; justify-content:center; align-items:center; } 
        .win-star-text{ font-size:2.5rem; font-weight:700; color:#fff; text-shadow:2px 2px 6px rgba(0,0,0,0.5); } 
        .win-buttons{ display:flex; gap:8px; margin-top:16px; } 
        .win-button{ background-color: rgba(0,0,0,0.28); color:white; padding:8px 16px; border-radius:9999px; font-weight:700; transition:transform 0.15s; border:none; } 
        .win-button:hover{ transform: translateY(-3px); } 
        .word-list-section{ width:320px; min-width:240px; max-width:340px; background-color: rgba(0,0,0,0.14); border-radius:12px; padding:12px; display:flex; flex-direction:column; align-items:stretch; } 
        .word-list-heading{ font-size:1.05rem; font-weight:700; margin-bottom:8px; } 
        .word-list{ display:flex; flex-direction:column; gap:8px; } 
        .word-item{ border-radius:8px; padding:6px 8px; font-weight:700; display:flex; justify-content:space-between; align-items:center; } 
        .word-item-text{ font-size:1.05rem; font-weight:800; color:black; } 
        .word-item-count{ font-size:1rem; font-weight:700; color:black; } 
        .tick{ font-size:1.2rem; margin-left:6px; color:black; } 
        .star-container{ display:grid; grid-template-columns: repeat(5, 1fr); grid-template-rows: repeat(2, 1fr); gap:8px; margin-top:12px; width:100%; max-width:240px; justify-content:center; margin-left:auto; margin-right:auto; } 
        .star{ width:32px; height:32px; background-color:#a78bfa; clip-path: polygon(50% 0%,61% 35%,98% 35%,68% 57%,79% 91%,50% 70%,21% 91%,32% 57%,2% 35%,39% 35%); cursor:pointer; transition: transform 0.18s, background-color 0.18s; } 
        .star.selected{ background-color:#ffffff !important; transform:scale(2); } 
        .star.used{ background-color:#000000; cursor:default; } 
        /* Hardcoded tile colors */ 
        .bg-red-400{ background-color:#f87171 !important; } 
        .bg-orange-400{ background-color:#fb923c !important; } 
        .bg-yellow-400{ background-color:#facc15 !important; } 
        .bg-green-400{ background-color:#4ade80 !important; } 
        .bg-blue-400{ background-color:#60a5fa !important; } 
        .bg-purple-400{ background-color:#a78bfa !important; } 
        .bg-pink-400{ background-color:#f472b6 !important; } 
        .bg-teal-400{ background-color:#2dd4bf !important; } 
        .bg-brown-400{ background-color:#cf9c1b !important; } 
        .bg-black-400{ background-color:#9aa1a0 !important; } 
        .text-black{ color:black !important; } 
        .controls-row{ display:flex; gap:8px; align-items:center; justify-content:center; margin-bottom:8px; } 
        button{ background-color: rgba(0,0,0,0.28); color:white; padding:8px 14px; border-radius:9999px; font-weight:700; transition:transform 0.15s; border:none; } 
        button:hover{ transform: translateY(-3px); } 
        <h1 class="title">Kupu Rapu</h1> 
        <p class="subtitle">Drag to connect adjacent letters to find words. Complete the level to reveal translations!</p> 
        <div class="level-controls"> 
            <div class="controls-row"> 
                <button id="prev-level">◀ Prev</button> 
                <div class="level-indicator" id="level-indicator">Level 1 / 10</div> 
                <button id="next-level">Next ▶</button> 
        <div class="main-content"> 
            <div id="game-container" class="game-section"> 
                <div id="word-builder" class="word-builder"></div> 
                <div id="grid-container" class="grid"></div> 
                <div id="message-box" class="message-box opacity-0 transition-opacity duration-300"></div> 
                <div id="win-screen" class="hidden"></div> 
            <div class="word-list-section"> 
                <div class="word-list-heading">Words to find</div> 
                <div id="word-list" class="word-list"></div> 
                <div class="star-container" id="star-container"></div> 
        document.addEventListener('DOMContentLoaded', () => { 
            const gridContainer = document.getElementById('grid-container'); 
            const messageBox = document.getElementById('message-box'); 
            const winScreen = document.getElementById('win-screen'); 
            const gameContainer = document.getElementById('game-container'); 
            const wordListEl = document.getElementById('word-list'); 
            const wordBuilderEl = document.getElementById('word-builder'); 
            const starContainer = document.getElementById('star-container'); 
            const prevLevelBtn = document.getElementById('prev-level'); 
            const nextLevelBtn = document.getElementById('next-level'); 
            const levelIndicator = document.getElementById('level-indicator'); 
            const FIND_COUNT_PER_WORD = 1; 
            let foundWordCounts = {}; 
            let wordPlacementCounts = {}; 
            let isStarSelected = false; 
            const letters = ['a','e','h','i','k','m','n','o','p','r','t','u','w']; 
    bg: 'linear-gradient(135deg, #FF6B6B 0%, #FFE66D 100%)', 
      { w: 'ākonga', t: 'student', c: 'bg-green-400' },   // same 
      { w: 'akomanga', t: 'classroom', c: 'bg-pink-400' }, // same 
      { w: 'akōranga', t: 'learning', c: 'bg-orange-400' }, // same 
      { w: 'kaiako', t: 'teacher', c: 'bg-blue-400' },    // same 
      { w: 'tamariki', t: 'children', c: 'bg-yellow-400' } // replaced from Whakapapa 
    bg: 'linear-gradient(135deg, #4ECDC4 0%, #1A535C 100%)', 
      { w: 'whānau', t: 'family', c: 'bg-yellow-400' },   // same 
      { w: 'tūpuna', t: 'ancestors', c: 'bg-teal-400' },  // same 
      { w: 'māmā', t: 'mother', c: 'bg-red-400' },        // same 
      { w: 'pāpā', t: 'father', c: 'bg-orange-400' },     // same 
      { w: 'kuia', t: 'elderly woman', c: 'bg-blue-400' } // same 
    bg: 'linear-gradient(135deg, #2A6041 0%, #A8D5BA 100%)', 
      { w: 'manu', t: 'bird', c: 'bg-green-400' },        // same 
      { w: 'iwi', t: 'tribe', c: 'bg-yellow-400' },       // same 
      { w: 'rākau', t: 'tree', c: 'bg-green-400' },       // same 
      { w: 'pipi', t: 'shellfish', c: 'bg-teal-400' },    // same 
      { w: 'moana', t: 'sea', c: 'bg-blue-400' }          // same 
    bg: 'linear-gradient(135deg, #FF9F43 0%, #EE6352 100%)', 
      { w: 'kākahu', t: 'clothes', c: 'bg-teal-400' },   // same 
      { w: 'panekoti', t: 'skirt', c: 'bg-yellow-400' }, // revised 
      { w: 'tarau', t: 'trousers', c: 'bg-orange-400' }, // revised 
      { w: 'pōtae', t: 'hat', c: 'bg-green-400' },      // revised 
      { w: 'poraka', t: 'jumper', c: 'bg-blue-400' }    // revised 
    bg: 'linear-gradient(135deg, #483D8B 0%, #B0C4DE 100%)', 
      { w: 'papatuanuku', t: 'Earth Mother', c: 'bg-green-400' }, // checked macrons 
      { w: 'ranginui', t: 'Sky Father', c: 'bg-blue-400' },      // same 
      { w: 'tāne', t: 'Forest God', c: 'bg-yellow-400' },       // same 
      { w: 'tangaroa', t: 'Sea God', c: 'bg-teal-400' },        // same 
      { w: 'rongo', t: 'God of Peace', c: 'bg-orange-400' }     // revised from Tūmatauenga 
    bg: 'linear-gradient(135deg, #FF6F61 0%, #D4A5A5 100%)', 
      { w: 'kōwhai', t: 'yellow', c: 'bg-yellow-400' }, // same 
      { w: 'parauri', t: 'brown', c: 'bg-brown-400' },   // same 
      { w: 'karaka', t: 'orange', c: 'bg-orange-400' },  // same 
      { w: 'kākāriki', t: 'green', c: 'bg-green-400' },  // same 
      { w: 'pango', t: 'black', c: 'bg-black-400' }      // same 
    bg: 'linear-gradient(135deg, #1B4332 0%, #74C69D 100%)', 
      { w: 'tokohia', t: 'many', c: 'bg-green-400' },  // same 
      { w: 'tuatahi', t: 'first', c: 'bg-blue-400' },  // same 
      { w: 'tuarua', t: 'second', c: 'bg-yellow-400' }, // same 
      { w: 'tuawhā', t: 'fourth', c: 'bg-orange-400' }, // same 
      { w: 'tokorima', t: 'five', c: 'bg-red-400' }     // same 
    name: 'Taonga & Pounamu', 
    bg: 'linear-gradient(135deg, #74C69D 0%, #B5EAD7 100%)', 
      { w: 'taonga', t: 'treasure', c: 'bg-yellow-400' },     // same 
      { w: 'pounamu', t: 'greenstone', c: 'bg-teal-400' },    // same 
      { w: 'ngākau', t: 'heart', c: 'bg-red-400' },           // same 
      { w: 'mārama', t: 'clarity', c: 'bg-blue-400' },       // same 
      { w: 'pakiwaitara', t: 'story', c: 'bg-orange-400' }    // new 
    bg: 'linear-gradient(135deg, #1B4332 0%, #74C69D 100%)', 
      { w: 'tupuānuku', t: 'star 1', c: 'bg-pink-400' },    // same 
      { w: 'tupuārangi', t: 'star 2', c: 'bg-blue-400' },   // same 
      { w: 'waitī', t: 'star 3', c: 'bg-yellow-400' },       // same 
      { w: 'waitā', t: 'star 4', c: 'bg-green-400' },       // same 
      { w: 'pōhutukawa', t: 'star 5', c: 'bg-orange-400' } // same 
            function shuffle(array) { 
                for (let i = array.length - 1; i > 0; i--) { 
                    const j = Math.floor(Math.random() * (i + 1)); 
                    [array[i], array[j]] = [array[j], array[i]]; 
            function createTile(row, col, letter, colorClass) { 
                const tile = document.createElement('div'); 
                tile.classList.add('tile'); 
                if (colorClass) tile.classList.add(colorClass); 
                tile.classList.add('text-black'); 
                tile.dataset.letter = letter; 
                tile.innerHTML = `<span>${letter.toUpperCase()}</span>`; 
            function createStar(index) { 
                const star = document.createElement('div'); 
                star.classList.add('star'); 
                star.dataset.index = index; 
                star.style.backgroundColor = '#a78bfa'; // Match non-word tiles 
                star.addEventListener('click', () => handleStarClick(index)); 
                starContainer.appendChild(star); 
                starContainer.innerHTML = ''; 
                for (let i = 0; i < 10; i++) { 
                    const star = createStar(i); 
                    stars.push({ element: star, used: false }); 
            function displayWordList() { 
                wordListEl.innerHTML = ''; 
                wordsToFind.forEach(word => { 
                    const count = foundWordCounts[word] || 0; 
                    const info = wordInfo[word]; 
                    const wordItem = document.createElement('div'); 
                    wordItem.classList.add('word-item'); 
                    if (info && info.color) wordItem.classList.add(info.color); 
                    const left = document.createElement('div'); 
                    left.style.display = 'flex'; 
                    left.style.flexDirection = 'column'; 
                    left.style.alignItems = 'flex-start'; 
                    const wordText = document.createElement('span'); 
                    wordText.classList.add('word-item-text'); 
                    wordText.textContent = word.toUpperCase(); 
                    const translation = document.createElement('small'); 
                    translation.style.fontWeight = '600'; 
                    translation.style.marginTop = '4px'; 
                    translation.style.opacity = count > 0 ? '1' : '0.0'; 
                    translation.textContent = count > 0 ? `(${info ? info.translation : ''})` : ''; 
                    left.appendChild(wordText); 
                    left.appendChild(translation); 
                    const wordCount = document.createElement('span'); 
                    wordCount.classList.add('word-item-count'); 
                    wordCount.innerHTML = count > 0 ? '<span class="tick">✓</span>' : ''; 
                    wordItem.appendChild(left); 
                    wordItem.appendChild(wordCount); 
                    wordListEl.appendChild(wordItem); 
function placeWord(wordObj, board) { 
    const directions = [[0,1],[0,-1],[1,0],[-1,0],[1,1],[1,-1],[-1,1],[-1,-1]]; 
    while (!placed && attempts < maxAttempts) { 
        const startR = Math.floor(Math.random() * GRID_SIZE); 
        const startC = Math.floor(Math.random() * GRID_SIZE); 
        const path = [{r:startR,c:startC}]; 
        const visited = new Set([`${startR},${startC}`]); 
        const findPath = (r,c,wordIndex) => { 
            if (wordIndex === word.length) return true; 
            for (const [dr,dc] of directions) { 
                const key = `${newR},${newC}`; 
                if (newR>=0 && newR<GRID_SIZE && newC>=0 && newC<GRID_SIZE && !visited.has(key)) { 
                    const cell = board[newR][newC]; 
                    // 🔴 FIX: only allow empty cells (no overlaps allowed) 
                    if (cell === null || cell === undefined || cell.word === null) { 
                        path.push({r:newR,c:newC}); 
                        if (findPath(newR,newC,wordIndex+1)) return true; 
        const startCell = board[startR][startC]; 
        // 🔴 FIX: starting cell also must be empty 
        if (startCell === null || startCell === undefined || startCell.word === null) { 
            if (findPath(startR,startC,1)) { 
                if (path.length === word.length) { 
                    for (let i=0;i<word.length;i++){ 
                        board[r][c] = { letter: word[i], word: word, color: wordObj.c }; 
                    wordPlacementCounts[word] = (wordPlacementCounts[word] || 0) + 1; 
            function validateBoard(board) { 
                const wordsOnGrid = new Set(); 
                const directions = [[0,1],[0,-1],[1,0],[-1,0],[1,1],[1,-1],[-1,1],[-1,-1]]; 
                function checkPath(r, c, word, wordIndex, path, visited) { 
                    if (wordIndex === word.length) return true; 
                    for (const [dr, dc] of directions) { 
                        const newR = r + dr; const newC = c + dc; 
                        const key = `${newR},${newC}`; 
                        if (newR >= 0 && newR < GRID_SIZE && newC >= 0 && newC < GRID_SIZE && !visited.has(key)) { 
                            if (board[newR][newC] && board[newR][newC].letter === word[wordIndex]) { 
                                visited.add(key); path.push({r:newR,c:newC}); 
                                if (checkPath(newR, newC, word, wordIndex + 1, path, visited)) return true; 
                                path.pop(); visited.delete(key); 
                for (const word of wordsToFind) { 
                    for (let r = 0; r < GRID_SIZE && !found; r++) { 
                        for (let c = 0; c < GRID_SIZE && !found; c++) { 
                            if (board[r][c] && board[r][c].letter === word[0]) { 
                                const visited = new Set([`${r},${c}`]); 
                                if (checkPath(r, c, word, 1, path, visited) && path.length === word.length) { 
                return wordsOnGrid.size === wordsToFind.length; 
            function refreshBoard() { 
                const MAX_OVERALL_ATTEMPTS = 100; 
                let words = wordsToFind.map(w=>wordInfo[w].obj); 
                words.sort((a, b) => b.w.length - a.w.length); // Place longer words first 
                while (!success && overallAttempt < MAX_OVERALL_ATTEMPTS) { 
                    const localBoard = Array.from({length:GRID_SIZE},()=>Array(GRID_SIZE).fill(null)); 
                    for (const wobj of words) { 
                        const placed = placeWord(wobj, localBoard); 
                        if (!placed) { allPlaced = false; break; } 
                    if (allPlaced && validateBoard(localBoard)) { 
                        for (let r=0;r<GRID_SIZE;r++){ 
                            for (let c=0;c<GRID_SIZE;c++){ 
                                if (localBoard[r][c] === null) localBoard[r][c] = { letter: getRandomLetter(), word: null, color: 'bg-purple-400' }; 
                    gameBoard = Array.from({length:GRID_SIZE},()=>Array(GRID_SIZE).fill(null)); 
                    for (const w of words) placeWord(w, gameBoard); 
                    for (let r=0;r<GRID_SIZE;r++) for (let c=0;c<GRID_SIZE;c++) if (gameBoard[r][c]===null) gameBoard[r][c] = { letter: getRandomLetter(), word:null, color:'bg-purple-400' }; 
                    if (!validateBoard(gameBoard)) refreshBoard(); 
                wordPlacementCounts = {}; 
                const level = LEVELS[currentLevel]; 
                wordsToFind = level.words.map(o => o.w); 
                level.words.forEach(o => { 
                    wordInfo[o.w] = { translation: o.t, color: o.c, obj: o }; 
                    foundWordCounts[o.w] = 0; 
                    wordPlacementCounts[o.w] = 0; 
                document.body.style.background = level.bg; 
                levelIndicator.textContent = `Level ${currentLevel+1} / ${LEVELS.length} — ${level.name}`; 
                for (let r=0;r<GRID_SIZE;r++){ 
                    if (!gameBoard[r]) gameBoard[r] = Array(GRID_SIZE).fill(null); 
                    for (let c=0;c<GRID_SIZE;c++) if (!gameBoard[r][c]) gameBoard[r][c] = { letter: getRandomLetter(), word:null, color:'bg-purple-400' }; 
                gridContainer.innerHTML = ''; 
                gameBoard.forEach((row,r)=>{ 
                        const tile = createTile(r,c,cell.letter, cell.color); 
                        tile.addEventListener('click', ()=>handleTileClick(r,c)); 
                        gridContainer.appendChild(tile); 
            function getRandomLetter(){ return letters[Math.floor(Math.random()*letters.length)]; } 
            function getSelectedWord(){ return selectedTiles.map(t=>gameBoard[t.row][t.col].letter).join(''); } 
            function isValidAdjacency(newTile){ if (selectedTiles.length===0) return true; const last = selectedTiles[selectedTiles.length-1]; const dx=Math.abs(newTile.row-last.row); const dy=Math.abs(newTile.col-last.col); return (dx<=1 && dy<=1 && (dx>0||dy>0)); } 
            function showMessage(text, duration=1400){ messageBox.textContent = text; messageBox.style.opacity = '1'; setTimeout(()=>{ messageBox.style.opacity='0'; }, duration); } 
            function clearHighlights(){ document.querySelectorAll('.tile.selected').forEach(t=>t.classList.remove('selected')); selectedTiles=[]; wordBuilderEl.innerHTML=''; } 
            function handleStarClick(index) { 
                if (stars[index].used || isDragging) return; 
                const thisStar = stars[index].element; 
                if (thisStar.classList.contains('selected')) { 
                    thisStar.classList.remove('selected'); 
                    thisStar.style.backgroundColor = '#a78bfa'; // Restore default color 
                        s.element.classList.remove('selected'); 
                        s.element.style.backgroundColor = '#a78bfa'; // Ensure default color 
                    thisStar.classList.add('selected'); 
                    thisStar.style.backgroundColor = '#ffffff'; // Force white color 
            function getAdjacentTiles(row,col){ const tiles=[]; const dirs=[[0,0],[0,1],[0,-1],[1,0],[-1,0],[1,1],[1,-1],[-1,1],[-1,-1]]; for(const [dr,dc] of dirs){ const nr=row+dr, nc=col+dc; if(nr>=0 && nr<GRID_SIZE && nc>=0 && nc<GRID_SIZE) tiles.push({row:nr,col:nc}); } return tiles; } 
            function handleTileClick(row,col) { 
                    const selectedStarIdx = stars.findIndex(s => s.element.classList.contains('selected')); 
                    if (selectedStarIdx >= 0) { 
                        stars[selectedStarIdx].used = true; 
                        stars[selectedStarIdx].element.classList.remove('selected'); 
                        stars[selectedStarIdx].element.classList.add('used'); 
                        stars[selectedStarIdx].element.style.backgroundColor = '#000000'; // Ensure used color 
                        showMessage('Board refreshed!'); 
            function handleStart(e){ if (isStarSelected) return; isDragging=true; handleMove(e); } 
                const clientX = e.clientX !== undefined ? e.clientX : (e.touches && e.touches[0] && e.touches[0].clientX); 
                const clientY = e.clientY !== undefined ? e.clientY : (e.touches && e.touches[0] && e.touches[0].clientY); 
                const target = document.elementFromPoint(clientX, clientY); 
                const tile = target && target.closest('.tile'); 
                if (tile && tile !== lastTile){ 
                    const row=parseInt(tile.dataset.row); 
                    const col=parseInt(tile.dataset.col); 
                    const isAlready = selectedTiles.some(t=>t.row===row && t.col===col); 
                    if (!isAlready && isValidAdjacency(newTile)){ 
                        selectedTiles.push(newTile); 
                        tile.classList.add('selected'); 
                        const built=document.createElement('div'); 
                        built.classList.add('built-letter'); 
                        built.textContent = gameBoard[row][col].letter.toUpperCase(); 
                        wordBuilderEl.appendChild(built); 
                const word = getSelectedWord().toLowerCase(); 
                const foundWord = wordsToFind.find(w=>w===word); 
                if (foundWord && word.length >= 2) { 
                    foundWordCounts[foundWord] = (foundWordCounts[foundWord]||0) + 1; 
                    showMessage('Mīharo - you got it!'); 
                    dropLettersAndRefill(selectedTiles); 
                } else if (word.length > 1) { 
                    showMessage('That is not a valid word.'); 
            function tryToPlaceNewWord(){ 
                let wordsNotOnGrid = wordsToFind.filter(w=>foundWordCounts[w] < FIND_COUNT_PER_WORD); 
                const wordsOnGrid = new Set(); 
                for (let r=0;r<GRID_SIZE;r++) for (let c=0;c<GRID_SIZE;c++) if (gameBoard[r][c] && gameBoard[r][c].word) wordsOnGrid.add(gameBoard[r][c].word); 
                wordsNotOnGrid = wordsNotOnGrid.filter(w=>!wordsOnGrid.has(w)); 
                wordsNotOnGrid.sort((a, b) => b.length - a.length); // Place longer words first 
                if (wordsNotOnGrid.length>0){ 
                    for (const w of wordsNotOnGrid){ 
                        if (placeWord(wordInfo[w].obj, gameBoard)) return true; 
            function replaceRandomLetters(){ 
                for (let r=0;r<GRID_SIZE;r++) for (let c=0;c<GRID_SIZE;c++) if (!gameBoard[r][c] || !gameBoard[r][c].word) nonWordTiles.push({r,c}); 
                const tilesToReplace = nonWordTiles.slice(0, Math.min(20, nonWordTiles.length)); 
                tilesToReplace.forEach(({r,c})=> gameBoard[r][c]=null); 
                const wordsOnGrid = new Set(); 
                for (let r=0;r<GRID_SIZE;r++) for (let c=0;c<GRID_SIZE;c++) if (gameBoard[r][c] && gameBoard[r][c].word) wordsOnGrid.add(gameBoard[r][c].word); 
                let wordsNotOnGrid = wordsToFind.filter(w=>foundWordCounts[w] < FIND_COUNT_PER_WORD).filter(w=>!wordsOnGrid.has(w)); 
                wordsNotOnGrid.sort((a, b) => b.length - a.length); // Place longer words first 
                for (const word of wordsNotOnGrid) { 
                    placeWord(wordInfo[word].obj, gameBoard); 
                for (let r=0;r<GRID_SIZE;r++) for (let c=0;c<GRID_SIZE;c++) if (gameBoard[r][c]===null) gameBoard[r][c] = { letter: getRandomLetter(), word:null, color:'bg-purple-400' }; 
            function dropLettersAndRefill(tilesToRemove){ 
                const newGameBoard = Array.from({length:GRID_SIZE},()=>Array(GRID_SIZE).fill(null)); 
                const removeSet = new Set(tilesToRemove.map(t=>`${t.row},${t.col}`)); 
                for (let c=0;c<GRID_SIZE;c++){ 
                    for (let r=GRID_SIZE-1;r>=0;r--){ 
                        if (!removeSet.has(coord) && gameBoard[r][c]) columnStack.push(gameBoard[r][c]); 
                    let fillRow = GRID_SIZE-1; 
                    for (let i=0;i<columnStack.length;i++){ 
                        newGameBoard[fillRow][c] = columnStack[i]; 
                gameBoard = newGameBoard; 
                // Fill empty spaces with random letters first 
                for (let r=0;r<GRID_SIZE;r++) for (let c=0;c<GRID_SIZE;c++) if (gameBoard[r][c]===null) gameBoard[r][c] = { letter: getRandomLetter(), word:null, color:'bg-purple-400' }; 
                // Try to place remaining words 
                const wordsOnGrid = new Set(); 
                for (let r=0;r<GRID_SIZE;r++) for (let c=0;c<GRID_SIZE;c++) if (gameBoard[r][c] && gameBoard[r][c].word) wordsOnGrid.add(gameBoard[r][c].word); 
                const wordsToFindStillRemaining = wordsToFind.filter(w=>foundWordCounts[w] < FIND_COUNT_PER_WORD); 
                if (wordsToFindStillRemaining.length > 0 && wordsOnGrid.size < wordsToFindStillRemaining.length){ 
                    const maxAttempts = 300; // Increased to improve placement success 
                    while (wordsOnGrid.size < wordsToFindStillRemaining.length && attempts < maxAttempts){ 
                        const placed = tryToPlaceNewWord(); 
                        if (!placed) replaceRandomLetters(); 
                        for (let r=0;r<GRID_SIZE;r++) for (let c=0;c<GRID_SIZE;c++) if (gameBoard[r][c] && gameBoard[r][c].word) wordsOnGrid.add(gameBoard[r][c].word); 
                    // If still missing, show message but do not reset to avoid every move reset 
                    if (wordsOnGrid.size < wordsToFindStillRemaining.length) { 
                        showMessage('Some words could not be placed. Use a star to refresh if needed.'); 
            function checkWinCondition(){ 
                const allFound = wordsToFind.every(word=> foundWordCounts[word] >= FIND_COUNT_PER_WORD ); 
                    gameContainer.querySelectorAll('*').forEach(n=>n.style.display=''); 
                    winScreen.classList.remove('hidden'); 
                        <div class="win-overlay"> 
                                <span class="win-star-text">Ka Pai!</span> 
                            <div class="win-buttons"> 
                                <button class="win-button" id="replay-level-btn">Replay</button> 
                                <button class="win-button" id="next-level-btn">Next</button> 
                    document.getElementById('replay-level-btn').addEventListener('click', () => resetGame()); 
                    document.getElementById('next-level-btn').addEventListener('click', () => nextLevel()); 
                winScreen.classList.add('hidden'); 
                winScreen.innerHTML = ''; 
                if (currentLevel < LEVELS.length -1) { 
                    showMessage('You completed all levels! Ka rawe!'); 
            function attachEventListeners(){ 
                gridContainer.addEventListener('mousedown', handleStart); 
                gridContainer.addEventListener('mousemove', handleMove); 
                gridContainer.addEventListener('mouseup', handleEnd); 
                gridContainer.addEventListener('mouseleave', handleEnd); 
                gridContainer.addEventListener('touchstart', (e)=>handleStart(e.touches[0])); 
                gridContainer.addEventListener('touchmove', (e)=>handleMove(e.touches[0])); 
                gridContainer.addEventListener('touchend', handleEnd); 
                prevLevelBtn.addEventListener('click', ()=>{ prevLevel(); }); 
                nextLevelBtn.addEventListener('click', ()=>{ nextLevel(); });