diff --git a/assets/cash-money.mp3 b/assets/cash-money.mp3
new file mode 100644
index 0000000..04abc8e
Binary files /dev/null and b/assets/cash-money.mp3 differ
diff --git a/assets/icon.png b/assets/icon.png
new file mode 100644
index 0000000..ec545cd
Binary files /dev/null and b/assets/icon.png differ
diff --git a/css/base.css b/css/base.css
new file mode 100644
index 0000000..8626bbc
--- /dev/null
+++ b/css/base.css
@@ -0,0 +1,89 @@
+/* base.css */
+:root {
+ --background-color: #f0f0f0;
+ --text-color: #333;
+ --card-background: #ffffff;
+ --button-background: #007acc;
+ --button-hover: #005fa3;
+}
+
+body {
+ font-family: 'Sorts Mill Goudy', serif;
+ background-color: var(--background-color);
+ color: var(--text-color);
+ margin: 0;
+ padding: 20px;
+}
+
+.container {
+ max-width: 600px;
+ margin: 0 auto;
+ background-color: var(--card-background);
+ padding: 20px;
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+ border-radius: 8px;
+}
+
+h1 {
+ text-align: center;
+ margin-bottom: 20px;
+}
+
+form div {
+ margin-bottom: 15px;
+}
+
+label {
+ display: block;
+ margin-bottom: 5px;
+}
+
+input, select, textarea {
+ width: 100%;
+ padding: 8px;
+ box-sizing: border-box;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ background-color: var(--card-background);
+ color: var(--text-color);
+}
+
+button {
+ display: block;
+ width: 100%;
+ padding: 10px;
+ background-color: var(--button-background);
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ margin-top: 10px;
+}
+
+button:hover {
+ background-color: var(--button-hover);
+}
+
+#csv-output {
+ margin-top: 20px;
+ height: 200px;
+ background-color: var(--card-background);
+ color: var(--text-color);
+}
+
+footer {
+ text-align: center;
+ font-size: 0.5rem;
+ color: #666;
+ margin-top: 0px;
+ padding: 1px;
+}
+
+footer a {
+ color: #007acc;
+ text-decoration: none;
+}
+
+footer a:hover {
+ text-decoration: underline;
+}
diff --git a/css/components.css b/css/components.css
new file mode 100644
index 0000000..2350708
--- /dev/null
+++ b/css/components.css
@@ -0,0 +1,106 @@
+/* components.css */
+.mana-icon {
+ font-family: 'mana', sans-serif;
+ font-size: 24px;
+ cursor: pointer;
+ padding: 5px;
+ margin-right: 10px;
+}
+
+.mana-icon:hover {
+ opacity: 0.8;
+}
+
+
+.menu {
+ position: relative;
+ display: inline-block;
+}
+
+.hamburger-menu {
+ cursor: pointer;
+ font-size: 30px;
+ color: var(--text-color);
+}
+
+.menu-content {
+ display: none; /* Ensure it's hidden by default */
+ position: absolute;
+ top: 40px;
+ left: 0;
+ background-color: var(--background-color);
+ box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
+ padding: 10px;
+ z-index: 1;
+ min-width: 150px;
+ border-radius: 4px;
+}
+
+.menu-content.show {
+ display: block; /* Display menu when toggled */
+}
+
+.zoom-modal {
+ display: none; /* Ensure modal is hidden by default */
+ position: fixed;
+ z-index: 1000;
+ padding-top: 100px;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+ background-color: rgba(0, 0, 0, 0.8);
+}
+
+.zoomed-image {
+ margin: auto;
+ display: block;
+ width: 80%;
+ max-width: 700px;
+}
+
+/* Dark mode styles */
+/* Dark mode styles */
+body.dark-mode .menu-content {
+ background-color: #333;
+}
+
+body.dark-mode .hamburger-menu,
+body.dark-mode .menu-content label,
+body.dark-mode .menu-content input {
+ color: white;
+}
+
+.card-popup {
+ position: fixed;
+ bottom: 20px;
+ right: 20px;
+ max-width: 20%;
+ z-index: 1000;
+ background-color: rgba(0, 0, 0, 0.7);
+ padding: 10px;
+ border-radius: 8px;
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+ opacity: 0;
+ transition: opacity 0.5s ease-in-out;
+ display: none;
+}
+
+.card-popup img {
+ width: 100%;
+ height: auto;
+ border-radius: 4px;
+}
+
+@media (max-width: 600px) {
+ .card-popup {
+ max-width: 40%;
+ }
+}
+
+@media (max-width: 400px) {
+ .card-popup {
+ max-width: 60%;
+ }
+}
diff --git a/css/themes.css b/css/themes.css
new file mode 100644
index 0000000..55fca66
--- /dev/null
+++ b/css/themes.css
@@ -0,0 +1,102 @@
+/* Light and Dark mode base theme */
+:root {
+ --background-color: #f0f0f0;
+ --text-color: #333;
+ --card-background: #ffffff;
+ --button-background: #007acc;
+ --button-hover: #005fa3;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ --background-color: #1e1e1e;
+ --text-color: #ffffff;
+ --card-background: #2e2e2e;
+ --button-background: #1f6fb2;
+ --button-hover: #145b8c;
+ }
+}
+
+/* Mana Color Themes */
+.theme-white {
+ --background-color: #f9f8f6;
+ --text-color: #1e1e1e;
+ --card-background: #ffffff;
+ --button-background: #e5e5e5;
+ --button-hover: #cccccc;
+}
+
+.theme-blue {
+ --background-color: #d7e7f9;
+ --text-color: #002d72;
+ --card-background: #e0f2ff;
+ --button-background: #007acc;
+ --button-hover: #005fa3;
+}
+
+.theme-black {
+ --background-color: #333333;
+ --text-color: #ffffff;
+ --card-background: #444444;
+ --button-background: #1f1f1f;
+ --button-hover: #000000;
+}
+
+.theme-red {
+ --background-color: #fbe4e4;
+ --text-color: #8b0000;
+ --card-background: #ffe5e5;
+ --button-background: #d32f2f;
+ --button-hover: #b71c1c;
+}
+
+.theme-green {
+ --background-color: #e7f4e7;
+ --text-color: #004d00;
+ --card-background: #e0ffe0;
+ --button-background: #388e3c;
+ --button-hover: #2e7d32;
+}
+
+/* Dark Mode Variants for Mana Themes */
+@media (prefers-color-scheme: dark) {
+ .theme-white {
+ --background-color: #1e1e1e;
+ --text-color: #ffffff;
+ --card-background: #333333;
+ --button-background: #555555;
+ --button-hover: #777777;
+ }
+
+ .theme-blue {
+ --background-color: #001f3f;
+ --text-color: #ffffff;
+ --card-background: #002d72;
+ --button-background: #005fa3;
+ --button-hover: #007acc;
+ }
+
+ .theme-black {
+ --background-color: #000000;
+ --text-color: #e5e5e5;
+ --card-background: #1c1c1c;
+ --button-background: #333333;
+ --button-hover: #555555;
+ }
+
+ .theme-red {
+ --background-color: #330000;
+ --text-color: #ffaaaa;
+ --card-background: #8b0000;
+ --button-background: #b71c1c;
+ --button-hover: #d32f2f;
+ }
+
+ .theme-green {
+ --background-color: #002200;
+ --text-color: #ccffcc;
+ --card-background: #004d00;
+ --button-background: #2e7d32;
+ --button-hover: #388e3c;
+ }
+}
diff --git a/index.html b/index.html
index ff0e330..b9bdfd9 100644
--- a/index.html
+++ b/index.html
@@ -1,28 +1,33 @@
+
-
+
+
+
+
+
+
+
+
+
diff --git a/js/api.js b/js/api.js
new file mode 100644
index 0000000..5c81406
--- /dev/null
+++ b/js/api.js
@@ -0,0 +1,37 @@
+// api.js
+
+export async function fetchCardSuggestions(query) {
+ try {
+ const response = await fetch(`https://api.scryfall.com/cards/autocomplete?q=${encodeURIComponent(query)}`);
+ if (!response.ok) {
+ throw new Error('Network response was not ok');
+ }
+ const data = await response.json();
+ return data.data;
+ } catch (error) {
+ console.error('Fetch error:', error);
+ return [];
+ }
+}
+
+export async function fetchCardDetails(cardName, setCode) {
+ const response = await fetch(`https://api.scryfall.com/cards/named?exact=${encodeURIComponent(cardName)}&set=${encodeURIComponent(setCode)}`);
+ const data = await response.json();
+
+ if (data.object === 'error') {
+ return null;
+ }
+
+ return {
+ set: data.set.toUpperCase(),
+ card_id: data.collector_number,
+ mana_cost: data.mana_cost || 'N/A',
+ power: data.power || 'N/A',
+ toughness: data.toughness || 'N/A',
+ type: data.type_line.split('—')[0].trim(),
+ rarity: data.rarity || 'N/A',
+ price: data.prices.usd || '0.00',
+ imageUrl: data.image_uris ? data.image_uris.small : null,
+ name: data.name
+ };
+}
diff --git a/js/card.js b/js/card.js
new file mode 100644
index 0000000..5ee6d2f
--- /dev/null
+++ b/js/card.js
@@ -0,0 +1,68 @@
+// card.js
+
+import { updateCardDetails, loadCollection } from './storage.js';
+import { showCardPopup } from './popup.js';
+
+export async function addCard(cardList) {
+ const cardName = document.getElementById('card-name').value;
+ const setCodeInput = document.getElementById('set-code');
+ const cardIdInput = document.getElementById('card-id');
+
+ let setCode = setCodeInput.value;
+ let cardId = cardIdInput.value;
+
+ const cardDetails = await fetchCardDetails(cardName, setCode);
+
+ if (cardDetails) {
+ if (!setCode) {
+ setCode = cardDetails.set;
+ setCodeInput.value = setCode;
+ }
+ if (!cardId) {
+ cardId = cardDetails.card_id;
+ cardIdInput.value = cardId;
+ }
+
+ const cardData = {
+ name: cardName,
+ set: setCode,
+ card_id: cardId,
+ quantity: document.getElementById('quantity').value,
+ foil: document.getElementById('foil').value,
+ mana_cost: cardDetails.mana_cost,
+ power: cardDetails.power,
+ toughness: cardDetails.toughness,
+ type: cardDetails.type,
+ rarity: cardDetails.rarity,
+ price: cardDetails.price
+ };
+
+ updateCardDetails(cardData);
+ cardList.push(cardData); // Add the card to the list
+ showCardPopup(cardData.name, cardDetails.imageUrl, cardDetails.price);
+ } else {
+ alert("Card not found with the given name.");
+ }
+}
+
+export async function fetchCardDetails(cardName, setCode) {
+ const response = await fetch(`https://api.scryfall.com/cards/named?exact=${encodeURIComponent(cardName)}&set=${encodeURIComponent(setCode)}`);
+ const data = await response.json();
+
+ if (data.object === 'error') {
+ return null;
+ }
+
+ return {
+ set: data.set.toUpperCase(),
+ card_id: data.collector_number,
+ mana_cost: data.mana_cost || 'N/A',
+ power: data.power || 'N/A',
+ toughness: data.toughness || 'N/A',
+ type: data.type_line.split('—')[0].trim(),
+ rarity: data.rarity || 'N/A',
+ price: data.prices.usd || '0.00',
+ imageUrl: data.image_uris ? data.image_uris.small : null,
+ name: data.name
+ };
+}
diff --git a/js/csv.js b/js/csv.js
new file mode 100644
index 0000000..314a930
--- /dev/null
+++ b/js/csv.js
@@ -0,0 +1,44 @@
+// csv.js
+
+import { getRandomWordsFromFile } from './randomWords.js';
+
+export function generateCSVContent(cardList) {
+ let csvContent = "Card Name,Set,Card ID,Quantity,Foil,Mana Type,Power,Toughness,Type,Rarity\n";
+ cardList.forEach(card => {
+ const escapedValues = [
+ card.name,
+ card.set,
+ card.card_id,
+ card.quantity,
+ card.foil,
+ card.mana_cost,
+ card.power,
+ card.toughness,
+ card.type,
+ card.rarity
+ ].map(value => `"${value.replace(/"/g, '""')}"`); // Escape any existing quotes by doubling them
+ csvContent += escapedValues.join(",") + "\n";
+ });
+ return csvContent;
+}
+
+export async function downloadCSV(cardList) {
+ const csvContent = generateCSVContent(cardList);
+ const randomFileName = getRandomWordsFromFile();
+
+ // Create a blob with the CSV content
+ const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
+ const url = URL.createObjectURL(blob);
+
+ // Create a temporary link element
+ const link = document.createElement("a");
+ link.setAttribute("href", url);
+ link.setAttribute("download", `${randomFileName}.csv`);
+ document.body.appendChild(link);
+
+ // Trigger the download
+ link.click();
+
+ // Clean up and remove the link
+ document.body.removeChild(link);
+}
diff --git a/js/main.js b/js/main.js
new file mode 100644
index 0000000..2d020d3
--- /dev/null
+++ b/js/main.js
@@ -0,0 +1,93 @@
+// main.js
+
+import { addCard } from './card.js';
+import { downloadCSV } from './csv.js';
+import { saveCollection, loadCollection, clearCollection } from './storage.js';
+import { setTheme, applySavedTheme } from './theme.js';
+import { fetchCardSuggestions } from './api.js';
+
+document.addEventListener('DOMContentLoaded', () => {
+ applySavedTheme();
+
+ let cardList = loadCollection();
+
+ document.getElementById('add-card-button').addEventListener('click', () => {
+ addCard(cardList);
+ updateCSVContent(cardList);
+ });
+
+ document.getElementById('download-csv-button').addEventListener('click', () => downloadCSV(cardList));
+ document.getElementById('save-collection-button').addEventListener('click', () => saveCollection(cardList));
+
+ document.getElementById('clear-collection-button').addEventListener('click', () => {
+ if (confirm("Are you sure you want to clear your collection? This action cannot be undone.")) {
+ cardList = []; // Reset the card list
+ clearCollection(cardList);
+ updateCSVContent(cardList);
+ }
+ });
+
+ document.getElementById('card-name').addEventListener('input', async function() {
+ const query = this.value.trim();
+ if (query.length < 2) {
+ document.getElementById('suggestions').innerHTML = '';
+ return;
+ }
+ const suggestions = await fetchCardSuggestions(query);
+ const suggestionsDiv = document.getElementById('suggestions');
+ suggestionsDiv.innerHTML = '';
+
+ suggestions.forEach(suggestion => {
+ const div = document.createElement('div');
+ div.textContent = suggestion;
+ div.onclick = () => {
+ document.getElementById('card-name').value = suggestion;
+ suggestionsDiv.innerHTML = '';
+ };
+ suggestionsDiv.appendChild(div);
+ });
+ });
+
+ document.getElementById('sound-threshold').addEventListener('input', (event) => {
+ const soundThreshold = parseFloat(event.target.value);
+ localStorage.setItem('soundThreshold', soundThreshold);
+ });
+
+ document.getElementById('hamburger-menu').addEventListener('click', () => {
+ const menuContent = document.getElementById('menu-content');
+ menuContent.classList.toggle('show');
+ });
+
+ const isDarkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
+ if (isDarkMode) {
+ document.body.classList.add('dark-mode');
+ }
+});
+
+// Update the CSV content in the textarea
+function updateCSVContent(cardList) {
+ // Sort the cardList by set and then by card ID
+ cardList.sort((a, b) => {
+ if (a.set < b.set) return -1;
+ if (a.set > b.set) return 1;
+ return parseInt(a.card_id) - parseInt(b.card_id);
+ });
+
+ let csvContent = "Card Name,Set,Card ID,Quantity,Foil,Mana Type,Power,Toughness,Type,Rarity\n";
+ cardList.forEach(card => {
+ const escapedValues = [
+ card.name || '',
+ card.set || '',
+ card.card_id || '',
+ card.quantity || '',
+ card.foil || '',
+ card.mana_type || '',
+ card.power || '',
+ card.toughness || '',
+ card.type || '',
+ card.rarity || ''
+ ].map(value => `"${(value !== undefined ? value : '').replace(/"/g, '""')}"`);
+ csvContent += escapedValues.join(",") + "\n";
+ });
+ document.getElementById('csv-output').value = csvContent;
+}
diff --git a/js/menu.js b/js/menu.js
new file mode 100644
index 0000000..634f111
--- /dev/null
+++ b/js/menu.js
@@ -0,0 +1,4 @@
+export function toggleMenu() {
+ const menuContent = document.getElementById('menu-content');
+ menuContent.classList.toggle('show');
+}
diff --git a/js/popup.js b/js/popup.js
new file mode 100644
index 0000000..11e52f7
--- /dev/null
+++ b/js/popup.js
@@ -0,0 +1,40 @@
+// popup.js
+
+export async function showCardPopup(cardName, imageUrl, price) {
+ const soundThreshold = parseFloat(localStorage.getItem('soundThreshold')) || 1.00;
+ const cardPopup = document.getElementById('card-popup');
+
+ cardPopup.innerHTML = `
+
+ ${cardName}
+
+
+
+ Price: $${price}
+
+ `;
+ cardPopup.style.display = 'block';
+ cardPopup.style.opacity = 1;
+
+ // Check if the price exceeds the sound threshold and play sound
+ if (parseFloat(price) >= soundThreshold) {
+ playSound(); // Play the sound if the price exceeds the threshold
+ }
+
+ // Dissolve the popup after a few seconds
+ setTimeout(() => {
+ cardPopup.style.opacity = 0;
+ setTimeout(() => {
+ cardPopup.style.display = 'none';
+ }, 500);
+ }, 3000);
+}
+
+function playSound() {
+ const audio = new Audio('assets/cash-money.mp3');
+ audio.play().then(() => {
+ console.log('Sound played successfully');
+ }).catch(error => {
+ console.error('Error playing sound:', error);
+ });
+}
diff --git a/js/randomWords.js b/js/randomWords.js
new file mode 100644
index 0000000..db17189
--- /dev/null
+++ b/js/randomWords.js
@@ -0,0 +1,32 @@
+// randomWords.js
+
+export const randomWords = [
+ "nonstop", "detailed", "aspiring", "shock", "play", "bashful", "long", "quarter",
+ "six", "charge", "dock", "crabby", "dime", "wry", "story", "wiry", "rampant",
+ "return", "dare", "open", "shame", "many", "brush", "babies", "stem", "squeeze",
+ "judge", "heavenly", "defeated", "optimal", "invention", "object", "change",
+ "sink", "verdant", "jaded", "adjoining", "muddled", "switch", "helpless",
+ "motionless", "skirt", "shrug", "trip", "haircut", "oven", "lip", "habitual",
+ "yielding", "bag", "wheel", "attach", "ticket", "visit", "reflect", "suppose",
+ "present", "wound", "voyage", "real", "aunt", "religion", "redundant", "necessary",
+ "fail", "flower", "unpack", "join", "gamy", "tired", "welcome", "rightful", "jeans",
+ "obscene", "spring", "basket", "battle", "utter", "descriptive", "caring", "fry",
+ "resonant", "supply", "geese", "pets", "impulse", "scintillating", "tame", "release",
+ "tail", "depend", "lively", "nondescript", "punishment", "meek", "crooked",
+ "representative", "twist", "manage", "bored", "grotesque", "demonic", "camp",
+ "temporary", "coil", "passenger", "appliance", "clam", "smoggy", "tasteless", "guess",
+ "verse", "drab", "peep", "business", "paper", "female", "admire", "way", "moor",
+ "breezy", "opposite", "comparison", "tank", "suit", "ludicrous", "minister", "stiff",
+ "whine", "request", "camera", "internal", "improve", "unnatural", "decisive", "exist",
+ "grip", "electric", "bathe", "scandalous", "steer", "humdrum", "action", "rot",
+ "roll", "quartz", "amused", "sidewalk", "roll", "curve"
+];
+
+export function getRandomWordsFromFile() {
+ let randomWordsSelected = [];
+ for (let i = 0; i < 3; i++) {
+ const randomIndex = Math.floor(Math.random() * randomWords.length);
+ randomWordsSelected.push(randomWords[randomIndex]);
+ }
+ return randomWordsSelected.join('-');
+}
\ No newline at end of file
diff --git a/js/storage.js b/js/storage.js
new file mode 100644
index 0000000..3b695d4
--- /dev/null
+++ b/js/storage.js
@@ -0,0 +1,24 @@
+// storage.js
+
+export function saveCollection(cardList) {
+ localStorage.setItem('cardList', JSON.stringify(cardList));
+}
+
+export function loadCollection() {
+ const savedCollection = localStorage.getItem('cardList');
+ if (savedCollection) {
+ return JSON.parse(savedCollection);
+ }
+ return [];
+}
+
+export function updateCardDetails(cardData) {
+ const cardList = loadCollection();
+ cardList.push(cardData);
+ saveCollection(cardList);
+}
+
+export function clearCollection(cardList) {
+ cardList.length = 0; // Clear the cardList array
+ saveCollection(cardList); // Save the empty list to localStorage
+}
diff --git a/js/sw.js b/js/sw.js
new file mode 100644
index 0000000..27567c9
--- /dev/null
+++ b/js/sw.js
@@ -0,0 +1,54 @@
+// This is the service worker with the combined offline experience (Offline page + Offline copy of pages)
+
+const CACHE = "pwabuilder-offline-page";
+
+importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.1.2/workbox-sw.js');
+
+// TODO: replace the following with the correct offline fallback page i.e.: const offlineFallbackPage = "offline.html";
+const offlineFallbackPage = "ToDo-replace-this-name.html";
+
+self.addEventListener("message", (event) => {
+ if (event.data && event.data.type === "SKIP_WAITING") {
+ self.skipWaiting();
+ }
+});
+
+self.addEventListener('install', async (event) => {
+ event.waitUntil(
+ caches.open(CACHE)
+ .then((cache) => cache.add(offlineFallbackPage))
+ );
+});
+
+if (workbox.navigationPreload.isSupported()) {
+ workbox.navigationPreload.enable();
+}
+
+workbox.routing.registerRoute(
+ new RegExp('/*'),
+ new workbox.strategies.StaleWhileRevalidate({
+ cacheName: CACHE
+ })
+);
+
+self.addEventListener('fetch', (event) => {
+ if (event.request.mode === 'navigate') {
+ event.respondWith((async () => {
+ try {
+ const preloadResp = await event.preloadResponse;
+
+ if (preloadResp) {
+ return preloadResp;
+ }
+
+ const networkResp = await fetch(event.request);
+ return networkResp;
+ } catch (error) {
+
+ const cache = await caches.open(CACHE);
+ const cachedResp = await cache.match(offlineFallbackPage);
+ return cachedResp;
+ }
+ })());
+ }
+});
\ No newline at end of file
diff --git a/js/theme.js b/js/theme.js
new file mode 100644
index 0000000..d57cfa1
--- /dev/null
+++ b/js/theme.js
@@ -0,0 +1,19 @@
+export function setTheme(theme) {
+ // Remove all theme classes first
+ document.body.classList.remove('theme-white', 'theme-blue', 'theme-black', 'theme-red', 'theme-green');
+
+ // Add the selected theme class if it exists
+ if (theme) {
+ document.body.classList.add(theme);
+ }
+
+ // Save the selected theme to localStorage
+ localStorage.setItem('selectedTheme', theme);
+}
+
+export function applySavedTheme() {
+ const savedTheme = localStorage.getItem('selectedTheme');
+ if (savedTheme) {
+ setTheme(savedTheme);
+ }
+}
diff --git a/manifest.json b/manifest.json
index f45d790..09598b9 100644
--- a/manifest.json
+++ b/manifest.json
@@ -8,12 +8,12 @@
"description": "A PWA for generating CSV files with Magic: The Gathering card details",
"icons": [
{
- "src": "icon.png",
+ "src": "assets/icon.png",
"sizes": "192x192",
"type": "image/png"
},
{
- "src": "icon.png",
+ "src": "assets/icon.png",
"sizes": "512x512",
"type": "image/png"
}
diff --git a/offline.html b/offline.html
index e0db80a..3e36e2f 100644
--- a/offline.html
+++ b/offline.html
@@ -8,8 +8,7 @@
-
-
+
@@ -27,9 +26,5 @@
This app is not affiliated with Wizards of the Coast or Hasbro. All rights and trademarks are owned by their respective owners.
-
-