diff --git a/data/projects.json b/data/projects.json
index 86bae25..4ea6d78 100644
--- a/data/projects.json
+++ b/data/projects.json
@@ -318,5 +318,13 @@
"category": "Small Games",
"categoryKey": "games",
"difficulty": "medium"
+ },
+ {
+ "title": "Blackjack",
+ "slug": "blackjack",
+ "description": "Classic card game - Beat the dealer to 21! Features betting, realistic animations, and dark/light themes.",
+ "category": "Game",
+ "categoryKey": "game",
+ "difficulty": "Intermediate"
}
]
diff --git a/projects/blackjack/index.html b/projects/blackjack/index.html
new file mode 100644
index 0000000..a69220c
--- /dev/null
+++ b/projects/blackjack/index.html
@@ -0,0 +1,75 @@
+
+
+
+
+
+ Blackjack - 21
+
+
+
+
+
+
+
+
+
+ Blackjack
+
+
+ Chips:
+ 1000
+
+
+ Wins:
+ 0
+
+
+ Losses:
+ 0
+
+
+
+
+
+
+
+
+
+ Place Your Bet
+
+
+
+
+
+
+
+
+
+
+ Current Bet: $0
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/blackjack/main.js b/projects/blackjack/main.js
new file mode 100644
index 0000000..b59c048
--- /dev/null
+++ b/projects/blackjack/main.js
@@ -0,0 +1,444 @@
+// Game State
+const gameState = {
+ deck: [],
+ playerHand: [],
+ dealerHand: [],
+ chips: 1000,
+ currentBet: 0,
+ wins: 0,
+ losses: 0,
+ gameActive: false,
+ dealerRevealed: false
+};
+
+// Card suits and ranks
+const suits = ['♠', '♥', '♦', '♣'];
+const ranks = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];
+const values = {
+ 'A': 11, '2': 2, '3': 3, '4': 4, '5': 5,
+ '6': 6, '7': 7, '8': 8, '9': 9, '10': 10,
+ 'J': 10, 'Q': 10, 'K': 10
+};
+
+// DOM Elements
+const dealerCardsEl = document.getElementById('dealerCards');
+const playerCardsEl = document.getElementById('playerCards');
+const dealerValueEl = document.getElementById('dealerValue');
+const playerValueEl = document.getElementById('playerValue');
+const gameMessageEl = document.getElementById('gameMessage');
+const chipsEl = document.getElementById('chips');
+const winsEl = document.getElementById('wins');
+const lossesEl = document.getElementById('losses');
+const currentBetEl = document.getElementById('currentBet');
+const bettingSectionEl = document.getElementById('bettingSection');
+const gameControlsEl = document.getElementById('gameControls');
+const themeBtn = document.getElementById('themeBtn');
+
+// Buttons
+const hitBtn = document.getElementById('hitBtn');
+const standBtn = document.getElementById('standBtn');
+const newGameBtn = document.getElementById('newGameBtn');
+const placeBetBtn = document.getElementById('placeBetBtn');
+const customBetInput = document.getElementById('customBet');
+const betButtons = document.querySelectorAll('.bet-btn');
+
+// Sound effects (basic beep sounds using Web Audio API)
+const audioContext = new (window.AudioContext || window.webkitAudioContext)();
+
+function playSound(frequency, duration) {
+ const oscillator = audioContext.createOscillator();
+ const gainNode = audioContext.createGain();
+
+ oscillator.connect(gainNode);
+ gainNode.connect(audioContext.destination);
+
+ oscillator.frequency.value = frequency;
+ oscillator.type = 'sine';
+
+ gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
+ gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + duration);
+
+ oscillator.start(audioContext.currentTime);
+ oscillator.stop(audioContext.currentTime + duration);
+}
+
+function cardSound() {
+ playSound(400, 0.1);
+}
+
+function winSound() {
+ playSound(800, 0.2);
+ setTimeout(() => playSound(1000, 0.2), 100);
+}
+
+function loseSound() {
+ playSound(200, 0.3);
+}
+
+// Theme Toggle
+function initTheme() {
+ const savedTheme = localStorage.getItem('blackjack-theme') || 'dark';
+ document.documentElement.setAttribute('data-theme', savedTheme);
+ updateThemeIcon(savedTheme);
+}
+
+function toggleTheme() {
+ const currentTheme = document.documentElement.getAttribute('data-theme');
+ const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
+ document.documentElement.setAttribute('data-theme', newTheme);
+ localStorage.setItem('blackjack-theme', newTheme);
+ updateThemeIcon(newTheme);
+}
+
+function updateThemeIcon(theme) {
+ const icon = themeBtn.querySelector('.icon');
+ icon.textContent = theme === 'dark' ? '🌙' : '☀️';
+}
+
+// Initialize Deck
+function createDeck() {
+ const deck = [];
+ for (let suit of suits) {
+ for (let rank of ranks) {
+ deck.push({ rank, suit });
+ }
+ }
+ return shuffleDeck(deck);
+}
+
+function shuffleDeck(deck) {
+ for (let i = deck.length - 1; i > 0; i--) {
+ const j = Math.floor(Math.random() * (i + 1));
+ [deck[i], deck[j]] = [deck[j], deck[i]];
+ }
+ return deck;
+}
+
+// Card Value Calculation
+function calculateHandValue(hand) {
+ let value = 0;
+ let aces = 0;
+
+ for (let card of hand) {
+ value += values[card.rank];
+ if (card.rank === 'A') aces++;
+ }
+
+ // Adjust for Aces
+ while (value > 21 && aces > 0) {
+ value -= 10;
+ aces--;
+ }
+
+ return value;
+}
+
+// Display Functions
+function createCardElement(card, isHidden = false) {
+ const cardEl = document.createElement('div');
+ cardEl.className = 'card';
+
+ if (isHidden) {
+ cardEl.classList.add('back');
+ return cardEl;
+ }
+
+ const color = (card.suit === '♥' || card.suit === '♦') ? 'red' : 'black';
+ cardEl.classList.add(color);
+
+ cardEl.innerHTML = `
+ ${card.rank}
+ ${card.suit}
+ ${card.rank}
+ `;
+
+ return cardEl;
+}
+
+function displayHands(hideDealer = true) {
+ // Display dealer hand
+ dealerCardsEl.innerHTML = '';
+ gameState.dealerHand.forEach((card, index) => {
+ const isHidden = hideDealer && index === 1 && !gameState.dealerRevealed;
+ dealerCardsEl.appendChild(createCardElement(card, isHidden));
+ });
+
+ // Display player hand
+ playerCardsEl.innerHTML = '';
+ gameState.playerHand.forEach(card => {
+ playerCardsEl.appendChild(createCardElement(card));
+ });
+
+ // Update values
+ const dealerValue = calculateHandValue(gameState.dealerHand);
+ const playerValue = calculateHandValue(gameState.playerHand);
+
+ if (hideDealer && !gameState.dealerRevealed) {
+ const firstCardValue = values[gameState.dealerHand[0].rank];
+ dealerValueEl.textContent = firstCardValue;
+ } else {
+ dealerValueEl.textContent = dealerValue;
+ }
+
+ playerValueEl.textContent = playerValue;
+}
+
+function updateStats() {
+ chipsEl.textContent = gameState.chips;
+ winsEl.textContent = gameState.wins;
+ lossesEl.textContent = gameState.losses;
+ currentBetEl.textContent = gameState.currentBet;
+}
+
+function showMessage(message, type = '') {
+ gameMessageEl.textContent = message;
+ gameMessageEl.className = 'game-message';
+ if (type) {
+ gameMessageEl.classList.add(type);
+ }
+}
+
+// Betting Functions
+function placeBet(amount) {
+ if (amount > gameState.chips) {
+ showMessage('Not enough chips!', 'lose');
+ return false;
+ }
+
+ if (amount <= 0) {
+ showMessage('Invalid bet amount!', 'lose');
+ return false;
+ }
+
+ gameState.currentBet = amount;
+ gameState.chips -= amount;
+ updateStats();
+ startGame();
+ return true;
+}
+
+// Game Flow
+function startGame() {
+ gameState.deck = createDeck();
+ gameState.playerHand = [];
+ gameState.dealerHand = [];
+ gameState.gameActive = true;
+ gameState.dealerRevealed = false;
+
+ showMessage('');
+ bettingSectionEl.style.display = 'none';
+ gameControlsEl.style.display = 'flex';
+
+ // Deal initial cards
+ setTimeout(() => {
+ dealCard(gameState.playerHand);
+ cardSound();
+ }, 200);
+
+ setTimeout(() => {
+ dealCard(gameState.dealerHand);
+ cardSound();
+ }, 400);
+
+ setTimeout(() => {
+ dealCard(gameState.playerHand);
+ cardSound();
+ }, 600);
+
+ setTimeout(() => {
+ dealCard(gameState.dealerHand);
+ cardSound();
+ displayHands(true);
+ checkForBlackjack();
+ }, 800);
+}
+
+function dealCard(hand) {
+ const card = gameState.deck.pop();
+ hand.push(card);
+ displayHands(!gameState.dealerRevealed);
+}
+
+function checkForBlackjack() {
+ const playerValue = calculateHandValue(gameState.playerHand);
+ const dealerValue = calculateHandValue(gameState.dealerHand);
+
+ if (playerValue === 21) {
+ if (dealerValue === 21) {
+ endGame('draw', 'Both Blackjack! Push!');
+ } else {
+ endGame('win', 'Blackjack! You Win!');
+ }
+ }
+}
+
+function hit() {
+ if (!gameState.gameActive) return;
+
+ dealCard(gameState.playerHand);
+ cardSound();
+
+ const playerValue = calculateHandValue(gameState.playerHand);
+
+ if (playerValue > 21) {
+ endGame('lose', 'Bust! You Lose!');
+ } else if (playerValue === 21) {
+ stand();
+ }
+}
+
+function stand() {
+ if (!gameState.gameActive) return;
+
+ gameState.dealerRevealed = true;
+ hitBtn.disabled = true;
+ standBtn.disabled = true;
+
+ dealerPlay();
+}
+
+function dealerPlay() {
+ displayHands(false);
+
+ const dealerValue = calculateHandValue(gameState.dealerHand);
+
+ if (dealerValue < 17) {
+ setTimeout(() => {
+ dealCard(gameState.dealerHand);
+ cardSound();
+ dealerPlay();
+ }, 1000);
+ } else {
+ determineWinner();
+ }
+}
+
+function determineWinner() {
+ const playerValue = calculateHandValue(gameState.playerHand);
+ const dealerValue = calculateHandValue(gameState.dealerHand);
+
+ if (dealerValue > 21) {
+ endGame('win', 'Dealer Busts! You Win!');
+ } else if (playerValue > dealerValue) {
+ endGame('win', 'You Win!');
+ } else if (dealerValue > playerValue) {
+ endGame('lose', 'Dealer Wins!');
+ } else {
+ endGame('draw', 'Push! It\'s a Draw!');
+ }
+}
+
+function endGame(result, message) {
+ gameState.gameActive = false;
+ hitBtn.disabled = true;
+ standBtn.disabled = true;
+
+ showMessage(message, result);
+
+ if (result === 'win') {
+ const isBlackjack = calculateHandValue(gameState.playerHand) === 21 &&
+ gameState.playerHand.length === 2;
+ const winnings = isBlackjack ?
+ Math.floor(gameState.currentBet * 2.5) :
+ gameState.currentBet * 2;
+ gameState.chips += winnings;
+ gameState.wins++;
+ winSound();
+ } else if (result === 'lose') {
+ gameState.losses++;
+ loseSound();
+ } else {
+ gameState.chips += gameState.currentBet;
+ cardSound();
+ }
+
+ updateStats();
+
+ if (gameState.chips <= 0) {
+ setTimeout(() => {
+ alert('Game Over! You\'re out of chips. Resetting...');
+ resetGame();
+ }, 2000);
+ }
+}
+
+function newGame() {
+ if (gameState.chips <= 0) {
+ resetGame();
+ return;
+ }
+
+ gameState.currentBet = 0;
+ gameState.playerHand = [];
+ gameState.dealerHand = [];
+ gameState.gameActive = false;
+ gameState.dealerRevealed = false;
+
+ dealerCardsEl.innerHTML = '';
+ playerCardsEl.innerHTML = '';
+ dealerValueEl.textContent = '0';
+ playerValueEl.textContent = '0';
+ showMessage('');
+
+ bettingSectionEl.style.display = 'block';
+ gameControlsEl.style.display = 'none';
+ customBetInput.value = '';
+
+ hitBtn.disabled = false;
+ standBtn.disabled = false;
+
+ updateStats();
+}
+
+function resetGame() {
+ gameState.chips = 1000;
+ gameState.wins = 0;
+ gameState.losses = 0;
+ newGame();
+}
+
+// Event Listeners
+hitBtn.addEventListener('click', hit);
+standBtn.addEventListener('click', stand);
+newGameBtn.addEventListener('click', newGame);
+themeBtn.addEventListener('click', toggleTheme);
+
+betButtons.forEach(btn => {
+ btn.addEventListener('click', () => {
+ const betAmount = parseInt(btn.dataset.bet);
+ placeBet(betAmount);
+ });
+});
+
+placeBetBtn.addEventListener('click', () => {
+ const betAmount = parseInt(customBetInput.value);
+ if (betAmount) {
+ placeBet(betAmount);
+ } else {
+ showMessage('Enter a valid bet amount!', 'lose');
+ }
+});
+
+customBetInput.addEventListener('keypress', (e) => {
+ if (e.key === 'Enter') {
+ const betAmount = parseInt(customBetInput.value);
+ if (betAmount) {
+ placeBet(betAmount);
+ }
+ }
+});
+
+// Keyboard Controls
+document.addEventListener('keydown', (e) => {
+ if (!gameState.gameActive) return;
+
+ if (e.key === 'h' || e.key === 'H') {
+ hit();
+ } else if (e.key === 's' || e.key === 'S') {
+ stand();
+ }
+});
+
+// Initialize
+initTheme();
+updateStats();
\ No newline at end of file
diff --git a/projects/blackjack/style.css b/projects/blackjack/style.css
new file mode 100644
index 0000000..d4f6759
--- /dev/null
+++ b/projects/blackjack/style.css
@@ -0,0 +1,491 @@
+:root {
+ --bg-primary: #0f172a;
+ --bg-secondary: #1e293b;
+ --bg-table: #1a472a;
+ --text-primary: #f1f5f9;
+ --text-secondary: #94a3b8;
+ --accent: #10b981;
+ --accent-hover: #059669;
+ --card-bg: #ffffff;
+ --card-shadow: rgba(0, 0, 0, 0.3);
+ --border: #334155;
+ --message-win: #10b981;
+ --message-lose: #ef4444;
+ --message-draw: #f59e0b;
+}
+
+[data-theme="light"] {
+ --bg-primary: #f1f5f9;
+ --bg-secondary: #e2e8f0;
+ --bg-table: #2d6a3e;
+ --text-primary: #0f172a;
+ --text-secondary: #475569;
+ --accent: #059669;
+ --accent-hover: #047857;
+ --card-bg: #ffffff;
+ --card-shadow: rgba(0, 0, 0, 0.2);
+ --border: #cbd5e1;
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+ background: var(--bg-primary);
+ color: var(--text-primary);
+ min-height: 100vh;
+ transition: background-color 0.3s ease, color 0.3s ease;
+}
+
+.theme-toggle {
+ position: fixed;
+ top: 20px;
+ right: 20px;
+ z-index: 1000;
+}
+
+#themeBtn {
+ background: var(--bg-secondary);
+ border: 2px solid var(--border);
+ border-radius: 50%;
+ width: 50px;
+ height: 50px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 1.5rem;
+ transition: all 0.3s ease;
+}
+
+#themeBtn:hover {
+ transform: scale(1.1);
+ border-color: var(--accent);
+}
+
+.container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 20px;
+}
+
+header {
+ text-align: center;
+ margin-bottom: 30px;
+}
+
+h1 {
+ font-size: 3rem;
+ margin-bottom: 20px;
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
+}
+
+.stats {
+ display: flex;
+ justify-content: center;
+ gap: 30px;
+ flex-wrap: wrap;
+}
+
+.stat-item {
+ background: var(--bg-secondary);
+ padding: 15px 25px;
+ border-radius: 10px;
+ border: 2px solid var(--border);
+}
+
+.stat-label {
+ color: var(--text-secondary);
+ font-size: 0.9rem;
+ margin-right: 8px;
+}
+
+.stat-value {
+ font-size: 1.3rem;
+ font-weight: bold;
+ color: var(--accent);
+}
+
+.game-area {
+ background: var(--bg-table);
+ border-radius: 20px;
+ padding: 40px 20px;
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4);
+ min-height: 600px;
+ position: relative;
+}
+
+.dealer-section,
+.player-section {
+ margin-bottom: 40px;
+}
+
+.player-info {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20px;
+ padding: 0 20px;
+}
+
+.player-info h2 {
+ font-size: 1.5rem;
+}
+
+.hand-value {
+ background: var(--bg-secondary);
+ padding: 8px 20px;
+ border-radius: 8px;
+ font-size: 1.2rem;
+ font-weight: bold;
+ border: 2px solid var(--border);
+}
+
+.cards-container {
+ display: flex;
+ justify-content: center;
+ gap: 15px;
+ flex-wrap: wrap;
+ min-height: 140px;
+ align-items: center;
+}
+
+.card {
+ width: 90px;
+ height: 130px;
+ background: var(--card-bg);
+ border-radius: 8px;
+ box-shadow: 0 4px 8px var(--card-shadow);
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ padding: 10px;
+ position: relative;
+ animation: dealCard 0.3s ease-out;
+ transition: transform 0.2s ease;
+}
+
+.card:hover {
+ transform: translateY(-5px);
+}
+
+@keyframes dealCard {
+ from {
+ opacity: 0;
+ transform: translateY(-50px) rotateY(180deg);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0) rotateY(0);
+ }
+}
+
+.card.back {
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ justify-content: center;
+ align-items: center;
+}
+
+.card.back::before {
+ content: "🂠";
+ font-size: 4rem;
+ color: rgba(255, 255, 255, 0.3);
+}
+
+.card-rank {
+ font-size: 1.5rem;
+ font-weight: bold;
+}
+
+.card-suit {
+ font-size: 2rem;
+ text-align: center;
+}
+
+.card-rank-bottom {
+ font-size: 1.5rem;
+ font-weight: bold;
+ text-align: right;
+}
+
+.card.red {
+ color: #dc2626;
+}
+
+.card.black {
+ color: #0f172a;
+}
+
+.game-message {
+ text-align: center;
+ font-size: 2rem;
+ font-weight: bold;
+ margin: 30px 0;
+ min-height: 60px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ animation: messageAppear 0.5s ease-out;
+}
+
+@keyframes messageAppear {
+ from {
+ opacity: 0;
+ transform: scale(0.8);
+ }
+ to {
+ opacity: 1;
+ transform: scale(1);
+ }
+}
+
+.game-message.win {
+ color: var(--message-win);
+ text-shadow: 0 0 20px var(--message-win);
+}
+
+.game-message.lose {
+ color: var(--message-lose);
+ text-shadow: 0 0 20px var(--message-lose);
+}
+
+.game-message.draw {
+ color: var(--message-draw);
+ text-shadow: 0 0 20px var(--message-draw);
+}
+
+.betting-section {
+ text-align: center;
+ padding: 30px;
+ background: var(--bg-secondary);
+ border-radius: 15px;
+ margin: 20px auto;
+ max-width: 600px;
+}
+
+.betting-section h3 {
+ margin-bottom: 20px;
+ font-size: 1.5rem;
+}
+
+.bet-controls {
+ display: flex;
+ justify-content: center;
+ gap: 15px;
+ margin-bottom: 20px;
+ flex-wrap: wrap;
+}
+
+.bet-btn {
+ background: var(--accent);
+ color: white;
+ border: none;
+ padding: 15px 30px;
+ border-radius: 8px;
+ font-size: 1.1rem;
+ font-weight: bold;
+ cursor: pointer;
+ transition: all 0.3s ease;
+}
+
+.bet-btn:hover {
+ background: var(--accent-hover);
+ transform: translateY(-2px);
+ box-shadow: 0 5px 15px rgba(16, 185, 129, 0.3);
+}
+
+.custom-bet {
+ display: flex;
+ justify-content: center;
+ gap: 10px;
+ margin-bottom: 20px;
+ flex-wrap: wrap;
+}
+
+#customBet {
+ padding: 12px 20px;
+ border-radius: 8px;
+ border: 2px solid var(--border);
+ background: var(--bg-primary);
+ color: var(--text-primary);
+ font-size: 1rem;
+ width: 200px;
+}
+
+#placeBetBtn {
+ background: var(--accent);
+ color: white;
+ border: none;
+ padding: 12px 30px;
+ border-radius: 8px;
+ font-size: 1rem;
+ font-weight: bold;
+ cursor: pointer;
+ transition: all 0.3s ease;
+}
+
+#placeBetBtn:hover {
+ background: var(--accent-hover);
+}
+
+.current-bet {
+ font-size: 1.3rem;
+ font-weight: bold;
+ color: var(--accent);
+}
+
+.controls {
+ display: flex;
+ justify-content: center;
+ gap: 20px;
+ margin-top: 30px;
+ flex-wrap: wrap;
+}
+
+.control-btn {
+ padding: 15px 40px;
+ font-size: 1.2rem;
+ font-weight: bold;
+ border: none;
+ border-radius: 10px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+}
+
+.control-btn.primary {
+ background: var(--accent);
+ color: white;
+}
+
+.control-btn.primary:hover {
+ background: var(--accent-hover);
+ transform: translateY(-2px);
+ box-shadow: 0 5px 15px rgba(16, 185, 129, 0.3);
+}
+
+.control-btn.secondary {
+ background: #f59e0b;
+ color: white;
+}
+
+.control-btn.secondary:hover {
+ background: #d97706;
+ transform: translateY(-2px);
+ box-shadow: 0 5px 15px rgba(245, 158, 11, 0.3);
+}
+
+.control-btn.tertiary {
+ background: #6366f1;
+ color: white;
+}
+
+.control-btn.tertiary:hover {
+ background: #4f46e5;
+ transform: translateY(-2px);
+ box-shadow: 0 5px 15px rgba(99, 102, 241, 0.3);
+}
+
+.control-btn:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ transform: none;
+}
+
+@media (max-width: 768px) {
+ h1 {
+ font-size: 2rem;
+ }
+
+ .stats {
+ gap: 15px;
+ }
+
+ .stat-item {
+ padding: 10px 15px;
+ }
+
+ .game-area {
+ padding: 20px 10px;
+ }
+
+ .card {
+ width: 70px;
+ height: 100px;
+ padding: 8px;
+ }
+
+ .card-rank,
+ .card-rank-bottom {
+ font-size: 1.2rem;
+ }
+
+ .card-suit {
+ font-size: 1.5rem;
+ }
+
+ .game-message {
+ font-size: 1.5rem;
+ }
+
+ .control-btn {
+ padding: 12px 25px;
+ font-size: 1rem;
+ }
+
+ .betting-section {
+ padding: 20px;
+ }
+
+ .bet-controls {
+ gap: 10px;
+ }
+
+ .bet-btn {
+ padding: 12px 20px;
+ font-size: 1rem;
+ }
+}
+
+@media (max-width: 480px) {
+ .container {
+ padding: 10px;
+ }
+
+ h1 {
+ font-size: 1.5rem;
+ }
+
+ .cards-container {
+ gap: 8px;
+ }
+
+ .card {
+ width: 60px;
+ height: 85px;
+ padding: 5px;
+ }
+
+ .card-rank,
+ .card-rank-bottom {
+ font-size: 1rem;
+ }
+
+ .card-suit {
+ font-size: 1.2rem;
+ }
+
+ .controls {
+ gap: 10px;
+ }
+
+ .control-btn {
+ padding: 10px 20px;
+ font-size: 0.9rem;
+ }
+}
\ No newline at end of file