diff --git a/public/css/daily.css b/public/css/daily.css index c3e41c0..1d8440c 100644 --- a/public/css/daily.css +++ b/public/css/daily.css @@ -1,198 +1,208 @@ /* ============================================================ - public/css/daily.css - Daily Herausforderung – Karten-Pfad Overlay + public/css/daily.css – Daily World Map (SVG-Overlay Ansatz) ============================================================ */ +@keyframes dailyFadeIn { from{opacity:0} to{opacity:1} } +@keyframes dailyScaleIn { from{opacity:0;transform:translate(-50%,-50%) scale(.92)} to{opacity:1;transform:translate(-50%,-50%) scale(1)} } + /* ── Overlay ─────────────────────────────────────────────── */ #daily-map-overlay { position: fixed; inset: 0; z-index: 10000; - background: rgba(0, 0, 0, 0.92); + background: rgba(0,0,0,.88); display: flex; align-items: center; justify-content: center; - animation: dailyFadeIn 0.35s ease; + animation: dailyFadeIn .3s ease; } -@keyframes dailyFadeIn { from { opacity: 0; } to { opacity: 1; } } -@keyframes dailyPulse { 0%, 100% { box-shadow: 0 0 14px 4px rgba(80,160,255,0.7); } 50% { box-shadow: 0 0 28px 10px rgba(80,160,255,1); } } -@keyframes dailyGlow { 0%, 100% { opacity: 1; } 50% { opacity: 0.65; } } - /* ── Map Container ───────────────────────────────────────── */ #daily-map-wrap { position: relative; - max-width: min(95vw, 1000px); - max-height: 90vh; - border-radius: 14px; + max-width: min(96vw, 1020px); + border-radius: 16px; overflow: hidden; - box-shadow: 0 0 0 2px rgba(80, 140, 255, 0.4), 0 30px 80px rgba(0, 0, 0, 0.9); + animation: dailyScaleIn .3s cubic-bezier(.22,1,.36,1); + box-shadow: + 0 0 0 1px rgba(80,140,255,.4), + 0 0 0 3px rgba(80,140,255,.1), + 0 30px 80px rgba(0,0,0,.9); } #daily-map-img { display: block; width: 100%; height: auto; - max-height: 90vh; - object-fit: cover; user-select: none; pointer-events: none; } -/* ── Close Button ────────────────────────────────────────── */ -#daily-map-close { +/* ── SVG Overlay (liegt auf dem Bild) ────────────────────── */ +#daily-map-svg { position: absolute; - top: 12px; - right: 14px; - background: rgba(0, 0, 0, 0.7); - border: 1px solid rgba(255, 255, 255, 0.2); - border-radius: 50%; - width: 34px; - height: 34px; - display: flex; - align-items: center; - justify-content: center; - color: #fff; - font-size: 16px; - cursor: pointer; - z-index: 10; - transition: background 0.2s; + inset: 0; + width: 100%; + height: 100%; + overflow: visible; } -#daily-map-close:hover { background: rgba(200, 50, 50, 0.8); } -/* ── Title Banner ────────────────────────────────────────── */ +/* ── Stationen (SVG-Gruppen) ─────────────────────────────── */ +.ds-hit { + cursor: pointer; + fill: transparent; +} +.ds-locked .ds-hit { cursor: default; } + +/* Pfadlinie */ +.ds-path-line { + fill: none; + stroke: rgba(80,160,255,.25); + stroke-width: .7; + stroke-dasharray: 3 2.5; +} +.ds-path-line.done { + stroke: rgba(100,220,120,.4); +} + +/* Locked: dunkle Abdunklung über dem Bildkreis */ +.ds-locked .ds-overlay { + fill: rgba(0,0,5,.62); + stroke: rgba(50,60,100,.45); + stroke-width: .8; +} +.ds-locked .ds-num { + fill: rgba(120,130,160,.38); + font-family: "Cinzel", serif; + font-weight: 700; +} + +/* Available: transparente Mitte, leuchtender Rand */ +.ds-available .ds-overlay { + fill: rgba(40,100,255,.08); + stroke: rgba(100,200,255,.9); + stroke-width: 1.2; +} +.ds-available .ds-num { + fill: #fff; + font-family: "Cinzel", serif; + font-weight: 700; + filter: drop-shadow(0 0 3px rgba(180,220,255,.9)); +} +/* Pulsierender Außenring */ +.ds-available .ds-ring1 { + fill: none; + stroke: rgba(80,180,255,.65); + stroke-width: .9; +} +.ds-available .ds-ring2 { + fill: none; + stroke: rgba(80,180,255,.3); + stroke-width: .6; +} +/* Hover */ +.ds-available:hover .ds-overlay { + fill: rgba(60,130,255,.18); + stroke: rgba(150,220,255,1); + stroke-width: 1.5; +} +.ds-available:hover .ds-num { + filter: drop-shadow(0 0 6px rgba(200,240,255,1)); +} + +/* Done: grüne Einfärbung */ +.ds-done .ds-overlay { + fill: rgba(30,160,70,.35); + stroke: rgba(80,220,110,.85); + stroke-width: 1.2; +} +.ds-done .ds-check { + fill: #fff; + font-family: sans-serif; + font-weight: 700; + filter: drop-shadow(0 0 2px rgba(50,200,80,.8)); +} + +/* ── Titel ───────────────────────────────────────────────── */ #daily-map-title { position: absolute; top: 14px; left: 50%; transform: translateX(-50%); - background: rgba(0, 0, 0, 0.72); - border: 1px solid rgba(80, 140, 255, 0.45); - border-radius: 8px; - padding: 6px 22px; + background: linear-gradient(135deg, rgba(5,8,20,.9), rgba(8,12,28,.92)); + border: 1px solid rgba(80,140,255,.45); + border-radius: 20px; + padding: 7px 26px; font-family: "Cinzel", serif; - font-size: 15px; + font-size: 13px; color: #a0c8ff; - letter-spacing: 3px; + letter-spacing: 4px; white-space: nowrap; z-index: 10; + pointer-events: none; + box-shadow: 0 4px 20px rgba(0,0,0,.6); } -/* ── Circles ─────────────────────────────────────────────── */ -.daily-circle { +/* ── Schließen ───────────────────────────────────────────── */ +#daily-map-close { position: absolute; - width: 7%; /* scales with image width */ - aspect-ratio: 1; + top: 12px; right: 14px; + background: rgba(0,0,0,.65); + border: 1px solid rgba(255,255,255,.15); border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-family: "Cinzel", serif; - font-size: clamp(12px, 1.8vw, 22px); - font-weight: bold; - transform: translate(-50%, -50%); - cursor: default; - transition: transform 0.15s ease; - z-index: 5; - user-select: none; -} - -/* Completed station ─ grün */ -.daily-circle.done { - background: radial-gradient(circle at 40% 35%, #4ecf6a, #1a7a30); - border: 3px solid #7af09a; - color: #fff; - box-shadow: 0 0 14px rgba(78, 207, 106, 0.6); -} -.daily-circle.done::after { - content: "✓"; - font-size: clamp(10px, 1.5vw, 18px); -} - -/* Available station ─ blaues Pulsieren */ -.daily-circle.available { - background: radial-gradient(circle at 40% 35%, #5090ff, #1a3a9a); - border: 3px solid #90c0ff; - color: #fff; + width: 32px; height: 32px; + display: flex; align-items: center; justify-content: center; + color: rgba(255,255,255,.7); + font-size: 14px; cursor: pointer; - animation: dailyPulse 2s ease-in-out infinite; -} -.daily-circle.available:hover { - transform: translate(-50%, -50%) scale(1.15); - animation: none; - box-shadow: 0 0 30px 8px rgba(80, 160, 255, 0.9); + z-index: 20; + transition: .2s; } +#daily-map-close:hover { background: rgba(180,40,40,.8); color:#fff; } -/* Locked station ─ ausgegraut */ -.daily-circle.locked { - background: radial-gradient(circle at 40% 35%, #2a2a3a, #141420); - border: 3px solid rgba(80, 100, 150, 0.4); - color: rgba(150, 160, 200, 0.35); -} - -/* ── Progress Text ───────────────────────────────────────── */ +/* ── Progress Bar ────────────────────────────────────────── */ #daily-progress-bar-wrap { position: absolute; - bottom: 14px; - left: 50%; + bottom: 14px; left: 50%; transform: translateX(-50%); width: 60%; - background: rgba(0, 0, 0, 0.72); - border: 1px solid rgba(80, 140, 255, 0.35); - border-radius: 8px; - padding: 8px 16px; - z-index: 10; - text-align: center; - font-family: "Cinzel", serif; + background: rgba(5,8,20,.82); + border: 1px solid rgba(80,140,255,.3); + border-radius: 10px; + padding: 8px 18px 9px; + z-index: 10; pointer-events: none; } - #daily-progress-text { - font-size: 12px; - color: #a0c8ff; - letter-spacing: 1px; - margin-bottom: 5px; + font-family: "Cinzel", serif; + font-size: 11px; color: rgba(160,200,255,.8); + letter-spacing: 1px; text-align: center; margin-bottom: 6px; } - #daily-progress-track { - height: 6px; - background: rgba(80, 140, 255, 0.15); - border-radius: 3px; - overflow: hidden; + height: 5px; background: rgba(80,140,255,.12); border-radius: 3px; overflow: hidden; } - #daily-progress-fill { height: 100%; - background: linear-gradient(90deg, #3060cc, #60a0ff); - border-radius: 3px; - transition: width 0.6s ease; + background: linear-gradient(90deg, #2060dd, #60b0ff); + border-radius: 3px; transition: width .7s ease; + box-shadow: 0 0 8px rgba(80,160,255,.6); } /* ── All Done ────────────────────────────────────────────── */ #daily-all-done { - position: absolute; - inset: 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - background: rgba(0, 0, 0, 0.78); - border-radius: 14px; - z-index: 20; - animation: dailyFadeIn 0.4s ease; + position: absolute; inset: 0; + display: flex; flex-direction: column; + align-items: center; justify-content: center; + background: rgba(0,5,15,.8); border-radius: 16px; + z-index: 20; backdrop-filter: blur(4px); + animation: dailyFadeIn .4s ease; } -#daily-all-done .done-icon { font-size: 56px; margin-bottom: 14px; } -#daily-all-done .done-title { font-family: "Cinzel", serif; font-size: 22px; color: #7af09a; letter-spacing: 4px; margin-bottom: 8px; } -#daily-all-done .done-sub { font-family: "Cinzel", serif; font-size: 12px; color: #a0c8a0; margin-bottom: 24px; } +#daily-all-done .done-icon { font-size:56px; margin-bottom:16px; } +#daily-all-done .done-title { font-family:"Cinzel",serif; font-size:22px; color:#7af09a; letter-spacing:4px; margin-bottom:8px; } +#daily-all-done .done-sub { font-family:"Cinzel",serif; font-size:12px; color:#a0c8a0; margin-bottom:26px; } #daily-all-done .done-btn { - background: linear-gradient(135deg, #1a4a28, #27ae60); - border: 2px solid rgba(100, 220, 100, 0.6); - border-radius: 10px; - color: #fff; - font-family: "Cinzel", serif; - font-size: 13px; - letter-spacing: 3px; - padding: 11px 32px; - cursor: pointer; - transition: 0.2s; + background:linear-gradient(135deg,#1a4a28,#27ae60); + border:2px solid rgba(100,220,100,.6); border-radius:10px; color:#fff; + font-family:"Cinzel",serif; font-size:13px; letter-spacing:3px; + padding:11px 34px; cursor:pointer; transition:.2s; } -#daily-all-done .done-btn:hover { border-color: #7af09a; background: linear-gradient(135deg, #2a6a38, #37be70); } +#daily-all-done .done-btn:hover { border-color:#7af09a; } diff --git a/public/js/buildings/daily.js b/public/js/buildings/daily.js index 5747a38..d7d6006 100644 --- a/public/js/buildings/daily.js +++ b/public/js/buildings/daily.js @@ -1,211 +1,266 @@ /* ============================================================ public/js/buildings/daily.js - Tagesherausforderung – Karten-Pfad mit 7 Stationen gegen KI -============================================================ */ -/* ── Stationen: Position auf dem Bild (% left, % top) ───── */ -const DAILY_STATIONS = [ - { id: 1, left: 49.5, top: 86.5, label: "1" }, - { id: 2, left: 37.0, top: 73.0, label: "2" }, - { id: 3, left: 44.5, top: 62.0, label: "3" }, - { id: 4, left: 54.5, top: 53.5, label: "4" }, - { id: 5, left: 49.0, top: 46.0, label: "5" }, - { id: 6, left: 44.5, top: 37.5, label: "6" }, - { id: 7, left: 50.0, top: 22.0, label: "7" }, +/* ── Positionen (% in viewBox 0 0 100 100) ───────────────── */ +const STATIONS = [ + { id:1, cx:49.5, cy:86.5 }, + { id:2, cx:37.0, cy:73.0 }, + { id:3, cx:44.5, cy:62.0 }, + { id:4, cx:54.5, cy:53.5 }, + { id:5, cx:49.0, cy:46.0 }, + { id:6, cx:44.5, cy:37.5 }, + { id:7, cx:50.0, cy:22.0 }, ]; +const R = 4.8; // Kreis-Radius in SVG-Einheiten -let dailyDeckId = null; -let dailyOverlay = null; +let dailyDeckId = null; +let dailyOverlay = null; -/* ── Öffnet den Karten-Pfad ──────────────────────────────── */ +/* ── Karten-Pfad öffnen ──────────────────────────────────── */ export async function openDailyMap(deckId) { dailyDeckId = deckId; + document.getElementById('daily-map-overlay')?.remove(); - // Kein Duplikat - document.getElementById("daily-map-overlay")?.remove(); - - /* Fortschritt vom Server laden */ let completed = []; try { - const res = await fetch("/api/himmelstor/daily/progress"); - if (res.ok) { - const data = await res.json(); - completed = data.completed ?? []; - } - } catch (e) { console.error("[Daily] Fortschritt laden:", e); } + const r = await fetch('/api/himmelstor/daily/progress'); + if (r.ok) completed = (await r.json()).completed ?? []; + } catch {} - /* Overlay aufbauen */ - dailyOverlay = document.createElement("div"); - dailyOverlay.id = "daily-map-overlay"; + dailyOverlay = document.createElement('div'); + dailyOverlay.id = 'daily-map-overlay'; dailyOverlay.innerHTML = `
+
+
+ ${buildSvg(completed)}
+