1186 lines
75 KiB
HTML
1186 lines
75 KiB
HTML
<!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>
|