diff --git a/pyramid.js b/pyramid.js index d8efe78..ee3fdba 100644 --- a/pyramid.js +++ b/pyramid.js @@ -141,51 +141,47 @@ function renderBoard() { if (!isActive) return; - const boardRect = gameBoard.getBoundingClientRect(); const layoutRect = pyramidLayout.getBoundingClientRect(); - // If the board isn't visible yet or dimensions aren't ready, wait for the next frame - if (boardRect.width === 0 || layoutRect.width === 0) { + // If the board isn't visible yet or dimensions aren't ready, wait + if (layoutRect.width === 0) { requestAnimationFrame(renderBoard); return; } - const rootStyle = getComputedStyle(document.documentElement); - let cardWidth = parseFloat(rootStyle.getPropertyValue('--card-width')); - let horizontalGap = parseFloat(rootStyle.getPropertyValue('--gap')); + // Use the first available card to get the REAL pixel width/height calculated by CSS + const firstCardId = Object.keys(cardElements)[0]; + if (!firstCardId) return; + const sampleCard = cardElements[firstCardId]; + const cardRect = sampleCard.getBoundingClientRect(); + const cardWidth = cardRect.width; + const cardHeight = cardRect.height; - if (isNaN(cardWidth) || cardWidth === 0) cardWidth = 80; - if (isNaN(horizontalGap)) horizontalGap = 10; - - const cardHeight = cardWidth * 1.4; - const rowOverlap = 0.45; - - const boardTop = boardRect.top; - const boardLeft = boardRect.left; + // Calculate gap based on 1.5vw or fallback (matching style.css) + let horizontalGap = (window.innerWidth * 1.5) / 100; + if (window.innerWidth > 600) horizontalGap = (window.innerWidth * 1.2) / 100; // Desktop gap + + const verticalStep = cardHeight * 0.45; // Row overlap ratio // Position Pyramid Cards let index = 0; for (let row = 0; row < 7; row++) { - // Calculate total width of this row to center it const numCards = row + 1; const totalRowWidth = numCards * cardWidth + (numCards - 1) * horizontalGap; const startX = (layoutRect.width - totalRowWidth) / 2; - const y = row * (cardHeight * rowOverlap); + const y = row * verticalStep; for (let i = 0; i <= row; i++) { const card = pyramid[index]; if (card) { const el = cardElements[card.id]; - // Absolute position relative to the gameBoard - const finalTop = y + (layoutRect.top - boardTop); - const finalLeft = startX + i * (cardWidth + horizontalGap) + (layoutRect.left - boardLeft); - - el.style.top = `${finalTop}px`; - el.style.left = `${finalLeft}px`; + // Position relative to the pyramid-layout container + // Note: pyramid-layout has position: relative in pyramid.css + el.style.top = `${y}px`; + el.style.left = `${startX + i * (cardWidth + horizontalGap)}px`; el.style.zIndex = 100 + index; el.classList.add('is-flipped'); - // Mark if it's currently playable for visual feedback const exposed = isExposed(card.id); el.classList.toggle('is-exposed', exposed); } @@ -193,41 +189,38 @@ } } - // Position Stock + // Position Stock, Waste, Discard (these are in a separate container at the bottom) + // We'll use a slightly different approach for these to ensure they stay in their piles const sRect = stockEl.getBoundingClientRect(); + const wRect = wasteEl.getBoundingClientRect(); + const dRect = discardEl.getBoundingClientRect(); + const bRect = gameBoard.getBoundingClientRect(); + stock.forEach((card, i) => { const el = cardElements[card.id]; - el.style.top = `${sRect.top - boardTop + PILE_BORDER_WIDTH}px`; - el.style.left = `${sRect.left - boardLeft + PILE_BORDER_WIDTH}px`; + el.style.top = `${sRect.top - bRect.top + PILE_BORDER_WIDTH}px`; + el.style.left = `${sRect.left - bRect.left + PILE_BORDER_WIDTH}px`; el.style.zIndex = 10 + i; - el.classList.remove('is-flipped'); - el.classList.remove('is-selected'); - el.classList.remove('is-exposed'); + el.classList.remove('is-flipped', 'is-selected', 'is-exposed'); }); - // Position Waste - const wRect = wasteEl.getBoundingClientRect(); waste.forEach((card, i) => { const el = cardElements[card.id]; const isTop = (i === waste.length - 1); - el.style.top = `${wRect.top - boardTop + PILE_BORDER_WIDTH}px`; - el.style.left = `${wRect.left - boardLeft + PILE_BORDER_WIDTH}px`; - // Base z-index for waste is 500, +i to stack correctly - el.style.zIndex = 500 + i; + el.style.top = `${wRect.top - bRect.top + PILE_BORDER_WIDTH}px`; + el.style.left = `${wRect.left - bRect.left + PILE_BORDER_WIDTH}px`; + el.style.zIndex = 500 + i; el.classList.add('is-flipped'); el.classList.toggle('is-exposed', isTop); }); - // Position Discard - const dRect = discardEl.getBoundingClientRect(); discard.forEach((card, i) => { const el = cardElements[card.id]; - el.style.top = `${dRect.top - boardTop + PILE_BORDER_WIDTH}px`; - el.style.left = `${dRect.left - boardLeft + PILE_BORDER_WIDTH}px`; + el.style.top = `${dRect.top - bRect.top + PILE_BORDER_WIDTH}px`; + el.style.left = `${dRect.left - bRect.left + PILE_BORDER_WIDTH}px`; el.style.zIndex = 10 + i; el.classList.add('is-flipped'); - el.classList.remove('is-selected'); - el.classList.remove('is-exposed'); + el.classList.remove('is-selected', 'is-exposed'); }); checkWin();