diff --git a/ui/coach.css b/ui/coach.css
index 98ac8b3..535f096 100644
--- a/ui/coach.css
+++ b/ui/coach.css
@@ -1113,3 +1113,26 @@
flex: 1;
}
}
+
+/* ── Scryfall Card Hover Preview ──────────────────────────────────────── */
+#coach-card-preview {
+ position: fixed;
+ z-index: 9999;
+ pointer-events: none;
+ background: var(--bg-card, #1e1e2e);
+ border: 1px solid var(--border, #444);
+ border-radius: 12px;
+ padding: 4px;
+ box-shadow: 0 8px 32px rgba(0,0,0,.6);
+ transition: opacity .15s ease;
+}
+#coach-card-preview img {
+ display: block;
+ width: 240px;
+ height: auto;
+ border-radius: 10px;
+}
+td[data-card-name] .coach-card-name {
+ cursor: pointer;
+ border-bottom: 1px dashed var(--text-secondary, #888);
+}
diff --git a/ui/coach.js b/ui/coach.js
index ee5ad96..b177878 100644
--- a/ui/coach.js
+++ b/ui/coach.js
@@ -18,6 +18,58 @@
let expandedSessions = {}; // sessionId → bool
let dbDecks = []; // [{id, name}] from /api/decks
+ // ── Scryfall Card Hover Preview ─────────────────────────
+ const _scryfallImgCache = {};
+ let _previewEl = null;
+
+ function _ensurePreviewEl() {
+ if (_previewEl) return _previewEl;
+ _previewEl = document.createElement('div');
+ _previewEl.id = 'coach-card-preview';
+ _previewEl.style.display = 'none';
+ _previewEl.innerHTML = '';
+ document.body.appendChild(_previewEl);
+ return _previewEl;
+ }
+
+ function _showCardPreview(cardName, evt) {
+ const el = _ensurePreviewEl();
+ const img = el.querySelector('img');
+ if (_scryfallImgCache[cardName]) {
+ img.src = _scryfallImgCache[cardName];
+ } else {
+ img.src = '';
+ fetch('https://api.scryfall.com/cards/named?fuzzy=' + encodeURIComponent(cardName))
+ .then(r => r.ok ? r.json() : null)
+ .then(data => {
+ if (!data) return;
+ const url = (data.image_uris && data.image_uris.normal) || (data.card_faces && data.card_faces[0] && data.card_faces[0].image_uris && data.card_faces[0].image_uris.normal) || '';
+ _scryfallImgCache[cardName] = url;
+ if (el.style.display !== 'none') img.src = url;
+ }).catch(() => {});
+ }
+ el.style.display = 'block';
+ _positionPreview(evt);
+ }
+
+ function _positionPreview(evt) {
+ if (!_previewEl) return;
+ _previewEl.style.left = Math.max(0, Math.min(evt.clientX + 20, window.innerWidth - 260)) + 'px';
+ _previewEl.style.top = Math.max(0, Math.min(evt.clientY - 150, window.innerHeight - 370)) + 'px';
+ }
+
+ function _hideCardPreview() {
+ if (_previewEl) _previewEl.style.display = 'none';
+ }
+
+ function _attachCardHover(container) {
+ container.querySelectorAll('td[data-card-name]').forEach(td => {
+ td.addEventListener('mouseenter', e => _showCardPreview(td.dataset.cardName, e));
+ td.addEventListener('mousemove', e => _positionPreview(e));
+ td.addEventListener('mouseleave', _hideCardPreview);
+ });
+ }
+
// ── DOM References ──────────────────────────────────────
const deckSelect = document.getElementById('coach-deck-select');
const powerSlider = document.getElementById('coach-power-level');
@@ -551,6 +603,7 @@
).join('') +
'' +
'