diff --git a/aurora-livecam/SettingsManager.php b/aurora-livecam/SettingsManager.php index 6c8b7a6..3dc0415 100644 --- a/aurora-livecam/SettingsManager.php +++ b/aurora-livecam/SettingsManager.php @@ -26,7 +26,8 @@ class SettingsManager { return [ 'viewer_display' => [ 'enabled' => true, - 'min_viewers' => 1 + 'min_viewers' => 1, + 'update_interval' => 5 // Sekunden ], 'video_mode' => [ 'play_in_player' => true, @@ -36,6 +37,52 @@ class SettingsManager { 'default_speed' => 1, 'available_speeds' => [1, 10, 100] ], + // Punkt 2: UI-Anzeige Features + 'ui_display' => [ + 'show_recommendation_banner' => true, + 'show_qr_code' => true, + 'show_social_media' => true, + 'show_patrouille_suisse' => true + ], + // Punkt 3: Zoom & Timelapse + 'zoom_timelapse' => [ + 'show_zoom_controls' => true, + 'max_zoom_level' => 4.0, + 'timelapse_reverse_enabled' => true + ], + // Punkt 5: Content Management + 'content' => [ + 'guestbook_enabled' => true, + 'gallery_enabled' => true, + 'ai_events_enabled' => true, + 'max_guestbook_entries' => 50 + ], + // Punkt 6: Technische Settings + 'technical' => [ + 'viewer_update_interval' => 5, // Sekunden + 'session_timeout' => 30 // Sekunden + ], + // Punkt 7: Theme & Design + 'theme' => [ + 'default_theme' => 'theme-legacy', + 'show_theme_switcher' => false + ], + // Punkt 8: SEO & Meta + 'seo' => [ + 'custom_title' => '', + 'meta_description' => '', + 'meta_keywords' => '' + ], + // Weather Widget + 'weather' => [ + 'enabled' => true, + 'api_key' => '', + 'location' => 'Oberdürnten,CH', + 'lat' => '47.2833', + 'lon' => '8.7167', + 'update_interval' => 5, // Minuten + 'units' => 'metric' // metric (Celsius) oder imperial (Fahrenheit) + ], 'last_updated' => null, 'updated_by' => null ]; @@ -123,4 +170,111 @@ class SettingsManager { public function shouldAllowDownload() { return $this->get('video_mode.allow_download') === true; } + + // UI Display Helper + public function shouldShowRecommendationBanner() { + return $this->get('ui_display.show_recommendation_banner') === true; + } + + public function shouldShowQRCode() { + return $this->get('ui_display.show_qr_code') === true; + } + + public function shouldShowSocialMedia() { + return $this->get('ui_display.show_social_media') === true; + } + + public function shouldShowPatrouillesuisse() { + return $this->get('ui_display.show_patrouille_suisse') === true; + } + + // Content Management Helper + public function isGuestbookEnabled() { + return $this->get('content.guestbook_enabled') === true; + } + + public function isGalleryEnabled() { + return $this->get('content.gallery_enabled') === true; + } + + public function isAIEventsEnabled() { + return $this->get('content.ai_events_enabled') === true; + } + + public function getMaxGuestbookEntries() { + return $this->get('content.max_guestbook_entries') ?? 50; + } + + // Theme Helper + public function getDefaultTheme() { + return $this->get('theme.default_theme') ?? 'theme-legacy'; + } + + public function shouldShowThemeSwitcher() { + return $this->get('theme.show_theme_switcher') === true; + } + + // Technical Helper + public function getViewerUpdateInterval() { + return $this->get('technical.viewer_update_interval') ?? 5; + } + + public function getSessionTimeout() { + return $this->get('technical.session_timeout') ?? 30; + } + + // Zoom & Timelapse Helper + public function shouldShowZoomControls() { + return $this->get('zoom_timelapse.show_zoom_controls') === true; + } + + public function getMaxZoomLevel() { + return $this->get('zoom_timelapse.max_zoom_level') ?? 4.0; + } + + public function isTimelapseReverseEnabled() { + return $this->get('zoom_timelapse.timelapse_reverse_enabled') === true; + } + + // SEO Helper + public function getCustomTitle() { + $title = $this->get('seo.custom_title'); + return !empty($title) ? $title : null; + } + + public function getMetaDescription() { + return $this->get('seo.meta_description') ?? ''; + } + + public function getMetaKeywords() { + return $this->get('seo.meta_keywords') ?? ''; + } + + // Weather Helper + public function isWeatherEnabled() { + return $this->get('weather.enabled') === true; + } + + public function getWeatherApiKey() { + return $this->get('weather.api_key') ?? ''; + } + + public function getWeatherLocation() { + return $this->get('weather.location') ?? 'Oberdürnten,CH'; + } + + public function getWeatherCoords() { + return [ + 'lat' => $this->get('weather.lat') ?? '47.2833', + 'lon' => $this->get('weather.lon') ?? '8.7167' + ]; + } + + public function getWeatherUpdateInterval() { + return $this->get('weather.update_interval') ?? 5; + } + + public function getWeatherUnits() { + return $this->get('weather.units') ?? 'metric'; + } } diff --git a/aurora-livecam/WeatherManager.php b/aurora-livecam/WeatherManager.php new file mode 100644 index 0000000..bd96cec --- /dev/null +++ b/aurora-livecam/WeatherManager.php @@ -0,0 +1,215 @@ +settingsManager = $settingsManager; + } + + /** + * Holt aktuelle Wetterdaten (cached) + */ + public function getCurrentWeather() { + // Prüfe ob Weather aktiviert ist + if (!$this->settingsManager->isWeatherEnabled()) { + return null; + } + + // Prüfe Cache + $cached = $this->getCache(); + if ($cached !== null) { + return $cached; + } + + // Hole frische Daten von API (Open-Meteo) + $coords = $this->settingsManager->getWeatherCoords(); + + // Open-Meteo API URL - komplett kostenlos, kein API Key! + $url = "https://api.open-meteo.com/v1/forecast?" . http_build_query([ + 'latitude' => $coords['lat'], + 'longitude' => $coords['lon'], + 'current' => 'temperature_2m,relative_humidity_2m,precipitation,weather_code,wind_speed_10m,wind_direction_10m,pressure_msl,cloud_cover', + 'timezone' => 'Europe/Zurich' + ]); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_TIMEOUT, 5); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($httpCode !== 200 || !$response) { + return ['error' => 'API Fehler']; + } + + $data = json_decode($response, true); + if (!$data || !isset($data['current'])) { + return ['error' => 'Ungültige API Antwort']; + } + + $current = $data['current']; + + // Formatiere Daten + $weather = [ + 'temp' => round($current['temperature_2m'], 1), + 'feels_like' => round($current['temperature_2m'], 1), // Open-Meteo hat keine "feels like" + 'humidity' => $current['relative_humidity_2m'], + 'pressure' => round($current['pressure_msl'], 0), + 'wind_speed' => round($current['wind_speed_10m'], 1), // Schon in km/h! + 'wind_deg' => $current['wind_direction_10m'], + 'wind_direction' => $this->getWindDirection($current['wind_direction_10m']), + 'clouds' => $current['cloud_cover'] ?? 0, + 'description' => $this->getWeatherDescription($current['weather_code']), + 'icon' => $this->getWeatherIcon($current['weather_code']), + 'rain_1h' => $current['precipitation'] ?? 0, + 'snow_1h' => 0, // Open-Meteo gibt Niederschlag gesamt + 'location' => $this->settingsManager->getWeatherLocation(), + 'timestamp' => time() + ]; + + // Cache speichern + $this->saveCache($weather); + + return $weather; + } + + /** + * Wandelt WMO Weather Code in Beschreibung um + * https://open-meteo.com/en/docs + */ + private function getWeatherDescription($code) { + $descriptions = [ + 0 => 'Klar', + 1 => 'Überwiegend klar', + 2 => 'Teilweise bewölkt', + 3 => 'Bewölkt', + 45 => 'Neblig', + 48 => 'Nebel mit Reifablagerung', + 51 => 'Leichter Nieselregen', + 53 => 'Mäßiger Nieselregen', + 55 => 'Dichter Nieselregen', + 61 => 'Leichter Regen', + 63 => 'Mäßiger Regen', + 65 => 'Starker Regen', + 71 => 'Leichter Schneefall', + 73 => 'Mäßiger Schneefall', + 75 => 'Starker Schneefall', + 77 => 'Schneegraupeln', + 80 => 'Leichte Regenschauer', + 81 => 'Mäßige Regenschauer', + 82 => 'Starke Regenschauer', + 85 => 'Leichte Schneeschauer', + 86 => 'Starke Schneeschauer', + 95 => 'Gewitter', + 96 => 'Gewitter mit leichtem Hagel', + 99 => 'Gewitter mit starkem Hagel' + ]; + + return $descriptions[$code] ?? 'Unbekannt'; + } + + /** + * Wandelt WMO Weather Code in Icon-Code um (OpenWeatherMap kompatibel) + */ + private function getWeatherIcon($code) { + if ($code == 0) return '01d'; // Klar + if ($code >= 1 && $code <= 2) return '02d'; // Teilweise bewölkt + if ($code == 3) return '04d'; // Bewölkt + if ($code >= 45 && $code <= 48) return '50d'; // Nebel + if ($code >= 51 && $code <= 55) return '09d'; // Nieselregen + if ($code >= 61 && $code <= 65) return '10d'; // Regen + if ($code >= 71 && $code <= 77) return '13d'; // Schnee + if ($code >= 80 && $code <= 82) return '09d'; // Regenschauer + if ($code >= 85 && $code <= 86) return '13d'; // Schneeschauer + if ($code >= 95 && $code <= 99) return '11d'; // Gewitter + + return '01d'; // Default + } + + /** + * Wandelt Windrichtung (Grad) in Kompassrichtung um + */ + private function getWindDirection($deg) { + $directions = ['N', 'NNO', 'NO', 'ONO', 'O', 'OSO', 'SO', 'SSO', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW']; + $index = round($deg / 22.5) % 16; + return $directions[$index]; + } + + /** + * Holt Daten aus Cache (wenn noch gültig) + */ + private function getCache() { + if (!file_exists($this->cacheFile)) { + return null; + } + + $content = file_get_contents($this->cacheFile); + $data = json_decode($content, true); + + if (!$data || !isset($data['timestamp'])) { + return null; + } + + // Update-Intervall aus Settings holen (in Minuten) + $updateInterval = $this->settingsManager->getWeatherUpdateInterval() * 60; // Minuten -> Sekunden + + // Prüfe ob Cache noch gültig + if (time() - $data['timestamp'] < $updateInterval) { + return $data; + } + + return null; + } + + /** + * Speichert Daten im Cache + */ + private function saveCache($data) { + $json = json_encode($data, JSON_PRETTY_PRINT); + file_put_contents($this->cacheFile, $json, LOCK_EX); + } + + /** + * Gibt Wetter-Icon-Emoji zurück + */ + public function getWeatherEmoji($iconCode) { + $map = [ + '01d' => '☀️', '01n' => '🌙', + '02d' => '⛅', '02n' => '☁️', + '03d' => '☁️', '03n' => '☁️', + '04d' => '☁️', '04n' => '☁️', + '09d' => '🌧️', '09n' => '🌧️', + '10d' => '🌦️', '10n' => '🌧️', + '11d' => '⛈️', '11n' => '⛈️', + '13d' => '❄️', '13n' => '❄️', + '50d' => '🌫️', '50n' => '🌫️' + ]; + return $map[$iconCode] ?? '🌤️'; + } + + /** + * AJAX Handler für Wetter-Updates + */ + public function handleAjax() { + if ($_SERVER['REQUEST_METHOD'] !== 'GET') return; + if (!isset($_GET['weather_action'])) return; + + header('Content-Type: application/json'); + + if ($_GET['weather_action'] === 'get') { + $weather = $this->getCurrentWeather(); + echo json_encode(['success' => true, 'data' => $weather]); + exit; + } + } +} diff --git a/aurora-livecam/clear-cache.php b/aurora-livecam/clear-cache.php new file mode 100644 index 0000000..b1363fa --- /dev/null +++ b/aurora-livecam/clear-cache.php @@ -0,0 +1,15 @@ + diff --git a/aurora-livecam/index.php b/aurora-livecam/index.php index 3b12eed..bdde27c 100644 --- a/aurora-livecam/index.php +++ b/aurora-livecam/index.php @@ -4,12 +4,17 @@ use PHPMailer\PHPMailer\Exception; require __DIR__ . '/vendor/autoload.php'; require_once 'SettingsManager.php'; +require_once 'WeatherManager.php'; // SettingsManager initialisieren $settingsManager = new SettingsManager(); -// AJAX-Handler für Settings (VOR anderen Ausgaben!) +// WeatherManager initialisieren +$weatherManager = new WeatherManager($settingsManager); + +// AJAX-Handler für Settings und Weather (VOR anderen Ausgaben!) $settingsManager->handleAjax(); +$weatherManager->handleAjax(); if (isset($_GET['download_video'])) { $videoDir = './videos/'; @@ -559,7 +564,7 @@ class VisualCalendarManager { } // === AI-EREIGNISSE === - if (!empty($aiEvents)) { + if (!empty($aiEvents) && (!$this->settingsManager || $this->settingsManager->isAIEventsEnabled())) { $output .= '
'; $output .= '
🤖 AI-erkannte Ereignisse
'; $output .= '
'; @@ -1018,7 +1023,7 @@ class AdminManager { } public function displayAdminContent() { - global $settingsManager; + global $settingsManager, $siteConfig; $feedbacks = json_decode(file_get_contents('feedbacks.json') ?: '[]', true); @@ -1073,6 +1078,251 @@ class AdminManager { $output .= '
'; $output .= '
'; // settings-group + // UI Display Settings (Punkt 2) + $output .= '
'; + $output .= '

🖼️ UI Anzeige

'; + + $output .= '
'; + $output .= 'Empfehlungs-Banner anzeigen'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'QR-Code Section anzeigen'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Social Media Links anzeigen'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Patrouille Suisse Section anzeigen'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + $output .= '
'; // settings-group + + // Zoom & Timelapse Settings (Punkt 3) + $output .= '
'; + $output .= '

🔍 Zoom & Timelapse

'; + + $output .= '
'; + $output .= 'Zoom-Controls anzeigen'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Max Zoom-Level'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Timelapse Rückwärts-Modus'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + $output .= '
'; // settings-group + + // Content Management Settings (Punkt 5) + $output .= '
'; + $output .= '

📝 Content Management

'; + + $output .= '
'; + $output .= 'Gästebuch aktivieren'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Galerie aktivieren'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'KI-Events anzeigen'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Max Gästebuch-Einträge'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + $output .= '
'; // settings-group + + // Technical Settings (Punkt 6) + $output .= '
'; + $output .= '

⚙️ Technische Einstellungen

'; + + $output .= '
'; + $output .= 'Viewer Update-Intervall (Sekunden)'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Session Timeout (Sekunden)'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + $output .= '
'; // settings-group + + // Theme Settings (Punkt 7) + $output .= '
'; + $output .= '

🎨 Theme & Design

'; + + $output .= '
'; + $output .= 'Standard-Theme'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Theme-Switcher anzeigen'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + $output .= '
'; // settings-group + + // SEO Settings (Punkt 8) + $output .= '
'; + $output .= '

🔍 SEO & Meta

'; + + $output .= '
'; + $output .= 'Custom Title (leer = Standard)'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Meta Description'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Meta Keywords'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + $output .= '
'; // settings-group + + // Weather Settings + $output .= '
'; + $output .= '

🌤️ Wetter-Widget (Open-Meteo - 100% kostenlos!)

'; + + $output .= '
'; + $output .= 'Wetter-Widget anzeigen'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Standort (Stadt,Land)'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Latitude (Breitengrad)'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Longitude (Längengrad)'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Update-Intervall (Minuten)'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + + $output .= '
'; + $output .= 'Einheit'; + $output .= '
'; + $output .= ''; + $output .= '
'; + $output .= '
'; + $output .= '
'; // settings-group + $output .= ''; // admin-settings-panel // Bestehender Admin-Content @@ -1383,11 +1633,11 @@ $minViewersToShow = $settingsManager->get('viewer_display.min_viewers'); - <?php echo $siteConfig['siteTitle']; ?> + <?php echo $settingsManager->getCustomTitle() ?: $siteConfig['siteTitle']; ?> - - + + @@ -1874,6 +2124,90 @@ button[type="submit"]:hover { background-color: #45a049; } .delete-btn { background-color: #ff4136; color: white; border: none; padding: 5px 10px; cursor: pointer; font-size: 0.8em; margin-left: 10px; border-radius: 3px; } +/* Weather Widget */ +.weather-widget { + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + gap: 20px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + padding: 20px; + border-radius: 12px; + margin-bottom: 20px; + box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3); + animation: weatherFadeIn 0.5s ease; +} +.weather-widget.weather-error { + background: linear-gradient(135deg, #f44336 0%, #e91e63 100%); + color: white; + font-weight: bold; + justify-content: center; +} +.weather-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 5px; + padding: 10px 15px; + background: rgba(255, 255, 255, 0.15); + border-radius: 8px; + backdrop-filter: blur(10px); + min-width: 120px; + transition: transform 0.3s ease, background 0.3s ease; +} +.weather-item:hover { + transform: translateY(-3px); + background: rgba(255, 255, 255, 0.25); +} +.weather-icon { + font-size: 32px; + line-height: 1; +} +.weather-value { + font-size: 18px; + font-weight: bold; + color: white; + white-space: nowrap; +} +.weather-label { + font-size: 12px; + color: rgba(255, 255, 255, 0.9); + text-transform: uppercase; + letter-spacing: 0.5px; +} +.weather-description { + flex: 1 1 auto; + min-width: 180px; +} +.weather-description .weather-value { + font-size: 16px; + text-align: center; +} +@keyframes weatherFadeIn { + from { opacity: 0; transform: translateY(-10px); } + to { opacity: 1; transform: translateY(0); } +} +@media (max-width: 768px) { + .weather-widget { + gap: 10px; + padding: 15px 10px; + } + .weather-item { + min-width: 90px; + padding: 8px 10px; + } + .weather-icon { + font-size: 24px; + } + .weather-value { + font-size: 14px; + } + .weather-label { + font-size: 10px; + } +} + /* Guestbook */ .guestbook-entry { background-color: #f9f9f9; border-left: 5px solid #4CAF50; margin-bottom: 20px; padding: 15px; border-radius: 5px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } @@ -1896,6 +2230,119 @@ button[type="submit"]:hover { background-color: #45a049; } .modal-next { right: 0; } .modal-prev { left: 0; } +/* Admin Settings Panel */ +#admin-settings-panel { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + padding: 30px; + border-radius: 12px; + margin-bottom: 30px; + box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3); +} +#admin-settings-panel h3 { + color: white; + margin: 0 0 25px 0; + font-size: 24px; + text-align: center; +} +.settings-group { + background: rgba(255, 255, 255, 0.95); + padding: 20px; + border-radius: 8px; + margin-bottom: 15px; +} +.settings-group h4 { + margin: 0 0 15px 0; + color: #667eea; + font-size: 18px; + border-bottom: 2px solid #667eea; + padding-bottom: 8px; +} +.setting-row { + display: flex; + justify-content: space-between; + align-items: center; + padding: 12px 0; + border-bottom: 1px solid #f0f0f0; +} +.setting-row:last-child { + border-bottom: none; +} +.setting-label { + font-weight: 500; + color: #333; + flex: 1; +} +.setting-input { + display: flex; + align-items: center; + min-width: 200px; +} +.number-input, .text-input, .select-input { + width: 100%; + padding: 8px 12px; + border: 2px solid #ddd; + border-radius: 5px; + font-size: 14px; + transition: border-color 0.3s; +} +.number-input:focus, .text-input:focus, .select-input:focus { + outline: none; + border-color: #667eea; +} +.textarea-input { + width: 100%; + padding: 8px 12px; + border: 2px solid #ddd; + border-radius: 5px; + font-size: 14px; + font-family: Arial, sans-serif; + resize: vertical; + transition: border-color 0.3s; +} +.textarea-input:focus { + outline: none; + border-color: #667eea; +} +.toggle-switch { + position: relative; + display: inline-block; + width: 50px; + height: 24px; +} +.toggle-switch input { + opacity: 0; + width: 0; + height: 0; +} +.toggle-slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + transition: 0.3s; + border-radius: 24px; +} +.toggle-slider:before { + position: absolute; + content: ""; + height: 18px; + width: 18px; + left: 3px; + bottom: 3px; + background-color: white; + transition: 0.3s; + border-radius: 50%; +} +.toggle-switch input:checked + .toggle-slider { + background: linear-gradient(135deg, #667eea, #764ba2); +} +.toggle-switch input:checked + .toggle-slider:before { + transform: translateX(26px); +} + /* Language Switch */ #language-switch { position: fixed; top: 10px; right: 10px; z-index: 1000; background-color: rgba(255, 255, 255, 0.8); border-radius: 5px; padding: 5px; } .lang-button { background: none; border: none; cursor: pointer; padding: 5px; opacity: 0.7; transition: opacity 0.3s; margin: 0 2px; } @@ -2105,7 +2552,7 @@ body.theme-neo footer { - + @@ -2147,12 +2594,12 @@ body.theme-neo footer { - + @@ -2176,7 +2623,7 @@ body.theme-neo footer { -