<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>Jürgens Assistent</title>
<style>
:root {
--bg-gradient: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
--glass-card: rgba(255, 255, 255, 0.65);
--glass-border: rgba(255, 255, 255, 0.8);
--text-primary: #1c1c1e;
--accent-blue: #007AFF;
--accent-red: #FF3B30;
--radius-xl: 32px;
--key-bg: rgba(255,255,255,0.8);
}
body.dark-mode {
--bg-gradient: linear-gradient(135deg, #0f2027 0%, #203a43 100%);
--glass-card: rgba(30, 30, 30, 0.7);
--glass-border: rgba(255, 255, 255, 0.15);
--text-primary: #ffffff;
--accent-blue: #0A84FF;
--accent-red: #FF453A;
--key-bg: rgba(255,255,255,0.15);
}
body {
margin: 0; padding: 0;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", sans-serif;
background: var(--bg-gradient); background-attachment: fixed;
min-height: 100vh; color: var(--text-primary);
display: flex; flex-direction: column; justify-content: flex-start;
-webkit-font-smoothing: antialiased;
user-select: none; -webkit-user-select: none;
transition: background 0.5s ease;
}
/* --- OPTIMIERTER LADEBILDSCHIRM --- */
#splash-screen { position: fixed; inset: 0; background: var(--bg-gradient); z-index: 9999; display: flex; flex-direction: column; align-items: center; justify-content: center; transition: opacity 0.5s; }
.loader { width: 130px; height: 4px; border-radius: 30px; background: rgba(0,0,0,0.1); position: relative; margin-top: 10px; }
.dark-mode .loader { background: rgba(255,255,255,0.1); }
.loader::before { content: ""; position: absolute; background: var(--accent-blue); top: 0; left: 0; width: 0%; height: 100%; border-radius: 30px; animation: moving 1s ease-in-out infinite; }
@keyframes moving { 50% { width: 100%; } 100% { width: 0; right: 0; left: unset; } }
.screen {
width: 100%; max-width: 450px; margin: 0 auto;
display: flex; flex-direction: column; gap: 20px;
padding: 30px 20px 50px 20px; box-sizing: border-box;
animation: fadeSlide 0.4s ease-out;
min-height: 100vh; justify-content: flex-start; overflow-y: auto;
}
#home, #bill-auth { justify-content: center; }
.hidden { display: none !important; }
@keyframes fadeSlide { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
/* Design Elemente */
.avatar-box {
width: 80px; height: 80px; background: white; border-radius: 50%;
margin: 0 auto 15px auto; display: flex; align-items: center; justify-content: center;
font-size: 32px; font-weight: 600; box-shadow: 0 10px 20px rgba(0,0,0,0.05); color: #333;
}
.glass-card {
background: var(--glass-card); backdrop-filter: blur(30px); -webkit-backdrop-filter: blur(30px);
border: 1px solid var(--glass-border); border-radius: var(--radius-xl);
box-shadow: 0 20px 40px rgba(0,0,0,0.08); cursor: pointer; color: inherit;
}
/* Buttons & Grid */
.big-action-btn { padding: 30px 20px; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 15px; transition: transform 0.2s; }
.big-action-btn:active { transform: scale(0.97); }
.home-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; }
.small-action-btn { padding: 25px 10px; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 10px; transition: transform 0.2s; }
.small-action-btn:active { transform: scale(0.95); }
.big-icon { display: flex; align-items: center; justify-content: center; color: white; box-shadow: 0 8px 20px rgba(0,0,0,0.2); }
.icon-blue { background: var(--accent-blue); }
.icon-red { background: var(--accent-red); }
.icon-weather { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); box-shadow: 0 8px 20px rgba(0, 198, 255, 0.3); }
/* Liquid Nav Buttons */
.liquid-nav-btn {
background: var(--glass-card); backdrop-filter: blur(50px) saturate(150%); -webkit-backdrop-filter: blur(50px) saturate(150%);
border: 1px solid var(--glass-border); color: var(--text-primary); font-size: 15px; font-weight: 600;
padding: 10px 20px; border-radius: 25px; cursor: pointer;
box-shadow: 0 10px 20px rgba(0,0,0,0.08), inset 0 2px 5px rgba(255,255,255,0.4); transition: transform 0.1s;
}
.liquid-nav-btn:active { transform: scale(0.92); }
/* Roter Alarm-Tag */
.alert-tag {
background: rgba(255, 59, 48, 0.15); color: var(--accent-red); border: 1px solid rgba(255, 59, 48, 0.3);
font-size: 13px; font-weight: 600; padding: 6px 12px; border-radius: 20px;
display: inline-flex; align-items: center; justify-content: center; gap: 8px; margin-top: 5px;
}
.red-dot { width: 10px; height: 10px; background: var(--accent-red); border-radius: 50%; animation: pulse 1.5s infinite; }
@keyframes pulse { 0% { transform: scale(0.95); } 70% { transform: scale(1); box-shadow: 0 0 0 6px rgba(255, 59, 48, 0); } 100% { transform: scale(0.95); } }
/* Header & PIN */
.header-bar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; margin-top: 10px; position: relative; z-index: 10; }
.pin-display { display: flex; justify-content: center; gap: 25px; margin-bottom: 30px; }
.pin-dot { width: 20px; height: 20px; border: 2px solid var(--text-primary); border-radius: 50%; transition: background 0.2s; }
.pin-dot.filled { background: var(--text-primary); }
.keypad-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; max-width: 300px; margin: 0 auto; }
.key-btn { width: 75px; height: 75px; background: var(--key-bg); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 32px; font-weight: 500; box-shadow: 0 4px 10px rgba(0,0,0,0.05); cursor: pointer; transition: transform 0.1s; }
.key-btn:active { transform: scale(0.9); }
/* Info Styles */
.info-card { padding: 22px; margin-bottom: 15px; cursor: default; }
.info-box { background: rgba(0, 122, 255, 0.1); border-radius: 20px; padding: 15px; font-size: 14px; line-height: 1.4; margin-bottom: 10px; border-left: 4px solid var(--accent-blue); }
/* Firmenauswahl & Akten */
.company-card { display: flex; align-items: center; padding: 15px 20px; gap: 20px; margin-bottom: 12px; }
.company-logo { width: 60px; height: 60px; border-radius: 12px; object-fit: cover; background: white; }
.company-logo.contain { object-fit: contain; padding: 5px; }
.invoice-item { display: flex; align-items: center; gap: 15px; padding: 18px; margin-bottom: 12px; }
.invoice-info { flex: 1; }
.invoice-date { font-size: 17px; font-weight: 600; display: block; }
.invoice-desc { font-size: 13px; opacity: 0.6; }
/* Wetter & Nachrichten */
.weather-detail-row { display: flex; align-items: center; gap: 10px; font-size: 16px; margin-top: 8px; opacity: 0.85; }
.news-card { padding: 0; overflow: hidden; margin-bottom: 20px; cursor: pointer; display: flex; flex-direction: column; animation: fadeSlide 0.3s ease-out; }
.news-image { width: 100%; height: 180px; object-fit: cover; background: var(--key-bg); }
.news-content { padding: 15px; }
.news-date { font-size: 13px; opacity: 0.6; margin-bottom: 5px; }
.news-title { font-size: 19px; font-weight: 600; line-height: 1.3; }
/* Liquid Glass Notification Modal */
#notification-overlay {
position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.3); z-index: 2000;
display: flex; align-items: center; justify-content: center; opacity: 0; pointer-events: none; transition: opacity 0.4s ease; backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
#notification-overlay.active { opacity: 1; pointer-events: auto; }
.liquid-modal {
width: 85%; max-width: 340px; background: var(--glass-card); backdrop-filter: blur(50px) saturate(150%); -webkit-backdrop-filter: blur(50px) saturate(150%);
border: 1px solid var(--glass-border); border-radius: 32px; padding: 35px 25px; text-align: center;
box-shadow: 0 40px 80px rgba(0,0,0,0.2), inset 0 2px 5px rgba(255,255,255,0.3); transform: translateY(30px) scale(0.9); transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
#notification-overlay.active .liquid-modal { transform: translateY(0) scale(1); }
.modal-btn {
background: var(--accent-blue); color: white; border: none; padding: 15px 0; border-radius: 20px;
font-size: 17px; font-weight: 600; cursor: pointer; width: 100%; box-shadow: 0 8px 20px rgba(0, 122, 255, 0.35); transition: transform 0.1s; margin-top: 10px;
}
.modal-btn:active { transform: scale(0.95); }
</style>
<!-- OneSignal Integration Start -->
<script src="https://cdn.onesignal.com/sdks/web/v16/OneSignalSDK.page.js" defer></script>
<script>
window.OneSignalDeferred = window.OneSignalDeferred || [];
OneSignalDeferred.push(async function(OneSignal) {
await OneSignal.init({
appId: "fbc59751-4d4d-46a6-a6ca-c90891780002",
safari_web_id: "web.onesignal.auto.32551e0e-3454-416e-9258-23f2fe99c3c8",
notifyButton: {
enable: true,
},
});
});
</script>
<!-- OneSignal Integration Ende -->
</head>
<body>
<div id="splash-screen">
<div class="avatar-box">J</div>
<div class="loader"></div>
</div>
<div id="notification-overlay">
<div class="liquid-modal" id="modal-content">
</div>
</div>
<div id="home" class="screen">
<div style="text-align: center; margin-bottom: 5px;">
<div class="avatar-box">J</div>
<h1 style="font-size: 28px; margin: 0;">Hallo Jürgen</h1>
<div class="glass-card" style="margin-top: 15px; margin-bottom: 25px; padding: 18px; cursor: default;">
<div id="time-display" style="font-size: 48px; font-weight: 800; letter-spacing: 2px; color: var(--accent-blue); line-height: 1;">00:00</div>
<div id="date-display" style="font-size: 15px; font-weight: 600; opacity: 0.7; margin-top: 8px;">Lade Datum...</div>
</div>
</div>
<div class="glass-card big-action-btn" onclick="startAuth()">
<div class="big-icon icon-blue" style="width: 85px; height: 85px; font-size: 45px; border-radius: 24px;">📄</div>
<div style="display: flex; flex-direction: column; align-items: center;">
<h2 style="margin:0; font-size: 25px; text-align: center;">Rechnungen / Verträge</h2>
<p style="margin:6px 0 5px 0; font-size: 15px; opacity: 0.6;">Dokumente ansehen (PIN)</p>
</div>
</div>
<div class="home-grid">
<div class="glass-card small-action-btn" onclick="showScreen('weather-forecast')">
<div class="big-icon icon-weather" id="current-weather-icon" style="width: 55px; height: 55px; font-size: 28px; border-radius: 16px;">⛅</div>
<div>
<h2 style="margin:0; font-size: 18px;">Wetter</h2>
<p style="margin:4px 0 0 0; font-size: 15px; font-weight: bold; color: var(--accent-blue);" id="current-temp">Lädt...</p>
</div>
</div>
<div class="glass-card small-action-btn" onclick="showScreen('news-feed')">
<div class="big-icon icon-red" style="width: 55px; height: 55px; font-size: 28px; border-radius: 16px;">📰</div>
<div>
<h2 style="margin:0; font-size: 18px;">NDR News</h2>
<p style="margin:4px 0 0 0; font-size: 13px; opacity: 0.6;">Regional</p>
</div>
</div>
</div>
</div>
<div id="news-feed" class="screen hidden">
<div class="header-bar">
<button class="liquid-nav-btn" onclick="goHome()">❮ Zurück</button>
<h2 style="margin: 0; font-size: 24px;">Nachrichten</h2>
</div>
<p style="opacity: 0.7; margin: 0 0 10px 0; font-size: 15px;">Aktuelles vom NDR:</p>
<div id="news-list"><div style="text-align:center; opacity:0.5; padding: 20px;">Nachrichten werden geladen...</div></div>
<button id="load-more-btn" class="modal-btn" style="display: none; margin-top: 5px; margin-bottom: 20px;" onclick="renderNextNewsChunk()">Mehr Laden</button>
</div>
<div id="bill-auth" class="screen hidden">
<button class="liquid-nav-btn" onclick="goHome()" style="position:absolute; top:40px; left:20px; z-index: 50;">❮ Zurück</button>
<div style="text-align: center; margin-top: 50px;">
<div style="font-size: 40px; margin-bottom: 10px;">🔒</div>
<h2 style="font-size: 24px; margin: 0 0 5px 0;">Code eingeben</h2>
<p style="opacity: 0.6; margin-bottom: 20px;">Sicherheitsabfrage</p>
<div class="pin-display"><div class="pin-dot" id="dot0"></div><div class="pin-dot" id="dot1"></div><div class="pin-dot" id="dot2"></div><div class="pin-dot" id="dot3"></div></div>
<p id="errorMsg" style="color:#ff3b30; display:none; font-size: 18px; font-weight: 600; margin-bottom: 10px;">Falscher Code!</p>
<div class="keypad-grid">
<div class="key-btn" onclick="pressKey(1)">1</div><div class="key-btn" onclick="pressKey(2)">2</div><div class="key-btn" onclick="pressKey(3)">3</div>
<div class="key-btn" onclick="pressKey(4)">4</div><div class="key-btn" onclick="pressKey(5)">5</div><div class="key-btn" onclick="pressKey(6)">6</div>
<div class="key-btn" onclick="pressKey(7)">7</div><div class="key-btn" onclick="pressKey(8)">8</div><div class="key-btn" onclick="pressKey(9)">9</div>
<div class="key-btn" style="background:none;"></div><div class="key-btn" onclick="pressKey(0)">0</div><div class="key-btn" style="background:none;" onclick="deleteKey()">⌫</div>
</div>
</div>
</div>
<div id="weather-forecast" class="screen hidden">
<div class="header-bar"><button class="liquid-nav-btn" onclick="goHome()">❮ Zurück</button><h2 style="margin: 0; font-size: 24px;">Vorhersage</h2></div>
<p style="opacity: 0.7; margin: 0 0 10px 0; font-size: 15px;">Die nächsten 3 Tage in Steinloge:</p>
<div id="forecast-list"><div style="text-align:center; opacity:0.5; padding: 20px;">Wetterdaten werden geladen...</div></div>
</div>
<div id="bill-list" class="screen hidden">
<div class="header-bar">
<h2 style="margin: 0; font-size: 30px;">Anbieter</h2>
<button class="liquid-nav-btn" onclick="goHome()">Schließen</button>
</div>
<div class="info-box" style="margin-top: 10px; margin-bottom: 25px;">
🛡️ <b>Sicherheitshinweis:</b><br>Aufgrund eines Sicherheitsfaktors werden Rechnungen hier nur noch <b>5 Monate</b> lang angezeigt.
</div>
<div class="glass-card company-card" onclick="showScreen('details-telekom')"><img src="https://i.imgur.com/3V2BtpN.jpeg" class="company-logo" alt="Telekom"><div class="company-name">Telekom</div></div>
<div class="glass-card company-card" onclick="showScreen('details-klarmobil')"><img src="https://i.imgur.com/6cZj3Xl.jpeg" class="company-logo" alt="Klarmobil"><div class="company-name">Klarmobil</div></div>
<div class="glass-card company-card" onclick="showScreen('details-ewe')"><img src="https://i.imgur.com/o0cEsUh.png" class="company-logo contain" alt="EWE"><div class="company-name">EWE (Archiv)</div></div>
</div>
<div id="details-telekom" class="screen hidden">
<div class="header-bar"><button class="liquid-nav-btn" onclick="showScreen('bill-list')">❮ Zurück</button><h2 style="margin:0;">Telekom</h2></div>
<div class="glass-card invoice-item" data-invoice-date="2026-04-01" onclick="openLink('https://drive.google.com/file/d/18Ytz5yiTAg1gmf0SjKDPce5jGwrHmYah/view?usp=sharing')">
<div class="invoice-icon">🌐</div>
<div class="invoice-info"><span class="invoice-date">Auftragsbestätigung</span><span class="invoice-desc">WLAN Anschluss</span><div class="alert-tag" style="display: none;"><div class="red-dot"></div><span class="deletion-countdown-text">...</span></div></div>
</div>
</div>
<div id="details-klarmobil" class="screen hidden">
<div class="header-bar"><button class="liquid-nav-btn" onclick="showScreen('bill-list')">❮ Zurück</button><h2 style="margin:0;">Klarmobil</h2></div>
<div class="glass-card invoice-item" data-invoice-date="2026-05-15" onclick="openLink('https://drive.google.com/file/d/1zO5rqwpp-ADzAQKiQelsIcLRVqFFYVjC/view?usp=share_link')">
<div class="invoice-icon">📱</div><div class="invoice-info"><span class="invoice-date">Mai 2026</span><span class="invoice-desc">Mobilfunk Rechnung</span><div class="alert-tag" style="display: none;"><div class="red-dot"></div><span class="deletion-countdown-text">...</span></div></div>
</div>
<div class="glass-card invoice-item" data-invoice-date="2026-04-15" onclick="openLink('https://drive.google.com/file/d/1q9wjSLBo7l7Vl-FI6i8sE-CaisV3SMdv/view?usp=sharing')">
<div class="invoice-icon">📱</div><div class="invoice-info"><span class="invoice-date">April 2026</span><span class="invoice-desc">Mobilfunk Rechnung</span><div class="alert-tag" style="display: none;"><div class="red-dot"></div><span class="deletion-countdown-text">...</span></div></div>
</div>
<div class="glass-card invoice-item" data-invoice-date="2026-03-15" onclick="openLink('https://drive.google.com/file/d/1070Hho1aWCso6iXpN9OvgyPIeN9GfZ4J/view?usp=sharing')">
<div class="invoice-icon">📱</div><div class="invoice-info"><span class="invoice-date">März 2026</span><span class="invoice-desc">Mobilfunk Rechnung</span><div class="alert-tag" style="display: none;"><div class="red-dot"></div><span class="deletion-countdown-text">...</span></div></div>
</div>
<div class="glass-card invoice-item" data-invoice-date="2026-02-15" onclick="openLink('https://drive.google.com/file/d/1C2kjzeJDGcYoArr7xJdJb-XcyC45MjgL/view?usp=sharing')">
<div class="invoice-icon">📱</div><div class="invoice-info"><span class="invoice-date">Februar 2026</span><span class="invoice-desc">Mobilfunk Rechnung</span><div class="alert-tag" style="display: none;"><div class="red-dot"></div><span class="deletion-countdown-text">...</span></div></div>
</div>
<div class="glass-card invoice-item" data-invoice-date="2026-01-15" onclick="openLink('https://drive.google.com/file/d/1dsKiPkAUTVY981t-O6PXWS15VlmAgXEI/view?usp=sharing')">
<div class="invoice-icon">📱</div><div class="invoice-info"><span class="invoice-date">Januar 2026</span><span class="invoice-desc">Mobilfunk Rechnung</span><div class="alert-tag" style="display: none;"><div class="red-dot"></div><span class="deletion-countdown-text">...</span></div></div>
</div>
</div>
<div id="details-ewe" class="screen hidden">
<div class="header-bar"><button class="liquid-nav-btn" onclick="showScreen('bill-list')">❮ Zurück</button><h2 style="margin:0;">EWE</h2></div>
<div class="info-box">⚠️ <b>Hinweis:</b> Dieser Vertrag wurde eingestellt und von Klarmobil übernommen.</div>
<div class="glass-card invoice-item" data-invoice-date="2025-11-20" onclick="openLink('https://drive.google.com/file/d/1Y0hVOkO1qnJm-smnBbQ_kIBrOMVGO5wK/view?usp=sharing')">
<div class="invoice-icon">📄</div><div class="invoice-info"><span class="invoice-date">November 2025</span><span class="invoice-desc">Letzte Rechnung</span><div class="alert-tag" style="display: none;"><div class="red-dot"></div><span class="deletion-countdown-text">...</span></div></div>
</div>
</div>
<script>
const CORRECT_PIN = "1407";
let currentPin = "";
let inactivityTimer;
const TIMEOUT_MS = 30000;
function showNotification() {
const modal = document.getElementById('modal-content');
const now = new Date();
const updateEndDate = new Date('2026-04-12T23:59:59');
if (now <= updateEndDate) {
modal.innerHTML = `
<div style="font-size: 45px; margin-bottom: 15px;">✨</div>
<h3 style="margin: 0 0 12px 0; font-size: 22px;">Hallo Jürgen!</h3>
<p style="margin: 0 0 20px 0; font-size: 15px; opacity: 0.8; line-height: 1.5; text-align: left;">
Ich habe deinen Assistenten verbessert! Es gibt <b>drei neue Funktionen</b>:<br><br>
📂 <b>Rechnungen:</b> Jetzt übersichtlich nach Firmen sortiert.<br>
⛅ <b>Wetter:</b> Die aktuelle Vorhersage für Steinloge.<br>
📰 <b>Nachrichten:</b> Das Neueste vom NDR aus Niedersachsen.
</p>
<button class="modal-btn" onclick="closeNotification()">Viel Spaß!</button>
`;
document.getElementById('notification-overlay').classList.add('active');
}
}
function closeNotification() { document.getElementById('notification-overlay').classList.remove('active'); }
function updateClock() {
const now = new Date();
document.getElementById('time-display').innerText = String(now.getHours()).padStart(2, '0') + ':' + String(now.getMinutes()).padStart(2, '0');
const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
document.getElementById('date-display').innerText = "Heute ist " + now.toLocaleDateString('de-DE', options);
}
setInterval(updateClock, 1000);
function calculateDeletionCountdown() {
const now = new Date();
const invoices = document.querySelectorAll('.invoice-item[data-invoice-date]');
invoices.forEach(el => {
const invoiceDate = new Date(el.getAttribute('data-invoice-date'));
invoiceDate.setMonth(invoiceDate.getMonth() + 5);
const diffDays = Math.ceil((invoiceDate - now) / (1000 * 60 * 60 * 24));
const alertTag = el.querySelector('.alert-tag');
if (diffDays > 0 && diffDays <= 30) {
if(alertTag) alertTag.style.display = 'inline-flex';
if(el.querySelector('.deletion-countdown-text')) el.querySelector('.deletion-countdown-text').innerText = `Löschung in ${diffDays} Tagen`;
}
});
}
let allNewsItems = [];
let currentNewsIndex = 0;
const NEWS_CHUNK_SIZE = 3;
async function loadNews() {
try {
const rssUrl = encodeURIComponent('https://www.ndr.de/nachrichten/niedersachsen/index~rss2.xml');
const apiUrl = `https://api.rss2json.com/v1/api.json?rss_url=${rssUrl}`;
const res = await fetch(apiUrl);
const data = await res.json();
if(data.status === 'ok') {
allNewsItems = data.items;
currentNewsIndex = 0;
document.getElementById('news-list').innerHTML = '';
renderNextNewsChunk();
} else { throw new Error('Fehler'); }
} catch (e) {
document.getElementById('news-list').innerHTML = '<div style="text-align:center; opacity:0.5; padding:20px;">Nachrichten momentan nicht verfügbar.</div>';
}
}
function renderNextNewsChunk() {
let html = '';
let limit = Math.min(currentNewsIndex + NEWS_CHUNK_SIZE, allNewsItems.length);
for(let i = currentNewsIndex; i < limit; i++) {
let item = allNewsItems[i];
let imgUrl = (item.enclosure && item.enclosure.link) ? item.enclosure.link : item.thumbnail;
let imgTag = imgUrl ? `<img src="${imgUrl}" class="news-image" alt="Nachrichten Bild">` : '';
let dateObj = new Date(item.pubDate);
let dateString = dateObj.toLocaleDateString('de-DE', {day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute:'2-digit'}) + ' Uhr';
html += `
<div class="glass-card news-card" onclick="openLink('${item.link}')">
${imgTag}
<div class="news-content">
<div class="news-date">${dateString}</div>
<div class="news-title">${item.title}</div>
</div>
</div>
`;
}
document.getElementById('news-list').insertAdjacentHTML('beforeend', html);
currentNewsIndex = limit;
const loadBtn = document.getElementById('load-more-btn');
if(loadBtn) loadBtn.style.display = (currentNewsIndex >= allNewsItems.length) ? 'none' : 'block';
}
async function loadWeather() {
try {
const res = await fetch('https://api.open-meteo.com/v1/forecast?latitude=52.98&longitude=8.70¤t_weather=true&daily=weathercode,temperature_2m_max,temperature_2m_min,precipitation_probability_max,windspeed_10m_max&timezone=Europe%2FBerlin');
const data = await res.json();
const currentTemp = Math.round(data.current_weather.temperature);
const currentCode = data.current_weather.weathercode;
document.getElementById('current-temp').innerText = currentTemp + ' °C';
document.getElementById('current-weather-icon').innerText = getWeatherEmoji(currentCode);
let forecastHTML = '';
const days = ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'];
for(let i=1; i<=3; i++) {
const date = new Date(data.daily.time[i]);
const dayName = days[date.getDay()];
const max = Math.round(data.daily.temperature_2m_max[i]);
const min = Math.round(data.daily.temperature_2m_min[i]);
const code = data.daily.weathercode[i];
const rainProb = data.daily.precipitation_probability_max[i] || 0;
const wind = Math.round(data.daily.windspeed_10m_max[i]);
forecastHTML += `
<div class="glass-card info-card" style="display:flex; flex-direction:column; gap: 10px;">
<div style="display:flex; justify-content:space-between; align-items:center; border-bottom: 1px solid var(--glass-border); padding-bottom: 10px;">
<div style="font-weight:bold; font-size:22px;">${dayName}</div>
<div style="font-size:38px;">${getWeatherEmoji(code)}</div>
</div>
<div>
<div style="font-size:19px; color: var(--accent-blue); font-weight: bold;">${getWeatherText(code)}</div>
<div class="weather-detail-row">🌡️ ${min}°C bis ${max}°C</div>
<div class="weather-detail-row">💧 ${rainProb}% Regenrisiko</div>
<div class="weather-detail-row">💨 Wind: ${wind} km/h</div>
</div>
</div>
`;
}
document.getElementById('forecast-list').innerHTML = forecastHTML;
} catch (e) {
document.getElementById('current-temp').innerText = '-- °C';
}
}
function getWeatherEmoji(code) {
if (code === 0) return '☀️';
if (code >= 1 && code <= 3) return '⛅';
if (code === 45 || code === 48) return '🌫️';
if ((code >= 51 && code <= 67) || (code >= 80 && code <= 82)) return '🌧️';
if ((code >= 71 && code <= 77) || code === 85 || code === 86) return '❄️';
if (code >= 95) return '⛈️';
return '🌤️';
}
function getWeatherText(code) {
if (code === 0) return 'Sonnig & Klar';
if (code === 1 || code === 2) return 'Leicht bewölkt';
if (code === 3) return 'Stark bewölkt';
if (code === 45 || code === 48) return 'Nebel';
if (code >= 51 && code <= 55) return 'Nieselregen';
if (code >= 61 && code <= 65) return 'Regen';
if (code === 66 || code === 67) return 'Gefrierender Regen';
if (code >= 71 && code <= 77) return 'Schneefall';
if (code >= 80 && code <= 82) return 'Regenschauer';
if (code === 85 || code === 86) return 'Schneeschauer';
if (code >= 95) return 'Gewitter';
return 'Durchwachsen';
}
function checkTimeForDarkMode() {
const hour = new Date().getHours();
if (hour >= 19 || hour < 7) document.body.classList.add('dark-mode');
else document.body.classList.remove('dark-mode');
}
function resetTimer() {
clearTimeout(inactivityTimer);
const homeElement = document.getElementById('home');
if(homeElement && homeElement.classList.contains('hidden')) {
inactivityTimer = setTimeout(goHome, TIMEOUT_MS);
}
}
document.addEventListener('touchstart', resetTimer);
document.addEventListener('click', resetTimer);
function startAuth() { currentPin = ""; showScreen('bill-auth'); }
function checkPin() {
if(currentPin === CORRECT_PIN) {
showScreen('bill-list');
} else {
let errMsg = document.getElementById('errorMsg');
if(errMsg) errMsg.style.display = 'block';
setTimeout(() => { currentPin = ""; updateDots(); if(errMsg) errMsg.style.display = 'none'; }, 1000);
}
}
function pressKey(num) { if(currentPin.length < 4) { currentPin += num; updateDots(); if(currentPin.length === 4) setTimeout(checkPin, 200); } }
function deleteKey() { if(currentPin.length > 0) { currentPin = currentPin.slice(0, -1); updateDots(); let errMsg = document.getElementById('errorMsg'); if(errMsg) errMsg.style.display = 'none'; } }
function resetPin() { currentPin = ""; updateDots(); let errMsg = document.getElementById('errorMsg'); if(errMsg) errMsg.style.display = 'none'; }
function updateDots() { for(let i=0; i<4; i++) { let dot = document.getElementById('dot' + i); if(dot) dot.classList.toggle('filled', i < currentPin.length); } }
function showScreen(id) { document.querySelectorAll('.screen').forEach(el => el.classList.add('hidden')); const target = document.getElementById(id); if(target) target.classList.remove('hidden'); window.scrollTo(0,0); resetTimer(); }
function goHome() { resetPin(); closeNotification(); showScreen('home'); }
function openLink(url) { window.open(url, '_blank'); }
window.addEventListener('load', () => {
checkTimeForDarkMode();
updateClock();
calculateDeletionCountdown();
loadWeather();
loadNews();
setTimeout(() => {
let splash = document.getElementById('splash-screen');
if(splash) splash.style.opacity = '0';
setTimeout(() => {
if(splash) splash.style.display = 'none';
showNotification();
}, 500);
}, 1500);
});
</script>
</body>
</html>