Files
mealprep/specs/planner-layout-mockups.html
Marcel Raddatz 520dae5adf feat(recipes): add image upload, fix save 500, seed HelloFresh data
- Store hero image as base64 data URI in text column (V023 migration)
- Add file upload UI to RecipeForm with FileReader preview
- Remove isChildFriendly from RecipeCreateRequest (no form field)
- Fix 500 on save: effort values now lowercase, serves/cookTimeMin changed
  from primitive short to nullable Integer to survive omitted fields
- Fix empty categories panel: removed stale tagType=category filter
- Group category tags by type with German headings in recipe form
- Split SuggestionResponse.SuggestionRecipe (no image) from SlotRecipe
- Seed 11 HelloFresh recipes with ingredients, steps and tags (V101)
- Add frontend e2e scaffold, specs and dev yml

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 20:23:28 +02:00

1821 lines
80 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">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Planner Layout Mockups — 5 Konzepte</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Fraunces:wght@300;400&family=DM+Sans:wght@400;500;600&family=DM+Mono&display=swap" rel="stylesheet">
<style>
:root {
--color-page: #fafaf7;
--color-surface: #f5f4ee;
--color-subtle: #edecea;
--color-border: #d8d7d0;
--color-text: #1c1c18;
--color-text-muted: #6b6a63;
--green-tint: #e8f5ea;
--green-light: #aedcb0;
--green: #3d8c4a;
--green-dark: #2e6e39;
--green-deeper: #1e4a26;
--yellow-tint: #fdf6d8;
--yellow-light: #f9e08a;
--yellow: #f2c12e;
--yellow-dark: #c49610;
--yellow-text: #8a6800;
--blue-tint: #e6f1fb;
--blue: #2d7dd2;
--blue-dark: #185fa5;
--purple-tint: #eeedfe;
--purple: #534ab7;
--orange-tint: #fef0e6;
--orange: #e8862a;
--color-error: #dc4c3e;
--radius-xs: 2px;
--radius-sm: 4px;
--radius-md: 6px;
--radius-lg: 10px;
--radius-xl: 16px;
--shadow-card: 0 1px 3px rgba(28,28,24,.06),0 1px 2px rgba(28,28,24,.04);
--shadow-raised: 0 4px 12px rgba(28,28,24,.08),0 2px 4px rgba(28,28,24,.04);
--font-display: 'Fraunces', Georgia, serif;
--font-sans: 'DM Sans', system-ui, sans-serif;
--font-mono: 'DM Mono', monospace;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: var(--font-sans);
background: #e8e7e0;
color: var(--color-text);
padding: 40px 24px 80px;
}
/* ── Spec chrome ─────────────────────────────────────────────── */
.spec-page-title {
font-family: var(--font-sans);
font-size: 11px;
font-weight: 500;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--color-text-muted);
margin-bottom: 8px;
}
.spec-section-title {
font-family: var(--font-display);
font-size: 32px;
font-weight: 300;
color: var(--color-text);
margin-bottom: 6px;
}
.spec-section-sub {
font-family: var(--font-sans);
font-size: 14px;
color: var(--color-text-muted);
margin-bottom: 40px;
max-width: 680px;
line-height: 1.6;
}
.mockup-card {
background: var(--color-page);
border-radius: var(--radius-xl);
border: 1px solid var(--color-border);
overflow: hidden;
margin-bottom: 48px;
box-shadow: var(--shadow-raised);
}
.mockup-label {
display: flex;
align-items: baseline;
gap: 12px;
padding: 20px 24px 16px;
border-bottom: 1px solid var(--color-border);
background: var(--color-surface);
}
.mockup-number {
font-family: var(--font-mono);
font-size: 11px;
color: var(--color-text-muted);
background: var(--color-subtle);
padding: 2px 7px;
border-radius: var(--radius-sm);
flex-shrink: 0;
}
.mockup-title {
font-family: var(--font-display);
font-size: 18px;
font-weight: 300;
color: var(--color-text);
}
.mockup-tagline {
font-family: var(--font-sans);
font-size: 13px;
color: var(--color-text-muted);
margin-left: auto;
}
.annotation {
font-family: var(--font-sans);
font-size: 11px;
color: var(--color-text-muted);
border-left: 2px solid var(--color-border);
padding: 10px 14px;
margin: 0 24px 24px;
line-height: 1.5;
}
.annotation strong { color: var(--color-text); font-weight: 500; }
/* ── Shared chrome reuse ─────────────────────────────────────── */
.chrome-topbar {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 20px;
border-bottom: 1px solid var(--color-border);
background: var(--color-page);
}
.chrome-h1 {
font-family: var(--font-display);
font-size: 18px;
font-weight: 300;
color: var(--color-text);
}
.chrome-weekrange {
font-family: var(--font-sans);
font-size: 12px;
color: var(--color-text-muted);
margin-left: 4px;
}
.chrome-btn {
height: 32px;
padding: 0 10px;
border-radius: var(--radius-md);
border: 1px solid var(--color-border);
background: var(--color-page);
font-family: var(--font-sans);
font-size: 12px;
font-weight: 500;
letter-spacing: 0.04em;
color: var(--color-text);
cursor: pointer;
white-space: nowrap;
}
.chrome-btn-primary {
background: var(--green-dark);
color: white;
border-color: transparent;
}
.chrome-nav-arrow {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: var(--radius-md);
border: 1px solid var(--color-border);
font-size: 15px;
color: var(--color-text-muted);
}
.chrome-ml-auto { margin-left: auto; }
/* ── Score widget atoms ──────────────────────────────────────── */
.score-big {
font-family: var(--font-display);
font-size: 36px;
font-weight: 300;
color: var(--color-text);
line-height: 1;
}
.score-denom {
font-family: var(--font-sans);
font-size: 12px;
color: var(--color-text-muted);
}
.score-label {
font-family: var(--font-sans);
font-size: 11px;
font-weight: 500;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--color-text-muted);
}
.progress-bar {
height: 4px;
border-radius: 9999px;
background: var(--yellow-light);
overflow: hidden;
margin-top: 6px;
}
.progress-fill {
height: 100%;
border-radius: 9999px;
background: var(--yellow);
}
.progress-fill-green { background: var(--green); }
.progress-bar-track { background: var(--color-border); }
.sub-score-row {
display: flex;
align-items: center;
gap: 8px;
margin-top: 8px;
}
.sub-score-label {
font-family: var(--font-sans);
font-size: 11px;
color: var(--color-text-muted);
width: 88px;
flex-shrink: 0;
}
.sub-score-bar {
flex: 1;
height: 3px;
border-radius: 9999px;
background: var(--color-border);
overflow: hidden;
}
.sub-score-fill { height: 100%; border-radius: 9999px; }
.sub-score-val {
font-family: var(--font-mono);
font-size: 10px;
color: var(--color-text-muted);
width: 20px;
text-align: right;
}
.effort-row {
display: flex;
gap: 3px;
margin-top: 10px;
height: 20px;
border-radius: var(--radius-sm);
overflow: hidden;
}
.effort-seg {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-family: var(--font-sans);
font-size: 9px;
font-weight: 500;
letter-spacing: 0.02em;
color: white;
}
.warn-item {
display: flex;
gap: 6px;
font-family: var(--font-sans);
font-size: 11px;
color: var(--yellow-text);
margin-top: 6px;
line-height: 1.4;
}
/* ── Calendar tile atoms ─────────────────────────────────────── */
.cal-tile {
border-radius: var(--radius-md);
border: 1px solid var(--color-border);
background: var(--color-surface);
padding: 8px;
cursor: pointer;
transition: box-shadow 0.12s;
}
.cal-tile:hover { box-shadow: var(--shadow-raised); }
.cal-tile-empty {
border-style: dashed;
background: transparent;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
color: var(--color-text-muted);
}
.cal-tile-selected {
border: 2px solid var(--green);
background: var(--green-tint);
}
.cal-tile-today {
border: 2px solid var(--yellow);
background: var(--yellow-tint);
}
.cal-day-name {
font-family: var(--font-sans);
font-size: 9px;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--color-text-muted);
text-align: center;
margin-bottom: 4px;
}
.cal-day-badge {
width: 22px;
height: 22px;
border-radius: 9999px;
display: flex;
align-items: center;
justify-content: center;
font-family: var(--font-sans);
font-size: 10px;
font-weight: 500;
margin: 0 auto 6px;
color: var(--color-text);
}
.cal-day-badge-today { background: var(--yellow); color: white; }
.cal-day-badge-selected { background: var(--green-tint); color: var(--green-dark); }
.recipe-name-sm {
font-family: var(--font-display);
font-size: 12px;
font-weight: 300;
color: var(--color-text);
line-height: 1.3;
}
.recipe-meta-sm {
font-family: var(--font-sans);
font-size: 10px;
color: var(--color-text-muted);
margin-top: 3px;
}
.effort-badge {
display: inline-flex;
align-items: center;
padding: 1px 5px;
border-radius: var(--radius-xs);
font-family: var(--font-sans);
font-size: 9px;
font-weight: 500;
margin-top: 4px;
}
.effort-easy { background: var(--green-tint); color: var(--green-dark); }
.effort-medium { background: var(--yellow-tint); color: var(--yellow-text); }
.effort-hard { background: var(--orange-tint); color: var(--orange); }
.protein-badge {
display: inline-flex;
align-items: center;
gap: 3px;
padding: 1px 5px;
border-radius: var(--radius-xs);
font-family: var(--font-sans);
font-size: 9px;
font-weight: 500;
background: var(--purple-tint);
color: var(--purple);
margin-top: 3px;
}
/* ── Sidebar atom ────────────────────────────────────────────── */
.sidebar {
width: 200px;
flex-shrink: 0;
border-right: 1px solid var(--color-border);
background: var(--color-surface);
display: flex;
flex-direction: column;
padding: 16px;
gap: 16px;
}
.sidebar-section-label {
font-family: var(--font-sans);
font-size: 10px;
font-weight: 500;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--color-text-muted);
margin-bottom: 8px;
}
/* ── Right panel atom ────────────────────────────────────────── */
.right-panel {
width: 256px;
flex-shrink: 0;
border-left: 1px solid var(--color-border);
background: var(--color-page);
display: flex;
flex-direction: column;
padding: 16px;
}
.panel-section {
margin-bottom: 16px;
}
.panel-label {
font-family: var(--font-sans);
font-size: 10px;
font-weight: 500;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--color-text-muted);
margin-bottom: 8px;
}
/* ── Main content area ───────────────────────────────────────── */
.main-content {
flex: 1;
overflow: hidden;
padding: 16px;
}
/* ── Layout wrapper ──────────────────────────────────────────── */
.desktop-frame {
display: flex;
flex-direction: column;
height: 480px;
background: var(--color-page);
}
.desktop-body {
display: flex;
flex: 1;
overflow: hidden;
}
/* ── Mobile frame ────────────────────────────────────────────── */
.mobile-frame {
width: 360px;
height: 640px;
border-radius: 24px;
border: 6px solid #2a2a26;
overflow: hidden;
background: var(--color-page);
display: flex;
flex-direction: column;
margin: 0 auto;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
}
.mobile-status-bar {
height: 28px;
background: var(--color-page);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 16px;
font-family: var(--font-sans);
font-size: 10px;
font-weight: 500;
color: var(--color-text);
}
.mobile-topbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 14px;
border-bottom: 1px solid var(--color-border);
}
.mobile-h1 {
font-family: var(--font-display);
font-size: 17px;
font-weight: 300;
}
/* ── Helper classes ──────────────────────────────────────────── */
.flex { display: flex; }
.flex-col { flex-direction: column; }
.flex-1 { flex: 1; }
.items-center { align-items: center; }
.items-start { align-items: flex-start; }
.justify-between { justify-content: space-between; }
.gap-2 { gap: 8px; }
.gap-3 { gap: 12px; }
.gap-4 { gap: 16px; }
.w-full { width: 100%; }
.mt-1 { margin-top: 4px; }
.mt-2 { margin-top: 8px; }
.mt-3 { margin-top: 12px; }
.mt-4 { margin-top: 16px; }
.mb-1 { margin-bottom: 4px; }
.mb-2 { margin-bottom: 8px; }
.mb-3 { margin-bottom: 12px; }
.grid-7 {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 6px;
}
.divider {
height: 1px;
background: var(--color-border);
margin: 10px 0;
}
.text-muted {
font-family: var(--font-sans);
font-size: 12px;
color: var(--color-text-muted);
}
.link-sm {
font-family: var(--font-sans);
font-size: 11px;
font-weight: 500;
color: var(--yellow-text);
text-decoration: none;
cursor: pointer;
}
.link-sm:hover { text-decoration: underline; }
.stat-chip {
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
padding: 8px 10px;
flex: 1;
}
.stat-chip-val {
font-family: var(--font-display);
font-size: 20px;
font-weight: 300;
color: var(--color-text);
}
.stat-chip-label {
font-family: var(--font-sans);
font-size: 10px;
color: var(--color-text-muted);
margin-top: 1px;
}
.action-btn {
display: block;
width: 100%;
padding: 8px;
border-radius: var(--radius-md);
border: 1px solid var(--color-border);
background: var(--color-page);
font-family: var(--font-sans);
font-size: 12px;
font-weight: 500;
letter-spacing: 0.04em;
text-align: center;
color: var(--color-text);
cursor: pointer;
margin-top: 6px;
}
.action-btn-primary {
background: var(--green-dark);
color: white;
border-color: transparent;
}
.suggestion-row {
display: flex;
align-items: center;
gap: 8px;
padding: 7px 8px;
border-radius: var(--radius-md);
background: var(--color-surface);
border: 1px solid var(--color-border);
margin-top: 6px;
cursor: pointer;
}
.suggestion-row:hover { border-color: var(--green-light); }
.suggestion-name {
font-family: var(--font-sans);
font-size: 12px;
color: var(--color-text);
flex: 1;
}
.delta-badge {
font-family: var(--font-mono);
font-size: 10px;
font-weight: 500;
padding: 1px 5px;
border-radius: var(--radius-xs);
}
.delta-pos { background: var(--green-tint); color: var(--green-dark); }
.delta-neg { background: #fde8e8; color: var(--color-error); }
/* ── Spec footer ─────────────────────────────────────────────── */
.agent-section {
display: none;
}
/* ── Two-panel layout for mobile+desktop side-by-side ────────── */
.side-by-side {
display: flex;
gap: 24px;
padding: 24px;
align-items: flex-start;
flex-wrap: wrap;
}
.side-label {
font-family: var(--font-sans);
font-size: 10px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--color-text-muted);
text-align: center;
margin-bottom: 8px;
}
/* variety donut placeholder */
.score-ring {
width: 72px;
height: 72px;
border-radius: 50%;
background: conic-gradient(var(--yellow) 0% 78%, var(--yellow-light) 78% 100%);
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.score-ring::after {
content: '';
position: absolute;
width: 52px;
height: 52px;
border-radius: 50%;
background: var(--color-surface);
}
.score-ring-val {
position: relative;
z-index: 1;
font-family: var(--font-display);
font-size: 18px;
font-weight: 300;
color: var(--color-text);
}
.week-strip-mobile {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 4px;
padding: 10px 14px;
}
.day-pip {
display: flex;
flex-direction: column;
align-items: center;
gap: 3px;
cursor: pointer;
}
.day-pip-label {
font-family: var(--font-sans);
font-size: 9px;
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--color-text-muted);
}
.day-pip-circle {
width: 30px;
height: 30px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-family: var(--font-sans);
font-size: 11px;
font-weight: 500;
color: var(--color-text);
background: transparent;
position: relative;
}
.day-pip-dot {
width: 4px;
height: 4px;
border-radius: 50%;
background: var(--green);
}
.day-pip-circle-today { background: var(--yellow); color: white; }
.day-pip-circle-selected { background: var(--green-tint); color: var(--green-dark); }
.mobile-card {
margin: 10px 14px;
border-radius: var(--radius-lg);
border: 2px solid var(--color-border);
background: var(--color-surface);
padding: 14px;
}
.mobile-card-selected {
border-color: var(--green);
background: var(--green-tint);
}
.mobile-2col-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
padding: 10px 14px;
}
.mobile-grid-tile {
border-radius: var(--radius-md);
border: 1px solid var(--color-border);
background: var(--color-surface);
padding: 10px;
min-height: 72px;
display: flex;
flex-direction: column;
gap: 4px;
cursor: pointer;
}
.mobile-grid-tile-empty {
border-style: dashed;
background: transparent;
align-items: center;
justify-content: center;
color: var(--color-text-muted);
}
.mobile-grid-tile-today {
border: 2px solid var(--yellow);
background: var(--yellow-tint);
}
.mobile-grid-tile-selected {
border: 2px solid var(--green);
background: var(--green-tint);
}
.mobile-grid-day {
font-family: var(--font-sans);
font-size: 9px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--color-text-muted);
}
.mobile-grid-name {
font-family: var(--font-display);
font-size: 12px;
font-weight: 300;
color: var(--color-text);
line-height: 1.3;
}
.mobile-grid-meta {
font-family: var(--font-sans);
font-size: 10px;
color: var(--color-text-muted);
}
.score-inline-badge {
display: inline-flex;
align-items: baseline;
gap: 3px;
background: var(--yellow-tint);
border: 1px solid var(--yellow-light);
border-radius: var(--radius-md);
padding: 3px 8px;
}
.score-inline-val {
font-family: var(--font-display);
font-size: 14px;
font-weight: 300;
color: var(--color-text);
}
.score-inline-denom {
font-family: var(--font-sans);
font-size: 10px;
color: var(--color-text-muted);
}
</style>
</head>
<body>
<!-- ────────────────────────────────────────────────────────────── -->
<!-- HUMAN-READABLE SECTION -->
<!-- ────────────────────────────────────────────────────────────── -->
<p class="spec-page-title">Mealplan · Wochenplaner</p>
<h1 class="spec-section-title">Planner Layout — 5 Konzepte</h1>
<p class="spec-section-sub">
Problem: Desktop zeigt ~80 % leeren Platz. Die linke Sidebar hat den Variety-Score nur am unteren Rand.
Rechtes Panel beginnt mit „Kein Tag ausgewählt". Die Kacheln sind zu flach für die Datendichte die wir hätten.
Alle 5 Konzepte nutzen ausschließlich vorhandene API-Daten.
</p>
<!-- ═══════════════════════════════════════════════════════════════ -->
<!-- MOCKUP 1: Score Dashboard Sidebar -->
<!-- ═══════════════════════════════════════════════════════════════ -->
<div class="mockup-card">
<div class="mockup-label">
<span class="mockup-number">01</span>
<span class="mockup-title">Score Dashboard Sidebar</span>
<span class="mockup-tagline">Einfachster Win — Sidebar von oben befüllen</span>
</div>
<div style="padding:24px;">
<div class="desktop-frame">
<!-- Topbar -->
<div class="chrome-topbar">
<span class="chrome-h1">Wochenplaner</span>
<span class="chrome-weekrange">7.13. Apr</span>
<div class="chrome-nav-arrow"></div>
<div class="chrome-nav-arrow"></div>
<button class="chrome-btn">Heute</button>
<button class="chrome-btn chrome-btn-primary chrome-ml-auto">+ Gericht hinzufügen</button>
</div>
<div class="desktop-body">
<!-- LEFT SIDEBAR — now full of content -->
<div class="sidebar">
<!-- Score at TOP -->
<div style="background:var(--yellow-tint);border:1px solid var(--yellow-light);border-radius:var(--radius-lg);padding:12px;">
<div class="sidebar-section-label">Abwechslungs-Score</div>
<div style="display:flex;align-items:baseline;gap:4px;">
<span class="score-big" style="font-size:32px;">7.8</span>
<span class="score-denom">/10</span>
</div>
<div class="progress-bar" style="margin-top:6px;">
<div class="progress-fill" style="width:78%;"></div>
</div>
<a class="link-sm" style="display:block;margin-top:8px;">Variety überprüfen →</a>
</div>
<!-- Sub-scores -->
<div>
<div class="sidebar-section-label">Teilwerte</div>
<div class="sub-score-row">
<span class="sub-score-label">Proteinvielfalt</span>
<div class="sub-score-bar"><div class="sub-score-fill" style="width:80%;background:var(--green);"></div></div>
<span class="sub-score-val">8.0</span>
</div>
<div class="sub-score-row">
<span class="sub-score-label">Zutaten</span>
<div class="sub-score-bar"><div class="sub-score-fill" style="width:72%;background:var(--yellow);"></div></div>
<span class="sub-score-val">7.2</span>
</div>
<div class="sub-score-row">
<span class="sub-score-label">Aufwand</span>
<div class="sub-score-bar"><div class="sub-score-fill" style="width:82%;background:var(--green);"></div></div>
<span class="sub-score-val">8.2</span>
</div>
</div>
<!-- Effort distribution -->
<div>
<div class="sidebar-section-label">Aufwandverteilung</div>
<div style="display:flex;gap:3px;border-radius:var(--radius-sm);overflow:hidden;height:18px;">
<div style="flex:3;background:var(--green);display:flex;align-items:center;justify-content:center;font-family:var(--font-sans);font-size:9px;color:white;font-weight:500;">3 einfach</div>
<div style="flex:2;background:var(--yellow);display:flex;align-items:center;justify-content:center;font-family:var(--font-sans);font-size:9px;color:white;font-weight:500;">2 mittel</div>
<div style="flex:1;background:var(--orange);display:flex;align-items:center;justify-content:center;font-family:var(--font-sans);font-size:9px;color:white;font-weight:500;">1</div>
</div>
</div>
<!-- Warnings -->
<div>
<div class="sidebar-section-label">Überschneidungen</div>
<div class="warn-item">⚠ Hähnchen an 3 Tagen</div>
<div class="warn-item">⚠ Tomaten an 2 Tagen</div>
</div>
<!-- Progress: geplante Tage -->
<div>
<div class="sidebar-section-label" style="margin-bottom:4px;">Geplant</div>
<div style="display:flex;align-items:baseline;gap:4px;">
<span style="font-family:var(--font-display);font-size:22px;font-weight:300;color:var(--color-text);">5</span>
<span style="font-family:var(--font-sans);font-size:11px;color:var(--color-text-muted);">von 7 Tagen</span>
</div>
<div style="display:flex;gap:3px;margin-top:6px;">
<div style="flex:1;height:4px;border-radius:9999px;background:var(--green);"></div>
<div style="flex:1;height:4px;border-radius:9999px;background:var(--green);"></div>
<div style="flex:1;height:4px;border-radius:9999px;background:var(--green);"></div>
<div style="flex:1;height:4px;border-radius:9999px;background:var(--green);"></div>
<div style="flex:1;height:4px;border-radius:9999px;background:var(--green);"></div>
<div style="flex:1;height:4px;border-radius:9999px;background:var(--color-border);"></div>
<div style="flex:1;height:4px;border-radius:9999px;background:var(--color-border);"></div>
</div>
</div>
</div>
<!-- MAIN CALENDAR — taller tiles -->
<main class="main-content">
<div class="grid-7">
<!-- Mo -->
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">Mo</div>
<div class="cal-day-badge">7</div>
<div class="cal-tile" style="flex:1;min-height:160px;">
<p class="recipe-name-sm">Hähnchen-Curry</p>
<p class="recipe-meta-sm">35 Min</p>
<span class="effort-badge effort-medium">mittel</span>
<span class="protein-badge">Hähnchen</span>
</div>
</div>
<!-- Di -->
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">Di</div>
<div class="cal-day-badge cal-day-badge-today" style="background:var(--yellow);color:white;">8</div>
<div class="cal-tile cal-tile-today" style="flex:1;min-height:160px;border-radius:var(--radius-md);border:2px solid var(--yellow);background:var(--yellow-tint);">
<p class="recipe-name-sm">Pasta Bolognese</p>
<p class="recipe-meta-sm">45 Min</p>
<span class="effort-badge effort-medium">mittel</span>
<span class="protein-badge">Rind</span>
</div>
</div>
<!-- Mi -->
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">Mi</div>
<div class="cal-day-badge cal-day-badge-selected" style="background:var(--green-tint);color:var(--green-dark);">9</div>
<div class="cal-tile cal-tile-selected" style="flex:1;min-height:160px;border-radius:var(--radius-md);border:2px solid var(--green);background:var(--green-tint);">
<p class="recipe-name-sm">Gemüse-Stir-fry</p>
<p class="recipe-meta-sm">20 Min</p>
<span class="effort-badge effort-easy">einfach</span>
<span class="protein-badge">Tofu</span>
</div>
</div>
<!-- Do -->
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">Do</div>
<div class="cal-day-badge">10</div>
<div class="cal-tile" style="flex:1;min-height:160px;">
<p class="recipe-name-sm">Lachsfilet mit Kartoffeln</p>
<p class="recipe-meta-sm">30 Min</p>
<span class="effort-badge effort-easy">einfach</span>
<span class="protein-badge">Fisch</span>
</div>
</div>
<!-- Fr -->
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">Fr</div>
<div class="cal-day-badge">11</div>
<div class="cal-tile" style="flex:1;min-height:160px;">
<p class="recipe-name-sm">Pizza Margherita</p>
<p class="recipe-meta-sm">50 Min</p>
<span class="effort-badge effort-hard">aufwändig</span>
<span class="protein-badge">vegetarisch</span>
</div>
</div>
<!-- Sa -->
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">Sa</div>
<div class="cal-day-badge">12</div>
<div class="cal-tile cal-tile-empty" style="flex:1;min-height:160px;border-radius:var(--radius-md);">
<span style="font-size:16px;color:var(--color-text-muted);">+</span>
<span style="font-family:var(--font-sans);font-size:10px;color:var(--color-text-muted);">wählen</span>
</div>
</div>
<!-- So -->
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">So</div>
<div class="cal-day-badge">13</div>
<div class="cal-tile cal-tile-empty" style="flex:1;min-height:160px;border-radius:var(--radius-md);">
<span style="font-size:16px;color:var(--color-text-muted);">+</span>
<span style="font-family:var(--font-sans);font-size:10px;color:var(--color-text-muted);">wählen</span>
</div>
</div>
</div>
</main>
<!-- RIGHT PANEL -->
<div class="right-panel">
<div class="panel-section">
<div class="panel-label">Mittwoch, 9. Apr</div>
<p style="font-family:var(--font-display);font-size:16px;font-weight:300;color:var(--color-text);line-height:1.4;">Gemüse-Stir-fry</p>
<p style="font-family:var(--font-sans);font-size:12px;color:var(--color-text-muted);margin-top:4px;">20 Min · einfach</p>
</div>
<div style="display:flex;flex-direction:column;gap:6px;">
<button class="action-btn action-btn-primary">Koch-Modus</button>
<button class="action-btn">Rezept ansehen</button>
<button class="action-btn">Gericht tauschen</button>
<button class="action-btn" style="color:var(--color-error);border-color:var(--color-error);">Entfernen</button>
</div>
</div>
</div>
</div>
</div>
<div class="annotation">
<strong>Was ändert sich:</strong> Variety Score wird an den Anfang der Sidebar verschoben. Darunter folgen Teilwerte (3 Mini-Balken),
Aufwandverteilung (Farbbalken), Top-Warnungen, und ein 5/7-Fortschrittsindikator.
Kacheln werden auf 160 px min-height erhöht und zeigen Effort-Badge + Protein-Tag.
<br><br>
<strong>Vorteile:</strong> Minimaler Aufwand, keine Layout-Änderung, alle Daten bereits vorhanden (varietyScore API liefert sub-scores + overlaps).
Die Sidebar ist jetzt von oben bis unten gefüllt. Kacheln vermitteln mehr Kontext auf einen Blick.
</div>
</div>
<!-- ═══════════════════════════════════════════════════════════════ -->
<!-- MOCKUP 2: Week Stats Header + Full-Width Calendar -->
<!-- ═══════════════════════════════════════════════════════════════ -->
<div class="mockup-card">
<div class="mockup-label">
<span class="mockup-number">02</span>
<span class="mockup-title">Stats-Leiste + Fullscreen-Kalender</span>
<span class="mockup-tagline">2-Spalten-Layout, Kennzahlen als Kopfzeile</span>
</div>
<div style="padding:24px;">
<div class="desktop-frame" style="height:500px;">
<!-- Topbar -->
<div class="chrome-topbar">
<span class="chrome-h1">Wochenplaner</span>
<span class="chrome-weekrange">7.13. Apr</span>
<div class="chrome-nav-arrow"></div>
<div class="chrome-nav-arrow"></div>
<button class="chrome-btn">Heute</button>
<button class="chrome-btn chrome-btn-primary chrome-ml-auto">+ Gericht hinzufügen</button>
</div>
<!-- Stats row under topbar -->
<div style="display:flex;gap:8px;padding:10px 16px;border-bottom:1px solid var(--color-border);background:var(--color-surface);">
<div class="stat-chip">
<div class="stat-chip-val">7.8</div>
<div class="stat-chip-label">Abwechslungs-Score</div>
</div>
<div class="stat-chip">
<div class="stat-chip-val">5<span style="font-family:var(--font-sans);font-size:12px;color:var(--color-text-muted);">/7</span></div>
<div class="stat-chip-label">Tage geplant</div>
</div>
<div class="stat-chip">
<div class="stat-chip-val">34 <span style="font-family:var(--font-sans);font-size:12px;color:var(--color-text-muted);">Min</span></div>
<div class="stat-chip-label">Ø Kochzeit</div>
</div>
<div class="stat-chip" style="flex:2;">
<div class="stat-chip-label" style="margin-bottom:4px;">Aufwand</div>
<div style="display:flex;gap:2px;border-radius:var(--radius-sm);overflow:hidden;height:16px;">
<div style="flex:3;background:var(--green);display:flex;align-items:center;justify-content:center;font-family:var(--font-sans);font-size:8px;color:white;font-weight:500;">3×</div>
<div style="flex:2;background:var(--yellow);display:flex;align-items:center;justify-content:center;font-family:var(--font-sans);font-size:8px;color:white;font-weight:500;">2×</div>
<div style="flex:1;background:var(--orange);"></div>
</div>
</div>
<div style="flex:3;" class="stat-chip">
<div class="stat-chip-label" style="margin-bottom:4px;">Protein-Verteilung</div>
<div style="display:flex;gap:3px;flex-wrap:wrap;">
<span class="protein-badge">Hähnchen ×2</span>
<span class="protein-badge">Rind ×1</span>
<span class="protein-badge">Fisch ×1</span>
<span class="protein-badge">Tofu ×1</span>
</div>
</div>
</div>
<div class="desktop-body">
<!-- MAIN: Full-width calendar with taller tiles -->
<main style="flex:1;overflow-y:auto;padding:16px;">
<div class="grid-7" style="height:calc(100% - 8px);">
<!-- Mon -->
<div style="display:flex;flex-direction:column;gap:6px;">
<div class="cal-day-name">Montag</div>
<div class="cal-day-badge">7</div>
<div class="cal-tile" style="flex:1;">
<p class="recipe-name-sm">Hähnchen-Curry</p>
<p class="recipe-meta-sm">35 Min</p>
<div style="margin-top:6px;display:flex;flex-direction:column;gap:3px;">
<span class="effort-badge effort-medium">mittel</span>
<span class="protein-badge">Hähnchen</span>
</div>
</div>
</div>
<!-- Tue today -->
<div style="display:flex;flex-direction:column;gap:6px;">
<div class="cal-day-name" style="color:var(--yellow-text);">Dienstag</div>
<div class="cal-day-badge" style="background:var(--yellow);color:white;">8</div>
<div class="cal-tile" style="flex:1;border:2px solid var(--yellow);background:var(--yellow-tint);">
<p class="recipe-name-sm">Pasta Bolognese</p>
<p class="recipe-meta-sm">45 Min</p>
<div style="margin-top:6px;display:flex;flex-direction:column;gap:3px;">
<span class="effort-badge effort-medium">mittel</span>
<span class="protein-badge">Rind</span>
</div>
</div>
</div>
<!-- Wed selected -->
<div style="display:flex;flex-direction:column;gap:6px;">
<div class="cal-day-name" style="color:var(--green-dark);">Mittwoch</div>
<div class="cal-day-badge" style="background:var(--green-tint);color:var(--green-dark);">9</div>
<div class="cal-tile" style="flex:1;border:2px solid var(--green);background:var(--green-tint);">
<p class="recipe-name-sm">Gemüse-Stir-fry</p>
<p class="recipe-meta-sm">20 Min</p>
<div style="margin-top:6px;display:flex;flex-direction:column;gap:3px;">
<span class="effort-badge effort-easy">einfach</span>
<span class="protein-badge">Tofu</span>
</div>
</div>
</div>
<!-- Thu -->
<div style="display:flex;flex-direction:column;gap:6px;">
<div class="cal-day-name">Donnerstag</div>
<div class="cal-day-badge">10</div>
<div class="cal-tile" style="flex:1;">
<p class="recipe-name-sm">Lachs mit Kartoffeln</p>
<p class="recipe-meta-sm">30 Min</p>
<div style="margin-top:6px;display:flex;flex-direction:column;gap:3px;">
<span class="effort-badge effort-easy">einfach</span>
<span class="protein-badge">Fisch</span>
</div>
</div>
</div>
<!-- Fri -->
<div style="display:flex;flex-direction:column;gap:6px;">
<div class="cal-day-name">Freitag</div>
<div class="cal-day-badge">11</div>
<div class="cal-tile" style="flex:1;">
<p class="recipe-name-sm">Pizza Margherita</p>
<p class="recipe-meta-sm">50 Min</p>
<div style="margin-top:6px;display:flex;flex-direction:column;gap:3px;">
<span class="effort-badge effort-hard">aufwändig</span>
<span class="protein-badge">vegetarisch</span>
</div>
</div>
</div>
<!-- Sat empty -->
<div style="display:flex;flex-direction:column;gap:6px;">
<div class="cal-day-name">Samstag</div>
<div class="cal-day-badge">12</div>
<div class="cal-tile cal-tile-empty" style="flex:1;">
<span style="font-size:20px;">+</span>
<span style="font-family:var(--font-sans);font-size:10px;margin-top:2px;">Gericht wählen</span>
</div>
</div>
<!-- Sun empty -->
<div style="display:flex;flex-direction:column;gap:6px;">
<div class="cal-day-name">Sonntag</div>
<div class="cal-day-badge">13</div>
<div class="cal-tile cal-tile-empty" style="flex:1;">
<span style="font-size:20px;">+</span>
<span style="font-family:var(--font-sans);font-size:10px;margin-top:2px;">Gericht wählen</span>
</div>
</div>
</div>
</main>
<!-- RIGHT PANEL: day detail -->
<div class="right-panel">
<div class="panel-section">
<div class="panel-label">Mittwoch, 9. Apr</div>
<p style="font-family:var(--font-display);font-size:16px;font-weight:300;line-height:1.4;">Gemüse-Stir-fry</p>
<p style="font-family:var(--font-sans);font-size:12px;color:var(--color-text-muted);margin-top:4px;">20 Min · einfach</p>
</div>
<div class="divider"></div>
<div class="panel-section">
<div class="panel-label">Score-Vorschau</div>
<div style="display:flex;align-items:baseline;gap:4px;">
<span style="font-family:var(--font-display);font-size:24px;font-weight:300;">7.8</span>
<span class="text-muted">/10</span>
<span style="font-family:var(--font-sans);font-size:11px;color:var(--green-dark);margin-left:4px;">▲ +0.4</span>
</div>
<div class="progress-bar"><div class="progress-fill" style="width:78%;"></div></div>
</div>
<div style="display:flex;flex-direction:column;gap:6px;">
<button class="action-btn action-btn-primary">Koch-Modus</button>
<button class="action-btn">Rezept ansehen</button>
<button class="action-btn">Gericht tauschen</button>
</div>
</div>
</div>
</div>
</div>
<div class="annotation">
<strong>Was ändert sich:</strong> Die linke Sidebar entfällt — stattdessen gibt es eine horizontale Stats-Leiste direkt unter der Topbar.
Sie zeigt Score, geplante Tage, Ø Kochzeit, Aufwand-Farbbalken und Protein-Tags kompakt nebeneinander.
Der Kalender wächst auf die volle verbleibende Breite. Rechtes Panel zeigt beim ausgewählten Tag jetzt auch den aktuellen Score.
<br><br>
<strong>Vorteile:</strong> Maximaler Platz für den Kalender. Stats auf einen Blick ohne Scrolling. Variety-Score immer sichtbar.
Schwäche: Keine persistente Sidebar für Warnungen.
</div>
</div>
<!-- ═══════════════════════════════════════════════════════════════ -->
<!-- MOCKUP 3: Idle Panel = Wochenübersicht -->
<!-- ═══════════════════════════════════════════════════════════════ -->
<div class="mockup-card">
<div class="mockup-label">
<span class="mockup-number">03</span>
<span class="mockup-title">Rechtes Panel als Wochenübersicht</span>
<span class="mockup-tagline">„Kein Tag ausgewählt" durch echte Daten ersetzen</span>
</div>
<div style="padding:24px;">
<div class="desktop-frame" style="height:500px;">
<div class="chrome-topbar">
<span class="chrome-h1">Wochenplaner</span>
<span class="chrome-weekrange">7.13. Apr</span>
<div class="chrome-nav-arrow"></div>
<div class="chrome-nav-arrow"></div>
<button class="chrome-btn">Heute</button>
<button class="chrome-btn chrome-btn-primary chrome-ml-auto">+ Gericht hinzufügen</button>
</div>
<div class="desktop-body">
<!-- Sidebar: Score oben -->
<div class="sidebar" style="width:192px;">
<div style="background:var(--yellow-tint);border:1px solid var(--yellow-light);border-radius:var(--radius-lg);padding:12px;">
<div class="sidebar-section-label">Score</div>
<div style="display:flex;align-items:baseline;gap:4px;">
<span class="score-big" style="font-size:30px;">7.8</span>
<span class="score-denom">/10</span>
</div>
<div class="progress-bar" style="margin-top:6px;"><div class="progress-fill" style="width:78%;"></div></div>
<div class="sub-score-row" style="margin-top:8px;">
<span class="sub-score-label">Protein</span>
<div class="sub-score-bar"><div class="sub-score-fill" style="width:80%;background:var(--green);"></div></div>
<span class="sub-score-val">8.0</span>
</div>
<div class="sub-score-row">
<span class="sub-score-label">Zutaten</span>
<div class="sub-score-bar"><div class="sub-score-fill" style="width:72%;background:var(--yellow);"></div></div>
<span class="sub-score-val">7.2</span>
</div>
<div class="sub-score-row">
<span class="sub-score-label">Aufwand</span>
<div class="sub-score-bar"><div class="sub-score-fill" style="width:82%;background:var(--green);"></div></div>
<span class="sub-score-val">8.2</span>
</div>
<a class="link-sm" style="display:block;margin-top:8px;">Details →</a>
</div>
<div>
<div class="sidebar-section-label">Warnungen</div>
<div class="warn-item">⚠ Hähnchen ×3</div>
<div class="warn-item">⚠ Tomaten ×2</div>
</div>
</div>
<!-- MAIN: Calendar -->
<main class="main-content">
<div class="grid-7">
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">Mo</div>
<div class="cal-day-badge">7</div>
<div class="cal-tile" style="min-height:140px;">
<p class="recipe-name-sm">Hähnchen-Curry</p>
<p class="recipe-meta-sm">35 Min</p>
<span class="effort-badge effort-medium">mittel</span>
</div>
</div>
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">Di</div>
<div class="cal-day-badge" style="background:var(--yellow);color:white;">8</div>
<div class="cal-tile" style="min-height:140px;border:2px solid var(--yellow);background:var(--yellow-tint);">
<p class="recipe-name-sm">Pasta Bolognese</p>
<p class="recipe-meta-sm">45 Min</p>
<span class="effort-badge effort-medium">mittel</span>
</div>
</div>
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">Mi</div>
<div class="cal-day-badge">9</div>
<div class="cal-tile" style="min-height:140px;">
<p class="recipe-name-sm">Gemüse-Stir-fry</p>
<p class="recipe-meta-sm">20 Min</p>
<span class="effort-badge effort-easy">einfach</span>
</div>
</div>
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">Do</div>
<div class="cal-day-badge">10</div>
<div class="cal-tile" style="min-height:140px;">
<p class="recipe-name-sm">Lachs mit Kartoffeln</p>
<p class="recipe-meta-sm">30 Min</p>
<span class="effort-badge effort-easy">einfach</span>
</div>
</div>
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">Fr</div>
<div class="cal-day-badge">11</div>
<div class="cal-tile" style="min-height:140px;">
<p class="recipe-name-sm">Pizza Margherita</p>
<p class="recipe-meta-sm">50 Min</p>
<span class="effort-badge effort-hard">aufwändig</span>
</div>
</div>
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">Sa</div>
<div class="cal-day-badge">12</div>
<div class="cal-tile cal-tile-empty" style="min-height:140px;">+</div>
</div>
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">So</div>
<div class="cal-day-badge">13</div>
<div class="cal-tile cal-tile-empty" style="min-height:140px;">+</div>
</div>
</div>
</main>
<!-- RIGHT PANEL: IDLE state shows week summary -->
<div class="right-panel">
<div style="font-family:var(--font-sans);font-size:10px;font-weight:500;letter-spacing:0.08em;text-transform:uppercase;color:var(--color-text-muted);margin-bottom:12px;">Diese Woche</div>
<!-- Geplante Tage -->
<div style="display:flex;gap:4px;margin-bottom:12px;">
<div style="flex:1;background:var(--green-tint);border:1px solid var(--green-light);border-radius:var(--radius-md);padding:8px;text-align:center;">
<div style="font-family:var(--font-display);font-size:22px;font-weight:300;">5</div>
<div style="font-family:var(--font-sans);font-size:9px;color:var(--color-text-muted);">geplant</div>
</div>
<div style="flex:1;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-md);padding:8px;text-align:center;">
<div style="font-family:var(--font-display);font-size:22px;font-weight:300;">2</div>
<div style="font-family:var(--font-sans);font-size:9px;color:var(--color-text-muted);">offen</div>
</div>
<div style="flex:1;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-md);padding:8px;text-align:center;">
<div style="font-family:var(--font-display);font-size:22px;font-weight:300;">34</div>
<div style="font-family:var(--font-sans);font-size:9px;color:var(--color-text-muted);">Ø Min</div>
</div>
</div>
<div class="divider"></div>
<!-- Restliche Woche -->
<div style="font-family:var(--font-sans);font-size:10px;font-weight:500;letter-spacing:0.08em;text-transform:uppercase;color:var(--color-text-muted);margin-bottom:8px;">Ungeplante Tage</div>
<div style="display:flex;flex-direction:column;gap:4px;">
<div class="suggestion-row" style="flex-direction:column;align-items:flex-start;gap:4px;">
<span style="font-family:var(--font-sans);font-size:11px;font-weight:500;color:var(--color-text);">Samstag, 12. Apr</span>
<span style="font-family:var(--font-sans);font-size:10px;color:var(--color-text-muted);">Noch kein Gericht — Klicken zum Planen</span>
</div>
<div class="suggestion-row" style="flex-direction:column;align-items:flex-start;gap:4px;">
<span style="font-family:var(--font-sans);font-size:11px;font-weight:500;color:var(--color-text);">Sonntag, 13. Apr</span>
<span style="font-family:var(--font-sans);font-size:10px;color:var(--color-text-muted);">Noch kein Gericht — Klicken zum Planen</span>
</div>
</div>
<div class="divider"></div>
<!-- Heute Abend -->
<div style="font-family:var(--font-sans);font-size:10px;font-weight:500;letter-spacing:0.08em;text-transform:uppercase;color:var(--color-text-muted);margin-bottom:8px;">Heute Abend</div>
<div style="background:var(--yellow-tint);border:1px solid var(--yellow-light);border-radius:var(--radius-md);padding:10px;">
<p style="font-family:var(--font-display);font-size:14px;font-weight:300;">Pasta Bolognese</p>
<p style="font-family:var(--font-sans);font-size:11px;color:var(--color-text-muted);margin-top:2px;">45 Min · mittel</p>
<button class="action-btn action-btn-primary" style="margin-top:8px;padding:6px;">Koch-Modus</button>
</div>
<div style="margin-top:auto;padding-top:16px;">
<a class="link-sm" style="color:var(--color-text-muted);">Klicke einen Tag um Details zu sehen</a>
</div>
</div>
</div>
</div>
</div>
<div class="annotation">
<strong>Was ändert sich:</strong> Nur das rechte Panel im Idle-Zustand. Statt „Kein Tag ausgewählt" zeigt es eine echte Wochenübersicht:
Geplant/Offen/Ø Kochzeit, ungeplante Tage als Einladung zum Klicken, und „Heute Abend" als schnellen Koch-Modus-Einstieg.
<br><br>
<strong>Vorteile:</strong> Kein leerer Zustand mehr. Nutzer sehen sofort den Stand ihrer Woche. „Heute Abend" löst den häufigsten
Use-Case (abends schnell kochen starten) direkt. Minimale Änderungen am restlichen Layout.
</div>
</div>
<!-- ═══════════════════════════════════════════════════════════════ -->
<!-- MOCKUP 4: Score-Ring + Variety-Panel rechts -->
<!-- ═══════════════════════════════════════════════════════════════ -->
<div class="mockup-card">
<div class="mockup-label">
<span class="mockup-number">04</span>
<span class="mockup-title">Variety rechts, Kalender breiter</span>
<span class="mockup-tagline">Variety-Analyse ins rechte Panel, kein linkes Sidebar mehr</span>
</div>
<div style="padding:24px;">
<div class="desktop-frame" style="height:520px;">
<div class="chrome-topbar">
<span class="chrome-h1">Wochenplaner</span>
<span class="chrome-weekrange">7.13. Apr 2026</span>
<div class="chrome-nav-arrow"></div>
<div class="chrome-nav-arrow"></div>
<button class="chrome-btn">Heute</button>
<button class="chrome-btn chrome-btn-primary chrome-ml-auto">+ Gericht hinzufügen</button>
</div>
<div class="desktop-body">
<!-- MAIN: wider calendar, no left sidebar -->
<main style="flex:1;overflow-y:auto;padding:16px;">
<div class="grid-7" style="grid-template-columns:repeat(7,1fr);gap:8px;">
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">Mo, 7.</div>
<div class="cal-tile" style="min-height:180px;margin-top:4px;">
<p class="recipe-name-sm">Hähnchen-Curry</p>
<p class="recipe-meta-sm">35 Min</p>
<span class="effort-badge effort-medium" style="margin-top:6px;">mittel</span>
<span class="protein-badge" style="display:block;margin-top:3px;">Hähnchen</span>
</div>
</div>
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name" style="color:var(--yellow-text);">Di, 8. ★</div>
<div class="cal-tile" style="min-height:180px;margin-top:4px;border:2px solid var(--yellow);background:var(--yellow-tint);">
<p class="recipe-name-sm">Pasta Bolognese</p>
<p class="recipe-meta-sm">45 Min</p>
<span class="effort-badge effort-medium" style="margin-top:6px;">mittel</span>
<span class="protein-badge" style="display:block;margin-top:3px;">Rind</span>
</div>
</div>
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name" style="color:var(--green-dark);">Mi, 9.</div>
<div class="cal-tile" style="min-height:180px;margin-top:4px;border:2px solid var(--green);background:var(--green-tint);">
<p class="recipe-name-sm">Gemüse-Stir-fry</p>
<p class="recipe-meta-sm">20 Min</p>
<span class="effort-badge effort-easy" style="margin-top:6px;">einfach</span>
<span class="protein-badge" style="display:block;margin-top:3px;">Tofu</span>
</div>
</div>
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">Do, 10.</div>
<div class="cal-tile" style="min-height:180px;margin-top:4px;">
<p class="recipe-name-sm">Lachs mit Kartoffeln</p>
<p class="recipe-meta-sm">30 Min</p>
<span class="effort-badge effort-easy" style="margin-top:6px;">einfach</span>
<span class="protein-badge" style="display:block;margin-top:3px;">Fisch</span>
</div>
</div>
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">Fr, 11.</div>
<div class="cal-tile" style="min-height:180px;margin-top:4px;">
<p class="recipe-name-sm">Pizza Margherita</p>
<p class="recipe-meta-sm">50 Min</p>
<span class="effort-badge effort-hard" style="margin-top:6px;">aufwändig</span>
<span class="protein-badge" style="display:block;margin-top:3px;">vegetarisch</span>
</div>
</div>
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">Sa, 12.</div>
<div class="cal-tile cal-tile-empty" style="min-height:180px;margin-top:4px;">
<span style="font-size:22px;">+</span>
<span style="font-family:var(--font-sans);font-size:10px;margin-top:4px;">Gericht wählen</span>
</div>
</div>
<div style="display:flex;flex-direction:column;">
<div class="cal-day-name">So, 13.</div>
<div class="cal-tile cal-tile-empty" style="min-height:180px;margin-top:4px;">
<span style="font-size:22px;">+</span>
<span style="font-family:var(--font-sans);font-size:10px;margin-top:4px;">Gericht wählen</span>
</div>
</div>
</div>
</main>
<!-- RIGHT PANEL: always shows variety analysis + today quick action -->
<div class="right-panel" style="width:280px;">
<!-- Score ring + value -->
<div style="display:flex;align-items:center;gap:14px;margin-bottom:12px;">
<div class="score-ring">
<span class="score-ring-val">7.8</span>
</div>
<div>
<div class="sidebar-section-label" style="margin-bottom:2px;">Abwechslungs-Score</div>
<div class="sub-score-row" style="margin-top:4px;">
<span class="sub-score-label">Protein</span>
<div class="sub-score-bar"><div class="sub-score-fill" style="width:80%;background:var(--green);"></div></div>
<span class="sub-score-val">8.0</span>
</div>
<div class="sub-score-row">
<span class="sub-score-label">Zutaten</span>
<div class="sub-score-bar"><div class="sub-score-fill" style="width:72%;background:var(--yellow);"></div></div>
<span class="sub-score-val">7.2</span>
</div>
<div class="sub-score-row">
<span class="sub-score-label">Aufwand</span>
<div class="sub-score-bar"><div class="sub-score-fill" style="width:82%;background:var(--green);"></div></div>
<span class="sub-score-val">8.2</span>
</div>
</div>
</div>
<div class="divider"></div>
<!-- Aufwand-Verteilung -->
<div style="margin-bottom:12px;">
<div class="panel-label">Aufwand diese Woche</div>
<div style="display:flex;gap:3px;border-radius:var(--radius-sm);overflow:hidden;height:20px;margin-top:4px;">
<div style="flex:3;background:var(--green);display:flex;align-items:center;justify-content:center;font-family:var(--font-sans);font-size:9px;color:white;font-weight:500;">3 einfach</div>
<div style="flex:2;background:var(--yellow);display:flex;align-items:center;justify-content:center;font-family:var(--font-sans);font-size:9px;color:white;font-weight:500;">2 mittel</div>
<div style="flex:1;background:var(--orange);display:flex;align-items:center;justify-content:center;font-family:var(--font-sans);font-size:9px;color:white;font-weight:500;">1</div>
</div>
</div>
<!-- Warnungen -->
<div style="margin-bottom:12px;">
<div class="panel-label">Überschneidungen</div>
<div class="warn-item">⚠ Hähnchen an Mo, Mi, Do</div>
<div class="warn-item">⚠ Tomaten an Di, Do</div>
<a class="link-sm" style="display:block;margin-top:6px;">Variety-Analyse →</a>
</div>
<div class="divider"></div>
<!-- Heute Abend CTA -->
<div>
<div class="panel-label">Heute Abend</div>
<div style="background:var(--yellow-tint);border:1px solid var(--yellow-light);border-radius:var(--radius-md);padding:10px;">
<p style="font-family:var(--font-display);font-size:14px;font-weight:300;">Pasta Bolognese</p>
<p style="font-family:var(--font-sans);font-size:11px;color:var(--color-text-muted);margin-top:2px;">Dienstag · 45 Min · mittel</p>
<button class="action-btn action-btn-primary" style="margin-top:8px;padding:6px;">Koch-Modus starten</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="annotation">
<strong>Was ändert sich:</strong> Linke Sidebar komplett entfernt → Kalender gewinnt ~200 px Breite.
Das rechte Panel wird zum permanenten Variety-Dashboard: Score-Ring, Teilwerte, Aufwand-Balken, Warnungen.
Ganz unten: „Heute Abend" als direkter Koch-Modus-Einstieg. Beim Klick auf einen Tag ersetzt das Day-Detail-Panel diesen Inhalt.
<br><br>
<strong>Vorteile:</strong> Variety-Score ist immer im Blick, nicht nur am unteren Sidebar-Rand.
Breiterer Kalender = mehr Platz für Rezeptnamen. Klarer Haupt-CTA (Koch-Modus) ohne Tab-Wechsel.
</div>
</div>
<!-- ═══════════════════════════════════════════════════════════════ -->
<!-- MOCKUP 5: Mobile — 2-Spalten Tages-Gitter -->
<!-- ═══════════════════════════════════════════════════════════════ -->
<div class="mockup-card">
<div class="mockup-label">
<span class="mockup-number">05</span>
<span class="mockup-title">Mobile — Wochengitter statt Tagesstreifen</span>
<span class="mockup-tagline">Alle 7 Tage auf einmal sichtbar, Score im Header</span>
</div>
<div style="padding:24px;">
<div style="display:flex;gap:40px;flex-wrap:wrap;align-items:flex-start;justify-content:center;">
<!-- Current state comparison -->
<div>
<div class="side-label">Aktueller Zustand</div>
<div class="mobile-frame">
<div class="mobile-status-bar"><span>9:41</span><span>●●●</span></div>
<div class="mobile-topbar">
<span class="mobile-h1">Diese Woche</span>
<div style="display:flex;gap:6px;align-items:center;">
<span style="font-size:16px;color:var(--color-text-muted);"></span>
<span style="font-size:16px;color:var(--color-text-muted);"></span>
<button style="background:var(--green-dark);color:white;border:none;border-radius:var(--radius-md);padding:5px 10px;font-family:var(--font-sans);font-size:11px;font-weight:500;">+ Gericht</button>
</div>
</div>
<!-- Yellow score banner -->
<div style="margin:10px 14px 0;background:var(--yellow-tint);border:1px solid var(--yellow-light);border-radius:var(--radius-md);padding:10px;">
<div style="display:flex;align-items:baseline;gap:4px;">
<span style="font-family:var(--font-display);font-size:24px;font-weight:300;">7.8</span>
<span style="font-family:var(--font-sans);font-size:11px;color:var(--color-text-muted);">/10 Abwechslungs-Score</span>
</div>
<div class="progress-bar"><div class="progress-fill" style="width:78%;"></div></div>
<div style="font-family:var(--font-sans);font-size:10px;color:var(--yellow-text);margin-top:6px;">⚠ Hähnchen in 3 Mahlzeiten</div>
</div>
<!-- Week strip -->
<div class="week-strip-mobile">
<div class="day-pip"><span class="day-pip-label">Mo</span><div class="day-pip-circle"><div class="day-pip-dot"></div></div></div>
<div class="day-pip"><span class="day-pip-label">Di</span><div class="day-pip-circle day-pip-circle-today">8</div></div>
<div class="day-pip"><span class="day-pip-label">Mi</span><div class="day-pip-circle day-pip-circle-selected">9</div></div>
<div class="day-pip"><span class="day-pip-label">Do</span><div class="day-pip-circle"><div class="day-pip-dot"></div></div></div>
<div class="day-pip"><span class="day-pip-label">Fr</span><div class="day-pip-circle"><div class="day-pip-dot"></div></div></div>
<div class="day-pip"><span class="day-pip-label">Sa</span><div class="day-pip-circle" style="color:var(--color-text-muted);">12</div></div>
<div class="day-pip"><span class="day-pip-label">So</span><div class="day-pip-circle" style="color:var(--color-text-muted);">13</div></div>
</div>
<!-- Selected day card -->
<div style="font-family:var(--font-sans);font-size:10px;font-weight:500;text-transform:uppercase;letter-spacing:0.06em;color:var(--color-text-muted);padding:0 14px;margin-bottom:6px;">Mittwoch, 9. April</div>
<div class="mobile-card mobile-card-selected">
<p style="font-family:var(--font-display);font-size:18px;font-weight:300;">Gemüse-Stir-fry</p>
<p style="font-family:var(--font-sans);font-size:12px;color:var(--color-text-muted);margin-top:4px;">20 Min · einfach</p>
<div style="display:flex;gap:6px;margin-top:10px;">
<button style="flex:1;background:var(--green-dark);color:white;border:none;border-radius:var(--radius-md);padding:8px;font-family:var(--font-sans);font-size:11px;font-weight:500;">Jetzt kochen</button>
<button style="background:transparent;border:1px solid var(--color-border);border-radius:var(--radius-md);padding:8px;font-family:var(--font-sans);font-size:11px;color:var(--color-text);">Tauschen</button>
</div>
</div>
</div>
</div>
<!-- New mockup -->
<div>
<div class="side-label">Neuer Vorschlag — 2-Spalten-Gitter</div>
<div class="mobile-frame">
<div class="mobile-status-bar"><span>9:41</span><span>●●●</span></div>
<!-- Compact header with inline score badge -->
<div class="mobile-topbar" style="padding:8px 14px;">
<span class="mobile-h1">Diese Woche</span>
<div style="display:flex;gap:6px;align-items:center;">
<div class="score-inline-badge">
<span class="score-inline-val">7.8</span>
<span class="score-inline-denom">/10</span>
</div>
<span style="font-size:16px;color:var(--color-text-muted);"></span>
<span style="font-size:16px;color:var(--color-text-muted);"></span>
</div>
</div>
<!-- 2-col grid: all 7 days visible -->
<div style="overflow-y:auto;flex:1;">
<div class="mobile-2col-grid">
<!-- Mo -->
<div class="mobile-grid-tile">
<div class="mobile-grid-day">Montag · 7.</div>
<div class="mobile-grid-name">Hähnchen-Curry</div>
<div class="mobile-grid-meta">35 Min · mittel</div>
</div>
<!-- Di today -->
<div class="mobile-grid-tile mobile-grid-tile-today">
<div class="mobile-grid-day" style="color:var(--yellow-text);">Dienstag · 8. ★</div>
<div class="mobile-grid-name">Pasta Bolognese</div>
<div class="mobile-grid-meta">45 Min · mittel</div>
</div>
<!-- Mi selected -->
<div class="mobile-grid-tile mobile-grid-tile-selected" style="grid-column:1/-1;">
<div style="display:flex;justify-content:space-between;align-items:flex-start;">
<div>
<div class="mobile-grid-day" style="color:var(--green-dark);">Mittwoch · 9. — Ausgewählt</div>
<div class="mobile-grid-name" style="font-size:16px;margin-top:4px;">Gemüse-Stir-fry</div>
<div class="mobile-grid-meta" style="margin-top:3px;">20 Min · einfach</div>
</div>
<div style="display:flex;flex-direction:column;gap:5px;flex-shrink:0;margin-left:10px;">
<button style="background:var(--green-dark);color:white;border:none;border-radius:var(--radius-md);padding:6px 10px;font-family:var(--font-sans);font-size:10px;font-weight:500;white-space:nowrap;">Kochen</button>
<button style="background:transparent;border:1px solid var(--color-border);border-radius:var(--radius-md);padding:6px 10px;font-family:var(--font-sans);font-size:10px;white-space:nowrap;">Tauschen</button>
</div>
</div>
</div>
<!-- Do -->
<div class="mobile-grid-tile">
<div class="mobile-grid-day">Donnerstag · 10.</div>
<div class="mobile-grid-name">Lachs mit Kartoffeln</div>
<div class="mobile-grid-meta">30 Min · einfach</div>
</div>
<!-- Fr -->
<div class="mobile-grid-tile">
<div class="mobile-grid-day">Freitag · 11.</div>
<div class="mobile-grid-name">Pizza Margherita</div>
<div class="mobile-grid-meta">50 Min · aufwändig</div>
</div>
<!-- Sa empty -->
<div class="mobile-grid-tile mobile-grid-tile-empty">
<div class="mobile-grid-day" style="color:var(--color-text-muted);">Samstag · 12.</div>
<div style="font-size:18px;color:var(--color-border);margin-top:4px;">+</div>
<div class="mobile-grid-meta">wählen</div>
</div>
<!-- So empty -->
<div class="mobile-grid-tile mobile-grid-tile-empty">
<div class="mobile-grid-day" style="color:var(--color-text-muted);">Sonntag · 13.</div>
<div style="font-size:18px;color:var(--color-border);margin-top:4px;">+</div>
<div class="mobile-grid-meta">wählen</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="annotation">
<strong>Was ändert sich (Mobile):</strong> Die gelbe Score-Banner wird aus dem Scroll-Bereich herausgelöst und als kompaktes Badge
in die Topbar integriert (spart ~80 px). Der horizontale Tagesstreifen + separate „Restliche Woche" Liste werden ersetzt durch ein
2-Spalten-Gitter, das alle 7 Tage auf einmal zeigt. Der ausgewählte Tag expandiert zur vollen Breite mit integrierten Aktionen (kein separater großer Card mehr).
<br><br>
<strong>Vorteile:</strong> Auf einem Blick sieht man die ganze Woche. Kein Scrollen nötig um alle Tage zu sehen.
Score-Badge bleibt jederzeit sichtbar ohne Platz zu fressen. Expandierter Tag ersetzt das separate Tagesdetail-Pattern.
</div>
</div>
<!-- ────────────────────────────────────────────────────────────── -->
<!-- MACHINE-READABLE SECTION -->
<!-- ────────────────────────────────────────────────────────────── -->
<div class="agent-section" id="agent-section">
<!--
MACHINE-READABLE SPEC: Planner Layout Mockups
Generated: 2026-04-09
Author: Atlas (UI persona)
Scope: /planner desktop + mobile
═══════════════════════════════════════════════════════════════════
MOCKUP 01 — Score Dashboard Sidebar
═══════════════════════════════════════════════════════════════════
Layout: 3-column (sidebar | main | right-panel) — unchanged
Sidebar width: 200px (currently 224px, can shrink)
Changes:
- Sidebar: mt-auto removed from VarietyScoreCard wrapper
- Sidebar: score card now first child (no div wrapper needed)
- Sidebar: Add <ScoreBreakdownList> component below score card
(already exists: /frontend/src/lib/planner/ScoreBreakdownList.svelte)
- Sidebar: Add effort distribution mini bar
(data: slots.map(s => s.recipe?.effort) → count einfach/mittel/aufwändig)
- Sidebar: Add top-2 ingredient overlap warnings
(data: varietyScore.ingredientOverlaps.slice(0,2))
- Sidebar: Add "X von 7 Tagen geplant" progress row
(data: slots.filter(s => s.recipe).length)
Calendar tiles: min-height 140px → 180px
- Show: recipe.name, cookTimeMin, effort badge, protein tag (first protein tag from recipe.tags)
- effort-badge: einfach=green-tint/green-dark, mittel=yellow-tint/yellow-text, aufwändig=orange-tint/orange
- protein-badge: purple-tint/purple always
Data sources (all available):
- varietyScore.score ✓
- varietyScore.ingredientOverlaps ✓
- VarietyPreviewResponse.proteinDiversity / ingredientOverlap / effortBalance (sub-scores) ✓
- slots[].recipe.effort ✓
- slots.filter(s => s.recipe).length ✓
- slots[].recipe.tags (for protein tag) ✓
═══════════════════════════════════════════════════════════════════
MOCKUP 02 — Stats-Leiste + Full-Width Calendar
═══════════════════════════════════════════════════════════════════
Layout: 2-column (main | right-panel) — remove left sidebar
Stats bar: height 48px, flex row, gap-2, px-4
Position: between topbar and desktop-body
Chips (flex:1 each, except last flex:2 and flex:3):
1. score/10 → varietyScore.score
2. X/7 geplant → slots.filter(s=>s.recipe).length
3. Ø Min → Math.round(slots.filter(s=>s.recipe?.cookTimeMin).reduce(…) / count)
4. Aufwand bar (flex:2) → einfach/mittel/aufwändig counts
5. Protein tags (flex:3) → unique protein tags with counts
Calendar tile full-day label: "Montag" not "Mo" — use formatDayLabel
Right panel: keep existing day-detail state, add score delta display:
currentScore + delta when day is selected
═══════════════════════════════════════════════════════════════════
MOCKUP 03 — Idle Panel = Wochenübersicht
═══════════════════════════════════════════════════════════════════
Layout: 3-column — unchanged
Changes: only right panel idle state
Replace: <p>Kein Tag ausgewählt</p>
With: week summary component containing:
1. Stat chips: geplant count, offen count, avg cook time
2. "Ungeplante Tage" list → days.filter(d => !slotMap[d]?.recipe)
Each item: date label + "Klicken zum Planen" → onclick sets panelState recipe-picker
3. "Heute Abend" card → slotMap[today] if recipe exists
Show: recipe name, meta, Koch-Modus button
No new API calls needed — all derived from existing slots + today
═══════════════════════════════════════════════════════════════════
MOCKUP 04 — Variety Panel rechts, kein linkes Sidebar
═══════════════════════════════════════════════════════════════════
Layout: 2-column (main | right-panel), left sidebar removed
Right panel: 2 states:
STATE A (no day selected) — permanent variety dashboard:
- Score ring (CSS conic-gradient, hole via ::after)
- Sub-scores (3 bars)
- Effort distribution bar
- Top ingredient overlap warnings + link to /planner/variety
- "Heute Abend" CTA at bottom
STATE B (day selected) — existing day-detail content + score delta
Right panel width: 280px (was 280px — unchanged)
Main calendar: gains 200px width (sidebar removed)
Calendar day label: "Mo, 7." format — formatDayAbbr + dateNum
Score ring CSS:
background: conic-gradient(var(--yellow) 0% {score*10}%, var(--yellow-light) {score*10}% 100%)
After: 52px circle var(--color-surface) centered = donut hole
═══════════════════════════════════════════════════════════════════
MOCKUP 05 — Mobile 2-Column Grid
═══════════════════════════════════════════════════════════════════
Breakpoint: mobile only (< 1024px)
Changes:
A. Header: score badge replaces full VarietyScoreCard banner
Component: inline badge in header right area
Value: varietyScore.score.toFixed(1) + "/10"
Style: yellow-tint bg, yellow-light border, radius-md
Full banner removed → saves ~80px vertical space
B. Week navigation: score badge sits between score and nav arrows
Layout: flex row: [title] [score-badge] [] [] [+ Gericht]
C. Replace WeekStrip + DayMealCard + "Restliche Woche" section
With: 2-column CSS grid of day tiles
Grid: grid-cols-2, gap-2, px-3.5, overflow-y-auto
D. Tile states:
- default: border color-border, bg color-surface
- today: border-2 yellow, bg yellow-tint
- selected: grid-column span 2 (full width), expanded with actions
- empty: dashed border, placeholder +
E. Selected tile (expanded):
- grid-column: 1 / -1 (spans both columns)
- flex row: [name + meta] [actions column: Kochen btn + Tauschen btn]
- onclick same as handleSelectDay: selectedDay = day
F. Interaction:
- Tap tile → selectedDay = day (same state)
- No bottom sheet needed for basic day selection
- + empty tile → opens pickerOpen bottom sheet (unchanged)
- Existing tile → opens actionSheetOpen (unchanged, but triggered from tile click)
G. Ingredient overlap warnings:
- Removed from sticky banner (too much space)
- Accessible via "Variety überprüfen" link (score badge is tappable → /planner/variety)
TOKEN REFERENCE:
--yellow-tint: #fdf6d8 (today bg)
--yellow-light: #f9e08a (today border)
--green-tint: #e8f5ea (selected bg)
--green: #3d8c4a (selected border)
--color-surface: #f5f4ee (default tile bg)
--color-border: #d8d7d0 (default tile border)
--color-page: #fafaf7
--radius-md: 6px (tile radius)
--radius-lg: 10px (expanded tile)
═══════════════════════════════════════════════════════════════════
ACCESSIBILITY NOTES (all mockups)
═══════════════════════════════════════════════════════════════════
- Score ring: add role="img" aria-label="Abwechslungs-Score: 7.8 von 10"
- Sub-score bars: role="progressbar" aria-valuenow aria-valuemin=0 aria-valuemax=10
- Effort bar segments: aria-label="3 einfach, 2 mittel, 1 aufwändig"
- Mobile tile grid: each tile button gets aria-label="{dayLabel}: {recipeName or 'Kein Gericht'}"
- Expanded tile: focus management — when tile expands, move focus to action button
- Score badge in mobile header: role="status" (updates when score changes)
- Contrast check:
yellow-text (#8a6800) on yellow-tint (#fdf6d8): ~6.8:1 ✓ AAA
green-dark (#2e6e39) on green-tint (#e8f5ea): ~5.1:1 ✓ AA
orange (#e8862a) on orange-tint (#fef0e6): ~3.4:1 ✓ large text only
→ use orange-dark (#b46820) for small text on orange-tint: ~5.2:1 ✓ AA
═══════════════════════════════════════════════════════════════════
RECOMMENDED PRIORITY
═══════════════════════════════════════════════════════════════════
1. Mockup 01 — highest ROI, lowest risk. Sidebar already exists.
2. Mockup 03 — zero layout change, only right panel idle state.
Together 01+03 fix both reported problems with minimal scope.
3. Mockup 05 — mobile improvement, self-contained.
4. Mockup 04 — bigger refactor but best visual result.
5. Mockup 02 — breaks 3-panel convention, discuss first.
-->
</div>
</body>
</html>