/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Card class
var Card = Container.expand(function () {
	var self = Container.call(this);
	// Card properties
	self.rank = 1; // 1=Ace, 13=King
	self.suit = 0; // 0=spades (for MVP, only one suit)
	self.faceUp = false;
	self.selected = false;
	// Card graphics
	// Add a drop shadow and rounded rectangle background for realism
	// Scale card assets to fit calculated CARD_WIDTH and CARD_HEIGHT
	var scaleX = typeof CARD_WIDTH !== "undefined" ? CARD_WIDTH / BASE_CARD_WIDTH : 1;
	var scaleY = typeof CARD_HEIGHT !== "undefined" ? CARD_HEIGHT / BASE_CARD_HEIGHT : 1;
	var cardShadow = LK.getAsset('cardFace', {
		anchorX: 0.5,
		anchorY: 0.5,
		tint: 0x222222,
		alpha: 0.18,
		scaleX: 1.04 * scaleX,
		scaleY: 1.04 * scaleY
	});
	self.addChild(cardShadow);
	var cardFace = self.attachAsset('cardFace', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: scaleX,
		scaleY: scaleY
	});
	var cardBack = self.attachAsset('cardBack', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: scaleX,
		scaleY: scaleY
	});
	cardBack.visible = true;
	cardFace.visible = false;
	// Corner labels (rank + suit) for top-left and bottom-right
	var labelTL = new Text2('', {
		size: Math.floor(cardFace.height * 0.22),
		fill: 0xffffff,
		align: "left"
	});
	labelTL.anchor.set(0, 0);
	labelTL.x = -cardFace.width / 2 + Math.floor(cardFace.width * 0.08);
	labelTL.y = -cardFace.height / 2 + Math.floor(cardFace.height * 0.08);
	self.addChild(labelTL);
	var labelBR = new Text2('', {
		size: Math.floor(cardFace.height * 0.22),
		fill: 0xffffff,
		align: "right"
	});
	labelBR.anchor.set(1, 1);
	labelBR.x = cardFace.width / 2 - Math.floor(cardFace.width * 0.08);
	labelBR.y = cardFace.height / 2 - Math.floor(cardFace.height * 0.08);
	self.addChild(labelBR);
	// Set card data
	self.setCard = function (rank, suit, faceUp) {
		self.rank = rank;
		self.suit = suit;
		self.faceUp = faceUp;
		self.updateFace();
	};
	// Update card face/back and label
	self.updateFace = function () {
		cardFace.visible = self.faceUp;
		cardBack.visible = !self.faceUp;
		// Only spades for MVP
		var suitChar = '♠';
		var rankStr = '';
		if (self.rank === 1) rankStr = 'A';else if (self.rank === 11) rankStr = 'J';else if (self.rank === 12) rankStr = 'Q';else if (self.rank === 13) rankStr = 'K';else rankStr = '' + self.rank;
		// Show only in corners
		if (typeof labelTL !== "undefined" && typeof labelBR !== "undefined") {
			var labelText = rankStr + suitChar;
			labelTL.setText(labelText);
			labelBR.setText(labelText);
			labelTL.visible = true;
			labelBR.visible = true;
			if (self.faceUp) {
				labelTL.setStyle({
					fill: 0xffffff,
					alpha: 1
				});
				labelBR.setStyle({
					fill: 0xffffff,
					alpha: 1
				});
			} else {
				labelTL.setStyle({
					fill: 0xcccccc,
					alpha: 0.45
				});
				labelBR.setStyle({
					fill: 0xcccccc,
					alpha: 0.45
				});
			}
		}
		// Optionally, show a faint spider on the back for realism
		self.updateSelected();
	};
	// Visual feedback for selection
	self.updateSelected = function () {
		if (self.selected) {
			cardFace.tint = 0x99ccff;
			cardBack.tint = 0x99ccff;
		} else {
			cardFace.tint = 0xffffff;
			cardBack.tint = 0xffffff;
		}
	};
	// Flip card
	self.flip = function (faceUp) {
		self.faceUp = faceUp;
		self.updateFace();
	};
	// Touch events
	self.down = function (x, y, obj) {
		if (self.faceUp) {
			// Let game handle selection
			if (game) game.onCardDown(self, x, y, obj);
		}
	};
	return self;
});
// Stock pile class (for dealing new rows)
var StockPile = Container.expand(function () {
	var self = Container.call(this);
	self.cards = [];
	// Add card to stock
	self.addCard = function (card) {
		self.cards.push(card);
		self.addChild(card);
		card.x = 0;
		card.y = 0;
	};
	// Deal one card per tableau pile
	self.dealToTableau = function (tableauPiles) {
		if (self.cards.length < tableauPiles.length) return false;
		for (var i = 0; i < tableauPiles.length; i++) {
			var card = self.cards.shift();
			card.flip(true);
			tableauPiles[i].addCard(card);
		}
		return true;
	};
	// Is empty?
	self.isEmpty = function () {
		return self.cards.length === 0;
	};
	return self;
});
// Tableau pile class
var TableauPile = Container.expand(function () {
	var self = Container.call(this);
	self.cards = [];
	// Add card to pile
	self.addCard = function (card) {
		self.cards.push(card);
		self.addChild(card);
		self.layout();
	};
	// Remove card(s) from pile starting at index
	self.removeCardsFrom = function (idx) {
		var removed = [];
		while (self.cards.length > idx) {
			var c = self.cards.pop();
			c.parent.removeChild(c);
			removed.unshift(c);
		}
		self.layout();
		return removed;
	};
	// Get top card
	self.topCard = function () {
		if (self.cards.length === 0) return null;
		return self.cards[self.cards.length - 1];
	};
	// Layout cards in pile
	self.layout = function () {
		// Increase vertical spacing between cards for more space in each column
		var CARD_VERTICAL_SPACING = 110;
		for (var i = 0; i < self.cards.length; i++) {
			var c = self.cards[i];
			// Animate to new position using tween
			tween.stop(c, {
				x: true,
				y: true
			}); // Stop any previous tweens on x/y
			tween(c, {
				x: 0,
				y: i * CARD_VERTICAL_SPACING
			}, {
				duration: 400,
				easing: tween.cubicOut
			});
			c.zIndex = i;
		}
	};
	// Reveal top card if needed
	self.revealTop = function () {
		var top = self.topCard();
		if (top && !top.faceUp) {
			top.flip(true);
		}
	};
	// Get index of card in pile
	self.indexOf = function (card) {
		for (var i = 0; i < self.cards.length; i++) {
			if (self.cards[i] === card) return i;
		}
		return -1;
	};
	// Can move sequence starting at idx?
	self.canMoveSequence = function (idx) {
		// All cards from idx to end must be face up and in descending order
		for (var i = idx; i < self.cards.length - 1; i++) {
			var c1 = self.cards[i];
			var c2 = self.cards[i + 1];
			if (!c1.faceUp || !c2.faceUp) return false;
			if (c1.rank !== c2.rank + 1) return false;
		}
		return self.cards[idx].faceUp;
	};
	// Can accept a sequence of cards (cardsArr)?
	self.canAccept = function (cardsArr) {
		if (self.cards.length === 0) {
			// Only King can be placed on empty pile
			return cardsArr[0].rank === 13;
		} else {
			var top = self.topCard();
			var moving = cardsArr[0];
			return top.faceUp && top.rank === moving.rank + 1;
		}
	};
	// Remove completed set (K-A)
	self.removeCompleteSet = function () {
		// Check if last 13 cards are a complete set
		if (self.cards.length < 13) return false;
		for (var i = 0; i < 13; i++) {
			var c = self.cards[self.cards.length - 1 - i];
			if (!c.faceUp || c.rank !== 13 - i) return false;
		}
		// Remove them
		var removed = [];
		for (var i = 0; i < 13; i++) {
			var c = self.cards.pop();
			if (c.parent) c.parent.removeChild(c);
			removed.unshift(c);
		}
		self.layout();
		// Add to collected area (handled by animation in game logic)
		return removed; // Return the collected set for animation/cleanup
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0xcccccc
});
/**** 
* Game Code
****/ 
// (Removed stock label)
// Show number of stacks left as card decks on stock pile
var stockDecks = [];
function updateStockDecks() {
	// Remove old
	for (var i = 0; i < stockDecks.length; i++) {
		if (stockDecks[i].parent) stockDecks[i].parent.removeChild(stockDecks[i]);
	}
	stockDecks = [];
	// Each "stack" is 10 cards (8 stacks of 10 = 80, but Spider uses 50 in stock: 5 stacks of 10)
	var stacksLeft = Math.floor(stockPile.cards.length / TABLEAU_COUNT);
	for (var i = 0; i < stacksLeft; i++) {
		var deckImg = LK.getAsset('cardBack', {
			anchorX: 0.5,
			anchorY: 0.5,
			scaleX: CARD_WIDTH / BASE_CARD_WIDTH * 0.9,
			scaleY: CARD_HEIGHT / BASE_CARD_HEIGHT * 0.9
		});
		// Center bottom: horizontally centered, stacked with slight offset
		var centerX = GAME_WIDTH / 2;
		var bottomY = GAME_HEIGHT - CARD_HEIGHT / 2 - 40;
		deckImg.x = centerX + (i - (stacksLeft - 1) / 2) * 24;
		deckImg.y = bottomY - i * 6;
		// Do not blur or fade the stack count
		deckImg.alpha = 1;
		game.addChild(deckImg);
		stockDecks.push(deckImg);
	}
}
// Add a large faded spider icon to the background, centered and scaled for portrait
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
// Spider background: scale to fit width, center
var backgroundSpider = LK.getAsset('spider', {
	anchorX: 0.5,
	anchorY: 0.5,
	scaleX: 10,
	scaleY: 10
});
backgroundSpider.x = GAME_WIDTH / 2;
backgroundSpider.y = GAME_HEIGHT / 2;
backgroundSpider.alpha = 0.08;
game.addChildAt(backgroundSpider, 0); // Ensure it's behind all other elements
// Card and layout constants for portrait
var TABLEAU_COUNT = 8;
var GAME_MARGIN_X = 40;
var GAME_MARGIN_Y = 120;
// Get original card asset size
var tempCard = LK.getAsset('cardFace', {
	anchorX: 0.5,
	anchorY: 0.5
});
var BASE_CARD_WIDTH = tempCard.width;
var BASE_CARD_HEIGHT = tempCard.height;
// Calculate max card width to fit 8 columns with margin
var availableWidth = GAME_WIDTH - 2 * GAME_MARGIN_X;
var CARD_WIDTH = Math.floor(availableWidth / TABLEAU_COUNT);
var CARD_HEIGHT = Math.floor(BASE_CARD_HEIGHT * (CARD_WIDTH / BASE_CARD_WIDTH));
// No spacing between columns
var TABLEAU_SPACING = 0;
// Top offset for vertical layout (fit 2 rows of cards + margin)
var TABLEAU_TOP = GAME_MARGIN_Y + CARD_HEIGHT + 40;
// Center columns horizontally
var totalTableauWidth = TABLEAU_COUNT * CARD_WIDTH + (TABLEAU_COUNT - 1) * TABLEAU_SPACING;
var TABLEAU_LEFT = Math.round((GAME_WIDTH - totalTableauWidth) / 2);
// Stock and completed set positions (fit to portrait)
var STOCK_X = GAME_WIDTH - CARD_WIDTH - GAME_MARGIN_X;
var STOCK_Y = GAME_MARGIN_Y;
var COMPLETED_X = GAME_MARGIN_X + CARD_WIDTH / 2;
var COMPLETED_Y = GAME_MARGIN_Y;
// Clean up tempCard
if (tempCard.parent) tempCard.parent.removeChild(tempCard);
// Game state
var tableauPiles = [];
var stockPile = null;
var completedSets = 0;
var movesCount = 0; // Moves counter
var draggingCards = null;
var draggingFromPile = null;
var dragOffsetX = 0;
var dragOffsetY = 0;
var dragStartX = 0;
var dragStartY = 0;
var dragValidTarget = null;
var dragTargetPile = null;
var canDeal = true;
// Undo stack
var undoStack = [];
// Helper: auto-collect completed sets from all tableau piles
function autoCollectSets() {
	var collected = false;
	for (var auto_i = 0; auto_i < tableauPiles.length; auto_i++) {
		var pile = tableauPiles[auto_i];
		var removed;
		while (removed = pile.removeCompleteSet()) {
			LK.getSound('card_set').play();
			completedSets += 1;
			updateScore();
			updateCompletedSpiders();
			var spider = LK.getAsset('spider', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			spider.x = pile.x + CARD_WIDTH / 2;
			spider.y = pile.y + pile.cards.length * 40 + CARD_HEIGHT / 2;
			game.addChild(spider);
			(function (spider, setIndex, removedCards) {
				tween(spider, {
					y: COMPLETED_Y,
					x: COMPLETED_X + setIndex * (CARD_WIDTH * 0.7)
				}, {
					duration: 800,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						if (spider.parent) spider.parent.removeChild(spider);
						updateCompletedSpiders();
						// Remove finished set cards from game
						for (var rc = 0; rc < removedCards.length; rc++) {
							if (removedCards[rc].parent) removedCards[rc].parent.removeChild(removedCards[rc]);
						}
					}
				});
			})(spider, completedSets - 1, removed);
			collected = true;
		}
	}
	// Win condition: 8 sets
	if (completedSets >= 8) {
		LK.showYouWin();
		return;
	}
}
// Helper: clone game state for undo
function cloneGameState() {
	// Deep copy of tableau piles, stock, completedSets, movesCount
	var tableau = [];
	for (var i = 0; i < tableauPiles.length; i++) {
		var pile = tableauPiles[i];
		var pileArr = [];
		for (var j = 0; j < pile.cards.length; j++) {
			var c = pile.cards[j];
			pileArr.push({
				rank: c.rank,
				suit: c.suit,
				faceUp: c.faceUp
			});
		}
		tableau.push(pileArr);
	}
	var stock = [];
	for (var i = 0; i < stockPile.cards.length; i++) {
		var c = stockPile.cards[i];
		stock.push({
			rank: c.rank,
			suit: c.suit,
			faceUp: c.faceUp
		});
	}
	return {
		tableau: tableau,
		stock: stock,
		completedSets: completedSets,
		movesCount: movesCount
	};
}
// Helper: restore game state from undo
function restoreGameState(state) {
	// Remove all cards
	for (var i = 0; i < tableauPiles.length; i++) {
		var pile = tableauPiles[i];
		while (pile.cards.length > 0) {
			var c = pile.cards.pop();
			if (c.parent) c.parent.removeChild(c);
		}
	}
	while (stockPile.cards.length > 0) {
		var c = stockPile.cards.pop();
		if (c.parent) c.parent.removeChild(c);
	}
	// Restore tableau
	for (var i = 0; i < tableauPiles.length; i++) {
		var pileArr = state.tableau[i];
		for (var j = 0; j < pileArr.length; j++) {
			var cdata = pileArr[j];
			var card = new Card();
			card.setCard(cdata.rank, cdata.suit, cdata.faceUp);
			tableauPiles[i].addCard(card);
		}
	}
	// Restore stock
	for (var i = 0; i < state.stock.length; i++) {
		var cdata = state.stock[i];
		var card = new Card();
		card.setCard(cdata.rank, cdata.suit, cdata.faceUp);
		stockPile.addCard(card);
	}
	completedSets = state.completedSets;
	movesCount = state.movesCount;
	updateScore();
	updateCompletedSpiders();
	canDeal = true;
	updateStockDecks();
	draggingCards = null;
	draggingFromPile = null;
	dragValidTarget = null;
	dragTargetPile = null;
}
// Push undo state
function pushUndoState() {
	// Limit undo stack to 50
	if (undoStack.length > 50) undoStack.shift();
	undoStack.push(cloneGameState());
}
// GUI
var scoreTxt = new Text2('0', {
	size: 90,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var movesTxt = new Text2('Moves: 0', {
	size: 70,
	fill: 0xffffff
});
movesTxt.anchor.set(0.5, 0);
// Place moves counter under the sets counter (scoreTxt)
movesTxt.x = GAME_WIDTH / 2;
movesTxt.y = scoreTxt.y + scoreTxt.height + 10;
LK.gui.top.addChild(movesTxt);
// Undo button (now shown as an arrow icon)
var undoBtn = new Text2('↶', {
	size: 180,
	fill: 0xffffff
});
undoBtn.anchor.set(1, 1);
// Place at the bottom right corner of the screen (using LK.gui.bottomRight)
undoBtn.x = -40;
undoBtn.y = -40;
LK.gui.bottomRight.addChild(undoBtn);
// Moves counter next to undo button
var movesTxtBR = new Text2('0', {
	size: 70,
	fill: 0xffffff
});
movesTxtBR.anchor.set(1, 1);
// Place to the left of the undo button, aligned at bottom right
movesTxtBR.x = undoBtn.x - 120;
movesTxtBR.y = undoBtn.y - 10;
LK.gui.bottomRight.addChild(movesTxtBR);
// Undo button handler (moved here after undoBtn is defined)
undoBtn.down = function (x, y, obj) {
	if (undoStack.length === 0) return;
	var prev = undoStack.pop();
	// When redoing, do not decrease movesCount; keep current movesCount
	var currentMoves = movesCount;
	restoreGameState(prev);
	// Restore everything except movesCount (keep current)
	movesCount = currentMoves;
	updateScore();
};
// Restart button (shown as a circular arrow)
var restartBtn = new Text2('⟳', {
	size: 120,
	fill: 0xffffff
});
restartBtn.anchor.set(0, 0);
// Place at the top left corner of the screen (using LK.gui.topLeft)
// Add extra space to the right of the pause button (assume pauseBtn is at x=40, width=80, so start at 40+80+24=144)
restartBtn.x = 144; // Increased offset for more space between pause and restart
restartBtn.y = 40; // Down from top edge, visually aligned
LK.gui.topLeft.addChild(restartBtn);
restartBtn.down = function (x, y, obj) {
	resetGame();
};
// Removed dealBtn from top right
// Completed sets display
var completedSpiders = [];
// Initialize tableau piles
for (var i = 0; i < TABLEAU_COUNT; i++) {
	var pile = new TableauPile();
	// Align piles evenly across the screen, centered
	pile.x = TABLEAU_LEFT + i * (CARD_WIDTH + TABLEAU_SPACING) + CARD_WIDTH / 2;
	pile.y = TABLEAU_TOP;
	game.addChild(pile);
	tableauPiles.push(pile);
}
// Initialize stock pile
stockPile = new StockPile();
stockPile.x = STOCK_X;
stockPile.y = STOCK_Y;
game.addChild(stockPile);
// (Removed stock label)
// Shuffle and deal cards
function shuffleDeck() {
	// 8 decks of spades (104 cards)
	var deck = [];
	for (var d = 0; d < 8; d++) {
		for (var r = 1; r <= 13; r++) {
			var card = new Card();
			card.setCard(r, 0, false);
			deck.push(card);
		}
	}
	// Fisher-Yates shuffle
	for (var i = deck.length - 1; i > 0; i--) {
		var j = Math.floor(Math.random() * (i + 1));
		var tmp = deck[i];
		deck[i] = deck[j];
		deck[j] = tmp;
	}
	return deck;
}
function dealInitial() {
	var deck = shuffleDeck();
	// 52 cards to tableau (first 4 piles get 7, rest get 6)
	for (var i = 0; i < TABLEAU_COUNT; i++) {
		var count = i < 4 ? 7 : 6;
		for (var j = 0; j < count; j++) {
			var card = deck.shift();
			tableauPiles[i].addCard(card);
		}
	}
	// Flip top card of each pile
	for (var i = 0; i < TABLEAU_COUNT; i++) {
		tableauPiles[i].topCard().flip(true);
	}
	// Remaining 50 cards to stock
	while (deck.length > 0) {
		var card = deck.shift();
		stockPile.addCard(card);
	}
	completedSets = 0;
	updateScore();
	updateCompletedSpiders();
	updateStockDecks();
	canDeal = true;
}
function updateScore() {
	scoreTxt.setText('Sets: ' + completedSets);
	if (typeof movesTxt !== "undefined") {
		movesTxt.setText('Moves: ' + movesCount);
	}
	if (typeof movesTxtBR !== "undefined") {
		movesTxtBR.setText(movesCount + '');
	}
}
function updateCompletedSpiders() {
	// Remove old
	for (var i = 0; i < completedSpiders.length; i++) {
		if (completedSpiders[i].parent) completedSpiders[i].parent.removeChild(completedSpiders[i]);
	}
	completedSpiders = [];
	// Add new
	for (var i = 0; i < completedSets; i++) {
		var spider = LK.getAsset('spider', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		spider.x = COMPLETED_X + i * (CARD_WIDTH * 0.7);
		spider.y = COMPLETED_Y;
		game.addChild(spider);
		completedSpiders.push(spider);
	}
}
// Handle card selection and drag
game.onCardDown = function (card, x, y, obj) {
	// Find which pile this card is in
	var pile = null;
	var idx = -1;
	for (var i = 0; i < tableauPiles.length; i++) {
		var p = tableauPiles[i];
		var j = p.indexOf(card);
		if (j !== -1) {
			pile = p;
			idx = j;
			break;
		}
	}
	if (!pile) return;
	// Can move sequence?
	if (!pile.canMoveSequence(idx)) return;
	// Prepare drag
	pushUndoState();
	draggingCards = [];
	for (var k = idx; k < pile.cards.length; k++) {
		var c = pile.cards[k];
		c.selected = true;
		c.updateSelected();
		draggingCards.push(c);
	}
	draggingFromPile = pile;
	// Try to auto-move to a valid pile
	var autoMoved = false;
	for (var t = 0; t < tableauPiles.length; t++) {
		var targetPile = tableauPiles[t];
		if (targetPile === pile) continue;
		if (targetPile.canAccept(draggingCards)) {
			// Remove from old pile
			pile.removeCardsFrom(idx);
			// Add to new pile
			for (var m = 0; m < draggingCards.length; m++) {
				targetPile.addCard(draggingCards[m]);
			}
			// Play card move sound
			LK.getSound('card_move').play();
			// Reveal top card in old pile
			pile.revealTop();
			// Check for completed set
			var completedAny = false;
			while (targetPile.removeCompleteSet()) {
				// Play card set sound
				LK.getSound('card_set').play();
				completedSets += 1;
				updateScore();
				updateCompletedSpiders();
				// Animate spider
				var spider = LK.getAsset('spider', {
					anchorX: 0.5,
					anchorY: 0.5
				});
				spider.x = targetPile.x + CARD_WIDTH / 2;
				spider.y = targetPile.y + targetPile.cards.length * 40 + CARD_HEIGHT / 2;
				game.addChild(spider);
				(function (spider, setIndex) {
					tween(spider, {
						y: COMPLETED_Y,
						x: COMPLETED_X + setIndex * (CARD_WIDTH * 0.7)
					}, {
						duration: 800,
						easing: tween.easeOut,
						onFinish: function onFinish() {
							if (spider.parent) spider.parent.removeChild(spider);
							updateCompletedSpiders();
						}
					});
				})(spider, completedSets - 1);
				completedAny = true;
			}
			autoCollectSets();
			// Win condition: 8 sets
			if (completedSets >= 8) {
				LK.showYouWin();
				return;
			}
			// Deselect
			for (var m = 0; m < draggingCards.length; m++) {
				draggingCards[m].selected = false;
				draggingCards[m].updateSelected();
			}
			movesCount += 1; // Increment moves on auto-move
			updateScore();
			draggingCards = null;
			draggingFromPile = null;
			dragValidTarget = null;
			dragTargetPile = null;
			autoMoved = true;
			break;
		}
	}
	if (autoMoved) return;
	// Bring to front for manual drag
	for (var k = 0; k < draggingCards.length; k++) {
		game.addChild(draggingCards[k]);
	}
	// Offset
	dragOffsetX = card.x;
	dragOffsetY = card.y;
	dragStartX = card.parent.x + card.x;
	dragStartY = card.parent.y + card.y;
};
// Handle drag move
game.move = function (x, y, obj) {
	if (!draggingCards) return;
	// Move cards
	for (var i = 0; i < draggingCards.length; i++) {
		draggingCards[i].x = x - dragOffsetX;
		draggingCards[i].y = y - dragOffsetY + i * 60;
	}
	// Check for valid drop target
	dragValidTarget = null;
	dragTargetPile = null;
	for (var i = 0; i < tableauPiles.length; i++) {
		var pile = tableauPiles[i];
		// Don't allow drop on self
		if (pile === draggingFromPile) continue;
		// Get pile bounds
		var px = pile.x;
		var py = pile.y + pile.cards.length * 40;
		var pw = CARD_WIDTH;
		var ph = CARD_HEIGHT;
		// If pile is empty, allow drop anywhere in the pile area
		if (pile.cards.length === 0) {
			px = pile.x;
			py = pile.y;
			pw = CARD_WIDTH;
			ph = CARD_HEIGHT;
			if (x > px && x < px + pw && y > py && y < py + ph) {
				if (pile.canAccept(draggingCards)) {
					dragValidTarget = pile;
					dragTargetPile = pile;
					break;
				}
			}
		} else {
			if (x > px && x < px + pw && y > py - 40 && y < py + ph) {
				if (pile.canAccept(draggingCards)) {
					dragValidTarget = pile;
					dragTargetPile = pile;
					break;
				}
			}
		}
	}
};
// Handle drag end
game.up = function (x, y, obj) {
	if (!draggingCards) return;
	// Drop
	if (dragValidTarget && dragTargetPile) {
		pushUndoState();
		// Remove from old pile
		var idx = draggingFromPile.indexOf(draggingCards[0]);
		draggingFromPile.removeCardsFrom(idx);
		// Add to new pile
		for (var i = 0; i < draggingCards.length; i++) {
			dragTargetPile.addCard(draggingCards[i]);
		}
		// Play card move sound
		LK.getSound('card_move').play();
		movesCount += 1; // Increment moves on manual drag
		updateScore();
		// Reveal top card in old pile
		draggingFromPile.revealTop();
		// Check for completed set
		var completedAny = false;
		while (dragTargetPile.removeCompleteSet()) {
			// Play card set sound
			LK.getSound('card_set').play();
			completedSets += 1;
			updateScore();
			updateCompletedSpiders();
			// Animate spider
			var spider = LK.getAsset('spider', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			spider.x = dragTargetPile.x + CARD_WIDTH / 2;
			spider.y = dragTargetPile.y + dragTargetPile.cards.length * 40 + CARD_HEIGHT / 2;
			game.addChild(spider);
			(function (spider, setIndex) {
				tween(spider, {
					y: COMPLETED_Y,
					x: COMPLETED_X + setIndex * (CARD_WIDTH * 0.7)
				}, {
					duration: 800,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						if (spider.parent) spider.parent.removeChild(spider);
						updateCompletedSpiders();
					}
				});
			})(spider, completedSets - 1);
			completedAny = true;
		}
		autoCollectSets();
		// Win condition: 8 sets
		if (completedSets >= 8) {
			LK.showYouWin();
			return;
		}
	} else {
		// Return to original pile
		for (var i = 0; i < draggingCards.length; i++) {
			draggingCards[i].x = dragStartX - draggingFromPile.x;
			draggingCards[i].y = dragStartY - draggingFromPile.y + i * 60;
			draggingFromPile.addChild(draggingCards[i]);
		}
		draggingFromPile.layout();
	}
	// Deselect
	for (var i = 0; i < draggingCards.length; i++) {
		draggingCards[i].selected = false;
		draggingCards[i].updateSelected();
	}
	draggingCards = null;
	draggingFromPile = null;
	dragValidTarget = null;
	dragTargetPile = null;
};
// Deal button (shown above the stock pile decks)
var dealBtn = new Text2('Deal', {
	size: 90,
	fill: 0xffffff
});
dealBtn.anchor.set(0.5, 1);
// Position: above the stock pile decks, centered horizontally
dealBtn.x = GAME_WIDTH / 2;
dealBtn.y = GAME_HEIGHT - CARD_HEIGHT / 2 - 40 - 30;
game.addChild(dealBtn);
// Deal new row
dealBtn.down = function (x, y, obj) {
	if (!canDeal) return;
	// Only allow if all tableau piles have at least one card
	for (var i = 0; i < tableauPiles.length; i++) {
		if (tableauPiles[i].cards.length === 0) return;
	}
	if (stockPile.isEmpty()) return;
	canDeal = false;
	pushUndoState();
	// Animate deal
	var dealt = stockPile.dealToTableau(tableauPiles);
	if (dealt) {
		// Play shuffle sound when dealing from stock
		LK.getSound('shuffle').play();
		// Flip top card of each pile
		for (var i = 0; i < tableauPiles.length; i++) {
			tableauPiles[i].topCard().flip(true);
		}
		updateStockDecks();
		autoCollectSets();
	}
	// Allow next deal after short delay
	LK.setTimeout(function () {
		canDeal = true;
	}, 400);
};
// Touch on stock pile (deal)
stockPile.down = function (x, y, obj) {
	dealBtn.down(x, y, obj);
};
// Reset game
function resetGame() {
	// Remove all cards
	for (var i = 0; i < tableauPiles.length; i++) {
		var pile = tableauPiles[i];
		while (pile.cards.length > 0) {
			var c = pile.cards.pop();
			if (c.parent) c.parent.removeChild(c);
		}
	}
	while (stockPile.cards.length > 0) {
		var c = stockPile.cards.pop();
		if (c.parent) c.parent.removeChild(c);
	}
	completedSets = 0;
	movesCount = 0; // Reset moves counter
	updateScore();
	updateCompletedSpiders();
	updateStockDecks();
	canDeal = true;
	draggingCards = null;
	draggingFromPile = null;
	dragValidTarget = null;
	dragTargetPile = null;
	dealInitial();
}
// Game over: no more moves
function checkGameOver() {
	// If no moves and stock is empty
	var canMove = false;
	for (var i = 0; i < tableauPiles.length; i++) {
		var pile = tableauPiles[i];
		for (var j = 0; j < pile.cards.length; j++) {
			if (pile.canMoveSequence(j)) {
				// Try to move to another pile
				var seq = [];
				for (var k = j; k < pile.cards.length; k++) seq.push(pile.cards[k]);
				for (var t = 0; t < tableauPiles.length; t++) {
					if (t === i) continue;
					if (tableauPiles[t].canAccept(seq)) {
						canMove = true;
						break;
					}
				}
			}
			if (canMove) break;
		}
		if (canMove) break;
	}
	if (!canMove && stockPile.isEmpty()) {
		LK.showGameOver();
	}
}
// Game update
game.update = function () {
	// (auto-collect logic moved to after every move, deal, and flip)
	// Check for game over
	checkGameOver();
};
// Start game
dealInitial();
LK.playMusic('relaxing_bg'); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Card class
var Card = Container.expand(function () {
	var self = Container.call(this);
	// Card properties
	self.rank = 1; // 1=Ace, 13=King
	self.suit = 0; // 0=spades (for MVP, only one suit)
	self.faceUp = false;
	self.selected = false;
	// Card graphics
	// Add a drop shadow and rounded rectangle background for realism
	// Scale card assets to fit calculated CARD_WIDTH and CARD_HEIGHT
	var scaleX = typeof CARD_WIDTH !== "undefined" ? CARD_WIDTH / BASE_CARD_WIDTH : 1;
	var scaleY = typeof CARD_HEIGHT !== "undefined" ? CARD_HEIGHT / BASE_CARD_HEIGHT : 1;
	var cardShadow = LK.getAsset('cardFace', {
		anchorX: 0.5,
		anchorY: 0.5,
		tint: 0x222222,
		alpha: 0.18,
		scaleX: 1.04 * scaleX,
		scaleY: 1.04 * scaleY
	});
	self.addChild(cardShadow);
	var cardFace = self.attachAsset('cardFace', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: scaleX,
		scaleY: scaleY
	});
	var cardBack = self.attachAsset('cardBack', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: scaleX,
		scaleY: scaleY
	});
	cardBack.visible = true;
	cardFace.visible = false;
	// Corner labels (rank + suit) for top-left and bottom-right
	var labelTL = new Text2('', {
		size: Math.floor(cardFace.height * 0.22),
		fill: 0xffffff,
		align: "left"
	});
	labelTL.anchor.set(0, 0);
	labelTL.x = -cardFace.width / 2 + Math.floor(cardFace.width * 0.08);
	labelTL.y = -cardFace.height / 2 + Math.floor(cardFace.height * 0.08);
	self.addChild(labelTL);
	var labelBR = new Text2('', {
		size: Math.floor(cardFace.height * 0.22),
		fill: 0xffffff,
		align: "right"
	});
	labelBR.anchor.set(1, 1);
	labelBR.x = cardFace.width / 2 - Math.floor(cardFace.width * 0.08);
	labelBR.y = cardFace.height / 2 - Math.floor(cardFace.height * 0.08);
	self.addChild(labelBR);
	// Set card data
	self.setCard = function (rank, suit, faceUp) {
		self.rank = rank;
		self.suit = suit;
		self.faceUp = faceUp;
		self.updateFace();
	};
	// Update card face/back and label
	self.updateFace = function () {
		cardFace.visible = self.faceUp;
		cardBack.visible = !self.faceUp;
		// Only spades for MVP
		var suitChar = '♠';
		var rankStr = '';
		if (self.rank === 1) rankStr = 'A';else if (self.rank === 11) rankStr = 'J';else if (self.rank === 12) rankStr = 'Q';else if (self.rank === 13) rankStr = 'K';else rankStr = '' + self.rank;
		// Show only in corners
		if (typeof labelTL !== "undefined" && typeof labelBR !== "undefined") {
			var labelText = rankStr + suitChar;
			labelTL.setText(labelText);
			labelBR.setText(labelText);
			labelTL.visible = true;
			labelBR.visible = true;
			if (self.faceUp) {
				labelTL.setStyle({
					fill: 0xffffff,
					alpha: 1
				});
				labelBR.setStyle({
					fill: 0xffffff,
					alpha: 1
				});
			} else {
				labelTL.setStyle({
					fill: 0xcccccc,
					alpha: 0.45
				});
				labelBR.setStyle({
					fill: 0xcccccc,
					alpha: 0.45
				});
			}
		}
		// Optionally, show a faint spider on the back for realism
		self.updateSelected();
	};
	// Visual feedback for selection
	self.updateSelected = function () {
		if (self.selected) {
			cardFace.tint = 0x99ccff;
			cardBack.tint = 0x99ccff;
		} else {
			cardFace.tint = 0xffffff;
			cardBack.tint = 0xffffff;
		}
	};
	// Flip card
	self.flip = function (faceUp) {
		self.faceUp = faceUp;
		self.updateFace();
	};
	// Touch events
	self.down = function (x, y, obj) {
		if (self.faceUp) {
			// Let game handle selection
			if (game) game.onCardDown(self, x, y, obj);
		}
	};
	return self;
});
// Stock pile class (for dealing new rows)
var StockPile = Container.expand(function () {
	var self = Container.call(this);
	self.cards = [];
	// Add card to stock
	self.addCard = function (card) {
		self.cards.push(card);
		self.addChild(card);
		card.x = 0;
		card.y = 0;
	};
	// Deal one card per tableau pile
	self.dealToTableau = function (tableauPiles) {
		if (self.cards.length < tableauPiles.length) return false;
		for (var i = 0; i < tableauPiles.length; i++) {
			var card = self.cards.shift();
			card.flip(true);
			tableauPiles[i].addCard(card);
		}
		return true;
	};
	// Is empty?
	self.isEmpty = function () {
		return self.cards.length === 0;
	};
	return self;
});
// Tableau pile class
var TableauPile = Container.expand(function () {
	var self = Container.call(this);
	self.cards = [];
	// Add card to pile
	self.addCard = function (card) {
		self.cards.push(card);
		self.addChild(card);
		self.layout();
	};
	// Remove card(s) from pile starting at index
	self.removeCardsFrom = function (idx) {
		var removed = [];
		while (self.cards.length > idx) {
			var c = self.cards.pop();
			c.parent.removeChild(c);
			removed.unshift(c);
		}
		self.layout();
		return removed;
	};
	// Get top card
	self.topCard = function () {
		if (self.cards.length === 0) return null;
		return self.cards[self.cards.length - 1];
	};
	// Layout cards in pile
	self.layout = function () {
		// Increase vertical spacing between cards for more space in each column
		var CARD_VERTICAL_SPACING = 110;
		for (var i = 0; i < self.cards.length; i++) {
			var c = self.cards[i];
			// Animate to new position using tween
			tween.stop(c, {
				x: true,
				y: true
			}); // Stop any previous tweens on x/y
			tween(c, {
				x: 0,
				y: i * CARD_VERTICAL_SPACING
			}, {
				duration: 400,
				easing: tween.cubicOut
			});
			c.zIndex = i;
		}
	};
	// Reveal top card if needed
	self.revealTop = function () {
		var top = self.topCard();
		if (top && !top.faceUp) {
			top.flip(true);
		}
	};
	// Get index of card in pile
	self.indexOf = function (card) {
		for (var i = 0; i < self.cards.length; i++) {
			if (self.cards[i] === card) return i;
		}
		return -1;
	};
	// Can move sequence starting at idx?
	self.canMoveSequence = function (idx) {
		// All cards from idx to end must be face up and in descending order
		for (var i = idx; i < self.cards.length - 1; i++) {
			var c1 = self.cards[i];
			var c2 = self.cards[i + 1];
			if (!c1.faceUp || !c2.faceUp) return false;
			if (c1.rank !== c2.rank + 1) return false;
		}
		return self.cards[idx].faceUp;
	};
	// Can accept a sequence of cards (cardsArr)?
	self.canAccept = function (cardsArr) {
		if (self.cards.length === 0) {
			// Only King can be placed on empty pile
			return cardsArr[0].rank === 13;
		} else {
			var top = self.topCard();
			var moving = cardsArr[0];
			return top.faceUp && top.rank === moving.rank + 1;
		}
	};
	// Remove completed set (K-A)
	self.removeCompleteSet = function () {
		// Check if last 13 cards are a complete set
		if (self.cards.length < 13) return false;
		for (var i = 0; i < 13; i++) {
			var c = self.cards[self.cards.length - 1 - i];
			if (!c.faceUp || c.rank !== 13 - i) return false;
		}
		// Remove them
		var removed = [];
		for (var i = 0; i < 13; i++) {
			var c = self.cards.pop();
			if (c.parent) c.parent.removeChild(c);
			removed.unshift(c);
		}
		self.layout();
		// Add to collected area (handled by animation in game logic)
		return removed; // Return the collected set for animation/cleanup
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0xcccccc
});
/**** 
* Game Code
****/ 
// (Removed stock label)
// Show number of stacks left as card decks on stock pile
var stockDecks = [];
function updateStockDecks() {
	// Remove old
	for (var i = 0; i < stockDecks.length; i++) {
		if (stockDecks[i].parent) stockDecks[i].parent.removeChild(stockDecks[i]);
	}
	stockDecks = [];
	// Each "stack" is 10 cards (8 stacks of 10 = 80, but Spider uses 50 in stock: 5 stacks of 10)
	var stacksLeft = Math.floor(stockPile.cards.length / TABLEAU_COUNT);
	for (var i = 0; i < stacksLeft; i++) {
		var deckImg = LK.getAsset('cardBack', {
			anchorX: 0.5,
			anchorY: 0.5,
			scaleX: CARD_WIDTH / BASE_CARD_WIDTH * 0.9,
			scaleY: CARD_HEIGHT / BASE_CARD_HEIGHT * 0.9
		});
		// Center bottom: horizontally centered, stacked with slight offset
		var centerX = GAME_WIDTH / 2;
		var bottomY = GAME_HEIGHT - CARD_HEIGHT / 2 - 40;
		deckImg.x = centerX + (i - (stacksLeft - 1) / 2) * 24;
		deckImg.y = bottomY - i * 6;
		// Do not blur or fade the stack count
		deckImg.alpha = 1;
		game.addChild(deckImg);
		stockDecks.push(deckImg);
	}
}
// Add a large faded spider icon to the background, centered and scaled for portrait
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
// Spider background: scale to fit width, center
var backgroundSpider = LK.getAsset('spider', {
	anchorX: 0.5,
	anchorY: 0.5,
	scaleX: 10,
	scaleY: 10
});
backgroundSpider.x = GAME_WIDTH / 2;
backgroundSpider.y = GAME_HEIGHT / 2;
backgroundSpider.alpha = 0.08;
game.addChildAt(backgroundSpider, 0); // Ensure it's behind all other elements
// Card and layout constants for portrait
var TABLEAU_COUNT = 8;
var GAME_MARGIN_X = 40;
var GAME_MARGIN_Y = 120;
// Get original card asset size
var tempCard = LK.getAsset('cardFace', {
	anchorX: 0.5,
	anchorY: 0.5
});
var BASE_CARD_WIDTH = tempCard.width;
var BASE_CARD_HEIGHT = tempCard.height;
// Calculate max card width to fit 8 columns with margin
var availableWidth = GAME_WIDTH - 2 * GAME_MARGIN_X;
var CARD_WIDTH = Math.floor(availableWidth / TABLEAU_COUNT);
var CARD_HEIGHT = Math.floor(BASE_CARD_HEIGHT * (CARD_WIDTH / BASE_CARD_WIDTH));
// No spacing between columns
var TABLEAU_SPACING = 0;
// Top offset for vertical layout (fit 2 rows of cards + margin)
var TABLEAU_TOP = GAME_MARGIN_Y + CARD_HEIGHT + 40;
// Center columns horizontally
var totalTableauWidth = TABLEAU_COUNT * CARD_WIDTH + (TABLEAU_COUNT - 1) * TABLEAU_SPACING;
var TABLEAU_LEFT = Math.round((GAME_WIDTH - totalTableauWidth) / 2);
// Stock and completed set positions (fit to portrait)
var STOCK_X = GAME_WIDTH - CARD_WIDTH - GAME_MARGIN_X;
var STOCK_Y = GAME_MARGIN_Y;
var COMPLETED_X = GAME_MARGIN_X + CARD_WIDTH / 2;
var COMPLETED_Y = GAME_MARGIN_Y;
// Clean up tempCard
if (tempCard.parent) tempCard.parent.removeChild(tempCard);
// Game state
var tableauPiles = [];
var stockPile = null;
var completedSets = 0;
var movesCount = 0; // Moves counter
var draggingCards = null;
var draggingFromPile = null;
var dragOffsetX = 0;
var dragOffsetY = 0;
var dragStartX = 0;
var dragStartY = 0;
var dragValidTarget = null;
var dragTargetPile = null;
var canDeal = true;
// Undo stack
var undoStack = [];
// Helper: auto-collect completed sets from all tableau piles
function autoCollectSets() {
	var collected = false;
	for (var auto_i = 0; auto_i < tableauPiles.length; auto_i++) {
		var pile = tableauPiles[auto_i];
		var removed;
		while (removed = pile.removeCompleteSet()) {
			LK.getSound('card_set').play();
			completedSets += 1;
			updateScore();
			updateCompletedSpiders();
			var spider = LK.getAsset('spider', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			spider.x = pile.x + CARD_WIDTH / 2;
			spider.y = pile.y + pile.cards.length * 40 + CARD_HEIGHT / 2;
			game.addChild(spider);
			(function (spider, setIndex, removedCards) {
				tween(spider, {
					y: COMPLETED_Y,
					x: COMPLETED_X + setIndex * (CARD_WIDTH * 0.7)
				}, {
					duration: 800,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						if (spider.parent) spider.parent.removeChild(spider);
						updateCompletedSpiders();
						// Remove finished set cards from game
						for (var rc = 0; rc < removedCards.length; rc++) {
							if (removedCards[rc].parent) removedCards[rc].parent.removeChild(removedCards[rc]);
						}
					}
				});
			})(spider, completedSets - 1, removed);
			collected = true;
		}
	}
	// Win condition: 8 sets
	if (completedSets >= 8) {
		LK.showYouWin();
		return;
	}
}
// Helper: clone game state for undo
function cloneGameState() {
	// Deep copy of tableau piles, stock, completedSets, movesCount
	var tableau = [];
	for (var i = 0; i < tableauPiles.length; i++) {
		var pile = tableauPiles[i];
		var pileArr = [];
		for (var j = 0; j < pile.cards.length; j++) {
			var c = pile.cards[j];
			pileArr.push({
				rank: c.rank,
				suit: c.suit,
				faceUp: c.faceUp
			});
		}
		tableau.push(pileArr);
	}
	var stock = [];
	for (var i = 0; i < stockPile.cards.length; i++) {
		var c = stockPile.cards[i];
		stock.push({
			rank: c.rank,
			suit: c.suit,
			faceUp: c.faceUp
		});
	}
	return {
		tableau: tableau,
		stock: stock,
		completedSets: completedSets,
		movesCount: movesCount
	};
}
// Helper: restore game state from undo
function restoreGameState(state) {
	// Remove all cards
	for (var i = 0; i < tableauPiles.length; i++) {
		var pile = tableauPiles[i];
		while (pile.cards.length > 0) {
			var c = pile.cards.pop();
			if (c.parent) c.parent.removeChild(c);
		}
	}
	while (stockPile.cards.length > 0) {
		var c = stockPile.cards.pop();
		if (c.parent) c.parent.removeChild(c);
	}
	// Restore tableau
	for (var i = 0; i < tableauPiles.length; i++) {
		var pileArr = state.tableau[i];
		for (var j = 0; j < pileArr.length; j++) {
			var cdata = pileArr[j];
			var card = new Card();
			card.setCard(cdata.rank, cdata.suit, cdata.faceUp);
			tableauPiles[i].addCard(card);
		}
	}
	// Restore stock
	for (var i = 0; i < state.stock.length; i++) {
		var cdata = state.stock[i];
		var card = new Card();
		card.setCard(cdata.rank, cdata.suit, cdata.faceUp);
		stockPile.addCard(card);
	}
	completedSets = state.completedSets;
	movesCount = state.movesCount;
	updateScore();
	updateCompletedSpiders();
	canDeal = true;
	updateStockDecks();
	draggingCards = null;
	draggingFromPile = null;
	dragValidTarget = null;
	dragTargetPile = null;
}
// Push undo state
function pushUndoState() {
	// Limit undo stack to 50
	if (undoStack.length > 50) undoStack.shift();
	undoStack.push(cloneGameState());
}
// GUI
var scoreTxt = new Text2('0', {
	size: 90,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var movesTxt = new Text2('Moves: 0', {
	size: 70,
	fill: 0xffffff
});
movesTxt.anchor.set(0.5, 0);
// Place moves counter under the sets counter (scoreTxt)
movesTxt.x = GAME_WIDTH / 2;
movesTxt.y = scoreTxt.y + scoreTxt.height + 10;
LK.gui.top.addChild(movesTxt);
// Undo button (now shown as an arrow icon)
var undoBtn = new Text2('↶', {
	size: 180,
	fill: 0xffffff
});
undoBtn.anchor.set(1, 1);
// Place at the bottom right corner of the screen (using LK.gui.bottomRight)
undoBtn.x = -40;
undoBtn.y = -40;
LK.gui.bottomRight.addChild(undoBtn);
// Moves counter next to undo button
var movesTxtBR = new Text2('0', {
	size: 70,
	fill: 0xffffff
});
movesTxtBR.anchor.set(1, 1);
// Place to the left of the undo button, aligned at bottom right
movesTxtBR.x = undoBtn.x - 120;
movesTxtBR.y = undoBtn.y - 10;
LK.gui.bottomRight.addChild(movesTxtBR);
// Undo button handler (moved here after undoBtn is defined)
undoBtn.down = function (x, y, obj) {
	if (undoStack.length === 0) return;
	var prev = undoStack.pop();
	// When redoing, do not decrease movesCount; keep current movesCount
	var currentMoves = movesCount;
	restoreGameState(prev);
	// Restore everything except movesCount (keep current)
	movesCount = currentMoves;
	updateScore();
};
// Restart button (shown as a circular arrow)
var restartBtn = new Text2('⟳', {
	size: 120,
	fill: 0xffffff
});
restartBtn.anchor.set(0, 0);
// Place at the top left corner of the screen (using LK.gui.topLeft)
// Add extra space to the right of the pause button (assume pauseBtn is at x=40, width=80, so start at 40+80+24=144)
restartBtn.x = 144; // Increased offset for more space between pause and restart
restartBtn.y = 40; // Down from top edge, visually aligned
LK.gui.topLeft.addChild(restartBtn);
restartBtn.down = function (x, y, obj) {
	resetGame();
};
// Removed dealBtn from top right
// Completed sets display
var completedSpiders = [];
// Initialize tableau piles
for (var i = 0; i < TABLEAU_COUNT; i++) {
	var pile = new TableauPile();
	// Align piles evenly across the screen, centered
	pile.x = TABLEAU_LEFT + i * (CARD_WIDTH + TABLEAU_SPACING) + CARD_WIDTH / 2;
	pile.y = TABLEAU_TOP;
	game.addChild(pile);
	tableauPiles.push(pile);
}
// Initialize stock pile
stockPile = new StockPile();
stockPile.x = STOCK_X;
stockPile.y = STOCK_Y;
game.addChild(stockPile);
// (Removed stock label)
// Shuffle and deal cards
function shuffleDeck() {
	// 8 decks of spades (104 cards)
	var deck = [];
	for (var d = 0; d < 8; d++) {
		for (var r = 1; r <= 13; r++) {
			var card = new Card();
			card.setCard(r, 0, false);
			deck.push(card);
		}
	}
	// Fisher-Yates shuffle
	for (var i = deck.length - 1; i > 0; i--) {
		var j = Math.floor(Math.random() * (i + 1));
		var tmp = deck[i];
		deck[i] = deck[j];
		deck[j] = tmp;
	}
	return deck;
}
function dealInitial() {
	var deck = shuffleDeck();
	// 52 cards to tableau (first 4 piles get 7, rest get 6)
	for (var i = 0; i < TABLEAU_COUNT; i++) {
		var count = i < 4 ? 7 : 6;
		for (var j = 0; j < count; j++) {
			var card = deck.shift();
			tableauPiles[i].addCard(card);
		}
	}
	// Flip top card of each pile
	for (var i = 0; i < TABLEAU_COUNT; i++) {
		tableauPiles[i].topCard().flip(true);
	}
	// Remaining 50 cards to stock
	while (deck.length > 0) {
		var card = deck.shift();
		stockPile.addCard(card);
	}
	completedSets = 0;
	updateScore();
	updateCompletedSpiders();
	updateStockDecks();
	canDeal = true;
}
function updateScore() {
	scoreTxt.setText('Sets: ' + completedSets);
	if (typeof movesTxt !== "undefined") {
		movesTxt.setText('Moves: ' + movesCount);
	}
	if (typeof movesTxtBR !== "undefined") {
		movesTxtBR.setText(movesCount + '');
	}
}
function updateCompletedSpiders() {
	// Remove old
	for (var i = 0; i < completedSpiders.length; i++) {
		if (completedSpiders[i].parent) completedSpiders[i].parent.removeChild(completedSpiders[i]);
	}
	completedSpiders = [];
	// Add new
	for (var i = 0; i < completedSets; i++) {
		var spider = LK.getAsset('spider', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		spider.x = COMPLETED_X + i * (CARD_WIDTH * 0.7);
		spider.y = COMPLETED_Y;
		game.addChild(spider);
		completedSpiders.push(spider);
	}
}
// Handle card selection and drag
game.onCardDown = function (card, x, y, obj) {
	// Find which pile this card is in
	var pile = null;
	var idx = -1;
	for (var i = 0; i < tableauPiles.length; i++) {
		var p = tableauPiles[i];
		var j = p.indexOf(card);
		if (j !== -1) {
			pile = p;
			idx = j;
			break;
		}
	}
	if (!pile) return;
	// Can move sequence?
	if (!pile.canMoveSequence(idx)) return;
	// Prepare drag
	pushUndoState();
	draggingCards = [];
	for (var k = idx; k < pile.cards.length; k++) {
		var c = pile.cards[k];
		c.selected = true;
		c.updateSelected();
		draggingCards.push(c);
	}
	draggingFromPile = pile;
	// Try to auto-move to a valid pile
	var autoMoved = false;
	for (var t = 0; t < tableauPiles.length; t++) {
		var targetPile = tableauPiles[t];
		if (targetPile === pile) continue;
		if (targetPile.canAccept(draggingCards)) {
			// Remove from old pile
			pile.removeCardsFrom(idx);
			// Add to new pile
			for (var m = 0; m < draggingCards.length; m++) {
				targetPile.addCard(draggingCards[m]);
			}
			// Play card move sound
			LK.getSound('card_move').play();
			// Reveal top card in old pile
			pile.revealTop();
			// Check for completed set
			var completedAny = false;
			while (targetPile.removeCompleteSet()) {
				// Play card set sound
				LK.getSound('card_set').play();
				completedSets += 1;
				updateScore();
				updateCompletedSpiders();
				// Animate spider
				var spider = LK.getAsset('spider', {
					anchorX: 0.5,
					anchorY: 0.5
				});
				spider.x = targetPile.x + CARD_WIDTH / 2;
				spider.y = targetPile.y + targetPile.cards.length * 40 + CARD_HEIGHT / 2;
				game.addChild(spider);
				(function (spider, setIndex) {
					tween(spider, {
						y: COMPLETED_Y,
						x: COMPLETED_X + setIndex * (CARD_WIDTH * 0.7)
					}, {
						duration: 800,
						easing: tween.easeOut,
						onFinish: function onFinish() {
							if (spider.parent) spider.parent.removeChild(spider);
							updateCompletedSpiders();
						}
					});
				})(spider, completedSets - 1);
				completedAny = true;
			}
			autoCollectSets();
			// Win condition: 8 sets
			if (completedSets >= 8) {
				LK.showYouWin();
				return;
			}
			// Deselect
			for (var m = 0; m < draggingCards.length; m++) {
				draggingCards[m].selected = false;
				draggingCards[m].updateSelected();
			}
			movesCount += 1; // Increment moves on auto-move
			updateScore();
			draggingCards = null;
			draggingFromPile = null;
			dragValidTarget = null;
			dragTargetPile = null;
			autoMoved = true;
			break;
		}
	}
	if (autoMoved) return;
	// Bring to front for manual drag
	for (var k = 0; k < draggingCards.length; k++) {
		game.addChild(draggingCards[k]);
	}
	// Offset
	dragOffsetX = card.x;
	dragOffsetY = card.y;
	dragStartX = card.parent.x + card.x;
	dragStartY = card.parent.y + card.y;
};
// Handle drag move
game.move = function (x, y, obj) {
	if (!draggingCards) return;
	// Move cards
	for (var i = 0; i < draggingCards.length; i++) {
		draggingCards[i].x = x - dragOffsetX;
		draggingCards[i].y = y - dragOffsetY + i * 60;
	}
	// Check for valid drop target
	dragValidTarget = null;
	dragTargetPile = null;
	for (var i = 0; i < tableauPiles.length; i++) {
		var pile = tableauPiles[i];
		// Don't allow drop on self
		if (pile === draggingFromPile) continue;
		// Get pile bounds
		var px = pile.x;
		var py = pile.y + pile.cards.length * 40;
		var pw = CARD_WIDTH;
		var ph = CARD_HEIGHT;
		// If pile is empty, allow drop anywhere in the pile area
		if (pile.cards.length === 0) {
			px = pile.x;
			py = pile.y;
			pw = CARD_WIDTH;
			ph = CARD_HEIGHT;
			if (x > px && x < px + pw && y > py && y < py + ph) {
				if (pile.canAccept(draggingCards)) {
					dragValidTarget = pile;
					dragTargetPile = pile;
					break;
				}
			}
		} else {
			if (x > px && x < px + pw && y > py - 40 && y < py + ph) {
				if (pile.canAccept(draggingCards)) {
					dragValidTarget = pile;
					dragTargetPile = pile;
					break;
				}
			}
		}
	}
};
// Handle drag end
game.up = function (x, y, obj) {
	if (!draggingCards) return;
	// Drop
	if (dragValidTarget && dragTargetPile) {
		pushUndoState();
		// Remove from old pile
		var idx = draggingFromPile.indexOf(draggingCards[0]);
		draggingFromPile.removeCardsFrom(idx);
		// Add to new pile
		for (var i = 0; i < draggingCards.length; i++) {
			dragTargetPile.addCard(draggingCards[i]);
		}
		// Play card move sound
		LK.getSound('card_move').play();
		movesCount += 1; // Increment moves on manual drag
		updateScore();
		// Reveal top card in old pile
		draggingFromPile.revealTop();
		// Check for completed set
		var completedAny = false;
		while (dragTargetPile.removeCompleteSet()) {
			// Play card set sound
			LK.getSound('card_set').play();
			completedSets += 1;
			updateScore();
			updateCompletedSpiders();
			// Animate spider
			var spider = LK.getAsset('spider', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			spider.x = dragTargetPile.x + CARD_WIDTH / 2;
			spider.y = dragTargetPile.y + dragTargetPile.cards.length * 40 + CARD_HEIGHT / 2;
			game.addChild(spider);
			(function (spider, setIndex) {
				tween(spider, {
					y: COMPLETED_Y,
					x: COMPLETED_X + setIndex * (CARD_WIDTH * 0.7)
				}, {
					duration: 800,
					easing: tween.easeOut,
					onFinish: function onFinish() {
						if (spider.parent) spider.parent.removeChild(spider);
						updateCompletedSpiders();
					}
				});
			})(spider, completedSets - 1);
			completedAny = true;
		}
		autoCollectSets();
		// Win condition: 8 sets
		if (completedSets >= 8) {
			LK.showYouWin();
			return;
		}
	} else {
		// Return to original pile
		for (var i = 0; i < draggingCards.length; i++) {
			draggingCards[i].x = dragStartX - draggingFromPile.x;
			draggingCards[i].y = dragStartY - draggingFromPile.y + i * 60;
			draggingFromPile.addChild(draggingCards[i]);
		}
		draggingFromPile.layout();
	}
	// Deselect
	for (var i = 0; i < draggingCards.length; i++) {
		draggingCards[i].selected = false;
		draggingCards[i].updateSelected();
	}
	draggingCards = null;
	draggingFromPile = null;
	dragValidTarget = null;
	dragTargetPile = null;
};
// Deal button (shown above the stock pile decks)
var dealBtn = new Text2('Deal', {
	size: 90,
	fill: 0xffffff
});
dealBtn.anchor.set(0.5, 1);
// Position: above the stock pile decks, centered horizontally
dealBtn.x = GAME_WIDTH / 2;
dealBtn.y = GAME_HEIGHT - CARD_HEIGHT / 2 - 40 - 30;
game.addChild(dealBtn);
// Deal new row
dealBtn.down = function (x, y, obj) {
	if (!canDeal) return;
	// Only allow if all tableau piles have at least one card
	for (var i = 0; i < tableauPiles.length; i++) {
		if (tableauPiles[i].cards.length === 0) return;
	}
	if (stockPile.isEmpty()) return;
	canDeal = false;
	pushUndoState();
	// Animate deal
	var dealt = stockPile.dealToTableau(tableauPiles);
	if (dealt) {
		// Play shuffle sound when dealing from stock
		LK.getSound('shuffle').play();
		// Flip top card of each pile
		for (var i = 0; i < tableauPiles.length; i++) {
			tableauPiles[i].topCard().flip(true);
		}
		updateStockDecks();
		autoCollectSets();
	}
	// Allow next deal after short delay
	LK.setTimeout(function () {
		canDeal = true;
	}, 400);
};
// Touch on stock pile (deal)
stockPile.down = function (x, y, obj) {
	dealBtn.down(x, y, obj);
};
// Reset game
function resetGame() {
	// Remove all cards
	for (var i = 0; i < tableauPiles.length; i++) {
		var pile = tableauPiles[i];
		while (pile.cards.length > 0) {
			var c = pile.cards.pop();
			if (c.parent) c.parent.removeChild(c);
		}
	}
	while (stockPile.cards.length > 0) {
		var c = stockPile.cards.pop();
		if (c.parent) c.parent.removeChild(c);
	}
	completedSets = 0;
	movesCount = 0; // Reset moves counter
	updateScore();
	updateCompletedSpiders();
	updateStockDecks();
	canDeal = true;
	draggingCards = null;
	draggingFromPile = null;
	dragValidTarget = null;
	dragTargetPile = null;
	dealInitial();
}
// Game over: no more moves
function checkGameOver() {
	// If no moves and stock is empty
	var canMove = false;
	for (var i = 0; i < tableauPiles.length; i++) {
		var pile = tableauPiles[i];
		for (var j = 0; j < pile.cards.length; j++) {
			if (pile.canMoveSequence(j)) {
				// Try to move to another pile
				var seq = [];
				for (var k = j; k < pile.cards.length; k++) seq.push(pile.cards[k]);
				for (var t = 0; t < tableauPiles.length; t++) {
					if (t === i) continue;
					if (tableauPiles[t].canAccept(seq)) {
						canMove = true;
						break;
					}
				}
			}
			if (canMove) break;
		}
		if (canMove) break;
	}
	if (!canMove && stockPile.isEmpty()) {
		LK.showGameOver();
	}
}
// Game update
game.update = function () {
	// (auto-collect logic moved to after every move, deal, and flip)
	// Check for game over
	checkGameOver();
};
// Start game
dealInitial();
LK.playMusic('relaxing_bg');