Files

1186 lines
75 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="de" class="dark" x-data="{ activeTab: 'today' }">
<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">
<meta name="build-time" content="2026-10-13T05:26:47.035679+02:00">
<meta name="build-epoch" content="1791862007">
<title>Mila — Schlaf & Entwicklung</title>
<!-- PWA & Mobile Web Capabilities -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Mila">
<meta name="application-name" content="Mila">
<meta name="theme-color" content="#090A0F">
<meta name="msapplication-TileColor" content="#090A0F">
<link rel="manifest" href="/icons/mila.webmanifest">
<link rel="apple-touch-icon" href="/icons/mila-apple-touch-icon-v3.png">
<link rel="apple-touch-icon" sizes="180x180" href="/icons/mila-apple-touch-icon-v3.png">
<link rel="icon" type="image/png" sizes="192x192" href="/icons/mila-icon-192-v3.png">
<link rel="icon" type="image/png" sizes="512x512" href="/icons/mila-icon-512-v3.png">
<link rel="icon" type="image/png" sizes="32x32" href="/icons/mila-icon-32-v3.png">
<link rel="icon" type="image/png" sizes="16x16" href="/icons/mila-icon-16-v3.png">
<link rel="shortcut icon" href="/icons/favicon.ico">
<link rel="icon" href="/icons/favicon.ico">
<link rel="icon" type="image/svg+xml" href="/icons/mila-icon.svg">
<!-- Typography & Styling -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&family=Syne:wght@700;800&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
fontFamily: {
heading: ['Syne', 'sans-serif'],
sans: ['Plus Jakarta Sans', 'sans-serif'],
mono: ['JetBrains Mono', 'monospace'],
}
}
}
}
</script>
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"></script>
</head>
<body class="bg-[#090A0F] text-zinc-100 min-h-screen font-sans antialiased selection:bg-purple-500 selection:text-white pb-16">
<!-- PWA Install Banner (Android / Desktop Chrome) -->
<div id="pwa-install-banner" class="hidden max-w-4xl mx-auto px-4 pt-3">
<div class="flex items-center justify-between p-3 rounded-2xl bg-gradient-to-r from-purple-900/80 via-pink-900/50 to-zinc-900 border border-purple-500/40 shadow-xl backdrop-blur-md">
<div class="flex items-center gap-3">
<img src="/icons/mila-icon-192-v3.png" alt="Mila" class="w-9 h-9 rounded-xl object-cover shadow-md border border-purple-500/40">
<div>
<p class="text-xs font-bold text-white">Mila App installieren</p>
<p class="text-[11px] text-zinc-300">Direkt auf dem Homescreen nutzen</p>
</div>
</div>
<div class="flex items-center gap-2">
<button id="pwa-install-btn" class="px-3.5 py-1.5 rounded-xl bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-400 hover:to-pink-400 text-white text-xs font-bold shadow-lg shadow-purple-500/30 active:scale-95 transition">
Installieren
</button>
<button onclick="document.getElementById('pwa-install-banner').classList.add('hidden')" class="p-1 rounded-lg text-zinc-400 hover:text-white">
<i data-lucide="x" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
<!-- iOS Safari Install Guidance Banner -->
<div id="ios-install-banner" class="hidden max-w-4xl mx-auto px-4 pt-3">
<div class="flex items-center justify-between p-3 rounded-2xl bg-zinc-900/90 border border-purple-500/30 shadow-lg backdrop-blur-md">
<div class="flex items-center gap-2.5">
<span class="text-base">📱</span>
<p class="text-xs text-zinc-300">
Als App nutzen: Im Safari-Menü auf <span class="inline-flex items-center text-purple-400 font-semibold"><i data-lucide="share" class="w-3.5 h-3.5 inline mx-0.5"></i> Teilen</span> und <span class="text-white font-semibold">„Zum Home-Bildschirm“</span> (+) tippen.
</p>
</div>
<button onclick="dismissIosBanner()" class="p-1 rounded-lg text-zinc-400 hover:text-white">
<i data-lucide="x" class="w-4 h-4"></i>
</button>
</div>
</div>
<!-- Header & Live Status (Always sticky on mobile) -->
<header class="border-b border-zinc-800/80 bg-zinc-950/80 backdrop-blur-xl sticky top-0 z-40 px-4 py-3 sm:px-8">
<div class="max-w-4xl mx-auto flex items-center justify-between">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-2xl bg-gradient-to-tr from-purple-600 via-pink-500 to-teal-400 p-0.5 shadow-lg shadow-purple-500/20 overflow-hidden flex items-center justify-center">
<img src="/icons/mila-icon-192-v3.png" alt="Mila" class="w-full h-full object-cover rounded-[14px]">
</div>
<div>
<div class="flex items-center gap-2">
<h1 class="text-lg sm:text-xl font-heading font-extrabold tracking-tight bg-gradient-to-r from-purple-300 via-pink-300 to-indigo-200 bg-clip-text text-transparent">
Mila Graf
</h1>
<span class="text-[11px] px-2 py-0.5 rounded-full bg-purple-500/10 border border-purple-500/20 text-purple-300 font-medium">
6 Monate, 4 Wochen alt
</span>
</div>
<p class="text-xs text-zinc-400">Dienstag, 13.10.2026</p>
</div>
</div>
<!-- Live State Badge, Install Button & Manual Refresh Button -->
<div class="flex items-center gap-2">
<div class="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-emerald-500/15 border border-emerald-500/30 text-emerald-300 text-xs font-semibold shadow-sm shadow-emerald-500/10"><span class="w-2 h-2 rounded-full bg-emerald-400 animate-pulse"></span><span>Wach (<span class="live-wake-timer" data-end-iso="2026-10-12T18:15:00">11 h 11 min</span>)</span></div>
<button id="header-pwa-install-btn" onclick="triggerPwaInstall()" class="hidden inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-xl bg-purple-500/10 hover:bg-purple-500/20 border border-purple-500/30 text-purple-300 text-xs font-semibold transition" title="Mila App installieren">
<i data-lucide="download" class="w-3.5 h-3.5"></i>
<span class="hidden sm:inline">Installieren</span>
</button>
<button id="manual-refresh-btn" onclick="triggerManualRefresh()" title="Neu laden" class="p-2 rounded-xl bg-zinc-900/80 border border-zinc-800 text-zinc-400 hover:text-white hover:border-purple-500/40 hover:bg-zinc-800 transition">
<i data-lucide="refresh-cw" class="w-4 h-4"></i>
</button>
</div>
</div>
</header>
<main class="max-w-4xl mx-auto p-4 sm:p-6 space-y-6">
<!-- HERO SECTION: CURRENT DAY STRICTLY ON TOP -->
<section class="space-y-4">
<!-- Hero Banner / Current State Card -->
<div class="p-6 rounded-3xl bg-gradient-to-br from-emerald-900/20 via-zinc-900/70 to-zinc-950 border border-emerald-500/30 shadow-2xl relative overflow-hidden">
<div class="relative z-10 space-y-2">
<div class="flex items-center gap-2 text-xs font-mono tracking-wider uppercase text-emerald-400 font-bold">
<span>☀️ Status: Wach & Munter</span>
</div>
<div class="text-3xl sm:text-4xl font-extrabold tracking-tight text-white font-heading">
Wachfenster: <span class="live-wake-timer" data-end-iso="2026-10-12T18:15:00">11 h 11 min</span>
</div>
<p class="text-sm text-zinc-400">
Letztes Schläfchen beendet um 18:15 Uhr.
</p>
</div>
</div>
<!-- Key Metrics Strip for Today -->
<div class="grid grid-cols-2 sm:grid-cols-4 gap-3">
<div class="bg-zinc-900/80 border border-zinc-800 rounded-2xl p-4 shadow-md">
<div class="text-[11px] font-semibold uppercase tracking-wider text-zinc-400">24h Schlaf Heute</div>
<div class="text-2xl font-extrabold text-purple-300 font-mono mt-1">0 h</div>
<div class="text-[11px] text-zinc-500 mt-0.5">Nacht + Schläfchen</div>
</div>
<div class="bg-zinc-900/80 border border-zinc-800 rounded-2xl p-4 shadow-md">
<div class="text-[11px] font-semibold uppercase tracking-wider text-zinc-400">Tagesschläfchen</div>
<div class="text-2xl font-extrabold text-emerald-400 font-mono mt-1">0 Naps</div>
<div class="text-[11px] text-zinc-500 mt-0.5">0 min gesamt</div>
</div>
<div class="bg-zinc-900/80 border border-zinc-800 rounded-2xl p-4 shadow-md">
<div class="text-[11px] font-semibold uppercase tracking-wider text-zinc-400">Nachtschlaf</div>
<div class="text-2xl font-extrabold text-sky-400 font-mono mt-1">0 min</div>
<div class="text-[11px] text-zinc-500 mt-0.5">Hauptschlafphase</div>
</div>
<div class="bg-zinc-900/80 border border-zinc-800 rounded-2xl p-4 shadow-md">
<div class="text-[11px] font-semibold uppercase tracking-wider text-zinc-400">7-Tage-Schnitt</div>
<div class="text-2xl font-extrabold text-pink-400 font-mono mt-1">12.12 h</div>
<div class="text-[11px] text-zinc-500 mt-0.5">Alterskorridor: 12–15h</div>
</div>
</div>
<!-- TODAY'S DETAILED TIMELINE: NAPS & NIGHT -->
<div class="bg-zinc-900/80 border border-zinc-800/80 rounded-2xl p-5 shadow-xl space-y-4">
<div class="flex items-center justify-between border-b border-zinc-800/80 pb-3">
<div class="flex items-center gap-2">
<span class="text-lg">📋</span>
<h2 class="text-base font-bold text-zinc-100">Heutiger Tagesablauf im Detail</h2>
</div>
<span class="text-xs font-mono text-zinc-400">2026-10-13</span>
</div>
<!-- Tagesschläfchen Breakdown -->
<div class="space-y-2">
<div class="text-xs font-bold text-emerald-400 uppercase tracking-wider flex items-center gap-1.5">
<span>🌿</span>
<span>Tagesschläfchen (0 erfasst)</span>
</div>
<div class="space-y-2">
<div class="p-4 rounded-xl bg-zinc-900/40 border border-zinc-800/40 text-center text-zinc-500 text-sm">
Heute bisher noch kein Tagesschläfchen eingetragen.
</div>
</div>
</div>
<!-- Nachtschlaf Breakdown -->
<div class="space-y-2 pt-2 border-t border-zinc-800/50">
<div class="text-xs font-bold text-sky-400 uppercase tracking-wider flex items-center gap-1.5">
<span>🌙</span>
<span>Nachtschlaf</span>
</div>
<div class="space-y-2">
<div class="p-3 rounded-xl bg-zinc-900/40 border border-zinc-800/40 text-center text-zinc-500 text-xs">
Kein Nachtschlaf für das Tagesdatum zugeordnet (Nachtstart zählt zum Vortag).
</div>
</div>
</div>
</div>
<!-- CONDITIONAL MODULES: BOTTLES & DIAPERS -->
<div class="bg-zinc-900/80 border border-amber-500/20 rounded-2xl p-5 shadow-lg space-y-3">
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<span class="text-xl">🍼</span>
<h3 class="font-semibold text-zinc-200">Fläschchen heute</h3>
</div>
<span class="font-mono font-bold text-amber-400 text-lg">210 ml <span class="text-xs text-zinc-400 font-normal">(1x)</span></span>
</div>
<div class="flex flex-wrap gap-2 pt-1">
<span class="px-2 py-1 rounded bg-amber-500/10 border border-amber-500/20 text-amber-300 text-xs">04:15 Uhr (210 ml)</span>
</div>
</div>
</section>
<!-- DEVELOPMENT & TREND BENCHMARKS -->
<section class="bg-gradient-to-r from-purple-950/30 via-zinc-900/60 to-zinc-900/30 border border-zinc-800 rounded-2xl p-5 shadow-md">
<div class="flex items-center gap-2 mb-3">
<span class="text-lg">📈</span>
<h2 class="text-sm font-bold uppercase tracking-wider text-zinc-300">Entwicklungs-Benchmarks & Tendenzen</h2>
</div>
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4 text-xs text-zinc-400">
<div class="p-3 rounded-xl bg-zinc-950/50 border border-zinc-800/60 space-y-1">
<div class="text-zinc-500 font-medium">7-Tage-Ø Gesamtschlaf</div>
<div class="text-lg font-bold text-purple-300 font-mono">12.12 h</div>
<div>Nacht: <span class="text-sky-300 font-mono">9.93 h</span> · Tag: <span class="text-emerald-300 font-mono">3.1 Naps (2.19 h)</span></div>
</div>
<div class="p-3 rounded-xl bg-zinc-950/50 border border-zinc-800/60 space-y-1">
<div class="text-zinc-500 font-medium">30-Tage-Ø Gesamtschlaf</div>
<div class="text-lg font-bold text-pink-300 font-mono">13.77 h</div>
<div>Stabile zirkadiane Konsolidierung</div>
</div>
<div class="p-3 rounded-xl bg-zinc-950/50 border border-zinc-800/60 space-y-1">
<div class="text-zinc-500 font-medium">Altersreferenz (7 Monate)</div>
<div class="text-lg font-bold text-amber-300 font-mono">12 – 15 Std</div>
<div>Typisch 2–3 Naps, Wachfenster ~2.25–3.25h</div>
</div>
</div>
</section>
<!-- 30-DAY HISTORY TABLE -->
<section class="bg-zinc-900/80 border border-zinc-800/80 rounded-2xl p-5 shadow-xl space-y-4">
<div class="flex items-center justify-between pb-2 border-b border-zinc-800/60">
<div class="flex items-center gap-2">
<span class="text-lg">📅</span>
<h2 class="text-base font-bold text-zinc-100">Historie (Letzte 30 Tage)</h2>
</div>
<span class="text-xs text-zinc-400">DuckDB Aggregatdaten</span>
</div>
<div class="overflow-x-auto -mx-5 px-5">
<table class="w-full text-left text-sm whitespace-nowrap">
<thead class="text-[11px] uppercase bg-zinc-800/50 text-zinc-400">
<tr>
<th class="py-2.5 px-4 rounded-l-lg">Datum</th>
<th class="py-2.5 px-4">24h Gesamt</th>
<th class="py-2.5 px-4">Nacht</th>
<th class="py-2.5 px-4">Schläfchen</th>
<th class="py-2.5 px-4">Fläschchen</th>
<th class="py-2.5 px-4 rounded-r-lg">Windeln</th>
</tr>
</thead>
<tbody>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Mo, 12.10.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">2.67 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">0 min</td>
<td class="py-3.5 px-4 text-emerald-400">4 (160 min)</td>
<td class="py-3.5 px-4 text-zinc-400">540 ml (4x)</td>
<td class="py-3.5 px-4 text-zinc-400">1 (0 Stuhl)</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">08:05–08:39 (34m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">11:32–12:02 (30m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">14:11–15:22 (71m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">17:50–18:15 (25m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
So, 11.10.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">12.22 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">10 h 45 min</td>
<td class="py-3.5 px-4 text-emerald-400">3 (88 min)</td>
<td class="py-3.5 px-4 text-zinc-400">170 ml (1x)</td>
<td class="py-3.5 px-4 text-zinc-400">1 (1 Stuhl)</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">09:10–09:35 (25m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">11:05–11:40 (35m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">13:12–13:40 (28m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">19:25–06:10 (645m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Sa, 10.10.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">14.35 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">11 h 40 min</td>
<td class="py-3.5 px-4 text-emerald-400">2 (161 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">12:22–14:25 (123m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">16:10–16:48 (38m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">19:20–07:00 (700m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Fr, 09.10.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">12.42 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">11 h 20 min</td>
<td class="py-3.5 px-4 text-emerald-400">3 (65 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">12:35–12:55 (20m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">15:20–15:35 (15m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">17:10–17:40 (30m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">20:00–07:20 (680m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Do, 08.10.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">14.67 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">11 h 45 min</td>
<td class="py-3.5 px-4 text-emerald-400">3 (175 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">09:49–10:24 (35m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">11:55–12:22 (27m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">15:05–16:58 (113m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">19:15–07:00 (705m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Mi, 07.10.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">14.13 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">12 h 20 min</td>
<td class="py-3.5 px-4 text-emerald-400">3 (108 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">08:50–09:20 (30m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">11:21–12:01 (40m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">14:20–14:58 (38m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">18:40–07:00 (740m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Di, 06.10.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">14.38 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">11 h 40 min</td>
<td class="py-3.5 px-4 text-emerald-400">4 (163 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">08:58–09:38 (40m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">10:45–10:55 (10m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">12:08–12:41 (33m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">14:29–15:49 (80m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">19:20–07:00 (700m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Mo, 05.10.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">4.18 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">55 min</td>
<td class="py-3.5 px-4 text-emerald-400">4 (196 min)</td>
<td class="py-3.5 px-4 text-zinc-400">0 ml (2x)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">06:20–07:15 (55m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">08:12–09:00 (48m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">10:54–12:27 (93m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">14:36–15:06 (30m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">16:29–16:54 (25m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
So, 04.10.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">1.88 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">0 min</td>
<td class="py-3.5 px-4 text-emerald-400">4 (113 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">08:10–08:50 (40m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">10:50–10:51 (1m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">13:40–14:05 (25m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">15:20–16:07 (47m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Sa, 03.10.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">12.78 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">10 h 05 min</td>
<td class="py-3.5 px-4 text-emerald-400">5 (162 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">09:14–09:39 (25m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">10:59–12:00 (61m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">13:30–13:58 (28m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">14:52–15:20 (28m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">17:10–17:30 (20m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">20:10–06:15 (605m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Fr, 02.10.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">13.02 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">9 h 30 min</td>
<td class="py-3.5 px-4 text-emerald-400">4 (211 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">09:00–09:30 (30m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">11:25–11:49 (24m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">13:13–13:30 (17m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">14:55–17:15 (140m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">20:30–06:00 (570m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Do, 01.10.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">11.20 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">9 h 30 min</td>
<td class="py-3.5 px-4 text-emerald-400">3 (102 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">09:30–10:06 (36m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">11:30–12:00 (30m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">14:00–14:36 (36m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">21:00–06:30 (570m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Mi, 30.09.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">13.13 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">11 h 17 min</td>
<td class="py-3.5 px-4 text-emerald-400">3 (111 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">09:45–10:47 (62m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">13:18–13:38 (20m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">16:07–16:36 (29m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">19:13–06:30 (677m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Di, 29.09.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">13.83 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">11 h 53 min</td>
<td class="py-3.5 px-4 text-emerald-400">4 (117 min)</td>
<td class="py-3.5 px-4 text-zinc-400">0 ml (1x)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">09:51–10:38 (47m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">11:36–11:51 (15m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">13:35–14:05 (30m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">16:00–16:25 (25m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">18:57–06:50 (713m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Mo, 28.09.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">26.10 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">23 h 34 min</td>
<td class="py-3.5 px-4 text-emerald-400">4 (152 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">08:27–09:17 (50m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">10:52–11:40 (48m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">13:36–14:06 (30m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">16:05–16:29 (24m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">19:13–07:00 (707m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">19:13–07:00 (707m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
So, 27.09.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">12.88 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">10 h 10 min</td>
<td class="py-3.5 px-4 text-emerald-400">4 (163 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">09:10–09:30 (20m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">10:50–11:25 (35m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">13:39–15:07 (88m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">17:50–18:10 (20m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">19:55–06:05 (610m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Sa, 26.09.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">26.67 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">23 h 50 min</td>
<td class="py-3.5 px-4 text-emerald-400">3 (170 min)</td>
<td class="py-3.5 px-4 text-zinc-400">0 ml (1x)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">08:54–09:40 (46m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">12:38–14:07 (89m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">15:50–16:25 (35m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">18:55–06:50 (715m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">18:55–06:50 (715m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Fr, 25.09.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">15.13 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">11 h 33 min</td>
<td class="py-3.5 px-4 text-emerald-400">5 (215 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">07:39–08:08 (29m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">10:07–10:31 (24m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">10:40–12:39 (119m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">14:40–15:01 (21m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">16:43–17:05 (22m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">19:07–06:40 (693m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Do, 24.09.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">24.52 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">23 h 02 min</td>
<td class="py-3.5 px-4 text-emerald-400">4 (89 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">09:02–09:34 (32m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">12:31–12:55 (24m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">13:00–13:01 (1m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">14:47–15:19 (32m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">18:34–06:05 (691m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">18:34–06:05 (691m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Mi, 23.09.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">13.68 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">11 h 18 min</td>
<td class="py-3.5 px-4 text-emerald-400">4 (143 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">08:30–08:59 (29m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">11:40–11:55 (15m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">13:40–14:50 (70m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">16:36–17:05 (29m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">19:27–06:45 (678m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Di, 22.09.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">25.07 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">23 h 12 min</td>
<td class="py-3.5 px-4 text-emerald-400">5 (112 min)</td>
<td class="py-3.5 px-4 text-zinc-400">0 ml (1x)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">08:53–09:23 (30m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">09:53–09:59 (6m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">12:15–12:40 (25m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">14:35–15:05 (30m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">17:06–17:27 (21m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">18:51–06:27 (696m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">18:51–06:27 (696m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Mo, 21.09.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">3.48 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">0 min</td>
<td class="py-3.5 px-4 text-emerald-400">5 (209 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">08:00–08:10 (10m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">09:47–10:19 (32m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">10:34–12:25 (111m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">14:25–14:49 (24m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">15:43–16:15 (32m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
So, 20.09.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">14.02 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">10 h 55 min</td>
<td class="py-3.5 px-4 text-emerald-400">5 (186 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">06:40–06:41 (1m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">08:50–09:30 (40m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">11:00–11:35 (35m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">14:00–15:25 (85m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">16:40–17:05 (25m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">19:30–06:25 (655m)</span>
</td>
</tr>
<tr class="border-b border-zinc-800/60 hover:bg-zinc-900/40 transition">
<td class="py-3.5 px-4 font-mono font-medium text-zinc-200">
Sa, 19.09.
</td>
<td class="py-3.5 px-4 font-bold text-purple-300">14.02 h</td>
<td class="py-3.5 px-4 text-sky-400 font-semibold">11 h 55 min</td>
<td class="py-3.5 px-4 text-emerald-400">4 (126 min)</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
<td class="py-3.5 px-4 text-zinc-400">—</td>
</tr>
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
<td colspan="6" class="py-1.5 px-4 text-zinc-400 space-x-1">
<span class="text-zinc-500 font-mono text-[10px] uppercase">Einzelschläfchen:</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">06:30–06:31 (1m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">09:10–09:40 (30m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">10:55–12:00 (65m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-emerald-950/60 text-emerald-300 border-emerald-800/40">14:45–15:15 (30m)</span> <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs border bg-purple-950/60 text-purple-300 border-purple-800/40">18:45–06:40 (715m)</span>
</td>
</tr>
</tbody>
</table>
</div>
</section>
<!-- GROWTH & WHO PERCENTILES (COLLAPSIBLE CARD) -->
<section
x-data="{ growthOpen: false, growthTab: 'weight' }"
class="bg-zinc-900/80 border border-zinc-800/80 rounded-2xl shadow-xl overflow-hidden transition"
>
<!-- Collapsible Header Banner -->
<button
type="button"
@click="growthOpen = !growthOpen; if(growthOpen) { $nextTick(() => { window.initGrowthCharts && window.initGrowthCharts(); }); }"
class="w-full p-5 flex items-center justify-between text-left hover:bg-zinc-800/30 transition focus:outline-none"
>
<div class="flex items-center gap-3">
<div class="w-9 h-9 rounded-xl bg-pink-500/10 border border-pink-500/20 flex items-center justify-center text-pink-400 text-lg">
📏
</div>
<div>
<div class="flex items-center gap-2">
<h2 class="text-base font-bold text-zinc-100">Körpergröße & Gewicht (WHO-Perzentilen)</h2>
<span class="text-[11px] px-2 py-0.5 rounded-full bg-zinc-800 border border-zinc-700/60 text-zinc-400 font-mono">
0–24 Monate
</span>
</div>
<p class="text-xs text-zinc-400 mt-0.5">
Vergleich mit den offiziellen WHO-Standards für Mädchen (P3, P50 Median, P97)
</p>
</div>
</div>
<div class="flex items-center gap-3">
<span class="hidden sm:inline-flex text-xs px-2.5 py-1 rounded-lg bg-zinc-800/80 border border-zinc-700/60 text-zinc-300 font-mono">
Noch keine Messungen erfasst
</span>
<div
class="w-7 h-7 rounded-lg bg-zinc-800/60 flex items-center justify-center text-zinc-400 transition-transform duration-200"
:class="{ 'rotate-180': growthOpen }"
>
<i data-lucide="chevron-down" class="w-4 h-4"></i>
</div>
</div>
</button>
<!-- Expandable Content -->
<div x-show="growthOpen" x-cloak class="p-5 pt-0 border-t border-zinc-800/60 space-y-5">
<!-- Subheader Pill on Mobile -->
<div class="sm:hidden pt-3">
<span class="inline-block text-xs px-2.5 py-1 rounded-lg bg-zinc-800/80 border border-zinc-700/60 text-zinc-300 font-mono">
Noch keine Messungen erfasst
</span>
</div>
<!-- Controls: Tab Selector & Legend Info -->
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3 pt-4">
<!-- Toggle: Gewicht vs Körpergröße -->
<div class="inline-flex p-1 rounded-xl bg-zinc-950/80 border border-zinc-800 self-start">
<button
type="button"
@click="growthTab = 'weight'; $nextTick(() => { window.updateGrowthChartTab && window.updateGrowthChartTab('weight'); });"
:class="growthTab === 'weight' ? 'bg-gradient-to-r from-pink-500 to-purple-600 text-white shadow-md font-semibold' : 'text-zinc-400 hover:text-white'"
class="px-4 py-1.5 rounded-lg text-xs transition"
>
⚖️ Gewicht (kg)
</button>
<button
type="button"
@click="growthTab = 'height'; $nextTick(() => { window.updateGrowthChartTab && window.updateGrowthChartTab('height'); });"
:class="growthTab === 'height' ? 'bg-gradient-to-r from-pink-500 to-purple-600 text-white shadow-md font-semibold' : 'text-zinc-400 hover:text-white'"
class="px-4 py-1.5 rounded-lg text-xs transition"
>
📏 Körpergröße (cm)
</button>
</div>
<!-- Explanation Legend -->
<div class="flex items-center gap-3 text-[11px] text-zinc-400 flex-wrap">
<span class="inline-flex items-center gap-1.5">
<span class="w-2.5 h-2.5 rounded-full bg-pink-500"></span> Mila
</span>
<span class="inline-flex items-center gap-1.5">
<span class="w-3 h-0.5 bg-purple-400"></span> WHO Median (P50)
</span>
<span class="inline-flex items-center gap-1.5">
<span class="w-3 h-0.5 bg-zinc-500 border-b border-dashed"></span> P3–P97 Normkorridor (94%)
</span>
</div>
</div>
<!-- Chart Canvas Container -->
<div class="relative w-full h-72 sm:h-80 bg-zinc-950/50 rounded-2xl p-3 border border-zinc-800/60">
<canvas id="growthChart"></canvas>
</div>
<!-- Measurement History Table -->
<div class="space-y-2 pt-2">
<div class="flex items-center justify-between">
<h3 class="text-xs font-bold uppercase tracking-wider text-zinc-400 flex items-center gap-1.5">
<span>📋</span>
<span>Erfasste Messungen</span>
</h3>
<span class="text-[11px] text-zinc-500 font-mono">0 Messung(en)</span>
</div>
<div class="overflow-x-auto -mx-5 px-5">
<table class="w-full text-left text-xs whitespace-nowrap">
<thead class="text-[10px] uppercase bg-zinc-800/50 text-zinc-400 font-mono">
<tr>
<th class="py-2 px-4 rounded-l-lg">Datum</th>
<th class="py-2 px-4">Alter</th>
<th class="py-2 px-4">Gewicht</th>
<th class="py-2 px-4">Körpergröße</th>
<th class="py-2 px-4 rounded-r-lg">Notiz / Anlass</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="5" class="py-6 px-4 text-center text-zinc-500 text-xs">
Bisher noch keine manuellen Messwerte eingetragen. Messungen können per Telegram oder CLI erfasst werden.
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</section>
</main>
<!-- Floating Refresh Footer -->
<footer class="max-w-4xl mx-auto px-4 text-center text-xs text-zinc-500 space-y-1">
<p>Aktualisiert: <span id="build-time-display">13.10.2026 um 05:26:47 Uhr</span> · <button onclick="triggerManualRefresh()" class="text-purple-400 hover:text-purple-300 underline font-mono transition">Live Sync</button></p>
<p class="text-[11px]">Tipp: Im Safari-Menü auf „Zum Home-Bildschirm" tippen für die native App-Nutzung.</p>
</footer>
<script>
document.addEventListener('DOMContentLoaded', () => {
lucide.createIcons();
});
// ==============================================================================
// Growth Chart (Chart.js + WHO Percentiles)
// ==============================================================================
const growthData = {"who_weight": {"p3": [{"x": 0, "y": 2.4}, {"x": 1, "y": 3.2}, {"x": 2, "y": 4.0}, {"x": 3, "y": 4.6}, {"x": 4, "y": 5.1}, {"x": 5, "y": 5.5}, {"x": 6, "y": 5.8}, {"x": 7, "y": 6.1}, {"x": 8, "y": 6.3}, {"x": 9, "y": 6.6}, {"x": 10, "y": 6.8}, {"x": 11, "y": 7.0}, {"x": 12, "y": 7.1}, {"x": 13, "y": 7.3}, {"x": 14, "y": 7.5}, {"x": 15, "y": 7.7}, {"x": 16, "y": 7.8}, {"x": 17, "y": 8.0}, {"x": 18, "y": 8.2}, {"x": 19, "y": 8.3}, {"x": 20, "y": 8.5}, {"x": 21, "y": 8.7}, {"x": 22, "y": 8.8}, {"x": 23, "y": 9.0}, {"x": 24, "y": 9.2}], "p50": [{"x": 0, "y": 3.2}, {"x": 1, "y": 4.2}, {"x": 2, "y": 5.1}, {"x": 3, "y": 5.8}, {"x": 4, "y": 6.4}, {"x": 5, "y": 6.9}, {"x": 6, "y": 7.3}, {"x": 7, "y": 7.6}, {"x": 8, "y": 7.9}, {"x": 9, "y": 8.2}, {"x": 10, "y": 8.5}, {"x": 11, "y": 8.7}, {"x": 12, "y": 8.9}, {"x": 13, "y": 9.2}, {"x": 14, "y": 9.4}, {"x": 15, "y": 9.6}, {"x": 16, "y": 9.8}, {"x": 17, "y": 10.0}, {"x": 18, "y": 10.2}, {"x": 19, "y": 10.4}, {"x": 20, "y": 10.6}, {"x": 21, "y": 10.9}, {"x": 22, "y": 11.1}, {"x": 23, "y": 11.3}, {"x": 24, "y": 11.5}], "p97": [{"x": 0, "y": 4.2}, {"x": 1, "y": 5.4}, {"x": 2, "y": 6.5}, {"x": 3, "y": 7.4}, {"x": 4, "y": 8.1}, {"x": 5, "y": 8.7}, {"x": 6, "y": 9.2}, {"x": 7, "y": 9.6}, {"x": 8, "y": 10.0}, {"x": 9, "y": 10.4}, {"x": 10, "y": 10.7}, {"x": 11, "y": 11.0}, {"x": 12, "y": 11.3}, {"x": 13, "y": 11.6}, {"x": 14, "y": 11.9}, {"x": 15, "y": 12.2}, {"x": 16, "y": 12.5}, {"x": 17, "y": 12.7}, {"x": 18, "y": 13.0}, {"x": 19, "y": 13.3}, {"x": 20, "y": 13.5}, {"x": 21, "y": 13.8}, {"x": 22, "y": 14.1}, {"x": 23, "y": 14.3}, {"x": 24, "y": 14.6}]}, "who_height": {"p3": [{"x": 0, "y": 45.6}, {"x": 1, "y": 50.0}, {"x": 2, "y": 53.2}, {"x": 3, "y": 55.8}, {"x": 4, "y": 58.0}, {"x": 5, "y": 59.9}, {"x": 6, "y": 61.5}, {"x": 7, "y": 62.9}, {"x": 8, "y": 64.3}, {"x": 9, "y": 65.6}, {"x": 10, "y": 66.8}, {"x": 11, "y": 68.0}, {"x": 12, "y": 69.2}, {"x": 13, "y": 70.3}, {"x": 14, "y": 71.3}, {"x": 15, "y": 72.4}, {"x": 16, "y": 73.3}, {"x": 17, "y": 74.3}, {"x": 18, "y": 75.2}, {"x": 19, "y": 76.2}, {"x": 20, "y": 77.0}, {"x": 21, "y": 77.9}, {"x": 22, "y": 78.7}, {"x": 23, "y": 79.6}, {"x": 24, "y": 80.3}], "p50": [{"x": 0, "y": 49.1}, {"x": 1, "y": 53.7}, {"x": 2, "y": 57.1}, {"x": 3, "y": 59.8}, {"x": 4, "y": 62.1}, {"x": 5, "y": 64.0}, {"x": 6, "y": 65.7}, {"x": 7, "y": 67.3}, {"x": 8, "y": 68.7}, {"x": 9, "y": 70.1}, {"x": 10, "y": 71.5}, {"x": 11, "y": 72.8}, {"x": 12, "y": 74.0}, {"x": 13, "y": 75.2}, {"x": 14, "y": 76.4}, {"x": 15, "y": 77.5}, {"x": 16, "y": 78.6}, {"x": 17, "y": 79.7}, {"x": 18, "y": 80.7}, {"x": 19, "y": 81.7}, {"x": 20, "y": 82.7}, {"x": 21, "y": 83.7}, {"x": 22, "y": 84.6}, {"x": 23, "y": 85.5}, {"x": 24, "y": 86.4}], "p97": [{"x": 0, "y": 52.7}, {"x": 1, "y": 57.4}, {"x": 2, "y": 60.9}, {"x": 3, "y": 63.8}, {"x": 4, "y": 66.2}, {"x": 5, "y": 68.2}, {"x": 6, "y": 70.0}, {"x": 7, "y": 71.6}, {"x": 8, "y": 73.2}, {"x": 9, "y": 74.7}, {"x": 10, "y": 76.1}, {"x": 11, "y": 77.5}, {"x": 12, "y": 78.9}, {"x": 13, "y": 80.2}, {"x": 14, "y": 81.4}, {"x": 15, "y": 82.7}, {"x": 16, "y": 83.9}, {"x": 17, "y": 85.0}, {"x": 18, "y": 86.2}, {"x": 19, "y": 87.3}, {"x": 20, "y": 88.4}, {"x": 21, "y": 89.4}, {"x": 22, "y": 90.5}, {"x": 23, "y": 91.5}, {"x": 24, "y": 92.5}]}, "mila_weight": [], "mila_height": []};
let growthChartInstance = null;
let currentGrowthMetric = 'weight';
window.initGrowthCharts = function() {
const ctx = document.getElementById('growthChart');
if (!ctx) return;
if (growthChartInstance) {
growthChartInstance.resize();
return;
}
window.renderGrowthChart(currentGrowthMetric);
};
window.updateGrowthChartTab = function(metric) {
currentGrowthMetric = metric;
window.renderGrowthChart(metric);
};
window.renderGrowthChart = function(metric) {
const ctx = document.getElementById('growthChart');
if (!ctx) return;
if (growthChartInstance) {
growthChartInstance.destroy();
}
const isWeight = (metric === 'weight');
const whoObj = isWeight ? growthData.who_weight : growthData.who_height;
const milaPoints = isWeight ? growthData.mila_weight : growthData.mila_height;
const yUnit = isWeight ? 'kg' : 'cm';
const yLabel = isWeight ? 'Gewicht (kg)' : 'Körpergröße (cm)';
growthChartInstance = new Chart(ctx, {
type: 'line',
data: {
datasets: [
{
label: 'WHO P97 (Obere Grenze)',
data: whoObj.p97,
borderColor: 'rgba(244, 63, 94, 0.45)',
borderWidth: 1.5,
borderDash: [4, 4],
pointRadius: 0,
pointHoverRadius: 0,
fill: false,
tension: 0.3,
},
{
label: 'WHO P3 (Untere Grenze)',
data: whoObj.p3,
borderColor: 'rgba(56, 189, 248, 0.45)',
borderWidth: 1.5,
borderDash: [4, 4],
pointRadius: 0,
pointHoverRadius: 0,
fill: {
target: 0,
above: 'rgba(168, 85, 247, 0.08)',
},
tension: 0.3,
},
{
label: 'WHO P50 (Median)',
data: whoObj.p50,
borderColor: 'rgba(168, 85, 247, 0.85)',
borderWidth: 2.5,
pointRadius: 0,
pointHoverRadius: 0,
fill: false,
tension: 0.3,
},
{
label: 'Mila',
data: milaPoints,
borderColor: '#EC4899',
backgroundColor: '#EC4899',
borderWidth: 2.5,
pointRadius: 6,
pointHoverRadius: 8,
pointBackgroundColor: '#EC4899',
pointBorderColor: '#FFFFFF',
pointBorderWidth: 2,
showLine: true,
tension: 0.15,
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
animation: { duration: 350 },
interaction: { mode: 'nearest', intersect: false },
plugins: {
legend: { display: false },
tooltip: {
backgroundColor: 'rgba(24, 24, 27, 0.95)',
borderColor: 'rgba(63, 63, 70, 0.8)',
borderWidth: 1,
titleColor: '#F4F4F5',
bodyColor: '#D4D4D8',
padding: 10,
displayColors: true,
callbacks: {
title: function(items) {
if (!items.length) return '';
return 'Alter: ' + items[0].parsed.x + ' Monate';
},
label: function(context) {
const dsLabel = context.dataset.label || '';
const yVal = context.parsed.y;
if (dsLabel === 'Mila') {
const raw = context.raw || {};
const dateStr = raw.date ? ' am ' + raw.date : '';
const pctStr = raw.pct ? ' (' + raw.pct + ')' : '';
return '👶 Mila: ' + yVal + ' ' + yUnit + pctStr + dateStr;
}
return dsLabel + ': ' + yVal + ' ' + yUnit;
}
}
}
},
scales: {
x: {
type: 'linear',
min: 0,
max: 24,
title: {
display: true,
text: 'Alter in Monaten',
color: '#71717A',
font: { size: 11, family: 'JetBrains Mono' }
},
grid: { color: 'rgba(255, 255, 255, 0.05)' },
ticks: {
color: '#A1A1AA',
stepSize: 2,
callback: function(val) { return val + 'M'; },
font: { family: 'JetBrains Mono', size: 10 }
}
},
y: {
title: {
display: true,
text: yLabel,
color: '#71717A',
font: { size: 11, family: 'JetBrains Mono' }
},
grid: { color: 'rgba(255, 255, 255, 0.05)' },
ticks: {
color: '#A1A1AA',
font: { family: 'JetBrains Mono', size: 10 }
}
}
}
}
});
};
// Service Worker Registration for PWA installability & offline support
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/family/sw.js', { scope: '/family/' })
.then(reg => console.log('[PWA] Service Worker registered:', reg.scope))
.catch(err => console.warn('[PWA] Service Worker registration failed:', err));
});
}
// Chrome/Android/Desktop PWA BeforeInstallPrompt & iOS Detection
let deferredInstallPrompt = null;
const isIos = (/iPad|iPhone|iPod/.test(navigator.userAgent) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) && !window.MSStream;
const isStandalone = window.navigator.standalone === true || window.matchMedia('(display-mode: standalone)').matches;
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault();
deferredInstallPrompt = e;
const banner = document.getElementById('pwa-install-banner');
if (banner && !isStandalone) banner.classList.remove('hidden');
const headerBtn = document.getElementById('header-pwa-install-btn');
if (headerBtn && !isStandalone) headerBtn.classList.remove('hidden');
});
window.addEventListener('appinstalled', () => {
console.log('[PWA] App successfully installed');
const banner = document.getElementById('pwa-install-banner');
if (banner) banner.classList.add('hidden');
const headerBtn = document.getElementById('header-pwa-install-btn');
if (headerBtn) headerBtn.classList.add('hidden');
deferredInstallPrompt = null;
});
const installBtn = document.getElementById('pwa-install-btn');
if (installBtn) {
installBtn.addEventListener('click', () => {
triggerPwaInstall();
});
}
// iOS Safari Detection & Guidance Banner
if (isIos && !isStandalone) {
const headerBtn = document.getElementById('header-pwa-install-btn');
if (headerBtn) headerBtn.classList.remove('hidden');
if (!localStorage.getItem('dismissed_ios_mila_pwa')) {
const iosBanner = document.getElementById('ios-install-banner');
if (iosBanner) iosBanner.classList.remove('hidden');
}
}
function dismissIosBanner() {
localStorage.setItem('dismissed_ios_mila_pwa', 'true');
const iosBanner = document.getElementById('ios-install-banner');
if (iosBanner) iosBanner.classList.add('hidden');
}
window.triggerPwaInstall = function() {
if (deferredInstallPrompt) {
deferredInstallPrompt.prompt();
deferredInstallPrompt.userChoice.then(({ outcome }) => {
if (outcome === 'accepted') {
const banner = document.getElementById('pwa-install-banner');
if (banner) banner.classList.add('hidden');
const headerBtn = document.getElementById('header-pwa-install-btn');
if (headerBtn) headerBtn.classList.add('hidden');
}
deferredInstallPrompt = null;
});
} else if (isIos) {
const iosBanner = document.getElementById('ios-install-banner');
if (iosBanner) {
iosBanner.classList.remove('hidden');
iosBanner.scrollIntoView({ behavior: 'smooth' });
} else {
alert("Als App nutzen: Im Safari-Menü auf 'Teilen' [↑] tippen und 'Zum Home-Bildschirm' (+) wählen.");
}
} else {
alert("Zum Installieren: Im Browser-Menü auf 'App installieren' oder das Installations-Symbol in der Adressleiste tippen.");
}
};
// ==============================================================================
// Self-Updating Engine & Live Tickers
// ==============================================================================
(function() {
const currentBuildEpoch = parseInt(document.querySelector('meta[name="build-epoch"]')?.content || '0', 10);
let lastCheckMs = Date.now();
let isChecking = false;
// 1. Live Running Sleep/Wake Timer (increments live in DOM every 5 seconds)
function tickLiveTimers() {
document.querySelectorAll('.live-sleep-timer').forEach(el => {
const iso = el.dataset.startIso;
if (!iso) return;
const startMs = new Date(iso).getTime();
if (isNaN(startMs)) return;
const diffMs = Math.max(0, Date.now() - startMs);
const mins = Math.floor(diffMs / 60000);
const h = Math.floor(mins / 60);
const m = mins % 60;
el.textContent = h > 0 ? (h + ' h ' + String(m).padStart(2, '0') + ' min') : (m + ' min');
});
document.querySelectorAll('.live-wake-timer').forEach(el => {
const iso = el.dataset.endIso;
if (!iso) return;
const endMs = new Date(iso).getTime();
if (isNaN(endMs)) return;
const diffMs = Math.max(0, Date.now() - endMs);
const mins = Math.floor(diffMs / 60000);
const h = Math.floor(mins / 60);
const m = mins % 60;
el.textContent = h > 0 ? (h + ' h ' + String(m).padStart(2, '0') + ' min') : (m + ' min');
});
}
setInterval(tickLiveTimers, 5000);
tickLiveTimers();
// 2. Server Update Checker
async function checkForUpdates() {
if (isChecking) return;
isChecking = true;
try {
const res = await fetch(window.location.pathname + '?_poll=' + Date.now(), {
cache: 'no-store',
headers: { 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache' }
});
if (res.ok) {
const html = await res.text();
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
const remoteEpoch = parseInt(doc.querySelector('meta[name="build-epoch"]')?.content || '0', 10);
if (remoteEpoch && currentBuildEpoch && remoteEpoch > currentBuildEpoch) {
console.log('[AutoUpdate] Server has newer build (' + remoteEpoch + ' > ' + currentBuildEpoch + '). Reloading...');
window.location.reload();
return;
}
}
} catch (err) {
console.warn('[AutoUpdate] Check failed:', err);
} finally {
isChecking = false;
lastCheckMs = Date.now();
}
}
// 3. Auto-update on reopen / foreground resume (PWA & Mobile Safari)
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
tickLiveTimers();
if (Date.now() - lastCheckMs > 10000) {
checkForUpdates();
}
}
});
window.addEventListener('pageshow', (e) => {
tickLiveTimers();
if (e.persisted || Date.now() - lastCheckMs > 10000) {
checkForUpdates();
}
});
window.addEventListener('focus', () => {
tickLiveTimers();
if (Date.now() - lastCheckMs > 15000) {
checkForUpdates();
}
});
// 4. Background check every 30 seconds when visible
setInterval(() => {
if (document.visibilityState === 'visible') {
checkForUpdates();
}
}, 30000);
// 5. Manual refresh trigger
window.triggerManualRefresh = function() {
const btn = document.getElementById('manual-refresh-btn');
if (btn) {
const icon = btn.querySelector('svg') || btn.querySelector('i');
if (icon) icon.classList.add('animate-spin');
}
window.location.reload();
};
})();
</script>
</body>
</html>