From fe24adf9512eb03e8dc685d2d827db78b0573122 Mon Sep 17 00:00:00 2001 From: Claude Code Date: Sat, 7 Mar 2026 17:11:26 +0100 Subject: [PATCH] Lagebild: Quellen-Tab als Tile-Grid mit Aufklapp-Detail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Quellen werden als 6-Spalten-Kachel-Grid dargestellt (wie im echten Monitor) - Jede Kachel zeigt Favicon, Quellenname, Sprache und Artikelanzahl - Klick auf Kachel öffnet Detail-Panel mit allen Artikeln dieser Quelle - Nur eine Quelle gleichzeitig offen, Panel erscheint unter der Kachel-Reihe - Gold-Glow Hover-Effekte, Slide-In Animation - Responsive: 6 Spalten Desktop, 4 Tablet, 2 Mobile - Live-Feed: Quellen-Zeile entfernt Co-Authored-By: Claude Opus 4.6 --- lagebild/index.html | 13 +- lagebild/lagebild.css | 2707 +++++++++++++++++++++-------------------- lagebild/lagebild.js | 1807 ++++++++++++++------------- 3 files changed, 2353 insertions(+), 2174 deletions(-) diff --git a/lagebild/index.html b/lagebild/index.html index d7d24d3..1437d3a 100644 --- a/lagebild/index.html +++ b/lagebild/index.html @@ -114,13 +114,14 @@
-

Quellen & Quellenberichte

-

Alle vom AegisSight Monitor aggregierten Quellen und Artikel

+

Quellen

+

Alle vom AegisSight Monitor überwachten Quellen

-
-
-

Alle Artikel

-
+
+
+
+
+
diff --git a/lagebild/lagebild.css b/lagebild/lagebild.css index 73e7fe0..e086559 100644 --- a/lagebild/lagebild.css +++ b/lagebild/lagebild.css @@ -1,1317 +1,1392 @@ -/* ========================================================================== - AegisSight Lagebild Page - Dark Theme Design Refresh - ========================================================================== */ - -/* ---------- Variables ---------- */ -.lagebild-page { - --lb-bg: #0B1121; - --lb-bg-card: #151D2E; - --lb-bg-secondary: #1A2440; - --lb-border: #1E2D45; - --lb-text: #E8ECF4; - --lb-text-sec: #8896AB; - --lb-accent: #C8A851; - --lb-accent-hover: #B5923E; - --lb-success: #10B981; - --lb-warning: #F59E0B; - --lb-error: #EF4444; - --lb-glow: rgba(200, 168, 81, 0.35); - --lb-glow-soft: rgba(200, 168, 81, 0.15); -} - -/* ---------- Page Base ---------- */ -.lagebild-page { - background: var(--lb-bg); - min-height: 100vh; - color: var(--lb-text); -} - -/* ---------- Scroll Progress Bar ---------- */ -.scroll-progress { - position: fixed; - top: 0; - left: 0; - height: 3px; - width: 0; - background: linear-gradient(90deg, var(--lb-accent), #E8D48B); - z-index: 99999; - transition: width 0.08s linear; - box-shadow: 0 0 10px var(--lb-glow), 0 0 3px var(--lb-accent); -} - -/* ---------- Navigation Dark Override ---------- */ -.lagebild-page .navbar { - background: rgba(11, 17, 33, 0.95) !important; - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - border-bottom: 1px solid var(--lb-border) !important; - box-shadow: none !important; -} -.lagebild-page .logo-img { - background: rgba(160, 175, 200, 0.85); - padding: 4px 10px; - border-radius: 6px; -} -.lagebild-page .nav-menu a { - color: var(--lb-text) !important; -} -.lagebild-page .nav-menu a:hover { - color: var(--lb-accent) !important; -} -.lagebild-page .nav-menu a.nav-active { - color: var(--lb-accent) !important; -} -.lagebild-page .lang-toggle { - color: var(--lb-text-sec) !important; - border-color: var(--lb-border) !important; -} -.lagebild-page .lang-toggle:hover { - color: var(--lb-accent) !important; - border-color: var(--lb-accent) !important; -} -.lagebild-page .hamburger span { - background: var(--lb-text) !important; -} - -/* ---------- Footer Dark Override ---------- */ -.lagebild-page .footer { - background: #080D1A !important; - border-top: 1px solid var(--lb-border); -} -.lagebild-page .footer h4 { - color: var(--lb-accent) !important; -} -.lagebild-page .footer p, -.lagebild-page .footer a, -.lagebild-page .footer li, -.lagebild-page .footer ul li a { - color: var(--lb-text-sec) !important; -} -.lagebild-page .footer a:hover { - color: var(--lb-accent) !important; -} -.lagebild-page .copyright { - color: var(--lb-text-sec) !important; - opacity: 0.5; -} - -/* ---------- Hero Section ---------- */ -.lagebild-hero { - background: linear-gradient(135deg, #0a0f1c 0%, #111B30 50%, #0B1121 100%); - padding: 150px 20px 70px; - text-align: center; - color: #fff; - position: relative; - overflow: hidden; -} -.hero-bg-pattern { - position: absolute; - inset: 0; - background: - radial-gradient(circle at 20% 80%, rgba(200, 168, 81, 0.08) 0%, transparent 50%), - radial-gradient(circle at 80% 20%, rgba(200, 168, 81, 0.05) 0%, transparent 50%), - radial-gradient(circle at 50% 50%, rgba(15, 114, 181, 0.06) 0%, transparent 60%); - pointer-events: none; -} -.lagebild-hero .container { - position: relative; - z-index: 1; -} - -/* Hero Particles Canvas */ -#hero-particles { - position: absolute; - inset: 0; - width: 100%; - height: 100%; - z-index: 0; - pointer-events: none; -} - -/* Hero Badge */ -.hero-badge { - display: inline-flex; - align-items: center; - gap: 8px; - background: rgba(200, 168, 81, 0.12); - border: 1px solid rgba(200, 168, 81, 0.25); - padding: 6px 16px; - border-radius: 20px; - font-size: 0.8rem; - font-weight: 600; - letter-spacing: 1.5px; - color: var(--lb-accent); - margin-bottom: 1.5rem; - box-shadow: 0 0 20px var(--lb-glow-soft); -} -.badge-dot { - width: 8px; - height: 8px; - background: var(--lb-accent); - border-radius: 50%; - animation: pulse-dot 2s infinite; - box-shadow: 0 0 8px var(--lb-glow); -} -@keyframes pulse-dot { - 0%, 100% { opacity: 1; transform: scale(1); } - 50% { opacity: 0.4; transform: scale(0.7); } -} - -/* Hero Title */ -.lagebild-hero h1 { - font-family: 'Bebas Neue', sans-serif; - font-size: 3.5rem; - letter-spacing: 5px; - color: #fff; - margin: 0 0 0.3rem; - line-height: 1; -} -.hero-incident-title { - font-size: 1.5rem; - font-weight: 300; - color: rgba(255, 255, 255, 0.85); - margin: 0 0 0.5rem; -} -.hero-date-info { - font-size: 0.85em; - color: rgba(255, 255, 255, 0.5); - font-weight: 400; -} - -/* Hero Stat Cards */ -.hero-stats { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 14px; - margin-top: 2rem; - max-width: 650px; - margin-left: auto; - margin-right: auto; -} -.stat-card { - display: flex; - align-items: center; - gap: 12px; - background: rgba(255, 255, 255, 0.05); - border: 1px solid rgba(255, 255, 255, 0.08); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); - padding: 14px 16px; - border-radius: var(--radius-md, 8px); - transition: border-color 0.3s, background 0.3s, box-shadow 0.3s; -} -.stat-card:hover { - border-color: rgba(200, 168, 81, 0.4); - background: rgba(255, 255, 255, 0.08); - box-shadow: 0 0 24px var(--lb-glow-soft), 0 4px 16px rgba(0, 0, 0, 0.2); -} -.stat-card-icon { - width: 36px; - height: 36px; - display: flex; - align-items: center; - justify-content: center; - background: rgba(200, 168, 81, 0.1); - border-radius: var(--radius-md, 8px); - color: var(--lb-accent); - flex-shrink: 0; -} -.stat-card-icon svg { - width: 18px; - height: 18px; -} -.stat-card-content { - min-width: 0; -} -.stat-card-value { - display: block; - font-size: 1.35rem; - font-weight: 700; - color: #fff; - line-height: 1.1; -} -.stat-card-label { - display: block; - font-size: 0.72rem; - color: rgba(255, 255, 255, 0.55); - text-transform: uppercase; - letter-spacing: 0.5px; - margin-top: 2px; -} - -/* ---------- Live Feed Ticker ---------- */ -.live-feed { - margin-top: 1.5rem; - height: 28px; - overflow: hidden; - position: relative; -} -.live-feed-item { - position: absolute; - width: 100%; - text-align: center; - font-size: 0.82rem; - color: rgba(255, 255, 255, 0.5); - letter-spacing: 0.3px; - display: flex; - align-items: center; - justify-content: center; - gap: 8px; - opacity: 0; - transform: translateY(10px); - transition: opacity 0.5s, transform 0.5s; -} -.live-feed-item.active { - opacity: 1; - transform: translateY(0); -} -.live-feed-dot { - width: 6px; - height: 6px; - border-radius: 50%; - background: var(--lb-accent); - box-shadow: 0 0 6px var(--lb-glow); - animation: pulse-dot 2s infinite; - flex-shrink: 0; -} - -/* ---------- Control Bar ---------- */ -.control-bar { - background: var(--lb-bg-card); - border-bottom: 1px solid var(--lb-border); - padding: 0 20px; -} -.control-bar .container { - max-width: 1000px; - margin: 0 auto; -} - -/* Timeline Strip */ -.timeline-wrapper { - padding: 12px 0; - border-bottom: 1px solid var(--lb-border); -} -.timeline-strip { - display: flex; - gap: 4px; - overflow-x: auto; - scroll-behavior: smooth; - padding: 4px 0; - scrollbar-width: thin; - scrollbar-color: var(--lb-border) transparent; -} -.timeline-strip::-webkit-scrollbar { - height: 4px; -} -.timeline-strip::-webkit-scrollbar-track { - background: transparent; -} -.timeline-strip::-webkit-scrollbar-thumb { - background: var(--lb-border); - border-radius: 2px; -} -.timeline-day { - display: flex; - flex-direction: column; - align-items: center; - padding: 8px 14px; - border-radius: var(--radius-sm, 4px); - border: 1px solid var(--lb-border); - background: transparent; - cursor: pointer; - transition: all 0.2s; - flex-shrink: 0; - min-width: 64px; - position: relative; - color: var(--lb-text-sec); - font-family: inherit; -} -.timeline-day:hover { - background: var(--lb-bg-secondary); - border-color: rgba(200, 168, 81, 0.4); -} -.timeline-day.active { - background: rgba(200, 168, 81, 0.1); - border-color: var(--lb-accent); - box-shadow: 0 0 12px var(--lb-glow-soft); -} -.timeline-dot { - position: absolute; - top: -4px; - right: -4px; - width: 10px; - height: 10px; - background: var(--lb-accent); - border-radius: 50%; - animation: pulse-dot 2s infinite; - border: 2px solid var(--lb-bg-card); - box-shadow: 0 0 8px var(--lb-glow); -} -.timeline-day-num { - font-size: 1.1rem; - font-weight: 700; - line-height: 1; -} -.timeline-day.active .timeline-day-num { - color: var(--lb-accent); -} -.timeline-day-month { - font-size: 0.62rem; - text-transform: uppercase; - letter-spacing: 0.5px; - opacity: 0.7; - margin-top: 1px; -} -.timeline-day-count { - font-size: 0.68rem; - margin-top: 4px; - padding-top: 4px; - border-top: 1px solid var(--lb-border); - width: 100%; - text-align: center; - opacity: 0.6; -} -.timeline-day.active .timeline-day-count { - opacity: 1; - color: var(--lb-accent); -} -.timeline-day-updates { - font-size: 0.58rem; - opacity: 0.4; -} -.timeline-day-label { - font-size: 0.58rem; - color: var(--lb-accent); - font-weight: 600; - margin-top: 2px; -} - -/* Timeline Dropdown */ -.timeline-dropdown { - display: none; - background: var(--lb-bg-secondary); - border: 1px solid var(--lb-border); - border-top: none; - border-radius: 0 0 var(--radius-sm, 4px) var(--radius-sm, 4px); - padding: 10px 14px; - margin-top: 4px; -} -.timeline-dropdown.open { - display: block; -} -.timeline-dropdown-header { - font-size: 0.78rem; - color: var(--lb-text-sec); - margin-bottom: 8px; - font-weight: 500; -} -.timeline-snap-list { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); - gap: 6px; -} -.timeline-snap-item { - display: inline-flex; - align-items: center; - gap: 8px; - padding: 6px 12px; - border-radius: var(--radius-sm, 4px); - border: 1px solid var(--lb-border); - background: transparent; - color: var(--lb-text-sec); - font-size: 0.78rem; - cursor: pointer; - font-family: inherit; - transition: all 0.2s; -} -.timeline-snap-item:hover { - background: var(--lb-bg-card); - border-color: rgba(200, 168, 81, 0.4); - color: var(--lb-text); -} -.timeline-snap-item.active { - background: rgba(200, 168, 81, 0.1); - border-color: var(--lb-accent); - color: var(--lb-accent); -} -.timeline-snap-time { - font-weight: 600; -} -.timeline-snap-meta { - font-size: 0.7rem; - opacity: 0.7; -} - -/* Tab Navigation */ +/* ========================================================================== + AegisSight Lagebild Page - Dark Theme Design Refresh + ========================================================================== */ + +/* ---------- Variables ---------- */ +.lagebild-page { + --lb-bg: #0B1121; + --lb-bg-card: #151D2E; + --lb-bg-secondary: #1A2440; + --lb-border: #1E2D45; + --lb-text: #E8ECF4; + --lb-text-sec: #8896AB; + --lb-accent: #C8A851; + --lb-accent-hover: #B5923E; + --lb-success: #10B981; + --lb-warning: #F59E0B; + --lb-error: #EF4444; + --lb-glow: rgba(200, 168, 81, 0.35); + --lb-glow-soft: rgba(200, 168, 81, 0.15); +} + +/* ---------- Page Base ---------- */ +.lagebild-page { + background: var(--lb-bg); + min-height: 100vh; + color: var(--lb-text); +} + +/* ---------- Scroll Progress Bar ---------- */ +.scroll-progress { + position: fixed; + top: 0; + left: 0; + height: 3px; + width: 0; + background: linear-gradient(90deg, var(--lb-accent), #E8D48B); + z-index: 99999; + transition: width 0.08s linear; + box-shadow: 0 0 10px var(--lb-glow), 0 0 3px var(--lb-accent); +} + +/* ---------- Navigation Dark Override ---------- */ +.lagebild-page .navbar { + background: rgba(11, 17, 33, 0.95) !important; + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-bottom: 1px solid var(--lb-border) !important; + box-shadow: none !important; +} +.lagebild-page .logo-img { + background: rgba(160, 175, 200, 0.85); + padding: 4px 10px; + border-radius: 6px; +} +.lagebild-page .nav-menu a { + color: var(--lb-text) !important; +} +.lagebild-page .nav-menu a:hover { + color: var(--lb-accent) !important; +} +.lagebild-page .nav-menu a.nav-active { + color: var(--lb-accent) !important; +} +.lagebild-page .lang-toggle { + color: var(--lb-text-sec) !important; + border-color: var(--lb-border) !important; +} +.lagebild-page .lang-toggle:hover { + color: var(--lb-accent) !important; + border-color: var(--lb-accent) !important; +} +.lagebild-page .hamburger span { + background: var(--lb-text) !important; +} + +/* ---------- Footer Dark Override ---------- */ +.lagebild-page .footer { + background: #080D1A !important; + border-top: 1px solid var(--lb-border); +} +.lagebild-page .footer h4 { + color: var(--lb-accent) !important; +} +.lagebild-page .footer p, +.lagebild-page .footer a, +.lagebild-page .footer li, +.lagebild-page .footer ul li a { + color: var(--lb-text-sec) !important; +} +.lagebild-page .footer a:hover { + color: var(--lb-accent) !important; +} +.lagebild-page .copyright { + color: var(--lb-text-sec) !important; + opacity: 0.5; +} + +/* ---------- Hero Section ---------- */ +.lagebild-hero { + background: linear-gradient(135deg, #0a0f1c 0%, #111B30 50%, #0B1121 100%); + padding: 150px 20px 70px; + text-align: center; + color: #fff; + position: relative; + overflow: hidden; +} +.hero-bg-pattern { + position: absolute; + inset: 0; + background: + radial-gradient(circle at 20% 80%, rgba(200, 168, 81, 0.08) 0%, transparent 50%), + radial-gradient(circle at 80% 20%, rgba(200, 168, 81, 0.05) 0%, transparent 50%), + radial-gradient(circle at 50% 50%, rgba(15, 114, 181, 0.06) 0%, transparent 60%); + pointer-events: none; +} +.lagebild-hero .container { + position: relative; + z-index: 1; +} + +/* Hero Particles Canvas */ +#hero-particles { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + z-index: 0; + pointer-events: none; +} + +/* Hero Badge */ +.hero-badge { + display: inline-flex; + align-items: center; + gap: 8px; + background: rgba(200, 168, 81, 0.12); + border: 1px solid rgba(200, 168, 81, 0.25); + padding: 6px 16px; + border-radius: 20px; + font-size: 0.8rem; + font-weight: 600; + letter-spacing: 1.5px; + color: var(--lb-accent); + margin-bottom: 1.5rem; + box-shadow: 0 0 20px var(--lb-glow-soft); +} +.badge-dot { + width: 8px; + height: 8px; + background: var(--lb-accent); + border-radius: 50%; + animation: pulse-dot 2s infinite; + box-shadow: 0 0 8px var(--lb-glow); +} +@keyframes pulse-dot { + 0%, 100% { opacity: 1; transform: scale(1); } + 50% { opacity: 0.4; transform: scale(0.7); } +} + +/* Hero Title */ +.lagebild-hero h1 { + font-family: 'Bebas Neue', sans-serif; + font-size: 3.5rem; + letter-spacing: 5px; + color: #fff; + margin: 0 0 0.3rem; + line-height: 1; +} +.hero-incident-title { + font-size: 1.5rem; + font-weight: 300; + color: rgba(255, 255, 255, 0.85); + margin: 0 0 0.5rem; +} +.hero-date-info { + font-size: 0.85em; + color: rgba(255, 255, 255, 0.5); + font-weight: 400; +} + +/* Hero Stat Cards */ +.hero-stats { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 14px; + margin-top: 2rem; + max-width: 650px; + margin-left: auto; + margin-right: auto; +} +.stat-card { + display: flex; + align-items: center; + gap: 12px; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.08); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + padding: 14px 16px; + border-radius: var(--radius-md, 8px); + transition: border-color 0.3s, background 0.3s, box-shadow 0.3s; +} +.stat-card:hover { + border-color: rgba(200, 168, 81, 0.4); + background: rgba(255, 255, 255, 0.08); + box-shadow: 0 0 24px var(--lb-glow-soft), 0 4px 16px rgba(0, 0, 0, 0.2); +} +.stat-card-icon { + width: 36px; + height: 36px; + display: flex; + align-items: center; + justify-content: center; + background: rgba(200, 168, 81, 0.1); + border-radius: var(--radius-md, 8px); + color: var(--lb-accent); + flex-shrink: 0; +} +.stat-card-icon svg { + width: 18px; + height: 18px; +} +.stat-card-content { + min-width: 0; +} +.stat-card-value { + display: block; + font-size: 1.35rem; + font-weight: 700; + color: #fff; + line-height: 1.1; +} +.stat-card-label { + display: block; + font-size: 0.72rem; + color: rgba(255, 255, 255, 0.55); + text-transform: uppercase; + letter-spacing: 0.5px; + margin-top: 2px; +} + +/* ---------- Live Feed Ticker ---------- */ +.live-feed { + margin-top: 1.5rem; + height: 28px; + overflow: hidden; + position: relative; +} +.live-feed-item { + position: absolute; + width: 100%; + text-align: center; + font-size: 0.82rem; + color: rgba(255, 255, 255, 0.5); + letter-spacing: 0.3px; + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + opacity: 0; + transform: translateY(10px); + transition: opacity 0.5s, transform 0.5s; +} +.live-feed-item.active { + opacity: 1; + transform: translateY(0); +} +.live-feed-dot { + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--lb-accent); + box-shadow: 0 0 6px var(--lb-glow); + animation: pulse-dot 2s infinite; + flex-shrink: 0; +} + +/* ---------- Control Bar ---------- */ +.control-bar { + background: var(--lb-bg-card); + border-bottom: 1px solid var(--lb-border); + padding: 0 20px; +} +.control-bar .container { + max-width: 1000px; + margin: 0 auto; +} + +/* Timeline Strip */ +.timeline-wrapper { + padding: 12px 0; + border-bottom: 1px solid var(--lb-border); +} +.timeline-strip { + display: flex; + gap: 4px; + overflow-x: auto; + scroll-behavior: smooth; + padding: 4px 0; + scrollbar-width: thin; + scrollbar-color: var(--lb-border) transparent; +} +.timeline-strip::-webkit-scrollbar { + height: 4px; +} +.timeline-strip::-webkit-scrollbar-track { + background: transparent; +} +.timeline-strip::-webkit-scrollbar-thumb { + background: var(--lb-border); + border-radius: 2px; +} +.timeline-day { + display: flex; + flex-direction: column; + align-items: center; + padding: 8px 14px; + border-radius: var(--radius-sm, 4px); + border: 1px solid var(--lb-border); + background: transparent; + cursor: pointer; + transition: all 0.2s; + flex-shrink: 0; + min-width: 64px; + position: relative; + color: var(--lb-text-sec); + font-family: inherit; +} +.timeline-day:hover { + background: var(--lb-bg-secondary); + border-color: rgba(200, 168, 81, 0.4); +} +.timeline-day.active { + background: rgba(200, 168, 81, 0.1); + border-color: var(--lb-accent); + box-shadow: 0 0 12px var(--lb-glow-soft); +} +.timeline-dot { + position: absolute; + top: -4px; + right: -4px; + width: 10px; + height: 10px; + background: var(--lb-accent); + border-radius: 50%; + animation: pulse-dot 2s infinite; + border: 2px solid var(--lb-bg-card); + box-shadow: 0 0 8px var(--lb-glow); +} +.timeline-day-num { + font-size: 1.1rem; + font-weight: 700; + line-height: 1; +} +.timeline-day.active .timeline-day-num { + color: var(--lb-accent); +} +.timeline-day-month { + font-size: 0.62rem; + text-transform: uppercase; + letter-spacing: 0.5px; + opacity: 0.7; + margin-top: 1px; +} +.timeline-day-count { + font-size: 0.68rem; + margin-top: 4px; + padding-top: 4px; + border-top: 1px solid var(--lb-border); + width: 100%; + text-align: center; + opacity: 0.6; +} +.timeline-day.active .timeline-day-count { + opacity: 1; + color: var(--lb-accent); +} +.timeline-day-updates { + font-size: 0.58rem; + opacity: 0.4; +} +.timeline-day-label { + font-size: 0.58rem; + color: var(--lb-accent); + font-weight: 600; + margin-top: 2px; +} + +/* Timeline Dropdown */ +.timeline-dropdown { + display: none; + background: var(--lb-bg-secondary); + border: 1px solid var(--lb-border); + border-top: none; + border-radius: 0 0 var(--radius-sm, 4px) var(--radius-sm, 4px); + padding: 10px 14px; + margin-top: 4px; +} +.timeline-dropdown.open { + display: block; +} +.timeline-dropdown-header { + font-size: 0.78rem; + color: var(--lb-text-sec); + margin-bottom: 8px; + font-weight: 500; +} +.timeline-snap-list { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); + gap: 6px; +} +.timeline-snap-item { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 6px 12px; + border-radius: var(--radius-sm, 4px); + border: 1px solid var(--lb-border); + background: transparent; + color: var(--lb-text-sec); + font-size: 0.78rem; + cursor: pointer; + font-family: inherit; + transition: all 0.2s; +} +.timeline-snap-item:hover { + background: var(--lb-bg-card); + border-color: rgba(200, 168, 81, 0.4); + color: var(--lb-text); +} +.timeline-snap-item.active { + background: rgba(200, 168, 81, 0.1); + border-color: var(--lb-accent); + color: var(--lb-accent); +} +.timeline-snap-time { + font-weight: 600; +} +.timeline-snap-meta { + font-size: 0.7rem; + opacity: 0.7; +} + +/* Tab Navigation */ .tab-nav { - justify-content: center; - display: flex; - gap: 0; -} -.tab-btn { - padding: 12px 20px; - border: none; - background: transparent; - cursor: pointer; - font-size: 0.9rem; - font-weight: 600; - color: var(--lb-text-sec); - border-bottom: 3px solid transparent; - transition: all 0.2s; - font-family: inherit; -} -.tab-btn:hover { - color: var(--lb-text); - text-shadow: 0 0 12px var(--lb-glow-soft); -} -.tab-btn.active { - color: var(--lb-accent); - border-bottom-color: var(--lb-accent); - text-shadow: 0 0 16px var(--lb-glow-soft); -} -.tab-badge { - display: inline-block; - background: rgba(200, 168, 81, 0.12); - color: var(--lb-accent); - padding: 1px 8px; - border-radius: 10px; - font-size: 0.7rem; - font-weight: 600; - margin-left: 4px; - vertical-align: middle; -} -.tab-btn.active .tab-badge { - background: rgba(200, 168, 81, 0.22); -} - -/* Tab Panels with Slide Animation */ -.tab-panel { display: none; } -.tab-panel.active { - display: block; - animation: tabFadeSlideIn 0.35s ease-out; -} -@keyframes tabFadeSlideIn { - from { opacity: 0; transform: translateY(12px); } - to { opacity: 1; transform: translateY(0); } -} - -/* ---------- Main Content ---------- */ -.lagebild-main { - padding: 2rem 20px 4rem; -} -.lagebild-main .container { - max-width: 1000px; - margin: 0 auto; -} - -/* ---------- Content Cards ---------- */ -.content-card { - background: var(--lb-bg-card); - border-radius: var(--radius-sm, 4px); - border: 1px solid var(--lb-border); - margin-bottom: 1.5rem; - overflow: hidden; - position: relative; -} -.content-card::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 3px; - background: var(--lb-accent); - box-shadow: 0 2px 12px var(--lb-glow-soft); -} -.card-header { - padding: 24px 32px 0; - display: flex; - justify-content: space-between; - align-items: baseline; - flex-wrap: wrap; - gap: 8px; -} -.card-header h2 { - font-size: 1.3rem; - font-weight: 700; - color: var(--lb-text); - margin: 0; -} -.card-timestamp { - font-size: 0.85rem; - color: var(--lb-text-sec); - font-weight: 500; -} -.card-description { - font-size: 0.85rem; - color: var(--lb-text-sec); - margin: 4px 0 0; - width: 100%; -} -.card-body { - padding: 20px 32px 28px; -} -.card-footer { - padding: 0 32px 28px; - border-top: 1px solid var(--lb-border); - padding-top: 20px; - margin: 0 32px; -} - -/* ---------- Lagebild Summary ---------- */ -#summary-content { - line-height: 1.85; - font-size: 1.02rem; - color: var(--lb-text); -} -#summary-content h2 { - font-size: 1.15rem; - font-weight: 700; - color: var(--lb-accent); - margin: 1.8rem 0 0.8rem; - padding-bottom: 0.4rem; - border-bottom: 2px solid var(--lb-border); -} -#summary-content h2:first-child { - margin-top: 0; -} -#summary-content h3 { - font-size: 1.05rem; - font-weight: 600; - color: var(--lb-text); - margin: 1.5rem 0 0.6rem; -} -#summary-content p { - margin: 0 0 1rem; -} -#summary-content ul { - margin: 0 0 1rem; - padding-left: 1.5rem; -} -#summary-content li { - margin-bottom: 0.4rem; - color: var(--lb-text); -} -#summary-content strong { - color: #fff; -} - -/* Citations */ -.citation-ref { - color: var(--lb-accent); - font-weight: 700; - cursor: pointer; - text-decoration: none; - font-size: 0.78em; - vertical-align: super; - line-height: 1; - padding: 0 1px; - transition: color 0.2s; -} -.citation-ref:hover { - color: var(--lb-accent-hover); - text-decoration: underline; -} - -/* Source Highlight (smooth scroll target) */ -.source-highlight { - background: rgba(200, 168, 81, 0.15) !important; - border-radius: 4px; - transition: background 1.5s ease-out; -} - -/* Sources List */ -.sources-section h3 { - font-size: 1.1rem; - font-weight: 700; - color: var(--lb-text); - margin: 0 0 12px; -} -.section-subtitle { - font-size: 1.1rem; - font-weight: 700; - color: var(--lb-text); - margin: 2rem 0 12px; - padding-top: 1.5rem; - border-top: 1px solid var(--lb-border); -} -.sources-list { - list-style: none; - padding: 0; - margin: 0; - counter-reset: src; - columns: 2; - column-gap: 24px; -} -.sources-list li { - counter-increment: src; - padding: 4px 0; - font-size: 0.88rem; - color: var(--lb-text); - break-inside: avoid; -} -.sources-list li::before { - content: "[" counter(src) "]"; - color: var(--lb-accent); - font-weight: 700; - font-size: 0.82rem; - margin-right: 6px; -} -.sources-list a { - color: var(--lb-accent); - text-decoration: none; -} -.sources-list a:hover { text-decoration: underline; } -.source-name { - font-weight: 600; - color: var(--lb-text); -} - -/* Inline sources (Lagebild tab footer) - Collapsible */ -.inline-sources-toggle { - display: inline-flex; - align-items: center; - gap: 8px; - font-size: 0.9rem; - font-weight: 600; - color: var(--lb-text-sec); - cursor: pointer; - padding: 10px 16px; - user-select: none; - transition: all 0.2s; - background: var(--lb-bg-secondary); - border: 1px solid var(--lb-border); - border-radius: var(--radius-sm, 4px); -} -.inline-sources-toggle:hover { - color: var(--lb-accent); - border-color: rgba(200, 168, 81, 0.4); - background: rgba(200, 168, 81, 0.06); -} -.inline-sources-arrow { - display: inline-flex; - align-items: center; - justify-content: center; - width: 20px; - height: 20px; - font-size: 1.1rem; - transition: transform 0.2s; - color: var(--lb-accent); -} -#inline-sources.open .inline-sources-arrow { - transform: rotate(90deg); -} -.inline-sources-body { - display: none; - padding: 8px 0 0; - font-size: 0.82rem; - line-height: 1.8; - color: var(--lb-text-sec); -} -#inline-sources.open .inline-sources-body { - display: block; -} -.src-inline .src-nr { - color: var(--lb-accent); - font-weight: 700; -} -.src-sep { - color: var(--lb-border); - margin: 0 2px; -} -.inline-sources-body a { - color: var(--lb-accent); - text-decoration: none; -} -.inline-sources-body a:hover { - text-decoration: underline; -} - -/* ---------- Article Cards ---------- */ -.article-card { - display: flex; - gap: 16px; - padding: 16px 0; - border-bottom: 1px solid var(--lb-border); -} -.article-card:last-child { border-bottom: none; } -.article-date { - flex-shrink: 0; - width: 60px; - text-align: center; -} -.article-date .day { - display: block; - font-size: 1.3rem; - font-weight: 700; - color: var(--lb-accent); - line-height: 1; -} -.article-date .month { - display: block; - font-size: 0.72rem; - color: var(--lb-text-sec); - text-transform: uppercase; - letter-spacing: 0.5px; -} -.article-info { - flex: 1; - min-width: 0; -} -.article-headline { - font-size: 0.95rem; - font-weight: 600; - color: var(--lb-text); - margin: 0 0 6px; - line-height: 1.4; -} -.article-headline a { - color: inherit; - text-decoration: none; -} -.article-headline a:hover { - color: var(--lb-accent); -} -.article-meta { - display: flex; - align-items: center; - gap: 12px; - font-size: 0.8rem; - color: var(--lb-text-sec); - flex-wrap: wrap; -} -.article-source { - font-weight: 600; - color: var(--lb-text); - display: inline-flex; - align-items: center; - gap: 4px; -} -.article-favicon { - width: 16px; - height: 16px; - border-radius: 2px; - vertical-align: middle; -} -.article-lang { - background: var(--lb-bg-secondary); - border: 1px solid var(--lb-border); - padding: 1px 6px; - border-radius: 3px; - font-size: 0.7rem; - text-transform: uppercase; - color: var(--lb-text-sec); -} -.article-link { - color: var(--lb-accent) !important; - text-decoration: none !important; - font-size: 0.78rem; - display: inline-flex; - align-items: center; - gap: 3px; -} -.article-link:hover { - text-decoration: underline !important; -} - -/* ---------- Map ---------- */ -#map-container { - background: var(--lb-bg-secondary); -} -.lagebild-page .map-legend { - background: var(--lb-bg-card) !important; - color: var(--lb-text) !important; - border: 1px solid var(--lb-border) !important; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3) !important; -} -/* Leaflet controls dark */ -.lagebild-page .leaflet-control-zoom a { - background: var(--lb-bg-card) !important; - color: var(--lb-text) !important; - border-color: var(--lb-border) !important; -} -.lagebild-page .leaflet-control-zoom a:hover { - background: var(--lb-bg-secondary) !important; -} -.lagebild-page .leaflet-control-attribution { - background: rgba(11, 17, 33, 0.8) !important; - color: var(--lb-text-sec) !important; -} -.lagebild-page .leaflet-control-attribution a { - color: var(--lb-accent) !important; -} - -/* Map Pulse Markers */ -.pulse-marker-wrapper { - position: relative; - width: 20px; - height: 20px; -} -.pulse-marker-ring { - position: absolute; - width: 20px; - height: 20px; - border-radius: 50%; - border: 2px solid; - animation: mapPulseRing 2.5s ease-out infinite; - opacity: 0; -} -.pulse-marker-ring:nth-child(2) { - animation-delay: 0.8s; -} -.pulse-marker-dot { - position: absolute; - width: 10px; - height: 10px; - border-radius: 50%; - top: 5px; - left: 5px; -} -@keyframes mapPulseRing { - 0% { transform: scale(1); opacity: 0.8; } - 100% { transform: scale(3.5); opacity: 0; } -} - -/* ---------- Fact Check Cards ---------- */ -.fc-stats { - display: flex; - gap: 12px; - margin-bottom: 24px; - flex-wrap: wrap; -} -.fc-stat { - background: var(--lb-bg-secondary); - border-radius: var(--radius-sm, 4px); - padding: 14px 20px; - text-align: center; - min-width: 80px; - border: 1px solid var(--lb-border); -} -.fc-stat.confirmed { - background: rgba(16, 185, 129, 0.08); - border-color: rgba(16, 185, 129, 0.2); -} -.fc-stat.unconfirmed { - background: rgba(245, 158, 11, 0.08); - border-color: rgba(245, 158, 11, 0.2); -} -.fc-stat.contradicted { - background: rgba(239, 68, 68, 0.08); - border-color: rgba(239, 68, 68, 0.2); -} -.fc-stat-num { - display: block; - font-size: 1.6rem; - font-weight: 800; - color: var(--lb-text); -} -.fc-stat.confirmed .fc-stat-num { color: var(--lb-success); } -.fc-stat.unconfirmed .fc-stat-num { color: var(--lb-warning); } -.fc-stat.contradicted .fc-stat-num { color: var(--lb-error); } -.fc-stat-label { - font-size: 0.75rem; - color: var(--lb-text-sec); - text-transform: uppercase; - letter-spacing: 0.5px; - font-weight: 600; -} - -.factcheck-card { - background: var(--lb-bg-secondary); - border-radius: var(--radius-sm, 4px); - padding: 20px; - margin-bottom: 12px; - border-left: 4px solid var(--lb-border); - transition: transform 0.2s, box-shadow 0.2s; -} -.factcheck-card:hover { - transform: translateY(-1px); - box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3); -} -.factcheck-card.highlight { - background: rgba(200, 168, 81, 0.06); - border-left-color: var(--lb-accent); - box-shadow: 0 2px 12px rgba(200, 168, 81, 0.1); -} -.factcheck-card[data-status="confirmed"], -.factcheck-card[data-status="established"] { - border-left-color: var(--lb-success); -} -.factcheck-card[data-status="unconfirmed"], -.factcheck-card[data-status="unverified"] { - border-left-color: var(--lb-warning); -} -.factcheck-card[data-status="contradicted"], -.factcheck-card[data-status="disputed"] { - border-left-color: var(--lb-error); -} -.factcheck-card[data-status="developing"] { - border-left-color: #3b82f6; -} -.factcheck-card[data-status="false"] { - border-left-color: #dc2626; -} - -.factcheck-header { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 8px; -} -.factcheck-sources { - font-size: 0.8rem; - color: var(--lb-text-sec); -} -.factcheck-claim { - font-size: 0.95rem; - color: var(--lb-text); - margin: 0 0 4px; - line-height: 1.5; -} - -/* Status Badges */ -.status-badge { - display: inline-block; - padding: 3px 10px; - border-radius: var(--radius-sm, 4px); - font-size: 0.72rem; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.5px; -} -.status-badge.confirmed, .status-badge.established { - background: rgba(16, 185, 129, 0.15); - color: #34d399; -} -.status-badge.unconfirmed, .status-badge.unverified { - background: rgba(245, 158, 11, 0.15); - color: #fbbf24; -} -.status-badge.contradicted, .status-badge.disputed { - background: rgba(239, 68, 68, 0.15); - color: #f87171; -} -.status-badge.developing { - background: rgba(59, 130, 246, 0.15); - color: #60a5fa; -} -.status-badge.false { - background: rgba(220, 38, 38, 0.15); - color: #f87171; -} - -/* Status Progression */ -.status-progression { - display: flex; - align-items: center; - gap: 6px; - margin-top: 10px; - padding-top: 10px; - border-top: 1px solid var(--lb-border); - font-size: 0.78rem; - flex-wrap: wrap; -} -.progression-label { - color: var(--lb-text-sec); - font-weight: 500; - margin-right: 4px; -} -.progression-arrow { - color: var(--lb-accent); - font-size: 1rem; -} -.progression-step { - display: flex; - align-items: center; - gap: 4px; -} -.progression-time { - color: var(--lb-text-sec); - font-size: 0.7rem; -} - -/* Evidence block */ -.factcheck-evidence { - font-size: 0.82rem; - color: var(--lb-text-sec); - margin: 10px 0 0; - line-height: 1.6; - padding: 10px 14px; - background: rgba(0, 0, 0, 0.2); - border-radius: var(--radius-sm, 4px); - border: 1px solid var(--lb-border); -} -.factcheck-evidence strong { - color: var(--lb-text); -} -.factcheck-evidence a { - color: var(--lb-accent) !important; - word-break: break-all; -} - -/* ---------- Floating CTA Pill ---------- */ -.floating-cta { - position: fixed; - bottom: 24px; - left: 50%; - transform: translateX(-50%) translateY(100px); - display: flex; - align-items: center; - gap: 16px; - background: rgba(21, 29, 46, 0.92); - backdrop-filter: blur(16px); - -webkit-backdrop-filter: blur(16px); - border: 1px solid rgba(200, 168, 81, 0.25); - border-radius: 50px; - padding: 10px 14px 10px 24px; - z-index: 1000; - opacity: 0; - transition: opacity 0.4s, transform 0.4s; - pointer-events: none; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); -} -.floating-cta.visible { - opacity: 1; - transform: translateX(-50%) translateY(0); - pointer-events: auto; -} -.floating-cta.dismissed { - opacity: 0; - transform: translateX(-50%) translateY(100px); - pointer-events: none; -} -.floating-cta-text { - font-size: 0.88rem; - color: var(--lb-text-sec); - font-weight: 500; - white-space: nowrap; -} -.floating-cta-btn { - display: inline-block; - background: var(--lb-accent); - color: #0a0f1c; - padding: 8px 20px; - border-radius: 50px; - font-weight: 700; - text-decoration: none; - font-size: 0.85rem; - white-space: nowrap; - transition: background 0.2s, transform 0.2s, box-shadow 0.2s; - box-shadow: 0 0 16px var(--lb-glow-soft); -} -.floating-cta-btn:hover { - background: var(--lb-accent-hover); - transform: scale(1.03); - box-shadow: 0 0 28px var(--lb-glow); -} -.floating-cta-close { - background: none; - border: none; - color: var(--lb-text-sec); - font-size: 1.3rem; - cursor: pointer; - padding: 0 4px; - line-height: 1; - transition: color 0.2s; - font-family: inherit; -} -.floating-cta-close:hover { - color: var(--lb-text); -} - -@media (max-width: 768px) { - .floating-cta { - left: 12px; - right: 12px; - transform: translateX(0) translateY(100px); - border-radius: 16px; - gap: 10px; - padding: 10px 12px 10px 16px; - } - .floating-cta.visible { - transform: translateX(0) translateY(0); - } - .floating-cta.dismissed { - transform: translateX(0) translateY(100px); - } - .floating-cta-text { - font-size: 0.8rem; - white-space: normal; - } - .floating-cta-btn { - font-size: 0.8rem; - padding: 7px 14px; - flex-shrink: 0; - } -} - -/* ---------- Loading Skeleton ---------- */ -.loading-skeleton { padding: 20px 0; } -.skeleton-line { - height: 16px; - background: linear-gradient(90deg, var(--lb-bg-secondary) 25%, var(--lb-border) 50%, var(--lb-bg-secondary) 75%); - background-size: 200% 100%; - animation: shimmer 1.5s infinite; - border-radius: var(--radius-sm, 4px); - margin-bottom: 12px; -} -.skeleton-line.short { width: 60%; } -@keyframes shimmer { - 0% { background-position: 200% 0; } - 100% { background-position: -200% 0; } -} - -/* Error */ -.lagebild-error { - text-align: center; - padding: 40px 20px; - color: var(--lb-text-sec); -} - -/* ---------- Scroll Reveal ---------- */ -.reveal { - opacity: 0; - transform: translateY(20px); - transition: opacity 0.4s ease-out, transform 0.4s ease-out; -} -.reveal.revealed { - opacity: 1; - transform: translateY(0); -} - -/* ---------- Responsive ---------- */ - -/* Tablet */ -@media (max-width: 1024px) { - .hero-stats { - max-width: 550px; - } - .stat-card { - padding: 12px 14px; - } - .stat-card-value { - font-size: 1.15rem; - } -} - -/* Mobile */ -@media (max-width: 768px) { - .lagebild-hero { - padding: 120px 16px 50px; - } - .lagebild-hero h1 { - font-size: 2.5rem; - letter-spacing: 3px; - } - .hero-incident-title { - font-size: 1.2rem; - } - .hero-stats { - grid-template-columns: repeat(2, 1fr); - gap: 10px; - margin-top: 1.5rem; - } - .stat-card { - padding: 10px 12px; - gap: 10px; - } - .stat-card-icon { - width: 32px; - height: 32px; - } - .stat-card-value { - font-size: 1.1rem; - } - .stat-card-label { - font-size: 0.65rem; - } - - .control-bar .container { - flex-direction: column; - align-items: stretch; - } - .timeline-strip { - gap: 3px; - } - .timeline-day { - padding: 6px 10px; - min-width: 54px; - } - .timeline-day-num { - font-size: 0.95rem; - } - .timeline-dropdown { - padding: 8px 10px; - } - .timeline-snap-list { - grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); - gap: 4px; - } - .timeline-snap-item { - padding: 5px 10px; - font-size: 0.72rem; - } - .tab-nav { - overflow-x: auto; - -webkit-overflow-scrolling: touch; - } - .tab-btn { - padding: 10px 14px; - font-size: 0.82rem; - white-space: nowrap; - } - - .card-header { - padding: 16px 20px 0; - } - .card-body { - padding: 16px 20px 20px; - } - .card-footer { - margin: 0 20px; - padding: 16px 20px 20px; - } - .lagebild-main { - padding: 1rem 12px 3rem; - } - .factcheck-header { - flex-direction: column; - align-items: flex-start; - gap: 6px; - } - .article-card { - flex-direction: column; - gap: 8px; - } - .article-date { - width: auto; - text-align: left; - display: flex; - gap: 6px; - align-items: baseline; - } - .article-date .day { - font-size: 1rem; - } - #map-container { - height: 350px !important; - } - .fc-stats { - gap: 8px; - } - .fc-stat { - padding: 10px 14px; - min-width: 70px; - } - .status-progression { - gap: 4px; - } - - .sources-list { - columns: 1; - } - - .live-feed { - margin-top: 1rem; - } -} + justify-content: center; + display: flex; + gap: 0; +} +.tab-btn { + padding: 12px 20px; + border: none; + background: transparent; + cursor: pointer; + font-size: 0.9rem; + font-weight: 600; + color: var(--lb-text-sec); + border-bottom: 3px solid transparent; + transition: all 0.2s; + font-family: inherit; +} +.tab-btn:hover { + color: var(--lb-text); + text-shadow: 0 0 12px var(--lb-glow-soft); +} +.tab-btn.active { + color: var(--lb-accent); + border-bottom-color: var(--lb-accent); + text-shadow: 0 0 16px var(--lb-glow-soft); +} +.tab-badge { + display: inline-block; + background: rgba(200, 168, 81, 0.12); + color: var(--lb-accent); + padding: 1px 8px; + border-radius: 10px; + font-size: 0.7rem; + font-weight: 600; + margin-left: 4px; + vertical-align: middle; +} +.tab-btn.active .tab-badge { + background: rgba(200, 168, 81, 0.22); +} + +/* Tab Panels with Slide Animation */ +.tab-panel { display: none; } +.tab-panel.active { + display: block; + animation: tabFadeSlideIn 0.35s ease-out; +} +@keyframes tabFadeSlideIn { + from { opacity: 0; transform: translateY(12px); } + to { opacity: 1; transform: translateY(0); } +} + +/* ---------- Main Content ---------- */ +.lagebild-main { + padding: 2rem 20px 4rem; +} +.lagebild-main .container { + max-width: 1000px; + margin: 0 auto; +} + +/* ---------- Content Cards ---------- */ +.content-card { + background: var(--lb-bg-card); + border-radius: var(--radius-sm, 4px); + border: 1px solid var(--lb-border); + margin-bottom: 1.5rem; + overflow: hidden; + position: relative; +} +.content-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 3px; + background: var(--lb-accent); + box-shadow: 0 2px 12px var(--lb-glow-soft); +} +.card-header { + padding: 24px 32px 0; + display: flex; + justify-content: space-between; + align-items: baseline; + flex-wrap: wrap; + gap: 8px; +} +.card-header h2 { + font-size: 1.3rem; + font-weight: 700; + color: var(--lb-text); + margin: 0; +} +.card-timestamp { + font-size: 0.85rem; + color: var(--lb-text-sec); + font-weight: 500; +} +.card-description { + font-size: 0.85rem; + color: var(--lb-text-sec); + margin: 4px 0 0; + width: 100%; +} +.card-body { + padding: 20px 32px 28px; +} +.card-footer { + padding: 0 32px 28px; + border-top: 1px solid var(--lb-border); + padding-top: 20px; + margin: 0 32px; +} + +/* ---------- Lagebild Summary ---------- */ +#summary-content { + line-height: 1.85; + font-size: 1.02rem; + color: var(--lb-text); +} +#summary-content h2 { + font-size: 1.15rem; + font-weight: 700; + color: var(--lb-accent); + margin: 1.8rem 0 0.8rem; + padding-bottom: 0.4rem; + border-bottom: 2px solid var(--lb-border); +} +#summary-content h2:first-child { + margin-top: 0; +} +#summary-content h3 { + font-size: 1.05rem; + font-weight: 600; + color: var(--lb-text); + margin: 1.5rem 0 0.6rem; +} +#summary-content p { + margin: 0 0 1rem; +} +#summary-content ul { + margin: 0 0 1rem; + padding-left: 1.5rem; +} +#summary-content li { + margin-bottom: 0.4rem; + color: var(--lb-text); +} +#summary-content strong { + color: #fff; +} + +/* Citations */ +.citation-ref { + color: var(--lb-accent); + font-weight: 700; + cursor: pointer; + text-decoration: none; + font-size: 0.78em; + vertical-align: super; + line-height: 1; + padding: 0 1px; + transition: color 0.2s; +} +.citation-ref:hover { + color: var(--lb-accent-hover); + text-decoration: underline; +} + +/* Source Highlight (smooth scroll target) */ +.source-highlight { + background: rgba(200, 168, 81, 0.15) !important; + border-radius: 4px; + transition: background 1.5s ease-out; +} + +/* ---------- Source Overview Grid ---------- */ +.sources-overview-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; + flex-wrap: wrap; + gap: 12px; +} +.sources-overview-title { + font-size: 1.05rem; + font-weight: 700; + color: var(--lb-text); +} +.sources-lang-chips { + display: flex; + gap: 8px; +} +.sources-lang-chip { + background: rgba(200, 168, 81, 0.12); + color: var(--lb-accent); + padding: 4px 12px; + border-radius: 12px; + font-size: 0.78rem; + font-weight: 600; +} +.sources-grid { + display: grid; + grid-template-columns: repeat(6, 1fr); + gap: 10px; +} +.source-tile { + background: var(--lb-bg-secondary); + border: 1px solid var(--lb-border); + border-radius: 4px; + padding: 10px; + cursor: pointer; + transition: all 0.2s; + position: relative; + display: flex; + flex-direction: column; + gap: 6px; + min-height: 64px; + min-width: 0; + overflow: hidden; +} +.source-tile::before { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 3px; + background: var(--lb-border); + border-radius: 4px 4px 0 0; + transition: background 0.2s; +} +.source-tile:hover { + border-color: rgba(200, 168, 81, 0.4); + box-shadow: 0 0 20px var(--lb-glow-soft); +} +.source-tile:hover::before { + background: var(--lb-accent); +} +.source-tile.active { + border-color: var(--lb-accent); + box-shadow: 0 0 24px var(--lb-glow-soft); + background: rgba(200, 168, 81, 0.06); +} +.source-tile.active::before { + background: var(--lb-accent); +} +.source-tile-top { + display: flex; + align-items: center; + gap: 6px; + min-width: 0; +} +.source-tile-favicon { + width: 16px; + height: 16px; + border-radius: 2px; + flex-shrink: 0; +} +.source-tile-name { + font-size: 0.78rem; + font-weight: 600; + color: var(--lb-text); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.source-tile-bottom { + display: flex; + justify-content: space-between; + align-items: flex-end; + margin-top: auto; +} +.source-tile-lang { + font-size: 0.65rem; + color: var(--lb-text-sec); + background: var(--lb-bg-card); + padding: 2px 6px; + border-radius: 3px; + border: 1px solid var(--lb-border); + text-transform: uppercase; +} +.source-tile-count { + font-size: 1.1rem; + font-weight: 800; + color: var(--lb-accent); + line-height: 1; +} + +/* Source Detail Panel */ +.source-detail-panel { + grid-column: 1 / -1; + background: var(--lb-bg-card); + border: 1px solid rgba(200, 168, 81, 0.3); + border-radius: 4px; + overflow: hidden; + animation: sourceDetailSlideIn 0.3s ease-out; +} +@keyframes sourceDetailSlideIn { + from { opacity: 0; transform: translateY(-8px); } + to { opacity: 1; transform: translateY(0); } +} +.source-detail-header { + display: flex; + align-items: center; + gap: 12px; + padding: 16px 20px; + border-bottom: 1px solid var(--lb-border); + background: rgba(200, 168, 81, 0.04); +} +.source-detail-name { + font-size: 1rem; + font-weight: 700; + color: var(--lb-text); + display: flex; + align-items: center; + gap: 8px; +} +.source-detail-count { + font-size: 0.85rem; + color: var(--lb-text-sec); + margin-left: auto; +} +.source-detail-close { + background: none; + border: none; + color: var(--lb-text-sec); + font-size: 1.5rem; + cursor: pointer; + padding: 0 4px; + line-height: 1; + transition: color 0.2s; + font-family: inherit; +} +.source-detail-close:hover { + color: var(--lb-text); +} +.source-detail-articles { + padding: 8px 20px 16px; + max-height: 500px; + overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: var(--lb-border) transparent; +} +.source-detail-article { + display: flex; + justify-content: space-between; + align-items: center; + gap: 16px; + padding: 8px 0; + border-bottom: 1px solid var(--lb-border); +} +.source-detail-article:last-child { + border-bottom: none; +} +.source-detail-article-title { + font-size: 0.88rem; + color: var(--lb-text); + text-decoration: none; + flex: 1; + min-width: 0; + line-height: 1.4; +} +a.source-detail-article-title:hover { + color: var(--lb-accent); +} +.source-detail-article-date { + font-size: 0.78rem; + color: var(--lb-text-sec); + white-space: nowrap; + flex-shrink: 0; +} + +/* Inline sources (Lagebild tab footer) - Collapsible */ +.inline-sources-toggle { + display: inline-flex; + align-items: center; + gap: 8px; + font-size: 0.9rem; + font-weight: 600; + color: var(--lb-text-sec); + cursor: pointer; + padding: 10px 16px; + user-select: none; + transition: all 0.2s; + background: var(--lb-bg-secondary); + border: 1px solid var(--lb-border); + border-radius: var(--radius-sm, 4px); +} +.inline-sources-toggle:hover { + color: var(--lb-accent); + border-color: rgba(200, 168, 81, 0.4); + background: rgba(200, 168, 81, 0.06); +} +.inline-sources-arrow { + display: inline-flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + font-size: 1.1rem; + transition: transform 0.2s; + color: var(--lb-accent); +} +#inline-sources.open .inline-sources-arrow { + transform: rotate(90deg); +} +.inline-sources-body { + display: none; + padding: 8px 0 0; + font-size: 0.82rem; + line-height: 1.8; + color: var(--lb-text-sec); +} +#inline-sources.open .inline-sources-body { + display: block; +} +.src-inline .src-nr { + color: var(--lb-accent); + font-weight: 700; +} +.src-sep { + color: var(--lb-border); + margin: 0 2px; +} +.inline-sources-body a { + color: var(--lb-accent); + text-decoration: none; +} +.inline-sources-body a:hover { + text-decoration: underline; +} + + + +/* ---------- Map ---------- */ +#map-container { + background: var(--lb-bg-secondary); +} +.lagebild-page .map-legend { + background: var(--lb-bg-card) !important; + color: var(--lb-text) !important; + border: 1px solid var(--lb-border) !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3) !important; +} +/* Leaflet controls dark */ +.lagebild-page .leaflet-control-zoom a { + background: var(--lb-bg-card) !important; + color: var(--lb-text) !important; + border-color: var(--lb-border) !important; +} +.lagebild-page .leaflet-control-zoom a:hover { + background: var(--lb-bg-secondary) !important; +} +.lagebild-page .leaflet-control-attribution { + background: rgba(11, 17, 33, 0.8) !important; + color: var(--lb-text-sec) !important; +} +.lagebild-page .leaflet-control-attribution a { + color: var(--lb-accent) !important; +} + +/* Map Pulse Markers */ +.pulse-marker-wrapper { + position: relative; + width: 20px; + height: 20px; +} +.pulse-marker-ring { + position: absolute; + width: 20px; + height: 20px; + border-radius: 50%; + border: 2px solid; + animation: mapPulseRing 2.5s ease-out infinite; + opacity: 0; +} +.pulse-marker-ring:nth-child(2) { + animation-delay: 0.8s; +} +.pulse-marker-dot { + position: absolute; + width: 10px; + height: 10px; + border-radius: 50%; + top: 5px; + left: 5px; +} +@keyframes mapPulseRing { + 0% { transform: scale(1); opacity: 0.8; } + 100% { transform: scale(3.5); opacity: 0; } +} + +/* ---------- Fact Check Cards ---------- */ +.fc-stats { + display: flex; + gap: 12px; + margin-bottom: 24px; + flex-wrap: wrap; +} +.fc-stat { + background: var(--lb-bg-secondary); + border-radius: var(--radius-sm, 4px); + padding: 14px 20px; + text-align: center; + min-width: 80px; + border: 1px solid var(--lb-border); +} +.fc-stat.confirmed { + background: rgba(16, 185, 129, 0.08); + border-color: rgba(16, 185, 129, 0.2); +} +.fc-stat.unconfirmed { + background: rgba(245, 158, 11, 0.08); + border-color: rgba(245, 158, 11, 0.2); +} +.fc-stat.contradicted { + background: rgba(239, 68, 68, 0.08); + border-color: rgba(239, 68, 68, 0.2); +} +.fc-stat-num { + display: block; + font-size: 1.6rem; + font-weight: 800; + color: var(--lb-text); +} +.fc-stat.confirmed .fc-stat-num { color: var(--lb-success); } +.fc-stat.unconfirmed .fc-stat-num { color: var(--lb-warning); } +.fc-stat.contradicted .fc-stat-num { color: var(--lb-error); } +.fc-stat-label { + font-size: 0.75rem; + color: var(--lb-text-sec); + text-transform: uppercase; + letter-spacing: 0.5px; + font-weight: 600; +} + +.factcheck-card { + background: var(--lb-bg-secondary); + border-radius: var(--radius-sm, 4px); + padding: 20px; + margin-bottom: 12px; + border-left: 4px solid var(--lb-border); + transition: transform 0.2s, box-shadow 0.2s; +} +.factcheck-card:hover { + transform: translateY(-1px); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3); +} +.factcheck-card.highlight { + background: rgba(200, 168, 81, 0.06); + border-left-color: var(--lb-accent); + box-shadow: 0 2px 12px rgba(200, 168, 81, 0.1); +} +.factcheck-card[data-status="confirmed"], +.factcheck-card[data-status="established"] { + border-left-color: var(--lb-success); +} +.factcheck-card[data-status="unconfirmed"], +.factcheck-card[data-status="unverified"] { + border-left-color: var(--lb-warning); +} +.factcheck-card[data-status="contradicted"], +.factcheck-card[data-status="disputed"] { + border-left-color: var(--lb-error); +} +.factcheck-card[data-status="developing"] { + border-left-color: #3b82f6; +} +.factcheck-card[data-status="false"] { + border-left-color: #dc2626; +} + +.factcheck-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 8px; +} +.factcheck-sources { + font-size: 0.8rem; + color: var(--lb-text-sec); +} +.factcheck-claim { + font-size: 0.95rem; + color: var(--lb-text); + margin: 0 0 4px; + line-height: 1.5; +} + +/* Status Badges */ +.status-badge { + display: inline-block; + padding: 3px 10px; + border-radius: var(--radius-sm, 4px); + font-size: 0.72rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.5px; +} +.status-badge.confirmed, .status-badge.established { + background: rgba(16, 185, 129, 0.15); + color: #34d399; +} +.status-badge.unconfirmed, .status-badge.unverified { + background: rgba(245, 158, 11, 0.15); + color: #fbbf24; +} +.status-badge.contradicted, .status-badge.disputed { + background: rgba(239, 68, 68, 0.15); + color: #f87171; +} +.status-badge.developing { + background: rgba(59, 130, 246, 0.15); + color: #60a5fa; +} +.status-badge.false { + background: rgba(220, 38, 38, 0.15); + color: #f87171; +} + +/* Status Progression */ +.status-progression { + display: flex; + align-items: center; + gap: 6px; + margin-top: 10px; + padding-top: 10px; + border-top: 1px solid var(--lb-border); + font-size: 0.78rem; + flex-wrap: wrap; +} +.progression-label { + color: var(--lb-text-sec); + font-weight: 500; + margin-right: 4px; +} +.progression-arrow { + color: var(--lb-accent); + font-size: 1rem; +} +.progression-step { + display: flex; + align-items: center; + gap: 4px; +} +.progression-time { + color: var(--lb-text-sec); + font-size: 0.7rem; +} + +/* Evidence block */ +.factcheck-evidence { + font-size: 0.82rem; + color: var(--lb-text-sec); + margin: 10px 0 0; + line-height: 1.6; + padding: 10px 14px; + background: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-sm, 4px); + border: 1px solid var(--lb-border); +} +.factcheck-evidence strong { + color: var(--lb-text); +} +.factcheck-evidence a { + color: var(--lb-accent) !important; + word-break: break-all; +} + +/* ---------- Floating CTA Pill ---------- */ +.floating-cta { + position: fixed; + bottom: 24px; + left: 50%; + transform: translateX(-50%) translateY(100px); + display: flex; + align-items: center; + gap: 16px; + background: rgba(21, 29, 46, 0.92); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + border: 1px solid rgba(200, 168, 81, 0.25); + border-radius: 50px; + padding: 10px 14px 10px 24px; + z-index: 1000; + opacity: 0; + transition: opacity 0.4s, transform 0.4s; + pointer-events: none; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); +} +.floating-cta.visible { + opacity: 1; + transform: translateX(-50%) translateY(0); + pointer-events: auto; +} +.floating-cta.dismissed { + opacity: 0; + transform: translateX(-50%) translateY(100px); + pointer-events: none; +} +.floating-cta-text { + font-size: 0.88rem; + color: var(--lb-text-sec); + font-weight: 500; + white-space: nowrap; +} +.floating-cta-btn { + display: inline-block; + background: var(--lb-accent); + color: #0a0f1c; + padding: 8px 20px; + border-radius: 50px; + font-weight: 700; + text-decoration: none; + font-size: 0.85rem; + white-space: nowrap; + transition: background 0.2s, transform 0.2s, box-shadow 0.2s; + box-shadow: 0 0 16px var(--lb-glow-soft); +} +.floating-cta-btn:hover { + background: var(--lb-accent-hover); + transform: scale(1.03); + box-shadow: 0 0 28px var(--lb-glow); +} +.floating-cta-close { + background: none; + border: none; + color: var(--lb-text-sec); + font-size: 1.3rem; + cursor: pointer; + padding: 0 4px; + line-height: 1; + transition: color 0.2s; + font-family: inherit; +} +.floating-cta-close:hover { + color: var(--lb-text); +} + +@media (max-width: 768px) { + .floating-cta { + left: 12px; + right: 12px; + transform: translateX(0) translateY(100px); + border-radius: 16px; + gap: 10px; + padding: 10px 12px 10px 16px; + } + .floating-cta.visible { + transform: translateX(0) translateY(0); + } + .floating-cta.dismissed { + transform: translateX(0) translateY(100px); + } + .floating-cta-text { + font-size: 0.8rem; + white-space: normal; + } + .floating-cta-btn { + font-size: 0.8rem; + padding: 7px 14px; + flex-shrink: 0; + } +} + +/* ---------- Loading Skeleton ---------- */ +.loading-skeleton { padding: 20px 0; } +.skeleton-line { + height: 16px; + background: linear-gradient(90deg, var(--lb-bg-secondary) 25%, var(--lb-border) 50%, var(--lb-bg-secondary) 75%); + background-size: 200% 100%; + animation: shimmer 1.5s infinite; + border-radius: var(--radius-sm, 4px); + margin-bottom: 12px; +} +.skeleton-line.short { width: 60%; } +@keyframes shimmer { + 0% { background-position: 200% 0; } + 100% { background-position: -200% 0; } +} + +/* Error */ +.lagebild-error { + text-align: center; + padding: 40px 20px; + color: var(--lb-text-sec); +} + +/* ---------- Scroll Reveal ---------- */ +.reveal { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.4s ease-out, transform 0.4s ease-out; +} +.reveal.revealed { + opacity: 1; + transform: translateY(0); +} + +/* ---------- Responsive ---------- */ + +/* Tablet */ +@media (max-width: 1024px) { + .sources-grid { + grid-template-columns: repeat(4, 1fr); + } + .hero-stats { + max-width: 550px; + } + .stat-card { + padding: 12px 14px; + } + .stat-card-value { + font-size: 1.15rem; + } +} + +/* Mobile */ +@media (max-width: 768px) { + .lagebild-hero { + padding: 120px 16px 50px; + } + .lagebild-hero h1 { + font-size: 2.5rem; + letter-spacing: 3px; + } + .hero-incident-title { + font-size: 1.2rem; + } + .hero-stats { + grid-template-columns: repeat(2, 1fr); + gap: 10px; + margin-top: 1.5rem; + } + .stat-card { + padding: 10px 12px; + gap: 10px; + } + .stat-card-icon { + width: 32px; + height: 32px; + } + .stat-card-value { + font-size: 1.1rem; + } + .stat-card-label { + font-size: 0.65rem; + } + + .control-bar .container { + flex-direction: column; + align-items: stretch; + } + .timeline-strip { + gap: 3px; + } + .timeline-day { + padding: 6px 10px; + min-width: 54px; + } + .timeline-day-num { + font-size: 0.95rem; + } + .timeline-dropdown { + padding: 8px 10px; + } + .timeline-snap-list { + grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); + gap: 4px; + } + .timeline-snap-item { + padding: 5px 10px; + font-size: 0.72rem; + } + .tab-nav { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + .tab-btn { + padding: 10px 14px; + font-size: 0.82rem; + white-space: nowrap; + } + + .card-header { + padding: 16px 20px 0; + } + .card-body { + padding: 16px 20px 20px; + } + .card-footer { + margin: 0 20px; + padding: 16px 20px 20px; + } + .lagebild-main { + padding: 1rem 12px 3rem; + } + .factcheck-header { + flex-direction: column; + align-items: flex-start; + gap: 6px; + } + .sources-grid { + grid-template-columns: repeat(2, 1fr); + gap: 8px; + } + .source-tile { + padding: 10px; + min-height: 70px; + } + .source-tile-count { + font-size: 1.1rem; + } + .source-detail-header { + padding: 12px 16px; + } + .source-detail-articles { + padding: 8px 16px 12px; + max-height: 350px; + } + .source-detail-article { + flex-direction: column; + align-items: flex-start; + gap: 4px; + } + #map-container { + height: 350px !important; + } + .fc-stats { + gap: 8px; + } + .fc-stat { + padding: 10px 14px; + min-width: 70px; + } + .status-progression { + gap: 4px; + } + + + .live-feed { + margin-top: 1rem; + } +} diff --git a/lagebild/lagebild.js b/lagebild/lagebild.js index 96af58c..95a9427 100644 --- a/lagebild/lagebild.js +++ b/lagebild/lagebild.js @@ -1,852 +1,955 @@ -/** - * AegisSight Lagebild Page - Dark Theme Design Refresh - * Count-Up, Timeline, Scroll-Reveal, Particles, Live-Feed, Pulse-Markers - */ - -/** Feste Zeitzone fuer alle Anzeigen - NIEMALS aendern. */ -var TIMEZONE = 'Europe/Berlin'; - -var Lagebild = { - data: null, - allSnapshots: {}, - currentView: null, - map: null, - timelineGroups: null, - - /* ===== Inline SVG Icons ===== */ - icons: { - clock: '', - fileText: '', - globe: '', - shieldCheck: '', - externalLink: '' - }, - - async init() { - if (typeof initTranslations === 'function') { - try { initTranslations(); } catch(e) {} - } - this.initScrollProgress(); - this.initParticles(); - try { - var resp = await fetch('data/current.json?t=' + Date.now()); - if (!resp.ok) throw new Error('HTTP ' + resp.status); - this.data = await resp.json(); - this.currentView = { - summary: this.data.current_lagebild.summary_markdown, - sources_json: this.data.current_lagebild.sources_json, - updated_at: this.data.current_lagebild.updated_at || this.data.generated_at, - articles: this.data.articles, - fact_checks: this.data.fact_checks - }; - this.render(); - this.initTabs(); - this.initLangToggle(); - this.initScrollReveal(); - this.initFloatingCta(); - this.initLiveFeed(); - } catch (e) { - console.error('Lagebild laden fehlgeschlagen:', e); - this.showError(); - } - }, - - render: function() { - this.renderHero(); - this.renderTimeline(); - this.renderTabBadges(); - this.renderCurrentView(); - }, - - /* ===== SCROLL PROGRESS BAR ===== */ - initScrollProgress: function() { - var bar = document.getElementById('scroll-progress'); - if (!bar) return; - window.addEventListener('scroll', function() { - var scrollTop = window.scrollY; - var docHeight = document.documentElement.scrollHeight - window.innerHeight; - if (docHeight <= 0) return; - bar.style.width = ((scrollTop / docHeight) * 100) + '%'; - }); - }, - - /* ===== HERO PARTICLES ===== */ - initParticles: function() { - var canvas = document.getElementById('hero-particles'); - if (!canvas) return; - var ctx = canvas.getContext('2d'); - var particles = []; - var count = 35; - var connectDist = 120; - - function resize() { - var hero = canvas.parentElement; - canvas.width = hero.offsetWidth; - canvas.height = hero.offsetHeight; - } - resize(); - window.addEventListener('resize', resize); - - for (var i = 0; i < count; i++) { - particles.push({ - x: Math.random() * canvas.width, - y: Math.random() * canvas.height, - vx: (Math.random() - 0.5) * 0.4, - vy: (Math.random() - 0.5) * 0.4, - r: Math.random() * 1.5 + 0.5 - }); - } - - function draw() { - ctx.clearRect(0, 0, canvas.width, canvas.height); - - // Draw connections - for (var i = 0; i < particles.length; i++) { - for (var j = i + 1; j < particles.length; j++) { - var dx = particles[i].x - particles[j].x; - var dy = particles[i].y - particles[j].y; - var dist = Math.sqrt(dx * dx + dy * dy); - if (dist < connectDist) { - var alpha = (1 - dist / connectDist) * 0.15; - ctx.beginPath(); - ctx.strokeStyle = 'rgba(200, 168, 81, ' + alpha + ')'; - ctx.lineWidth = 0.5; - ctx.moveTo(particles[i].x, particles[i].y); - ctx.lineTo(particles[j].x, particles[j].y); - ctx.stroke(); - } - } - } - - // Draw & move particles - for (var k = 0; k < particles.length; k++) { - var p = particles[k]; - ctx.beginPath(); - ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2); - ctx.fillStyle = 'rgba(200, 168, 81, 0.4)'; - ctx.fill(); - - p.x += p.vx; - p.y += p.vy; - if (p.x < 0 || p.x > canvas.width) p.vx *= -1; - if (p.y < 0 || p.y > canvas.height) p.vy *= -1; - } - - requestAnimationFrame(draw); - } - draw(); - }, - - /* ===== LIVE FEED TICKER ===== */ - initLiveFeed: function() { - var container = document.getElementById('live-feed'); - if (!container) return; - - var d = this.data; - var genDate = new Date(this.toUTC(d.generated_at)); - var diffMin = Math.max(1, Math.round((Date.now() - genDate.getTime()) / 60000)); - var diffText = diffMin < 60 ? ('vor ' + diffMin + ' Min') : ('vor ' + Math.round(diffMin / 60) + ' Std'); - - var messages = [ - 'Letzte Aktualisierung: ' + diffText, - d.incident.source_count + ' Quellen aktiv \u00fcberwacht', - d.incident.article_count + ' Artikel analysiert \u2013 ' + d.incident.factcheck_count + ' Faktenchecks durchgef\u00fchrt', - ]; - - var h = ''; - for (var i = 0; i < messages.length; i++) { - h += '
'; - h += ''; - h += '' + messages[i] + ''; - h += '
'; - } - container.innerHTML = h; - - var current = 0; - var items = container.querySelectorAll('.live-feed-item'); - setInterval(function() { - items[current].classList.remove('active'); - current = (current + 1) % items.length; - items[current].classList.add('active'); - }, 4000); - }, - - /* ===== HERO ===== */ - renderHero: function() { - var d = this.data; - document.getElementById('incident-title').innerHTML = - this.esc(this.fixUmlauts(d.incident.title)) + - ' \u2013 Stand: ' + this.fmtDateOnly(d.generated_at) + ', ' + this.fmtTimeOnly(d.generated_at) + ' Uhr'; - - // Stat Cards (3: Artikel, Quellen, Faktenchecks) - var statsHtml = ''; - statsHtml += this.statCard(this.icons.fileText, '0', 'Artikel'); - statsHtml += this.statCard(this.icons.globe, '0', 'Quellen'); - statsHtml += this.statCard(this.icons.shieldCheck, '0', 'Faktenchecks'); - document.getElementById('hero-stats').innerHTML = statsHtml; - - // Start count-up animations - var self = this; - requestAnimationFrame(function() { - var els = document.querySelectorAll('.count-up'); - for (var i = 0; i < els.length; i++) { - self.animateCount(els[i], parseInt(els[i].getAttribute('data-target')), 800); - } - }); - }, - - statCard: function(icon, value, label) { - return '
' + - '
' + icon + '
' + - '
' + - '' + value + '' + - '' + label + '' + - '
'; - }, - - /* ===== COUNT-UP ANIMATION ===== */ - animateCount: function(element, target, duration) { - var start = performance.now(); - function update(now) { - var elapsed = now - start; - var progress = Math.min(elapsed / duration, 1); - var eased = 1 - Math.pow(1 - progress, 3); // easeOutCubic - var current = Math.round(target * eased); - element.textContent = current.toLocaleString('de-DE'); - if (progress < 1) { - requestAnimationFrame(update); - } - } - requestAnimationFrame(update); - }, - - /* ===== TIMELINE STRIP ===== */ - renderTimeline: function() { - var snaps = this.data.available_snapshots || []; - var current = { - id: 'current', - article_count: this.data.incident.article_count, - fact_check_count: this.data.incident.factcheck_count, - created_at: this.data.generated_at - }; - var all = [current].concat(snaps); - - // Group by date - var groups = {}; - for (var i = 0; i < all.length; i++) { - var s = all[i]; - var dateKey = this.toDateKey(s.created_at); - if (!groups[dateKey]) groups[dateKey] = []; - groups[dateKey].push(s); - } - - // Sort each group descending (newest first) - for (var dk in groups) { - groups[dk].sort(function(a, b) { - return new Date(Lagebild.toUTC(b.created_at)) - new Date(Lagebild.toUTC(a.created_at)); - }); - } - - this.timelineGroups = groups; - var dates = Object.keys(groups).sort(); - var strip = document.getElementById('timeline-strip'); - var h = ''; - - for (var j = 0; j < dates.length; j++) { - var date = dates[j]; - var daySnaps = groups[date]; - var latest = daySnaps[0]; - var isActive = (j === dates.length - 1); - var d = new Date(date + 'T12:00:00Z'); - - h += ''; - } - - strip.innerHTML = h; - - // Scroll to active day - var active = strip.querySelector('.timeline-day.active'); - if (active) { - setTimeout(function() { - active.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' }); - }, 150); - } - - // Click handler for day buttons - var self = this; - strip.addEventListener('click', function(e) { - var btn = e.target.closest('.timeline-day'); - if (!btn) return; - - var allDays = strip.querySelectorAll('.timeline-day'); - for (var k = 0; k < allDays.length; k++) allDays[k].classList.remove('active'); - btn.classList.add('active'); - - var dateKey = btn.getAttribute('data-date'); - var snapId = btn.getAttribute('data-snapshot-id'); - - self.showTimelineDropdown(dateKey, snapId); - - if (snapId === 'current') { - self.currentView = { - summary: self.data.current_lagebild.summary_markdown, - sources_json: self.data.current_lagebild.sources_json, - updated_at: self.data.current_lagebild.updated_at || self.data.generated_at, - articles: self.data.articles, - fact_checks: self.data.fact_checks - }; - self.renderCurrentView(); - } else { - self.loadSnapshot(parseInt(snapId)); - } - }); - - // Click handler for dropdown snapshot items (delegated, set up once) - var dropdown = document.getElementById('timeline-dropdown'); - dropdown.addEventListener('click', function(e) { - var item = e.target.closest('.timeline-snap-item'); - if (!item) return; - - var items = dropdown.querySelectorAll('.timeline-snap-item'); - for (var k = 0; k < items.length; k++) items[k].classList.remove('active'); - item.classList.add('active'); - - var snapId = item.getAttribute('data-snapshot-id'); - if (snapId === 'current') { - self.currentView = { - summary: self.data.current_lagebild.summary_markdown, - sources_json: self.data.current_lagebild.sources_json, - updated_at: self.data.current_lagebild.updated_at || self.data.generated_at, - articles: self.data.articles, - fact_checks: self.data.fact_checks - }; - self.renderCurrentView(); - } else { - self.loadSnapshot(parseInt(snapId)); - } - }); - - // Show dropdown for newest day by default - var newestDate = dates[dates.length - 1]; - if (newestDate && groups[newestDate].length > 1) { - this.showTimelineDropdown(newestDate, groups[newestDate][0].id); - } - }, - - showTimelineDropdown: function(dateKey, activeSnapId) { - var dropdown = document.getElementById('timeline-dropdown'); - var snaps = this.timelineGroups[dateKey]; - - if (!snaps || snaps.length <= 1) { - dropdown.classList.remove('open'); - dropdown.innerHTML = ''; - return; - } - - var d = new Date(dateKey + 'T12:00:00Z'); - var dateLabel = d.toLocaleDateString('de-DE', { day: 'numeric', month: 'long', year: 'numeric', timeZone: 'UTC' }); - - var h = '
' + dateLabel + ' \u2013 ' + snaps.length + ' Updates
'; - h += '
'; - for (var i = 0; i < snaps.length; i++) { - var snap = snaps[i]; - var isActive = (String(snap.id) === String(activeSnapId)); - h += ''; - } - h += '
'; - - dropdown.innerHTML = h; - dropdown.classList.add('open'); - }, - - toDateKey: function(iso) { - if (!iso) return ''; - var d = new Date(this.toUTC(iso)); - return d.toLocaleDateString('en-CA', { timeZone: TIMEZONE }); - }, - - /* ===== TAB BADGES ===== */ - renderTabBadges: function() { - var quellenBadge = document.getElementById('tab-badge-quellen'); - var fcBadge = document.getElementById('tab-badge-faktenchecks'); - if (quellenBadge) quellenBadge.textContent = this.data.incident.source_count; - if (fcBadge) fcBadge.textContent = this.data.incident.factcheck_count; - }, - - /* ===== SNAPSHOT LOADING ===== */ - loadSnapshot: async function(id) { - if (this.allSnapshots[id]) { - this.currentView = this.allSnapshots[id]; - this.renderCurrentView(); - return; - } - try { - var resp = await fetch('data/snapshot-' + id + '.json'); - if (!resp.ok) throw new Error('HTTP ' + resp.status); - var sd = await resp.json(); - var sj = sd.sources_json; - if (typeof sj === 'string') { try { sj = JSON.parse(sj); } catch(e) { sj = []; } } - this.currentView = { - summary: sd.summary, - sources_json: sj || [], - updated_at: sd.created_at, - articles: this.data.articles, - fact_checks: this.data.fact_checks - }; - this.allSnapshots[id] = this.currentView; - this.renderCurrentView(); - } catch (e) { console.error('Snapshot Fehler:', e); } - }, - - renderCurrentView: function() { - this.renderSummary(); - this.renderInlineSources(); - this.renderSourcesTab(); - this.renderArticlesTab(); - this.renderFactChecksTab(); - if (document.getElementById('panel-karte').classList.contains('active')) { - this.renderMap(); - } - }, - - /* ===== TAB: LAGEBILD ===== */ - renderSummary: function() { - var v = this.currentView; - document.getElementById('lagebild-timestamp').textContent = this.fmtDT(v.updated_at); - var md = this.fixUmlauts(v.summary || ''); - var html = this.mdToHtml(md); - - // Build source lookup for citation links - var srcMap = {}; - var sources = v.sources_json || []; - for (var i = 0; i < sources.length; i++) { - srcMap[sources[i].nr] = sources[i]; - } - var self = this; - html = html.replace(/\[(\d+)\]/g, function(match, nr) { - var src = srcMap[nr]; - if (src && src.url) { - return '[' + nr + ']'; - } - return '[' + nr + ']'; - }); - - document.getElementById('summary-content').innerHTML = html; - }, - - renderInlineSources: function() { - document.getElementById('inline-sources').innerHTML = ''; - }, - - /* ===== TAB: QUELLEN ===== */ - renderSourcesTab: function() { - var sources = this.currentView.sources_json || []; - var articles = this.currentView.articles || []; - var h = ''; - - h += '

Im Lagebild zitierte Quellen (' + sources.length + ')

'; - if (sources.length) { - h += '
    '; - for (var i = 0; i < sources.length; i++) { - var s = sources[i]; - if (s.url) { - h += '
  1. ' + this.esc(s.name || '') + '
  2. '; - } else { - h += '
  3. ' + this.esc(s.name || '') + '
  4. '; - } - } - h += '
'; - } - h += '
'; - document.getElementById('sources-cited').innerHTML = h; - - document.getElementById('articles-heading').textContent = 'Alle gesammelten Artikel (' + articles.length + ')'; - var ah = ''; - for (var i = 0; i < articles.length; i++) { - var a = articles[i]; - var dt = a.published_at || a.collected_at || ''; - var dObj = dt ? new Date(this.toUTC(dt)) : null; - var hl = this.fixUmlauts(a.headline_de || a.headline || ''); - var domain = this.extractDomain(a.source_url); - - ah += '
'; - ah += '
'; - } - document.getElementById('articles-content').innerHTML = ah; - }, - - renderArticlesTab: function() {}, - - /* ===== TAB: KARTE (Pulse Markers) ===== */ - renderMap: function() { - if (this.map) { this.map.remove(); this.map = null; } - this.map = L.map('map-container').setView([33.0, 48.0], 5); - - // Dark map tiles (CartoDB Dark Matter) - L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', { - attribution: '© OpenStreetMap © CARTO', - maxZoom: 19, - subdomains: 'abcd' - }).addTo(this.map); - - function pulseIcon(color) { - return L.divIcon({ - className: '', - html: '
' - + '
' - + '
' - + '
' - + '
', - iconSize: [20, 20], - iconAnchor: [10, 10], - popupAnchor: [0, -12] - }); - } - - var red = '#ef4444'; - var orange = '#f59e0b'; - var blue = '#3b82f6'; - - var locs = [ - {n:'Teheran, Iran',lat:35.6892,lng:51.3890,d:'Hauptziel der US-israelischen Luftschl\u00e4ge. \u00dcber 1.000 Tote nach f\u00fcnf Tagen Krieg.',c:red}, - {n:'Beirut, Libanon',lat:33.8938,lng:35.5018,d:'Gleichzeitige US-israelische Luftschl\u00e4ge auf Beirut und Teheran [6].',c:red}, - {n:'Juffair, Bahrain',lat:26.2235,lng:50.6001,d:'US-Marinebasis \u2013 Ziel iranischer Vergeltungsraketen [3].',c:orange}, - {n:'Al Udeid, Katar',lat:25.1173,lng:51.3150,d:'US-Luftwaffenst\u00fctzpunkt \u2013 Ziel iranischer Gegenangriffe.',c:orange}, - {n:'Tel Aviv, Israel',lat:32.0853,lng:34.7818,d:'Operationsbasis f\u00fcr israelische Angriffe auf den Iran.',c:blue}, - {n:'Ankara, T\u00fcrkei',lat:39.9334,lng:32.8597,d:'NATO vermutet iranischen Raketenbeschuss auf T\u00fcrkei [10]. Keine NATO-Beteiligung geplant.',c:orange}, - {n:'Bagdad, Irak',lat:33.3152,lng:44.3661,d:'Lage im Irak als Faktor im Kriegsverlauf [2].',c:blue}, - {n:'Persischer Golf',lat:27.0,lng:51.5,d:'Iran greift Energieinfrastruktur und diplomatische Einrichtungen in der Golfregion an.',c:orange}, - {n:'Dubai, VAE',lat:25.2048,lng:55.2708,d:'US-Botschaft in Dubai durch iranischen Angriff getroffen.',c:red}, - {n:'Washington D.C., USA',lat:38.9072,lng:-77.0369,d:'War-Powers-Abstimmung im Senat gescheitert (47:53). Trump verteidigt Iran-Krieg vor Kongress.',c:blue} - ]; - - for (var i = 0; i < locs.length; i++) { - var l = locs[i]; - L.marker([l.lat, l.lng], { icon: pulseIcon(l.c) }) - .addTo(this.map) - .bindPopup('' + l.n + '
' + l.d + ''); - } - - // Dark legend - var legend = L.control({ position: 'bottomright' }); - legend.onAdd = function() { - var div = L.DomUtil.create('div', 'map-legend'); - div.style.cssText = 'background:#151D2E;padding:10px 14px;border-radius:4px;border:1px solid #1E2D45;box-shadow:0 2px 8px rgba(0,0,0,0.3);font-size:0.8rem;line-height:1.8;color:#E8ECF4;'; - div.innerHTML = 'Legende
' - + ' Angegriffene Ziele
' - + ' Vergeltung / Eskalation
' - + ' Strategische Akteure'; - return div; - }; - legend.addTo(this.map); - - // Dark popup styling - if (!document.getElementById('leaflet-dark-style')) { - var style = document.createElement('style'); - style.id = 'leaflet-dark-style'; - style.textContent = '.lagebild-page .leaflet-popup-content-wrapper{background:#151D2E;color:#E8ECF4;border:1px solid #1E2D45;border-radius:4px;box-shadow:0 4px 16px rgba(0,0,0,0.4);}.lagebild-page .leaflet-popup-tip{background:#151D2E;}'; - document.head.appendChild(style); - } - - setTimeout(function() { if (Lagebild.map) Lagebild.map.invalidateSize(); }, 300); - }, - - /* ===== TAB: FAKTENCHECKS ===== */ - renderFactChecksTab: function() { - var checks = this.currentView.fact_checks || []; - if (!checks.length) { - document.getElementById('factchecks-content').innerHTML = '

Keine Faktenchecks verf\u00fcgbar.

'; - return; - } - - var stats = { confirmed: 0, unconfirmed: 0, contradicted: 0, developing: 0, established: 0, disputed: 0 }; - for (var k = 0; k < checks.length; k++) { - var st = checks[k].status || 'developing'; - if (stats[st] !== undefined) stats[st]++; - } - - var h = '
'; - h += '
' + checks.length + 'Gesamt
'; - h += '
' + (stats.confirmed + stats.established) + 'Best\u00e4tigt
'; - h += '
' + (stats.unconfirmed + stats.developing) + 'Offen
'; - if (stats.contradicted + stats.disputed > 0) - h += '
' + (stats.contradicted + stats.disputed) + 'Widerlegt
'; - h += '
'; - - checks = checks.slice().sort(function(a, b) { - var aH = (a.status_history || []).length; - var bH = (b.status_history || []).length; - if (bH !== aH) return bH - aH; - return (b.sources_count || 0) - (a.sources_count || 0); - }); - - for (var i = 0; i < checks.length; i++) { - var fc = checks[i]; - var status = fc.status || 'developing'; - var hasProg = fc.status_history && fc.status_history.length > 1; - - h += '
'; - h += '
'; - h += '' + this.stLabel(status) + ''; - h += '' + (fc.sources_count || 0) + ' unabh\u00e4ngige Quellen'; - h += '
'; - h += '

' + this.esc(this.fixUmlauts(fc.claim || '')) + '

'; - - if (fc.evidence) { - var ev = this.fixUmlauts(fc.evidence); - ev = this.esc(ev).replace(/(https?:\/\/[^\s,)]+)/g, '$1'); - h += '
Evidenz: ' + ev + '
'; - } - - if (hasProg) { - h += '
'; - h += 'Verlauf:'; - for (var j = 0; j < fc.status_history.length; j++) { - var step = fc.status_history[j]; - if (j > 0) h += ''; - h += ''; - h += '' + this.stLabel(step.status) + ''; - if (step.at) h += '' + this.fmtShort(step.at) + ''; - h += ''; - } - h += '
'; - } - h += '
'; - } - document.getElementById('factchecks-content').innerHTML = h; - }, - - /* ===== TABS ===== */ - initTabs: function() { - var btns = document.querySelectorAll('.tab-btn'); - var self = this; - for (var i = 0; i < btns.length; i++) { - btns[i].addEventListener('click', function() { - var tab = this.getAttribute('data-tab'); - for (var j = 0; j < btns.length; j++) btns[j].classList.remove('active'); - this.classList.add('active'); - var panels = document.querySelectorAll('.tab-panel'); - for (var j = 0; j < panels.length; j++) panels[j].classList.remove('active'); - var activePanel = document.getElementById('panel-' + tab); - activePanel.classList.add('active'); - - // Trigger reveal for cards in newly active panel - var revealCards = activePanel.querySelectorAll('.reveal:not(.revealed)'); - for (var k = 0; k < revealCards.length; k++) { - revealCards[k].classList.add('revealed'); - } - - if (tab === 'karte') self.renderMap(); - }); - } - }, - - initLangToggle: function() { - var btn = document.querySelector('.lang-toggle'); - if (!btn) return; - btn.addEventListener('click', function(e) { - e.preventDefault(); - if (typeof switchLanguage === 'function') { - var cur = (typeof getCurrentLanguage === 'function') ? getCurrentLanguage() : 'de'; - switchLanguage(cur === 'de' ? 'en' : 'de'); - } - }); - }, - - /* ===== FLOATING CTA ===== */ - initFloatingCta: function() { - var cta = document.createElement('div'); - cta.className = 'floating-cta'; - cta.innerHTML = 'AegisSight Monitor f\u00fcr Ihre Organisation' - + 'Kontakt aufnehmen \u2192' - + ''; - document.body.appendChild(cta); - - // Show after scrolling past hero - var shown = false; - window.addEventListener('scroll', function() { - if (shown) return; - if (window.scrollY > 400) { - cta.classList.add('visible'); - shown = true; - } - }); - - // Close button - cta.querySelector('.floating-cta-close').addEventListener('click', function(e) { - e.preventDefault(); - cta.classList.add('dismissed'); - setTimeout(function() { cta.classList.remove('dismissed'); }, 60000); - }); - }, - - /* ===== SCROLL REVEAL ===== */ - initScrollReveal: function() { - var cards = document.querySelectorAll('.content-card, .lagebild-cta'); - if (!('IntersectionObserver' in window)) { - for (var i = 0; i < cards.length; i++) cards[i].classList.add('revealed'); - return; - } - var observer = new IntersectionObserver(function(entries) { - entries.forEach(function(entry) { - if (entry.isIntersecting) { - entry.target.classList.add('revealed'); - observer.unobserve(entry.target); - } - }); - }, { threshold: 0.1 }); - - for (var i = 0; i < cards.length; i++) { - cards[i].classList.add('reveal'); - // Immediately reveal cards in the active (visible) tab panel - var panel = cards[i].closest('.tab-panel'); - if (!panel || panel.classList.contains('active')) { - cards[i].classList.add('revealed'); - } else { - observer.observe(cards[i]); - } - } - }, - - /* ===== HILFSFUNKTIONEN ===== */ - extractDomain: function(url) { - if (!url) return null; - try { return new URL(url).hostname; } catch(e) { return null; } - }, - - fixUmlauts: function(text) { - if (!text) return text; - var skip = ['Israel','Israelis','Jazeera','Euronews','Reuters','Februar', - 'Juffair','abgefeuert','Feindseligkeiten','Gegenschlag','neuesten', - 'auszuweiten','befeuert','feuerte','Feuer','feuer','neue','neuen', - 'neuer','neues','Neue','Aero','aero','Manoeuvre','Dauerfeuer']; - var ph = []; var c = 0; - for (var i = 0; i < skip.length; i++) { - var re = new RegExp('\\b' + skip[i] + '\\b', 'g'); - text = text.replace(re, function(m) { ph.push(m); return '##S' + (c++) + '##'; }); - } - text = text.replace(/ae/g, '\u00e4').replace(/Ae/g, '\u00c4'); - text = text.replace(/oe/g, '\u00f6').replace(/Oe/g, '\u00d6'); - text = text.replace(/ue/g, '\u00fc').replace(/Ue/g, '\u00dc'); - text = text.replace(/##S(\d+)##/g, function(m, idx) { return ph[parseInt(idx)]; }); - return text; - }, - - stLabel: function(s) { - return { confirmed: 'Best\u00e4tigt', unconfirmed: 'Unbest\u00e4tigt', established: 'Gesichert', - unverified: 'Nicht verifiziert', contradicted: 'Widerlegt', disputed: 'Umstritten', - developing: 'In Entwicklung', 'false': 'Falsch' }[s] || s; - }, - - mdToHtml: function(md) { - if (!md) return ''; - var lines = md.split('\n'), html = '', inList = false; - for (var i = 0; i < lines.length; i++) { - var l = lines[i]; - if (/^### (.+)$/.test(l)) { if (inList) { html += ''; inList = false; } html += '

' + l.replace(/^### /, '') + '

'; continue; } - if (/^## (.+)$/.test(l)) { if (inList) { html += ''; inList = false; } html += '

' + l.replace(/^## /, '') + '

'; continue; } - if (/^[-*] (.+)$/.test(l)) { if (!inList) { html += ''; inList = false; } - if (l.trim() === '') continue; - html += '

' + l + '

'; - } - if (inList) html += ''; - html = html.replace(/\*\*(.+?)\*\*/g, '$1'); - html = html.replace(/\*(.+?)\*/g, '$1'); - return html; - }, - - esc: function(s) { if (!s) return ''; var d = document.createElement('div'); d.textContent = s; return d.innerHTML; }, - - toUTC: function(s) { - if (!s) return s; - s = String(s).trim(); - if (/[Zz]$/.test(s) || /[+-]\d{2}:?\d{2}$/.test(s)) return s; - return s.replace(' ', 'T') + 'Z'; - }, - - fmtDT: function(iso) { - if (!iso) return ''; - try { - var d = new Date(this.toUTC(iso)); - if (isNaN(d.getTime())) return iso; - var opts = { timeZone: TIMEZONE, weekday: 'long', day: 'numeric', month: 'long', year: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false }; - var parts = new Intl.DateTimeFormat('de-DE', opts).formatToParts(d); - var p = {}; - parts.forEach(function(x) { p[x.type] = x.value; }); - return p.weekday + ', ' + p.day + '. ' + p.month + ' ' + p.year - + ' um ' + p.hour + ':' + p.minute + ' Uhr'; - } catch(e) { return iso; } - }, - - fmtDateOnly: function(iso) { - if (!iso) return ''; - try { - var d = new Date(this.toUTC(iso)); - if (isNaN(d.getTime())) return iso; - return d.toLocaleDateString('de-DE', { day: 'numeric', month: 'short', year: 'numeric', timeZone: TIMEZONE }); - } catch(e) { return iso; } - }, - - fmtTimeOnly: function(iso) { - if (!iso) return ''; - try { - var d = new Date(this.toUTC(iso)); - if (isNaN(d.getTime())) return iso; - return d.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit', timeZone: TIMEZONE }); - } catch(e) { return iso; } - }, - - fmtShort: function(iso) { - if (!iso) return ''; - try { return new Date(this.toUTC(iso)).toLocaleDateString('de-DE', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit', timeZone: TIMEZONE }); } - catch(e) { return iso; } - }, - - showError: function() { - document.getElementById('summary-content').innerHTML = - '

Das Lagebild konnte nicht geladen werden. Bitte versuchen Sie es sp\u00e4ter erneut.

'; - } -}; - -document.addEventListener('DOMContentLoaded', function() { Lagebild.init(); }); +/** + * AegisSight Lagebild Page - Dark Theme Design Refresh + * Count-Up, Timeline, Scroll-Reveal, Particles, Live-Feed, Pulse-Markers + */ + +/** Feste Zeitzone fuer alle Anzeigen - NIEMALS aendern. */ +var TIMEZONE = 'Europe/Berlin'; + +var Lagebild = { + data: null, + allSnapshots: {}, + currentView: null, + map: null, + timelineGroups: null, + + /* ===== Inline SVG Icons ===== */ + icons: { + clock: '', + fileText: '', + globe: '', + shieldCheck: '', + externalLink: '' + }, + + async init() { + if (typeof initTranslations === 'function') { + try { initTranslations(); } catch(e) {} + } + this.initScrollProgress(); + this.initParticles(); + try { + var resp = await fetch('data/current.json?t=' + Date.now()); + if (!resp.ok) throw new Error('HTTP ' + resp.status); + this.data = await resp.json(); + this.currentView = { + summary: this.data.current_lagebild.summary_markdown, + sources_json: this.data.current_lagebild.sources_json, + updated_at: this.data.current_lagebild.updated_at || this.data.generated_at, + articles: this.data.articles, + fact_checks: this.data.fact_checks + }; + this.render(); + this.initTabs(); + this.initLangToggle(); + this.initScrollReveal(); + this.initFloatingCta(); + this.initLiveFeed(); + } catch (e) { + console.error('Lagebild laden fehlgeschlagen:', e); + this.showError(); + } + }, + + render: function() { + this.renderHero(); + this.renderTimeline(); + this.renderTabBadges(); + this.renderCurrentView(); + }, + + /* ===== SCROLL PROGRESS BAR ===== */ + initScrollProgress: function() { + var bar = document.getElementById('scroll-progress'); + if (!bar) return; + window.addEventListener('scroll', function() { + var scrollTop = window.scrollY; + var docHeight = document.documentElement.scrollHeight - window.innerHeight; + if (docHeight <= 0) return; + bar.style.width = ((scrollTop / docHeight) * 100) + '%'; + }); + }, + + /* ===== HERO PARTICLES ===== */ + initParticles: function() { + var canvas = document.getElementById('hero-particles'); + if (!canvas) return; + var ctx = canvas.getContext('2d'); + var particles = []; + var count = 35; + var connectDist = 120; + + function resize() { + var hero = canvas.parentElement; + canvas.width = hero.offsetWidth; + canvas.height = hero.offsetHeight; + } + resize(); + window.addEventListener('resize', resize); + + for (var i = 0; i < count; i++) { + particles.push({ + x: Math.random() * canvas.width, + y: Math.random() * canvas.height, + vx: (Math.random() - 0.5) * 0.4, + vy: (Math.random() - 0.5) * 0.4, + r: Math.random() * 1.5 + 0.5 + }); + } + + function draw() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + + // Draw connections + for (var i = 0; i < particles.length; i++) { + for (var j = i + 1; j < particles.length; j++) { + var dx = particles[i].x - particles[j].x; + var dy = particles[i].y - particles[j].y; + var dist = Math.sqrt(dx * dx + dy * dy); + if (dist < connectDist) { + var alpha = (1 - dist / connectDist) * 0.15; + ctx.beginPath(); + ctx.strokeStyle = 'rgba(200, 168, 81, ' + alpha + ')'; + ctx.lineWidth = 0.5; + ctx.moveTo(particles[i].x, particles[i].y); + ctx.lineTo(particles[j].x, particles[j].y); + ctx.stroke(); + } + } + } + + // Draw & move particles + for (var k = 0; k < particles.length; k++) { + var p = particles[k]; + ctx.beginPath(); + ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2); + ctx.fillStyle = 'rgba(200, 168, 81, 0.4)'; + ctx.fill(); + + p.x += p.vx; + p.y += p.vy; + if (p.x < 0 || p.x > canvas.width) p.vx *= -1; + if (p.y < 0 || p.y > canvas.height) p.vy *= -1; + } + + requestAnimationFrame(draw); + } + draw(); + }, + + /* ===== LIVE FEED TICKER ===== */ + initLiveFeed: function() { + var container = document.getElementById('live-feed'); + if (!container) return; + + var d = this.data; + var genDate = new Date(this.toUTC(d.generated_at)); + var diffMin = Math.max(1, Math.round((Date.now() - genDate.getTime()) / 60000)); + var diffText = diffMin < 60 ? ('vor ' + diffMin + ' Min') : ('vor ' + Math.round(diffMin / 60) + ' Std'); + + var messages = [ + 'Letzte Aktualisierung: ' + diffText, + + d.incident.article_count + ' Artikel analysiert \u2013 ' + d.incident.factcheck_count + ' Faktenchecks durchgef\u00fchrt', + ]; + + var h = ''; + for (var i = 0; i < messages.length; i++) { + h += '
'; + h += ''; + h += '' + messages[i] + ''; + h += '
'; + } + container.innerHTML = h; + + var current = 0; + var items = container.querySelectorAll('.live-feed-item'); + setInterval(function() { + items[current].classList.remove('active'); + current = (current + 1) % items.length; + items[current].classList.add('active'); + }, 4000); + }, + + /* ===== HERO ===== */ + renderHero: function() { + var d = this.data; + document.getElementById('incident-title').innerHTML = + this.esc(this.fixUmlauts(d.incident.title)) + + ' \u2013 Stand: ' + this.fmtDateOnly(d.generated_at) + ', ' + this.fmtTimeOnly(d.generated_at) + ' Uhr'; + + // Stat Cards (3: Artikel, Quellen, Faktenchecks) + var statsHtml = ''; + statsHtml += this.statCard(this.icons.fileText, '0', 'Artikel'); + statsHtml += this.statCard(this.icons.globe, '0', 'Quellen'); + statsHtml += this.statCard(this.icons.shieldCheck, '0', 'Faktenchecks'); + document.getElementById('hero-stats').innerHTML = statsHtml; + + // Start count-up animations + var self = this; + requestAnimationFrame(function() { + var els = document.querySelectorAll('.count-up'); + for (var i = 0; i < els.length; i++) { + self.animateCount(els[i], parseInt(els[i].getAttribute('data-target')), 800); + } + }); + }, + + statCard: function(icon, value, label) { + return '
' + + '
' + icon + '
' + + '
' + + '' + value + '' + + '' + label + '' + + '
'; + }, + + /* ===== COUNT-UP ANIMATION ===== */ + animateCount: function(element, target, duration) { + var start = performance.now(); + function update(now) { + var elapsed = now - start; + var progress = Math.min(elapsed / duration, 1); + var eased = 1 - Math.pow(1 - progress, 3); // easeOutCubic + var current = Math.round(target * eased); + element.textContent = current.toLocaleString('de-DE'); + if (progress < 1) { + requestAnimationFrame(update); + } + } + requestAnimationFrame(update); + }, + + /* ===== TIMELINE STRIP ===== */ + renderTimeline: function() { + var snaps = this.data.available_snapshots || []; + var current = { + id: 'current', + article_count: this.data.incident.article_count, + fact_check_count: this.data.incident.factcheck_count, + created_at: this.data.generated_at + }; + var all = [current].concat(snaps); + + // Group by date + var groups = {}; + for (var i = 0; i < all.length; i++) { + var s = all[i]; + var dateKey = this.toDateKey(s.created_at); + if (!groups[dateKey]) groups[dateKey] = []; + groups[dateKey].push(s); + } + + // Sort each group descending (newest first) + for (var dk in groups) { + groups[dk].sort(function(a, b) { + return new Date(Lagebild.toUTC(b.created_at)) - new Date(Lagebild.toUTC(a.created_at)); + }); + } + + this.timelineGroups = groups; + var dates = Object.keys(groups).sort(); + var strip = document.getElementById('timeline-strip'); + var h = ''; + + for (var j = 0; j < dates.length; j++) { + var date = dates[j]; + var daySnaps = groups[date]; + var latest = daySnaps[0]; + var isActive = (j === dates.length - 1); + var d = new Date(date + 'T12:00:00Z'); + + h += ''; + } + + strip.innerHTML = h; + + // Scroll to active day + var active = strip.querySelector('.timeline-day.active'); + if (active) { + setTimeout(function() { + active.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' }); + }, 150); + } + + // Click handler for day buttons + var self = this; + strip.addEventListener('click', function(e) { + var btn = e.target.closest('.timeline-day'); + if (!btn) return; + + var allDays = strip.querySelectorAll('.timeline-day'); + for (var k = 0; k < allDays.length; k++) allDays[k].classList.remove('active'); + btn.classList.add('active'); + + var dateKey = btn.getAttribute('data-date'); + var snapId = btn.getAttribute('data-snapshot-id'); + + self.showTimelineDropdown(dateKey, snapId); + + if (snapId === 'current') { + self.currentView = { + summary: self.data.current_lagebild.summary_markdown, + sources_json: self.data.current_lagebild.sources_json, + updated_at: self.data.current_lagebild.updated_at || self.data.generated_at, + articles: self.data.articles, + fact_checks: self.data.fact_checks + }; + self.renderCurrentView(); + } else { + self.loadSnapshot(parseInt(snapId)); + } + }); + + // Click handler for dropdown snapshot items (delegated, set up once) + var dropdown = document.getElementById('timeline-dropdown'); + dropdown.addEventListener('click', function(e) { + var item = e.target.closest('.timeline-snap-item'); + if (!item) return; + + var items = dropdown.querySelectorAll('.timeline-snap-item'); + for (var k = 0; k < items.length; k++) items[k].classList.remove('active'); + item.classList.add('active'); + + var snapId = item.getAttribute('data-snapshot-id'); + if (snapId === 'current') { + self.currentView = { + summary: self.data.current_lagebild.summary_markdown, + sources_json: self.data.current_lagebild.sources_json, + updated_at: self.data.current_lagebild.updated_at || self.data.generated_at, + articles: self.data.articles, + fact_checks: self.data.fact_checks + }; + self.renderCurrentView(); + } else { + self.loadSnapshot(parseInt(snapId)); + } + }); + + // Show dropdown for newest day by default + var newestDate = dates[dates.length - 1]; + if (newestDate && groups[newestDate].length > 1) { + this.showTimelineDropdown(newestDate, groups[newestDate][0].id); + } + }, + + showTimelineDropdown: function(dateKey, activeSnapId) { + var dropdown = document.getElementById('timeline-dropdown'); + var snaps = this.timelineGroups[dateKey]; + + if (!snaps || snaps.length <= 1) { + dropdown.classList.remove('open'); + dropdown.innerHTML = ''; + return; + } + + var d = new Date(dateKey + 'T12:00:00Z'); + var dateLabel = d.toLocaleDateString('de-DE', { day: 'numeric', month: 'long', year: 'numeric', timeZone: 'UTC' }); + + var h = '
' + dateLabel + ' \u2013 ' + snaps.length + ' Updates
'; + h += '
'; + for (var i = 0; i < snaps.length; i++) { + var snap = snaps[i]; + var isActive = (String(snap.id) === String(activeSnapId)); + h += ''; + } + h += '
'; + + dropdown.innerHTML = h; + dropdown.classList.add('open'); + }, + + toDateKey: function(iso) { + if (!iso) return ''; + var d = new Date(this.toUTC(iso)); + return d.toLocaleDateString('en-CA', { timeZone: TIMEZONE }); + }, + + /* ===== TAB BADGES ===== */ + renderTabBadges: function() { + var quellenBadge = document.getElementById('tab-badge-quellen'); + var fcBadge = document.getElementById('tab-badge-faktenchecks'); + if (quellenBadge) quellenBadge.textContent = this.data.incident.source_count; + if (fcBadge) fcBadge.textContent = this.data.incident.factcheck_count; + }, + + /* ===== SNAPSHOT LOADING ===== */ + loadSnapshot: async function(id) { + if (this.allSnapshots[id]) { + this.currentView = this.allSnapshots[id]; + this.renderCurrentView(); + return; + } + try { + var resp = await fetch('data/snapshot-' + id + '.json'); + if (!resp.ok) throw new Error('HTTP ' + resp.status); + var sd = await resp.json(); + var sj = sd.sources_json; + if (typeof sj === 'string') { try { sj = JSON.parse(sj); } catch(e) { sj = []; } } + this.currentView = { + summary: sd.summary, + sources_json: sj || [], + updated_at: sd.created_at, + articles: this.data.articles, + fact_checks: this.data.fact_checks + }; + this.allSnapshots[id] = this.currentView; + this.renderCurrentView(); + } catch (e) { console.error('Snapshot Fehler:', e); } + }, + + renderCurrentView: function() { + this.renderSummary(); + this.renderInlineSources(); + this.renderSourcesTab(); + this.renderArticlesTab(); + this.renderFactChecksTab(); + if (document.getElementById('panel-karte').classList.contains('active')) { + this.renderMap(); + } + }, + + /* ===== TAB: LAGEBILD ===== */ + renderSummary: function() { + var v = this.currentView; + document.getElementById('lagebild-timestamp').textContent = this.fmtDT(v.updated_at); + var md = this.fixUmlauts(v.summary || ''); + var html = this.mdToHtml(md); + + // Build source lookup for citation links + var srcMap = {}; + var sources = v.sources_json || []; + for (var i = 0; i < sources.length; i++) { + srcMap[sources[i].nr] = sources[i]; + } + var self = this; + html = html.replace(/\[(\d+)\]/g, function(match, nr) { + var src = srcMap[nr]; + if (src && src.url) { + return '[' + nr + ']'; + } + return '[' + nr + ']'; + }); + + document.getElementById('summary-content').innerHTML = html; + }, + + renderInlineSources: function() { + document.getElementById('inline-sources').innerHTML = ''; + }, + + /* ===== TAB: QUELLEN (Tile Grid) ===== */ + renderSourcesTab: function() { + var articles = this.currentView.articles || []; + var container = document.getElementById('sources-grid-container'); + if (!container) return; + + // Aggregate by source + var sourceMap = {}; + for (var i = 0; i < articles.length; i++) { + var a = articles[i]; + var name = a.source || 'Unbekannt'; + if (!sourceMap[name]) sourceMap[name] = { count: 0, articles: [], languages: {}, domain: null }; + sourceMap[name].count++; + sourceMap[name].articles.push(a); + var lang = (a.language || '').toUpperCase(); + if (lang) sourceMap[name].languages[lang] = (sourceMap[name].languages[lang] || 0) + 1; + if (!sourceMap[name].domain && a.source_url) sourceMap[name].domain = this.extractDomain(a.source_url); + } + + // Sort by count desc + var sources = []; + for (var name in sourceMap) { + sources.push({ name: name, data: sourceMap[name] }); + } + sources.sort(function(a, b) { return b.data.count - a.data.count; }); + + // Language totals + var langTotals = {}; + for (var i = 0; i < articles.length; i++) { + var lang = (articles[i].language || '').toUpperCase(); + if (lang) langTotals[lang] = (langTotals[lang] || 0) + 1; + } + + var h = ''; + + // Header + h += '
'; + h += '' + articles.length + ' Artikel aus ' + sources.length + ' Quellen'; + h += '
'; + var langKeys = Object.keys(langTotals).sort(function(a, b) { return langTotals[b] - langTotals[a]; }); + for (var i = 0; i < langKeys.length; i++) { + h += '' + langKeys[i] + ' ' + langTotals[langKeys[i]] + ''; + } + h += '
'; + + // Grid + h += '
'; + for (var i = 0; i < sources.length; i++) { + var s = sources[i]; + var langBadge = Object.keys(s.data.languages).join('/'); + h += '
'; + h += '
'; + if (s.data.domain) { + h += ''; + } + h += '' + this.esc(s.name) + ''; + h += '
'; + h += '
'; + h += '' + langBadge + ''; + h += '' + s.data.count + ''; + h += '
'; + h += '
'; + } + h += '
'; + + container.innerHTML = h; + this._sourceTiles = sources; + + // Click handler + var self = this; + document.getElementById('sources-grid').addEventListener('click', function(e) { + var tile = e.target.closest('.source-tile'); + if (!tile) return; + self.toggleSourceDetail(tile); + }); + }, + + toggleSourceDetail: function(tile) { + var grid = document.getElementById('sources-grid'); + var idx = parseInt(tile.getAttribute('data-source-index')); + var existingPanel = grid.querySelector('.source-detail-panel'); + var wasActive = tile.classList.contains('active'); + + // Remove active from all tiles + var allTiles = grid.querySelectorAll('.source-tile'); + for (var k = 0; k < allTiles.length; k++) allTiles[k].classList.remove('active'); + + // Remove existing panel + if (existingPanel) existingPanel.remove(); + + // If same tile was active, just close + if (wasActive) return; + + tile.classList.add('active'); + + // Find last tile in same visual row (by offsetTop) + var clickedTop = tile.offsetTop; + var lastInRow = tile; + for (var k = 0; k < allTiles.length; k++) { + if (allTiles[k].offsetTop === clickedTop) { + lastInRow = allTiles[k]; + } + } + + // Build detail panel + var src = this._sourceTiles[idx]; + var arts = src.data.articles.slice().sort(function(a, b) { + var da = new Date(Lagebild.toUTC(a.published_at || a.collected_at || '')); + var db = new Date(Lagebild.toUTC(b.published_at || b.collected_at || '')); + return db - da; + }); + + var h = '
'; + h += '
'; + h += ''; + if (src.data.domain) { + h += ' '; + } + h += this.esc(src.name) + ''; + h += '' + src.data.count + ' Artikel'; + h += ''; + h += '
'; + h += '
'; + for (var j = 0; j < arts.length; j++) { + var a = arts[j]; + var dt = a.published_at || a.collected_at || ''; + var dObj = dt ? new Date(this.toUTC(dt)) : null; + var hl = this.fixUmlauts(a.headline_de || a.headline || ''); + h += '
'; + if (a.source_url) { + h += '' + this.esc(hl) + ' ' + this.icons.externalLink + ''; + } else { + h += '' + this.esc(hl) + ''; + } + if (dObj && !isNaN(dObj.getTime())) { + h += ''; + } + h += '
'; + } + h += '
'; + + // Insert after last tile in row + lastInRow.insertAdjacentHTML('afterend', h); + + // Close button handler + var panel = grid.querySelector('.source-detail-panel'); + var self = this; + panel.querySelector('.source-detail-close').addEventListener('click', function(e) { + e.stopPropagation(); + panel.remove(); + tile.classList.remove('active'); + }); + + // Scroll into view + setTimeout(function() { + panel.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); + }, 50); + }, + + renderArticlesTab: function() {}, + + /* ===== TAB: KARTE (Pulse Markers) ===== */ + renderMap: function() { + if (this.map) { this.map.remove(); this.map = null; } + this.map = L.map('map-container').setView([33.0, 48.0], 5); + + // Dark map tiles (CartoDB Dark Matter) + L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', { + attribution: '© OpenStreetMap © CARTO', + maxZoom: 19, + subdomains: 'abcd' + }).addTo(this.map); + + function pulseIcon(color) { + return L.divIcon({ + className: '', + html: '
' + + '
' + + '
' + + '
' + + '
', + iconSize: [20, 20], + iconAnchor: [10, 10], + popupAnchor: [0, -12] + }); + } + + var red = '#ef4444'; + var orange = '#f59e0b'; + var blue = '#3b82f6'; + + var locs = [ + {n:'Teheran, Iran',lat:35.6892,lng:51.3890,d:'Hauptziel der US-israelischen Luftschl\u00e4ge. \u00dcber 1.000 Tote nach f\u00fcnf Tagen Krieg.',c:red}, + {n:'Beirut, Libanon',lat:33.8938,lng:35.5018,d:'Gleichzeitige US-israelische Luftschl\u00e4ge auf Beirut und Teheran [6].',c:red}, + {n:'Juffair, Bahrain',lat:26.2235,lng:50.6001,d:'US-Marinebasis \u2013 Ziel iranischer Vergeltungsraketen [3].',c:orange}, + {n:'Al Udeid, Katar',lat:25.1173,lng:51.3150,d:'US-Luftwaffenst\u00fctzpunkt \u2013 Ziel iranischer Gegenangriffe.',c:orange}, + {n:'Tel Aviv, Israel',lat:32.0853,lng:34.7818,d:'Operationsbasis f\u00fcr israelische Angriffe auf den Iran.',c:blue}, + {n:'Ankara, T\u00fcrkei',lat:39.9334,lng:32.8597,d:'NATO vermutet iranischen Raketenbeschuss auf T\u00fcrkei [10]. Keine NATO-Beteiligung geplant.',c:orange}, + {n:'Bagdad, Irak',lat:33.3152,lng:44.3661,d:'Lage im Irak als Faktor im Kriegsverlauf [2].',c:blue}, + {n:'Persischer Golf',lat:27.0,lng:51.5,d:'Iran greift Energieinfrastruktur und diplomatische Einrichtungen in der Golfregion an.',c:orange}, + {n:'Dubai, VAE',lat:25.2048,lng:55.2708,d:'US-Botschaft in Dubai durch iranischen Angriff getroffen.',c:red}, + {n:'Washington D.C., USA',lat:38.9072,lng:-77.0369,d:'War-Powers-Abstimmung im Senat gescheitert (47:53). Trump verteidigt Iran-Krieg vor Kongress.',c:blue} + ]; + + for (var i = 0; i < locs.length; i++) { + var l = locs[i]; + L.marker([l.lat, l.lng], { icon: pulseIcon(l.c) }) + .addTo(this.map) + .bindPopup('' + l.n + '
' + l.d + ''); + } + + // Dark legend + var legend = L.control({ position: 'bottomright' }); + legend.onAdd = function() { + var div = L.DomUtil.create('div', 'map-legend'); + div.style.cssText = 'background:#151D2E;padding:10px 14px;border-radius:4px;border:1px solid #1E2D45;box-shadow:0 2px 8px rgba(0,0,0,0.3);font-size:0.8rem;line-height:1.8;color:#E8ECF4;'; + div.innerHTML = 'Legende
' + + ' Angegriffene Ziele
' + + ' Vergeltung / Eskalation
' + + ' Strategische Akteure'; + return div; + }; + legend.addTo(this.map); + + // Dark popup styling + if (!document.getElementById('leaflet-dark-style')) { + var style = document.createElement('style'); + style.id = 'leaflet-dark-style'; + style.textContent = '.lagebild-page .leaflet-popup-content-wrapper{background:#151D2E;color:#E8ECF4;border:1px solid #1E2D45;border-radius:4px;box-shadow:0 4px 16px rgba(0,0,0,0.4);}.lagebild-page .leaflet-popup-tip{background:#151D2E;}'; + document.head.appendChild(style); + } + + setTimeout(function() { if (Lagebild.map) Lagebild.map.invalidateSize(); }, 300); + }, + + /* ===== TAB: FAKTENCHECKS ===== */ + renderFactChecksTab: function() { + var checks = this.currentView.fact_checks || []; + if (!checks.length) { + document.getElementById('factchecks-content').innerHTML = '

Keine Faktenchecks verf\u00fcgbar.

'; + return; + } + + var stats = { confirmed: 0, unconfirmed: 0, contradicted: 0, developing: 0, established: 0, disputed: 0 }; + for (var k = 0; k < checks.length; k++) { + var st = checks[k].status || 'developing'; + if (stats[st] !== undefined) stats[st]++; + } + + var h = '
'; + h += '
' + checks.length + 'Gesamt
'; + h += '
' + (stats.confirmed + stats.established) + 'Best\u00e4tigt
'; + h += '
' + (stats.unconfirmed + stats.developing) + 'Offen
'; + if (stats.contradicted + stats.disputed > 0) + h += '
' + (stats.contradicted + stats.disputed) + 'Widerlegt
'; + h += '
'; + + checks = checks.slice().sort(function(a, b) { + var aH = (a.status_history || []).length; + var bH = (b.status_history || []).length; + if (bH !== aH) return bH - aH; + return (b.sources_count || 0) - (a.sources_count || 0); + }); + + for (var i = 0; i < checks.length; i++) { + var fc = checks[i]; + var status = fc.status || 'developing'; + var hasProg = fc.status_history && fc.status_history.length > 1; + + h += '
'; + h += '
'; + h += '' + this.stLabel(status) + ''; + h += '' + (fc.sources_count || 0) + ' unabh\u00e4ngige Quellen'; + h += '
'; + h += '

' + this.esc(this.fixUmlauts(fc.claim || '')) + '

'; + + if (fc.evidence) { + var ev = this.fixUmlauts(fc.evidence); + ev = this.esc(ev).replace(/(https?:\/\/[^\s,)]+)/g, '$1'); + h += '
Evidenz: ' + ev + '
'; + } + + if (hasProg) { + h += '
'; + h += 'Verlauf:'; + for (var j = 0; j < fc.status_history.length; j++) { + var step = fc.status_history[j]; + if (j > 0) h += ''; + h += ''; + h += '' + this.stLabel(step.status) + ''; + if (step.at) h += '' + this.fmtShort(step.at) + ''; + h += ''; + } + h += '
'; + } + h += '
'; + } + document.getElementById('factchecks-content').innerHTML = h; + }, + + /* ===== TABS ===== */ + initTabs: function() { + var btns = document.querySelectorAll('.tab-btn'); + var self = this; + for (var i = 0; i < btns.length; i++) { + btns[i].addEventListener('click', function() { + var tab = this.getAttribute('data-tab'); + for (var j = 0; j < btns.length; j++) btns[j].classList.remove('active'); + this.classList.add('active'); + var panels = document.querySelectorAll('.tab-panel'); + for (var j = 0; j < panels.length; j++) panels[j].classList.remove('active'); + var activePanel = document.getElementById('panel-' + tab); + activePanel.classList.add('active'); + + // Trigger reveal for cards in newly active panel + var revealCards = activePanel.querySelectorAll('.reveal:not(.revealed)'); + for (var k = 0; k < revealCards.length; k++) { + revealCards[k].classList.add('revealed'); + } + + if (tab === 'karte') self.renderMap(); + }); + } + }, + + initLangToggle: function() { + var btn = document.querySelector('.lang-toggle'); + if (!btn) return; + btn.addEventListener('click', function(e) { + e.preventDefault(); + if (typeof switchLanguage === 'function') { + var cur = (typeof getCurrentLanguage === 'function') ? getCurrentLanguage() : 'de'; + switchLanguage(cur === 'de' ? 'en' : 'de'); + } + }); + }, + + /* ===== FLOATING CTA ===== */ + initFloatingCta: function() { + var cta = document.createElement('div'); + cta.className = 'floating-cta'; + cta.innerHTML = 'AegisSight Monitor f\u00fcr Ihre Organisation' + + 'Kontakt aufnehmen \u2192' + + ''; + document.body.appendChild(cta); + + // Show after scrolling past hero + var shown = false; + window.addEventListener('scroll', function() { + if (shown) return; + if (window.scrollY > 400) { + cta.classList.add('visible'); + shown = true; + } + }); + + // Close button + cta.querySelector('.floating-cta-close').addEventListener('click', function(e) { + e.preventDefault(); + cta.classList.add('dismissed'); + setTimeout(function() { cta.classList.remove('dismissed'); }, 60000); + }); + }, + + /* ===== SCROLL REVEAL ===== */ + initScrollReveal: function() { + var cards = document.querySelectorAll('.content-card, .lagebild-cta'); + if (!('IntersectionObserver' in window)) { + for (var i = 0; i < cards.length; i++) cards[i].classList.add('revealed'); + return; + } + var observer = new IntersectionObserver(function(entries) { + entries.forEach(function(entry) { + if (entry.isIntersecting) { + entry.target.classList.add('revealed'); + observer.unobserve(entry.target); + } + }); + }, { threshold: 0.1 }); + + for (var i = 0; i < cards.length; i++) { + cards[i].classList.add('reveal'); + // Immediately reveal cards in the active (visible) tab panel + var panel = cards[i].closest('.tab-panel'); + if (!panel || panel.classList.contains('active')) { + cards[i].classList.add('revealed'); + } else { + observer.observe(cards[i]); + } + } + }, + + /* ===== HILFSFUNKTIONEN ===== */ + extractDomain: function(url) { + if (!url) return null; + try { return new URL(url).hostname; } catch(e) { return null; } + }, + + fixUmlauts: function(text) { + if (!text) return text; + var skip = ['Israel','Israelis','Jazeera','Euronews','Reuters','Februar', + 'Juffair','abgefeuert','Feindseligkeiten','Gegenschlag','neuesten', + 'auszuweiten','befeuert','feuerte','Feuer','feuer','neue','neuen', + 'neuer','neues','Neue','Aero','aero','Manoeuvre','Dauerfeuer']; + var ph = []; var c = 0; + for (var i = 0; i < skip.length; i++) { + var re = new RegExp('\\b' + skip[i] + '\\b', 'g'); + text = text.replace(re, function(m) { ph.push(m); return '##S' + (c++) + '##'; }); + } + text = text.replace(/ae/g, '\u00e4').replace(/Ae/g, '\u00c4'); + text = text.replace(/oe/g, '\u00f6').replace(/Oe/g, '\u00d6'); + text = text.replace(/ue/g, '\u00fc').replace(/Ue/g, '\u00dc'); + text = text.replace(/##S(\d+)##/g, function(m, idx) { return ph[parseInt(idx)]; }); + return text; + }, + + stLabel: function(s) { + return { confirmed: 'Best\u00e4tigt', unconfirmed: 'Unbest\u00e4tigt', established: 'Gesichert', + unverified: 'Nicht verifiziert', contradicted: 'Widerlegt', disputed: 'Umstritten', + developing: 'In Entwicklung', 'false': 'Falsch' }[s] || s; + }, + + mdToHtml: function(md) { + if (!md) return ''; + var lines = md.split('\n'), html = '', inList = false; + for (var i = 0; i < lines.length; i++) { + var l = lines[i]; + if (/^### (.+)$/.test(l)) { if (inList) { html += ''; inList = false; } html += '

' + l.replace(/^### /, '') + '

'; continue; } + if (/^## (.+)$/.test(l)) { if (inList) { html += ''; inList = false; } html += '

' + l.replace(/^## /, '') + '

'; continue; } + if (/^[-*] (.+)$/.test(l)) { if (!inList) { html += ''; inList = false; } + if (l.trim() === '') continue; + html += '

' + l + '

'; + } + if (inList) html += ''; + html = html.replace(/\*\*(.+?)\*\*/g, '$1'); + html = html.replace(/\*(.+?)\*/g, '$1'); + return html; + }, + + esc: function(s) { if (!s) return ''; var d = document.createElement('div'); d.textContent = s; return d.innerHTML; }, + + toUTC: function(s) { + if (!s) return s; + s = String(s).trim(); + if (/[Zz]$/.test(s) || /[+-]\d{2}:?\d{2}$/.test(s)) return s; + return s.replace(' ', 'T') + 'Z'; + }, + + fmtDT: function(iso) { + if (!iso) return ''; + try { + var d = new Date(this.toUTC(iso)); + if (isNaN(d.getTime())) return iso; + var opts = { timeZone: TIMEZONE, weekday: 'long', day: 'numeric', month: 'long', year: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false }; + var parts = new Intl.DateTimeFormat('de-DE', opts).formatToParts(d); + var p = {}; + parts.forEach(function(x) { p[x.type] = x.value; }); + return p.weekday + ', ' + p.day + '. ' + p.month + ' ' + p.year + + ' um ' + p.hour + ':' + p.minute + ' Uhr'; + } catch(e) { return iso; } + }, + + fmtDateOnly: function(iso) { + if (!iso) return ''; + try { + var d = new Date(this.toUTC(iso)); + if (isNaN(d.getTime())) return iso; + return d.toLocaleDateString('de-DE', { day: 'numeric', month: 'short', year: 'numeric', timeZone: TIMEZONE }); + } catch(e) { return iso; } + }, + + fmtTimeOnly: function(iso) { + if (!iso) return ''; + try { + var d = new Date(this.toUTC(iso)); + if (isNaN(d.getTime())) return iso; + return d.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit', timeZone: TIMEZONE }); + } catch(e) { return iso; } + }, + + fmtShort: function(iso) { + if (!iso) return ''; + try { return new Date(this.toUTC(iso)).toLocaleDateString('de-DE', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit', timeZone: TIMEZONE }); } + catch(e) { return iso; } + }, + + showError: function() { + document.getElementById('summary-content').innerHTML = + '

Das Lagebild konnte nicht geladen werden. Bitte versuchen Sie es sp\u00e4ter erneut.

'; + } +}; + +document.addEventListener('DOMContentLoaded', function() { Lagebild.init(); });