@@ -254,6 +301,64 @@
.feature-card h3 { font-size: 1.1rem; margin-bottom: 0.5rem; }
.feature-card p { color: #555; font-size: 0.95rem; }
+ /* PRICING */
+ .pricing { padding: 5rem 2rem; background: #F5F7FA; }
+ .pricing-sub { text-align: center; color: #666; margin-top: -2rem; margin-bottom: 3rem; }
+
+ .pricing-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
+ gap: 1.5rem;
+ align-items: stretch;
+ }
+
+ .plan {
+ background: #fff;
+ border-radius: 16px;
+ padding: 2rem;
+ border: 1.5px solid #eee;
+ display: flex;
+ flex-direction: column;
+ position: relative;
+ }
+ .plan-featured {
+ border-color: #F97316;
+ box-shadow: 0 4px 24px rgba(249,115,22,0.12);
+ }
+ .plan-badge {
+ position: absolute;
+ top: -12px;
+ left: 50%;
+ transform: translateX(-50%);
+ background: #F97316;
+ color: #fff;
+ padding: 0.2rem 0.9rem;
+ border-radius: 20px;
+ font-size: 0.75rem;
+ font-weight: 700;
+ }
+ .plan-name { font-size: 0.85rem; font-weight: 700; color: #888; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 0.75rem; }
+ .plan-price { font-size: 2rem; font-weight: 800; color: #0B1023; margin-bottom: 1.5rem; }
+ .plan-price span { font-size: 1rem; font-weight: 400; color: #888; }
+
+ .plan-features { list-style: none; margin: 0 0 2rem; padding: 0; display: flex; flex-direction: column; gap: 0.6rem; flex: 1; }
+ .plan-features li { font-size: 0.9rem; color: #444; }
+
+ .btn-plan {
+ display: block;
+ text-align: center;
+ padding: 0.75rem;
+ border-radius: 8px;
+ font-weight: 700;
+ font-size: 0.95rem;
+ border: 1.5px solid #0B1023;
+ color: #0B1023;
+ transition: all 0.15s;
+ }
+ .btn-plan:hover { background: #0B1023; color: #fff; }
+ .btn-plan-featured { background: #F97316; border-color: #F97316; color: #fff; }
+ .btn-plan-featured:hover { background: #ea6c10; border-color: #ea6c10; }
+
/* CTA */
.cta {
background: #0B1023;
diff --git a/app/src/routes/admin/+layout.svelte b/app/src/routes/admin/+layout.svelte
index ebf934a..a7013b9 100644
--- a/app/src/routes/admin/+layout.svelte
+++ b/app/src/routes/admin/+layout.svelte
@@ -14,9 +14,10 @@
}
const navItems = [
- { href: '/admin/dashboard', label: 'Dashboard', icon: '◈' },
- { href: '/admin/logs', label: 'Protokoll', icon: '≡' },
- { href: '/admin/stations', label: 'Stationen', icon: '⊞' }
+ { href: '/admin/dashboard', label: 'Dashboard', icon: '◈' },
+ { href: '/admin/logs', label: 'Einträge', icon: '≡' },
+ { href: '/admin/protokoll', label: 'Protokoll', icon: '📄' },
+ { href: '/admin/stations', label: 'Stationen', icon: '⊞' }
];
diff --git a/app/src/routes/admin/protokoll/+page.svelte b/app/src/routes/admin/protokoll/+page.svelte
new file mode 100644
index 0000000..41dce43
--- /dev/null
+++ b/app/src/routes/admin/protokoll/+page.svelte
@@ -0,0 +1,255 @@
+
+
+
Protokoll {months[selectedMonth-1]} {selectedYear} — checkflo
+
+
+
+
+
Monatsprotokoll
+
+
+
+
+
+
+
+
+
+
+
+
+ {#if loading}
+
Lädt…
+ {:else if logs.length === 0}
+
Keine Einträge im gewählten Zeitraum.
+
Keine Einträge im {months[selectedMonth-1]} {selectedYear}.
+ {:else}
+ {#each Object.entries(byStation()) as [stationName, stationLogs]}
+
+
+
+
+
+ | Datum / Zeit |
+ Temp. (°C) |
+ Status |
+ Notiz |
+ Geprüft von |
+
+
+
+ {#each stationLogs as log}
+
+ | {formatDate(log.created)} |
+ {log.temperature ? log.temperature + ' °C' : '—'} |
+
+
+ {STATUS_LABEL[log.status] ?? log.status}
+
+ |
+ {log.notes || '—'} |
+ {log.checked_by} |
+
+ {/each}
+
+
+
+ {/each}
+
+
+ Gesamt: {logs.length} Einträge ·
+ {logs.filter(l=>l.status==='ok').length} OK ·
+ {logs.filter(l=>l.status==='abweichung').length} Abweichungen ·
+ {logs.filter(l=>l.status==='kritisch').length} Kritisch
+
+ {/if}
+
+
+
+
+
diff --git a/app/src/routes/admin/stations/+page.svelte b/app/src/routes/admin/stations/+page.svelte
index c46836d..5df72ad 100644
--- a/app/src/routes/admin/stations/+page.svelte
+++ b/app/src/routes/admin/stations/+page.svelte
@@ -1,6 +1,7 @@
Stationen — checkflo
-
-
Stationen
-
Jeden QR-Code ausdrucken und an der Station befestigen. Der Link öffnet die Checkliste direkt im Browser.
+
+
{#if loading}
Lädt…
@@ -53,29 +71,19 @@
{#each stations as s}
-
-
+
+
{s.name}
{TYPE_LABEL[s.type] ?? s.type}
{#if s.target_temp_min || s.target_temp_max}
· {s.target_temp_min}° bis {s.target_temp_max}°C
{/if}
+
{qrUrl(s.qr_id)}
-
-
-
-
{qrUrl(s.qr_id)}
-
-
- QR öffnen
-
+ {#if qrCodes[s.qr_id]}
+

+ {/if}
{/each}
@@ -83,65 +91,98 @@
{/if}
+
+{#if !loading}
+
+ {#each stations as s}
+
+
{tenantName}
+
{s.name}
+
{TYPE_LABEL[s.type] ?? s.type}
+ {#if s.target_temp_min || s.target_temp_max}
+ · Zielbereich {s.target_temp_min}° bis {s.target_temp_max}°C
+ {/if}
+
+ {#if qrCodes[s.qr_id]}
+

+ {/if}
+
{qrUrl(s.qr_id)}
+
+
+ {/each}
+
+{/if}
+