Files
mealprep/specs/frontend/e4-variety-settings-kachel.html
Marcel Raddatz bd1604fc1d docs(specs): add detailed implementation spec for E4 variety settings (V2 Kontext-Preset)
5 states: S0 E1 hub update, S1 default, S2 preset selection + score simulation,
S3 advanced settings + Individuell chip, S4 reset confirmation dialog.
Includes API contract, preset mappings, weight multipliers, and LLM agent region.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 16:13:17 +02:00

982 lines
68 KiB
HTML
Raw 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>Recipe App — E4 Vielfalt-Einstellungen · Implementierungsspezifikation</title>
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,300;9..144,400;9..144,500&family=DM+Sans:wght@300;400;500;600&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet"/>
<style>
:root{--color-page:#FAFAF7;--color-surface:#F5F4EE;--color-subtle:#EDECEA;--color-border:#D8D7D0;--color-text-muted:#6B6A63;--color-text:#1C1C18;--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-light:#A4CFF4;--blue:#2D7DD2;--blue-dark:#185FA5;--purple-tint:#EEEDFE;--purple-light:#CECBF6;--purple:#534AB7;--purple-dark:#3C3489;--orange-tint:#FEF0E6;--orange:#E8862A;--orange-dark:#B46820;--red-tint:#FDECEA;--red:#DC4C3E;--red-dark:#B03328;--color-error:#DC4C3E;--font-display:'Fraunces',Georgia,serif;--font-sans:'DM Sans',system-ui,sans-serif;--font-mono:'DM Mono',monospace;--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);--shadow-overlay:0 8px 32px rgba(28,28,24,.12),0 2px 8px rgba(28,28,24,.06);}
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0;}
body{font-family:var(--font-sans);background:#E8E7E2;color:var(--color-text);font-size:14px;line-height:1.6;}
.doc{max-width:1200px;margin:0 auto;padding:48px 40px 120px;}
.doc-header{display:flex;justify-content:space-between;align-items:flex-end;padding-bottom:28px;border-bottom:1px solid var(--color-border);margin-bottom:48px;background:var(--color-page);margin:-48px -40px 48px;padding:48px 40px 28px;border-radius:var(--radius-xl) var(--radius-xl) 0 0;}
.doc-header h1{font-family:var(--font-display);font-size:28px;font-weight:500;letter-spacing:-.02em;margin-bottom:4px;}
.doc-header p{font-size:13px;color:var(--color-text-muted);}
.doc-meta{font-family:var(--font-mono);font-size:11px;color:var(--color-text-muted);text-align:right;line-height:1.9;}
.pill{display:inline-block;padding:2px 8px;border-radius:var(--radius-sm);font-size:10px;font-weight:500;letter-spacing:.05em;background:var(--green-tint);color:var(--green-dark);}
.section{margin-bottom:64px;}
.section-title{font-size:10px;font-weight:500;letter-spacing:.12em;text-transform:uppercase;color:var(--color-text-muted);padding-bottom:10px;border-bottom:1px solid var(--color-border);margin-bottom:24px;}
.prose{font-size:13px;color:var(--color-text-muted);line-height:1.65;max-width:720px;margin-bottom:20px;}
/* Journey header */
.jh{padding:20px 24px;border-radius:var(--radius-xl);margin-bottom:40px;display:flex;align-items:center;gap:16px;}
.jh .jn{font-family:var(--font-display);font-size:48px;font-weight:300;line-height:1;opacity:.5;}
.jh h2{font-family:var(--font-display);font-size:22px;font-weight:500;letter-spacing:-.02em;margin-bottom:4px;}
.jh p{font-size:13px;line-height:1.5;}.jh .fl{font-family:var(--font-mono);font-size:11px;margin-top:6px;opacity:.7;}
.jh-p{background:var(--purple-tint);border:1px solid var(--purple-light);}.jh-p .jn{color:var(--purple);}.jh-p p,.jh-p .fl{color:var(--purple-dark);}
/* Screen block */
.scr{margin-bottom:56px;}
.scr-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;}
.scr-head h3{font-family:var(--font-display);font-size:20px;font-weight:500;letter-spacing:-.02em;}
.scr-id{font-family:var(--font-mono);font-size:11px;color:var(--color-text-muted);padding:2px 8px;border:1px solid var(--color-border);border-radius:var(--radius-sm);background:var(--color-page);}
.scr-desc{font-size:12px;color:var(--color-text-muted);line-height:1.6;max-width:720px;margin-bottom:6px;}
.scr-var{font-size:11px;color:var(--color-text-muted);margin-bottom:20px;}.scr-var strong{color:var(--color-text);}
/* Device frames */
.previews{display:flex;gap:32px;flex-wrap:wrap;justify-content:center;align-items:flex-start;margin-bottom:20px;}
.prev-col{display:flex;flex-direction:column;align-items:center;gap:10px;}
.bp-lbl{font-family:var(--font-mono);font-size:10px;color:var(--color-text-muted);}
.phone{width:320px;flex-shrink:0;background:var(--color-page);border-radius:36px;overflow:hidden;box-shadow:var(--shadow-overlay),0 0 0 1px rgba(0,0,0,.07);display:flex;flex-direction:column;border:6px solid #1C1C18;}
.pst{padding:10px 20px 0;display:flex;justify-content:space-between;align-items:center;font-size:12px;background:var(--color-page);}.pst b{font-weight:600;}.pst span{font-size:10px;}
.pb{flex:1;overflow-y:auto;display:flex;flex-direction:column;}
.desk{width:100%;max-width:1040px;background:var(--color-page);border-radius:var(--radius-xl);overflow:hidden;box-shadow:var(--shadow-overlay),0 0 0 1px rgba(0,0,0,.06);display:flex;min-height:520px;}
/* Agent spec block */
.agent{background:var(--color-text);color:#E8E8E2;padding:24px;border-radius:var(--radius-lg);margin-top:20px;}
.agent h4{font-size:9px;font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:#5A5A55;margin-bottom:12px;}
.agent pre{font-family:var(--font-mono);font-size:10px;color:#444440;margin-bottom:16px;line-height:1.8;white-space:pre-wrap;}
.at{width:100%;border-collapse:collapse;font-family:var(--font-mono);font-size:10px;}
.at thead tr{border-bottom:1px solid #2A2A26;}.at th{text-align:left;padding:6px 10px;font-size:8px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:#5A5A55;font-family:var(--font-sans);}.at td{padding:5px 10px;border-bottom:1px solid #1E1E1A;vertical-align:top;line-height:1.5;}.at tr:last-child td{border-bottom:none;}.at td:first-child{color:#7A7A72;}.at td:nth-child(2){color:#E8E8E2;font-weight:500;}.at td:nth-child(3){color:#5A5A55;}.at .grp td{padding-top:14px;font-family:var(--font-sans);font-size:8px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:#3A3A36;}
/* LLM section */
.llm{background:var(--color-page);border:2px solid var(--green);border-radius:var(--radius-xl);padding:32px 40px;margin-top:64px;}
.llm h2{font-family:var(--font-display);font-size:22px;font-weight:500;letter-spacing:-.02em;margin-bottom:8px;color:var(--green-dark);}
.llm h3{font-size:14px;font-weight:600;margin:20px 0 8px;color:var(--color-text);}
.llm p,.llm li{font-size:13px;color:var(--color-text-muted);line-height:1.65;}
.llm ul,.llm ol{padding-left:20px;margin-bottom:12px;}
.llm li{margin-bottom:4px;}
.llm code{font-family:var(--font-mono);font-size:11px;background:var(--color-surface);padding:1px 5px;border-radius:3px;}
.llm table{width:100%;border-collapse:collapse;margin:12px 0;font-size:12px;}
.llm th,.llm td{text-align:left;padding:6px 10px;border-bottom:1px solid var(--color-border);}
.llm th{font-weight:500;color:var(--color-text);font-size:11px;text-transform:uppercase;letter-spacing:.05em;}
.llm td{color:var(--color-text-muted);}
/* Shared nav chrome */
.mtb{padding:10px 16px;background:var(--color-page);border-bottom:1px solid var(--color-border);display:flex;align-items:center;gap:10px;}
.mtb-back{font-size:12px;color:var(--color-text-muted);display:flex;align-items:center;gap:4px;flex-shrink:0;}
.mtb-t{font-family:var(--font-display);font-size:18px;font-weight:500;letter-spacing:-.02em;flex:1;}
.mbt{border-top:1px solid var(--color-border);background:var(--color-surface);padding:8px 16px 28px;display:flex;justify-content:space-around;flex-shrink:0;}
.mt-i{display:flex;flex-direction:column;align-items:center;gap:2px;}
.mt-ic{width:20px;height:20px;border-radius:4px;background:var(--color-subtle);display:flex;align-items:center;justify-content:center;font-size:11px;}
.mt-i.a .mt-ic{background:var(--green-tint);}
.mt-l{font-size:9px;font-weight:500;color:var(--color-text-muted);}
.mt-i.a .mt-l{color:var(--green-dark);}
.dsb{width:224px;flex-shrink:0;background:var(--color-surface);border-right:1px solid var(--color-border);display:flex;flex-direction:column;}
.dsb-logo{padding:20px 16px 16px;border-bottom:1px solid var(--color-border);}
.dsb-lm{display:flex;align-items:center;gap:8px;margin-bottom:2px;}
.dsb-ic{width:24px;height:24px;border-radius:5px;background:var(--green);display:flex;align-items:center;justify-content:center;font-size:12px;}
.dsb-nm{font-family:var(--font-display);font-size:16px;font-weight:500;letter-spacing:-.02em;}
.dsb-sub{font-size:10px;color:var(--color-text-muted);padding-left:32px;}
.dsb-nav{padding:12px 10px;flex:1;}
.dsb-nl{font-size:8px;font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:var(--color-text-muted);padding:0 8px;margin-bottom:4px;}
.dsb-ni{display:flex;align-items:center;gap:8px;padding:7px 8px;border-radius:var(--radius-md);font-size:13px;color:var(--color-text-muted);margin-bottom:2px;}
.dsb-ni.a{background:var(--green-tint);color:var(--green-dark);font-weight:500;}
.dsb-nc{font-size:13px;width:18px;text-align:center;}
.dm{flex:1;display:flex;flex-direction:column;min-width:0;}
.dtb{padding:14px 24px;border-bottom:1px solid var(--color-border);display:flex;justify-content:space-between;align-items:center;flex-shrink:0;}
.dtb-t{font-family:var(--font-display);font-size:18px;font-weight:500;letter-spacing:-.02em;}
.dtb-bc{font-size:12px;color:var(--color-text-muted);display:flex;align-items:center;gap:6px;margin-bottom:2px;}
.dtb-bc span{color:var(--color-border);}
.dmc{padding:24px;flex:1;overflow-y:auto;}
/* UI components */
.tog{display:flex;align-items:center;justify-content:space-between;padding:12px 0;border-bottom:1px solid var(--color-subtle);}
.tog:last-child{border-bottom:none;}
.tog-l{display:flex;flex-direction:column;gap:2px;}
.tog-name{font-size:13px;font-weight:500;}
.tog-hint{font-size:11px;color:var(--color-text-muted);}
.tog-sw{width:36px;height:20px;border-radius:10px;background:var(--green);flex-shrink:0;position:relative;}
.tog-sw::after{content:'';position:absolute;width:16px;height:16px;border-radius:50%;background:#fff;top:2px;right:2px;box-shadow:0 1px 3px rgba(0,0,0,.2);}
.tog-sw.off{background:var(--color-border);}
.tog-sw.off::after{right:auto;left:2px;}
.seg{display:flex;border:1px solid var(--color-border);border-radius:var(--radius-md);overflow:hidden;background:var(--color-surface);}
.seg-o{flex:1;text-align:center;font-size:11px;font-weight:500;padding:6px 0;color:var(--color-text-muted);}
.seg-o.a{background:var(--color-page);color:var(--color-text);box-shadow:var(--shadow-card);}
.seg-o.a-r{background:var(--red-tint);color:var(--red-dark);}
.seg-o.a-g{background:var(--green-tint);color:var(--green-dark);}
.grp{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden;margin-bottom:12px;}
.grp-hd{padding:10px 14px;border-bottom:1px solid var(--color-border);background:var(--color-subtle);}
.grp-hd-t{font-size:10px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--color-text-muted);}
.grp-b{padding:0 14px;}
.wr{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 0;border-bottom:1px solid var(--color-subtle);}
.wr:last-child{border-bottom:none;}
.wr-l{display:flex;flex-direction:column;gap:1px;min-width:0;}
.wr-name{font-size:12px;font-weight:500;}
.wr-sub{font-size:10px;color:var(--color-text-muted);}
/* Context chips */
.ctx-chips{display:flex;gap:8px;margin-bottom:16px;}
.ctx-chip{flex:1;padding:14px 12px;border-radius:var(--radius-xl);border:1.5px solid var(--color-border);background:var(--color-surface);display:flex;flex-direction:column;gap:3px;cursor:default;}
.ctx-chip.sel{border-color:var(--green-light);background:var(--green-tint);}
.ctx-chip.ind{border-color:var(--purple-light);background:var(--purple-tint);}
.ctx-em{font-size:18px;}
.ctx-name{font-size:12px;font-weight:600;color:var(--color-text);}
.ctx-chip.sel .ctx-name{color:var(--green-dark);}
.ctx-chip.ind .ctx-name{color:var(--purple-dark);}
.ctx-sub{font-size:10px;color:var(--color-text-muted);line-height:1.3;}
.ctx-chip.sel .ctx-sub{color:var(--green-dark);opacity:.7;}
.ctx-chip.ind .ctx-sub{color:var(--purple-dark);opacity:.7;}
/* Summary pills */
.s-pills{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:14px;}
.s-pill{font-size:10px;font-weight:500;padding:3px 8px;border-radius:20px;display:flex;align-items:center;gap:3px;}
.s-pill.on{background:var(--green-tint);color:var(--green-dark);}
.s-pill.off{background:var(--color-subtle);color:var(--color-text-muted);}
.s-pill.warn{background:var(--yellow-tint);color:var(--yellow-text);}
/* Accordion */
.acc{border:1px solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden;margin-bottom:12px;}
.acc-hd{padding:12px 14px;display:flex;justify-content:space-between;align-items:center;background:var(--color-surface);}
.acc-hd-t{font-size:13px;font-weight:500;}
.acc-hd-r{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--color-text-muted);}
.acc-b{padding:14px;border-top:1px solid var(--color-border);background:var(--color-page);}
/* Score preview */
.score-banner{background:var(--color-text);border-radius:var(--radius-lg);padding:14px 16px;margin-bottom:14px;display:flex;align-items:center;justify-content:space-between;gap:12px;}
.score-banner-l{}
.score-banner-label{font-size:10px;color:#6B6A63;margin-bottom:2px;}
.score-banner-val{font-family:var(--font-display);font-size:30px;font-weight:300;letter-spacing:-.02em;color:#E8E8E2;line-height:1;}
.score-banner-sub{font-size:10px;margin-top:3px;}
.score-banner-up{color:#6FCF97;}
.score-banner-neutral{color:#6B6A63;}
.score-banner-r{font-size:28px;opacity:.7;}
/* Summary detail rows (desktop right column) */
.sum-rows{display:flex;flex-direction:column;gap:5px;}
.sum-row{display:flex;justify-content:space-between;align-items:center;padding:7px 10px;border-radius:var(--radius-md);font-size:12px;}
.sum-row.on{background:var(--green-tint);}
.sum-row.off{background:var(--color-subtle);}
.sum-row.warn{background:var(--yellow-tint);}
.sum-row-name{font-weight:500;}
.sum-row.on .sum-row-name{color:var(--green-dark);}
.sum-row.off .sum-row-name{color:var(--color-text-muted);}
.sum-row.warn .sum-row-name{color:var(--yellow-text);}
.sum-row-val{font-size:10px;font-weight:500;}
.sum-row.on .sum-row-val{color:var(--green-dark);}
.sum-row.off .sum-row-val{color:var(--color-text-muted);}
.sum-row.warn .sum-row-val{color:var(--yellow-text);}
/* Reset link */
.reset-link{font-size:12px;color:var(--red-dark);padding:10px 0;display:block;text-align:center;}
/* Divider */
.sec-lbl{font-size:10px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:var(--color-text-muted);margin-bottom:8px;}
/* Modal overlay */
.overlay{position:relative;border-radius:var(--radius-xl);overflow:hidden;}
.modal-backdrop{position:absolute;inset:0;background:rgba(28,28,24,.4);display:flex;align-items:center;justify-content:center;padding:24px;}
.modal{background:var(--color-page);border-radius:var(--radius-xl);padding:24px;width:100%;max-width:280px;box-shadow:var(--shadow-overlay);}
.modal-title{font-family:var(--font-display);font-size:18px;font-weight:500;letter-spacing:-.02em;margin-bottom:8px;}
.modal-body{font-size:13px;color:var(--color-text-muted);line-height:1.6;margin-bottom:20px;}
.modal-acts{display:flex;flex-direction:column;gap:8px;}
.btn-dest{padding:11px 16px;border-radius:var(--radius-md);background:var(--red);color:#fff;font-weight:500;font-size:13px;text-align:center;}
.btn-ghost{padding:11px 16px;border-radius:var(--radius-md);background:var(--color-surface);border:1px solid var(--color-border);color:var(--color-text-muted);font-weight:500;font-size:13px;text-align:center;}
/* E1 hub card */
.hub-grid{display:grid;grid-template-columns:2fr 1fr;gap:12px;margin-bottom:12px;}
.hub-card{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-xl);padding:16px;}
.hub-card.primary{border-left:3px solid var(--green-dark);}
.hub-card.variety{border-left:3px solid var(--purple);}
.hub-stat{font-family:var(--font-display);font-size:36px;font-weight:300;letter-spacing:-.02em;line-height:1;margin-bottom:4px;}
.hub-stat.green{color:var(--green-dark);}
.hub-stat.purple{color:var(--purple);}
.hub-name{font-size:12px;font-weight:500;margin-bottom:2px;}
.hub-sub{font-size:11px;color:var(--color-text-muted);}
.hub-arr{font-size:12px;color:var(--color-text-muted);margin-top:10px;}
/* Settings hub bottom row */
.hub-row{display:grid;grid-template-columns:1fr 1fr;gap:12px;}
</style>
</head>
<body>
<div class="doc">
<!-- ── Header ── -->
<div class="doc-header">
<div>
<h1>E4 — Vielfalt-Einstellungen</h1>
<p>Implementierungsspezifikation · V2 Kontext-Preset · Journey J9</p>
</div>
<div class="doc-meta">
<span class="pill">v1.0</span><br>
Screens: E1 (Update) + E4<br>
States: 5<br>
Rolle: Planer only
</div>
</div>
<!-- ── Journey context ── -->
<div class="jh jh-p">
<div class="jn">J9</div>
<div>
<h2>Vielfalt-Algorithmus konfigurieren</h2>
<p>Planer passt Bewertungsregeln an den Haushaltskontext an — primär das Deaktivieren der Protein-Prüfung für vegetarische Haushalte.</p>
<div class="fl">E1 → E4 → C3 · Planer only · Auto-Save · Reset benötigt Bestätigung</div>
</div>
</div>
<!-- ════════════════════════════════════════
E1 — SETTINGS HUB UPDATE
═════════════════════════════════════════ -->
<div class="section">
<div class="section-title">E1 — Settings-Hub (Update)</div>
<p class="prose">Der bestehende Settings-Hub (E1) erhält eine dritte Kachel: "Vielfalt-Einstellungen". Die Kachel zeigt den aktuellen Vielfalt-Score als Kennzahl. Das Grid-Layout wird von 2-spaltig zu einem Mix aus Hauptkachel oben und zwei gleichbreiten Kacheln unten angepasst.</p>
<!-- S0: E1 Hub -->
<div class="scr">
<div class="scr-head"><h3>S0 · Settings-Hub mit Vielfalt-Kachel</h3><span class="scr-id">E1</span></div>
<div class="scr-desc">Die neue Vielfalt-Kachel erscheint in der unteren Reihe neben der Haushalt-Kachel. Zeigt den aktuellen Score als lila Kennzahl. Bei Score &lt; 6.0 färbt sich die Kennzahl orange als Aufmerksamkeitshinweis.</div>
<div class="scr-var"><strong>Änderung gegenüber E1 v1:</strong> dritte Kachel + Grid-Anpassung. Vorräte-Kachel bleibt primär (2fr oben).</div>
<div class="previews">
<div class="prev-col">
<div class="bp-lbl">Mobile · 320px</div>
<div class="phone">
<div class="pst"><b>9:41</b><span>●●●</span></div>
<div class="pb">
<div class="mtb"><div class="mtb-t">Einstellungen</div></div>
<div style="padding:16px;flex:1;">
<!-- Vorräte (primary, full width) -->
<div class="hub-card primary" style="margin-bottom:12px;">
<div class="hub-stat green">12</div>
<div class="hub-name">Vorräte</div>
<div class="hub-sub">Zutaten immer vorrätig</div>
<div class="hub-arr">Bearbeiten →</div>
</div>
<!-- Bottom row: 2 cards -->
<div class="hub-row">
<div class="hub-card">
<div class="hub-stat" style="font-size:28px;color:var(--blue-dark);">3</div>
<div class="hub-name">Haushalt</div>
<div class="hub-sub">Mitglieder</div>
<div class="hub-arr">Verwalten →</div>
</div>
<div class="hub-card variety">
<div class="hub-stat purple" style="font-size:28px;">7.4</div>
<div class="hub-name">Vielfalt</div>
<div class="hub-sub">Diese Woche</div>
<div class="hub-arr">Einstellungen →</div>
</div>
</div>
</div>
<div class="mbt">
<div class="mt-i"><div class="mt-ic">📅</div><div class="mt-l">Plan</div></div>
<div class="mt-i"><div class="mt-ic">🛒</div><div class="mt-l">Einkauf</div></div>
<div class="mt-i"><div class="mt-ic">🍳</div><div class="mt-l">Rezepte</div></div>
<div class="mt-i a"><div class="mt-ic">⚙️</div><div class="mt-l">Einstellungen</div></div>
</div>
</div>
</div>
</div>
<div class="prev-col" style="flex:1;min-width:600px;">
<div class="bp-lbl">Desktop · 1040px</div>
<div class="desk">
<div class="dsb">
<div class="dsb-logo"><div class="dsb-lm"><div class="dsb-ic">🥦</div><div class="dsb-nm">Mealprep</div></div><div class="dsb-sub">Familie Raddatz</div></div>
<div class="dsb-nav">
<div class="dsb-nl">Planung</div>
<div class="dsb-ni"><span class="dsb-nc">📅</span> Wochenplan</div>
<div class="dsb-ni"><span class="dsb-nc">🛒</span> Einkaufsliste</div>
<div class="dsb-ni"><span class="dsb-nc">🍳</span> Rezepte</div>
<div class="dsb-nl" style="margin-top:12px;">Haushalt</div>
<div class="dsb-ni a"><span class="dsb-nc">⚙️</span> Einstellungen</div>
</div>
</div>
<div class="dm">
<div class="dtb"><div class="dtb-t">Einstellungen</div></div>
<div class="dmc">
<div style="max-width:640px;">
<!-- Vorräte primary -->
<div class="hub-card primary" style="margin-bottom:16px;display:flex;align-items:center;justify-content:space-between;">
<div>
<div class="hub-stat green">12</div>
<div class="hub-name">Vorräte</div>
<div class="hub-sub">Zutaten, die immer vorrätig sind und nicht auf die Einkaufsliste kommen</div>
</div>
<div style="font-size:13px;font-weight:500;color:var(--green-dark);">Bearbeiten →</div>
</div>
<!-- Bottom row: 2 cards -->
<div class="hub-row">
<div class="hub-card" style="display:flex;align-items:center;justify-content:space-between;">
<div>
<div class="hub-stat" style="font-size:28px;color:var(--blue-dark);">3</div>
<div class="hub-name">Haushalt</div>
<div class="hub-sub">Mitglieder &amp; Rollen</div>
</div>
<div style="font-size:13px;font-weight:500;color:var(--blue-dark);">Verwalten →</div>
</div>
<div class="hub-card variety" style="display:flex;align-items:center;justify-content:space-between;">
<div>
<div class="hub-stat purple" style="font-size:28px;">7.4</div>
<div class="hub-name">Vielfalt-Einstellungen</div>
<div class="hub-sub">Algorithmus anpassen</div>
</div>
<div style="font-size:13px;font-weight:500;color:var(--purple-dark);">Einstellungen →</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="agent">
<h4>E1 Hub Update · S0</h4>
<pre>/* E1 grid: Vorräte (full width, 2fr, border-left: 3px solid --green-dark) on top row.
* Bottom row: 2 equal columns — Haushalt + Vielfalt-Einstellungen.
* Vielfalt card: border-left: 3px solid --purple. Stat color: --purple (7.4).
* If score < 6.0: stat color switches to --orange (Aufmerksamkeit) with no other change.
* Score value: load from GET /v1/week-plans?weekStart=current GET /v1/week-plans/{id}/variety-score.
* If no current plan: show "" as stat value, sub: "Kein Plan".
* Tap/click Vielfalt card navigate to E4. */</pre>
<table class="at"><thead><tr><th>Element</th><th>Wert</th><th>Notizen</th></tr></thead><tbody>
<tr class="grp"><td colspan="3">Vielfalt-Kachel</td></tr>
<tr><td>Kennzahl</td><td>varietyScore.score, 1 Dezimalstelle</td><td>Farbe: --purple normal, --orange wenn &lt; 6.0</td></tr>
<tr><td>Label</td><td>Vielfalt-Einstellungen</td><td>Desktop; Mobile: "Vielfalt"</td></tr>
<tr><td>Sub-Label</td><td>"Diese Woche" / "Kein Plan" / ""</td><td>Kein Plan = kein weekPlan für aktuelle Woche</td></tr>
<tr><td>Rand</td><td>border-left: 3px solid --purple</td><td>Analog zu Vorräte → --green-dark</td></tr>
<tr><td>Aktion</td><td>Tap → navigate /settings/variety</td><td>Route: +page.svelte unter (app)/settings/variety/</td></tr>
<tr class="grp"><td colspan="3">Grid-Layout</td></tr>
<tr><td>Mobile</td><td>Vorräte fullwidth + grid-template-columns: 1fr 1fr unten</td><td>Gap: 12px</td></tr>
<tr><td>Desktop</td><td>Vorräte fullwidth + grid-template-columns: 1fr 1fr unten</td><td>Max-width: 640px, gap: 16px</td></tr>
</tbody></table>
</div>
</div>
</div>
<!-- ════════════════════════════════════════
S1 — DEFAULT (KEIN CUSTOM-CONFIG)
═════════════════════════════════════════ -->
<div class="section">
<div class="section-title">E4 — Vielfalt-Einstellungen · States</div>
<div class="scr">
<div class="scr-head"><h3>S1 · Standard (kein Custom-Config)</h3><span class="scr-id">E4</span></div>
<div class="scr-desc">Erster Aufruf, kein haushaltsindividueller Config-Eintrag. Omnivor-Chip ist ausgewählt (Default-Zustand). Score-Preview zeigt den aktuellen tatsächlichen Score — keine Simulation nötig, da noch nichts geändert wurde. Hinweis-Text erklärt kurz den Zweck der Seite.</div>
<div class="scr-var"><strong>S1</strong> · Omnivor selected · Score-Preview = aktueller Score · Erweiterte Einstellungen eingeklappt</div>
<div class="previews">
<div class="prev-col">
<div class="bp-lbl">Mobile · 320px</div>
<div class="phone">
<div class="pst"><b>9:41</b><span>●●●</span></div>
<div class="pb">
<div class="mtb"><div class="mtb-back">← Einstellungen</div><div class="mtb-t">Vielfalt</div></div>
<div style="padding:16px;flex:1;overflow-y:auto;">
<div style="font-size:12px;color:var(--color-text-muted);line-height:1.6;margin-bottom:14px;">Passe den Algorithmus an deinen Haushalt an. Änderungen werden sofort übernommen.</div>
<div class="sec-lbl">Haushaltskontext</div>
<div class="ctx-chips">
<div class="ctx-chip sel">
<div class="ctx-em">🥩</div>
<div class="ctx-name">Omnivor</div>
<div class="ctx-sub">Alle Regeln aktiv</div>
</div>
<div class="ctx-chip">
<div class="ctx-em">🥦</div>
<div class="ctx-name">Vegetarisch</div>
<div class="ctx-sub">Protein deaktiviert</div>
</div>
<div class="ctx-chip">
<div class="ctx-em">🌱</div>
<div class="ctx-name">Vegan</div>
<div class="ctx-sub">Protein deaktiviert</div>
</div>
</div>
<div class="sec-lbl">Aktive Regeln</div>
<div class="s-pills">
<div class="s-pill on">✓ Protein</div>
<div class="s-pill on">✓ Küche</div>
<div class="s-pill on">✓ Zutaten · Mittel</div>
<div class="s-pill on">✓ Letzte Wochen · Mittel</div>
<div class="s-pill warn">⚠ Duplikate · Hoch</div>
</div>
<div class="acc">
<div class="acc-hd">
<div class="acc-hd-t">Erweiterte Einstellungen</div>
<div class="acc-hd-r"></div>
</div>
</div>
<div class="score-banner">
<div class="score-banner-l">
<div class="score-banner-label">Aktueller Score</div>
<div class="score-banner-val">7.4</div>
<div class="score-banner-sub score-banner-neutral">Keine Änderungen</div>
</div>
<div class="score-banner-r">📊</div>
</div>
<div class="reset-link" style="color:var(--color-text-muted);">Bereits Standard-Einstellungen</div>
</div>
<div class="mbt">
<div class="mt-i"><div class="mt-ic">📅</div><div class="mt-l">Plan</div></div>
<div class="mt-i"><div class="mt-ic">🛒</div><div class="mt-l">Einkauf</div></div>
<div class="mt-i"><div class="mt-ic">🍳</div><div class="mt-l">Rezepte</div></div>
<div class="mt-i a"><div class="mt-ic">⚙️</div><div class="mt-l">Einstellungen</div></div>
</div>
</div>
</div>
</div>
<div class="prev-col" style="flex:1;min-width:600px;">
<div class="bp-lbl">Desktop · 1040px</div>
<div class="desk">
<div class="dsb">
<div class="dsb-logo"><div class="dsb-lm"><div class="dsb-ic">🥦</div><div class="dsb-nm">Mealprep</div></div><div class="dsb-sub">Familie Raddatz</div></div>
<div class="dsb-nav">
<div class="dsb-nl">Planung</div>
<div class="dsb-ni"><span class="dsb-nc">📅</span> Wochenplan</div>
<div class="dsb-ni"><span class="dsb-nc">🛒</span> Einkaufsliste</div>
<div class="dsb-ni"><span class="dsb-nc">🍳</span> Rezepte</div>
<div class="dsb-nl" style="margin-top:12px;">Haushalt</div>
<div class="dsb-ni a"><span class="dsb-nc">⚙️</span> Einstellungen</div>
</div>
</div>
<div class="dm">
<div class="dtb"><div><div class="dtb-bc">Einstellungen <span></span> Vielfalt-Einstellungen</div><div class="dtb-t">Vielfalt-Einstellungen</div></div></div>
<div class="dmc">
<div style="display:grid;grid-template-columns:1fr 280px;gap:24px;max-width:800px;">
<div>
<div style="font-size:12px;color:var(--color-text-muted);line-height:1.6;margin-bottom:16px;">Passe den Algorithmus an deinen Haushaltskontext an. Änderungen werden sofort übernommen und wirken sich auf den nächsten Score-Abruf aus.</div>
<div class="sec-lbl">Haushaltskontext</div>
<div class="ctx-chips" style="margin-bottom:20px;">
<div class="ctx-chip sel"><div class="ctx-em">🥩</div><div class="ctx-name">Omnivor</div><div class="ctx-sub">Alle Regeln aktiv</div></div>
<div class="ctx-chip"><div class="ctx-em">🥦</div><div class="ctx-name">Vegetarisch</div><div class="ctx-sub">Protein deaktiviert</div></div>
<div class="ctx-chip"><div class="ctx-em">🌱</div><div class="ctx-name">Vegan</div><div class="ctx-sub">Protein deaktiviert</div></div>
</div>
<div class="acc">
<div class="acc-hd"><div class="acc-hd-t">Erweiterte Einstellungen</div><div class="acc-hd-r"></div></div>
</div>
<div class="reset-link" style="text-align:left;color:var(--color-text-muted);">Bereits Standard-Einstellungen</div>
</div>
<div>
<div class="score-banner">
<div>
<div class="score-banner-label">Aktueller Score</div>
<div class="score-banner-val">7.4 <span style="font-size:13px;opacity:.5;">/ 10</span></div>
<div class="score-banner-sub score-banner-neutral">Keine Änderungen aktiv</div>
</div>
<div class="score-banner-r">📊</div>
</div>
<div class="sec-lbl">Aktive Regeln</div>
<div class="sum-rows">
<div class="sum-row on"><span class="sum-row-name">Protein</span><span class="sum-row-val">Mittel</span></div>
<div class="sum-row on"><span class="sum-row-name">Küche</span><span class="sum-row-val">Mittel</span></div>
<div class="sum-row on"><span class="sum-row-name">Zutaten</span><span class="sum-row-val">Niedrig</span></div>
<div class="sum-row on"><span class="sum-row-name">Letzte Wochen</span><span class="sum-row-val">Mittel</span></div>
<div class="sum-row warn"><span class="sum-row-name">Duplikate</span><span class="sum-row-val">Hoch</span></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="agent">
<h4>E4 · S1 Default</h4>
<pre>/* Load: GET /v1/households/mine/variety-config → 404 if no custom config.
* On 404: use defaults (Omnivor preset), show Omnivor chip as selected.
* Score banner: show actual GET /v1/week-plans/{id}/variety-score (no simulation).
* "Bereits Standard-Einstellungen" replaces reset link if no custom config exists.
* Accordion: closed. */</pre>
<table class="at"><thead><tr><th>Element</th><th>Wert</th><th>Notizen</th></tr></thead><tbody>
<tr class="grp"><td colspan="3">Laden</td></tr>
<tr><td>Config-Load</td><td>GET /v1/households/mine/variety-config</td><td>404 → Defaults verwenden, Omnivor selected</td></tr>
<tr><td>Score-Load</td><td>GET /v1/week-plans/{id}/variety-score</td><td>Nur wenn weekPlan existiert; sonst Score-Banner ausblenden</td></tr>
<tr class="grp"><td colspan="3">Kontext-Chips</td></tr>
<tr><td>Omnivor</td><td>repeatTagTypes: ["protein","cuisine"], alle Gewichte Standard</td><td>Default-Preset = backend defaults</td></tr>
<tr><td>Vegetarisch</td><td>repeatTagTypes: ["cuisine"], wTagRepeat Standard</td><td>Protein deaktiviert</td></tr>
<tr><td>Vegan</td><td>repeatTagTypes: ["cuisine"], wTagRepeat Standard</td><td>Identisch zu Vegetarisch in v1</td></tr>
<tr><td>Individuell</td><td>Erscheint automatisch wenn Advanced abweicht vom Preset</td><td>Kein manuell wählbarer Chip — nur automatisch</td></tr>
<tr class="grp"><td colspan="3">Score-Banner (S1)</td></tr>
<tr><td>Wert</td><td>Aktueller Score (keine Simulation)</td><td>Label: "Aktueller Score"</td></tr>
<tr><td>Sub-Label</td><td>"Keine Änderungen"</td><td>Neutral-Farbe (#6B6A63)</td></tr>
</tbody></table>
</div>
</div>
<!-- S2: Vegetarisch selected -->
<div class="scr">
<div class="scr-head"><h3>S2 · Vegetarisch ausgewählt — Score-Simulation</h3><span class="scr-id">E4</span></div>
<div class="scr-desc">Planer tippt auf "Vegetarisch". Config wird sofort per PATCH gespeichert. Score-Banner lädt die simulierte Punktzahl: wie würde der aktuelle Plan mit der neuen Config abschneiden. Delta wird grün hervorgehoben. Protein-Pill wechselt zu "off". Erweiterte Einstellungen zeigt Protein-Toggle als deaktiviert.</div>
<div class="scr-var"><strong>S2</strong> · Vegetarisch selected · Score-Preview = simuliert · Protein-Pill = off</div>
<div class="previews">
<div class="prev-col">
<div class="bp-lbl">Mobile · 320px</div>
<div class="phone">
<div class="pst"><b>9:41</b><span>●●●</span></div>
<div class="pb">
<div class="mtb"><div class="mtb-back">← Einstellungen</div><div class="mtb-t">Vielfalt</div></div>
<div style="padding:16px;flex:1;overflow-y:auto;">
<div style="font-size:12px;color:var(--color-text-muted);line-height:1.6;margin-bottom:14px;">Passe den Algorithmus an deinen Haushalt an. Änderungen werden sofort übernommen.</div>
<div class="sec-lbl">Haushaltskontext</div>
<div class="ctx-chips">
<div class="ctx-chip"><div class="ctx-em">🥩</div><div class="ctx-name">Omnivor</div><div class="ctx-sub">Alle Regeln aktiv</div></div>
<div class="ctx-chip sel"><div class="ctx-em">🥦</div><div class="ctx-name">Vegetarisch</div><div class="ctx-sub">Protein deaktiviert</div></div>
<div class="ctx-chip"><div class="ctx-em">🌱</div><div class="ctx-name">Vegan</div><div class="ctx-sub">Protein deaktiviert</div></div>
</div>
<div class="sec-lbl">Aktive Regeln</div>
<div class="s-pills">
<div class="s-pill off"> Protein</div>
<div class="s-pill on">✓ Küche</div>
<div class="s-pill on">✓ Zutaten · Mittel</div>
<div class="s-pill on">✓ Letzte Wochen · Mittel</div>
<div class="s-pill warn">⚠ Duplikate · Hoch</div>
</div>
<div class="acc">
<div class="acc-hd"><div class="acc-hd-t">Erweiterte Einstellungen</div><div class="acc-hd-r"></div></div>
</div>
<div class="score-banner">
<div class="score-banner-l">
<div class="score-banner-label">Mit diesen Einstellungen</div>
<div class="score-banner-val">8.9</div>
<div class="score-banner-sub score-banner-up">↑ +1.5 gegenüber vorher</div>
</div>
<div class="score-banner-r">📈</div>
</div>
<div class="reset-link">Auf Standard zurücksetzen</div>
</div>
<div class="mbt">
<div class="mt-i"><div class="mt-ic">📅</div><div class="mt-l">Plan</div></div>
<div class="mt-i"><div class="mt-ic">🛒</div><div class="mt-l">Einkauf</div></div>
<div class="mt-i"><div class="mt-ic">🍳</div><div class="mt-l">Rezepte</div></div>
<div class="mt-i a"><div class="mt-ic">⚙️</div><div class="mt-l">Einstellungen</div></div>
</div>
</div>
</div>
</div>
<div class="prev-col" style="flex:1;min-width:600px;">
<div class="bp-lbl">Desktop · 1040px</div>
<div class="desk">
<div class="dsb">
<div class="dsb-logo"><div class="dsb-lm"><div class="dsb-ic">🥦</div><div class="dsb-nm">Mealprep</div></div><div class="dsb-sub">Familie Raddatz</div></div>
<div class="dsb-nav">
<div class="dsb-nl">Planung</div>
<div class="dsb-ni"><span class="dsb-nc">📅</span> Wochenplan</div>
<div class="dsb-ni"><span class="dsb-nc">🛒</span> Einkaufsliste</div>
<div class="dsb-ni"><span class="dsb-nc">🍳</span> Rezepte</div>
<div class="dsb-nl" style="margin-top:12px;">Haushalt</div>
<div class="dsb-ni a"><span class="dsb-nc">⚙️</span> Einstellungen</div>
</div>
</div>
<div class="dm">
<div class="dtb"><div><div class="dtb-bc">Einstellungen <span></span> Vielfalt-Einstellungen</div><div class="dtb-t">Vielfalt-Einstellungen</div></div></div>
<div class="dmc">
<div style="display:grid;grid-template-columns:1fr 280px;gap:24px;max-width:800px;">
<div>
<div style="font-size:12px;color:var(--color-text-muted);line-height:1.6;margin-bottom:16px;">Passe den Algorithmus an deinen Haushaltskontext an. Änderungen werden sofort übernommen und wirken sich auf den nächsten Score-Abruf aus.</div>
<div class="sec-lbl">Haushaltskontext</div>
<div class="ctx-chips" style="margin-bottom:20px;">
<div class="ctx-chip"><div class="ctx-em">🥩</div><div class="ctx-name">Omnivor</div><div class="ctx-sub">Alle Regeln aktiv</div></div>
<div class="ctx-chip sel"><div class="ctx-em">🥦</div><div class="ctx-name">Vegetarisch</div><div class="ctx-sub">Protein deaktiviert</div></div>
<div class="ctx-chip"><div class="ctx-em">🌱</div><div class="ctx-name">Vegan</div><div class="ctx-sub">Protein deaktiviert</div></div>
</div>
<div class="acc">
<div class="acc-hd"><div class="acc-hd-t">Erweiterte Einstellungen</div><div class="acc-hd-r"></div></div>
</div>
<div class="reset-link" style="text-align:left;">Auf Standard zurücksetzen</div>
</div>
<div>
<div class="score-banner">
<div>
<div class="score-banner-label">Mit diesen Einstellungen</div>
<div class="score-banner-val">8.9 <span style="font-size:13px;opacity:.5;">/ 10</span></div>
<div class="score-banner-sub score-banner-up">↑ +1.5 gegenüber vorher</div>
</div>
<div class="score-banner-r">📈</div>
</div>
<div class="sec-lbl">Aktive Regeln</div>
<div class="sum-rows">
<div class="sum-row off"><span class="sum-row-name">Protein</span><span class="sum-row-val">Deaktiviert</span></div>
<div class="sum-row on"><span class="sum-row-name">Küche</span><span class="sum-row-val">Mittel</span></div>
<div class="sum-row on"><span class="sum-row-name">Zutaten</span><span class="sum-row-val">Niedrig</span></div>
<div class="sum-row on"><span class="sum-row-name">Letzte Wochen</span><span class="sum-row-val">Mittel</span></div>
<div class="sum-row warn"><span class="sum-row-name">Duplikate</span><span class="sum-row-val">Hoch</span></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="agent">
<h4>E4 · S2 Vegetarisch</h4>
<pre>/* On chip tap (Vegetarisch):
* 1. Optimistic UI: swap selected chip, update pills, update sum-rows immediately.
* 2. PATCH /v1/households/mine/variety-config { repeatTagTypes: ["cuisine"],
* wTagRepeat: 1.5, wIngredientOverlap: 0.3, wRecentRepeat: 1.0, wPlanDuplicate: 2.0 }
* 3. On PATCH success: fire GET /v1/week-plans/{id}/variety-score?simulate=true
* with same config body → update score-banner with simulated score + delta.
* 4. On PATCH error: rollback to previous chip selection + show toast "Fehler beim Speichern".
* Score-Banner during load: show spinner in place of val. */</pre>
<table class="at"><thead><tr><th>Element</th><th>Wert</th><th>Notizen</th></tr></thead><tbody>
<tr class="grp"><td colspan="3">Score-Banner (S2)</td></tr>
<tr><td>Label</td><td>"Mit diesen Einstellungen"</td><td>Statt "Aktueller Score"</td></tr>
<tr><td>Delta</td><td>"↑ +X.X gegenüber vorher"</td><td>Grün (#6FCF97) wenn positiv; rot wenn negativ; neutral wenn = 0</td></tr>
<tr><td>Simulation-Endpoint</td><td>POST /v1/week-plans/{id}/variety-score/simulate</td><td>Body: VarietyScoreConfig-Felder. Neuer Endpoint nötig (Backend-Task).</td></tr>
<tr><td>Kein Plan</td><td>Score-Banner ausblenden</td><td>Kein simulierter Score ohne Plan möglich</td></tr>
<tr class="grp"><td colspan="3">Chip-Preset Vegetarisch</td></tr>
<tr><td>repeatTagTypes</td><td>["cuisine"]</td><td>Protein entfernt</td></tr>
<tr><td>wTagRepeat</td><td>1.5 (Standard)</td><td>Unverändert</td></tr>
<tr><td>wIngredientOverlap</td><td>0.3 (Standard)</td><td>Unverändert</td></tr>
<tr><td>wRecentRepeat</td><td>1.0 (Standard)</td><td>Unverändert</td></tr>
<tr><td>wPlanDuplicate</td><td>2.0 (Standard)</td><td>Unverändert</td></tr>
</tbody></table>
</div>
</div>
<!-- S3: Erweiterte Einstellungen -->
<div class="scr">
<div class="scr-head"><h3>S3 · Erweiterte Einstellungen geöffnet</h3><span class="scr-id">E4</span></div>
<div class="scr-desc">Planer öffnet das Accordion "Erweiterte Einstellungen". Er sieht Segmented Controls (Niedrig / Mittel / Hoch) für jeden Gewichts-Parameter. Ändert er einen Wert, der nicht mehr dem aktuellen Preset entspricht, erscheint automatisch ein vierter Chip "Individuell" (lila) und ersetzt den aktiven Preset-Chip. Score-Banner aktualisiert sich nach jeder Änderung.</div>
<div class="scr-var"><strong>S3</strong> · Erweiterte Einstellungen offen · "Individuell"-Chip erschienen (Planer hat Zutaten-Gewicht angepasst)</div>
<div class="previews">
<div class="prev-col">
<div class="bp-lbl">Mobile · 320px</div>
<div class="phone">
<div class="pst"><b>9:41</b><span>●●●</span></div>
<div class="pb">
<div class="mtb"><div class="mtb-back">← Einstellungen</div><div class="mtb-t">Vielfalt</div></div>
<div style="padding:16px;flex:1;overflow-y:auto;">
<div class="sec-lbl">Haushaltskontext</div>
<div class="ctx-chips" style="flex-wrap:wrap;">
<div class="ctx-chip" style="flex:1;min-width:60px;"><div class="ctx-em">🥩</div><div class="ctx-name">Omnivor</div></div>
<div class="ctx-chip" style="flex:1;min-width:60px;"><div class="ctx-em">🥦</div><div class="ctx-name">Vegetarisch</div></div>
<div class="ctx-chip" style="flex:1;min-width:60px;"><div class="ctx-em">🌱</div><div class="ctx-name">Vegan</div></div>
<div class="ctx-chip ind" style="flex:1;min-width:60px;"><div class="ctx-em"></div><div class="ctx-name">Individuell</div></div>
</div>
<div class="s-pills" style="margin-top:10px;">
<div class="s-pill off"> Protein</div>
<div class="s-pill on">✓ Küche</div>
<div class="s-pill on">✓ Zutaten · Hoch</div>
<div class="s-pill on">✓ Letzte Wochen · Mittel</div>
<div class="s-pill warn">⚠ Duplikate · Hoch</div>
</div>
<div class="acc">
<div class="acc-hd"><div class="acc-hd-t">Erweiterte Einstellungen</div><div class="acc-hd-r"></div></div>
<div class="acc-b">
<div style="font-size:10px;color:var(--color-text-muted);margin-bottom:10px;">Protein ist über den Kontext deaktiviert. Die übrigen Gewichte kannst du hier anpassen.</div>
<div class="wr">
<div class="wr-l"><div class="wr-name">Küche</div><div class="wr-sub">Tag-Wiederholung</div></div>
<div class="seg" style="width:108px"><div class="seg-o">Niedrig</div><div class="seg-o a">Mittel</div><div class="seg-o">Hoch</div></div>
</div>
<div class="wr">
<div class="wr-l"><div class="wr-name">Zutaten</div><div class="wr-sub">Überschneidung</div></div>
<div class="seg" style="width:108px"><div class="seg-o">Niedrig</div><div class="seg-o">Mittel</div><div class="seg-o a-r">Hoch</div></div>
</div>
<div class="wr">
<div class="wr-l"><div class="wr-name">Letzte Wochen</div><div class="wr-sub">Kochverlauf</div></div>
<div class="seg" style="width:108px"><div class="seg-o">Niedrig</div><div class="seg-o a">Mittel</div><div class="seg-o">Hoch</div></div>
</div>
<div class="wr">
<div class="wr-l"><div class="wr-name">Duplikate</div><div class="wr-sub">Im Plan</div></div>
<div class="seg" style="width:108px"><div class="seg-o">Niedrig</div><div class="seg-o">Mittel</div><div class="seg-o a-r">Hoch</div></div>
</div>
</div>
</div>
<div class="score-banner">
<div class="score-banner-l">
<div class="score-banner-label">Mit diesen Einstellungen</div>
<div class="score-banner-val">8.1</div>
<div class="score-banner-sub score-banner-up">↑ +0.7 gegenüber vorher</div>
</div>
<div class="score-banner-r">📈</div>
</div>
<div class="reset-link">Auf Standard zurücksetzen</div>
</div>
<div class="mbt">
<div class="mt-i"><div class="mt-ic">📅</div><div class="mt-l">Plan</div></div>
<div class="mt-i"><div class="mt-ic">🛒</div><div class="mt-l">Einkauf</div></div>
<div class="mt-i"><div class="mt-ic">🍳</div><div class="mt-l">Rezepte</div></div>
<div class="mt-i a"><div class="mt-ic">⚙️</div><div class="mt-l">Einstellungen</div></div>
</div>
</div>
</div>
</div>
<div class="prev-col" style="flex:1;min-width:600px;">
<div class="bp-lbl">Desktop · 1040px</div>
<div class="desk">
<div class="dsb">
<div class="dsb-logo"><div class="dsb-lm"><div class="dsb-ic">🥦</div><div class="dsb-nm">Mealprep</div></div><div class="dsb-sub">Familie Raddatz</div></div>
<div class="dsb-nav">
<div class="dsb-nl">Planung</div>
<div class="dsb-ni"><span class="dsb-nc">📅</span> Wochenplan</div>
<div class="dsb-ni"><span class="dsb-nc">🛒</span> Einkaufsliste</div>
<div class="dsb-ni"><span class="dsb-nc">🍳</span> Rezepte</div>
<div class="dsb-nl" style="margin-top:12px;">Haushalt</div>
<div class="dsb-ni a"><span class="dsb-nc">⚙️</span> Einstellungen</div>
</div>
</div>
<div class="dm">
<div class="dtb"><div><div class="dtb-bc">Einstellungen <span></span> Vielfalt-Einstellungen</div><div class="dtb-t">Vielfalt-Einstellungen</div></div></div>
<div class="dmc">
<div style="display:grid;grid-template-columns:1fr 280px;gap:24px;max-width:800px;">
<div>
<div class="sec-lbl">Haushaltskontext</div>
<div class="ctx-chips" style="margin-bottom:20px;">
<div class="ctx-chip"><div class="ctx-em">🥩</div><div class="ctx-name">Omnivor</div><div class="ctx-sub">Alle Regeln</div></div>
<div class="ctx-chip"><div class="ctx-em">🥦</div><div class="ctx-name">Vegetarisch</div><div class="ctx-sub">Protein aus</div></div>
<div class="ctx-chip"><div class="ctx-em">🌱</div><div class="ctx-name">Vegan</div><div class="ctx-sub">Protein aus</div></div>
<div class="ctx-chip ind"><div class="ctx-em"></div><div class="ctx-name">Individuell</div><div class="ctx-sub">Benutzerdefiniert</div></div>
</div>
<div class="acc">
<div class="acc-hd"><div class="acc-hd-t">Erweiterte Einstellungen</div><div class="acc-hd-r"></div></div>
<div class="acc-b">
<div style="font-size:11px;color:var(--color-text-muted);margin-bottom:12px;">Protein ist über den Haushaltskontext deaktiviert. Passe die Stärke der übrigen Regeln an.</div>
<div class="wr">
<div class="wr-l"><div class="wr-name">Küchen-Wiederholung</div><div class="wr-sub">Gleiche Küche an aufeinanderfolgenden Tagen</div></div>
<div class="seg" style="width:160px"><div class="seg-o">Niedrig</div><div class="seg-o a">Mittel</div><div class="seg-o">Hoch</div></div>
</div>
<div class="wr">
<div class="wr-l"><div class="wr-name">Zutaten-Überschneidung</div><div class="wr-sub">Gleiche Zutaten an aufeinanderfolgenden Tagen</div></div>
<div class="seg" style="width:160px"><div class="seg-o">Niedrig</div><div class="seg-o">Mittel</div><div class="seg-o a-r">Hoch</div></div>
</div>
<div class="wr">
<div class="wr-l"><div class="wr-name">Letzte Wochen</div><div class="wr-sub">Kochverlauf (14 Tage)</div></div>
<div class="seg" style="width:160px"><div class="seg-o">Niedrig</div><div class="seg-o a">Mittel</div><div class="seg-o">Hoch</div></div>
</div>
<div class="wr">
<div class="wr-l"><div class="wr-name">Doppelte Rezepte</div><div class="wr-sub">Gleiches Rezept mehrfach im Plan</div></div>
<div class="seg" style="width:160px"><div class="seg-o">Niedrig</div><div class="seg-o">Mittel</div><div class="seg-o a-r">Hoch</div></div>
</div>
</div>
</div>
<div class="reset-link" style="text-align:left;">Auf Standard zurücksetzen</div>
</div>
<div>
<div class="score-banner">
<div>
<div class="score-banner-label">Mit diesen Einstellungen</div>
<div class="score-banner-val">8.1 <span style="font-size:13px;opacity:.5;">/ 10</span></div>
<div class="score-banner-sub score-banner-up">↑ +0.7 gegenüber vorher</div>
</div>
<div class="score-banner-r">📈</div>
</div>
<div class="sec-lbl">Aktive Regeln</div>
<div class="sum-rows">
<div class="sum-row off"><span class="sum-row-name">Protein</span><span class="sum-row-val">Deaktiviert</span></div>
<div class="sum-row on"><span class="sum-row-name">Küche</span><span class="sum-row-val">Mittel</span></div>
<div class="sum-row warn"><span class="sum-row-name">Zutaten</span><span class="sum-row-val">Hoch ↑</span></div>
<div class="sum-row on"><span class="sum-row-name">Letzte Wochen</span><span class="sum-row-val">Mittel</span></div>
<div class="sum-row warn"><span class="sum-row-name">Duplikate</span><span class="sum-row-val">Hoch</span></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="agent">
<h4>E4 · S3 Erweiterte Einstellungen</h4>
<pre>/* Accordion öffnet sich per Click/Tap auf acc-hd. Keine Animation nötig — display toggle reicht.
* Erweiterte Einstellungen zeigt NUR aktive Tag-Typen als Gewichts-Rows.
* Wenn Protein deaktiviert (über Preset): Protein-Row wird in acc-b NICHT angezeigt.
* "Individuell"-Chip: erscheint automatisch wenn die Kombination repeatTagTypes+weights
* nicht exakt einem der drei Presets entspricht. Kein manueller Auslöser.
* Gewichts-Änderung → PATCH → Score-Simulation → Banner-Update.
* Debounce der Simulation: 300ms nach letzter Interaktion. */</pre>
<table class="at"><thead><tr><th>Element</th><th>Wert</th><th>Notizen</th></tr></thead><tbody>
<tr class="grp"><td colspan="3">Gewicht-Mapping</td></tr>
<tr><td>Niedrig</td><td>Faktor 0.5 × Standard-Gewicht</td><td>wTagRepeat: 0.75, wIngredient: 0.15, wRecent: 0.5, wDuplicate: 1.0</td></tr>
<tr><td>Mittel</td><td>Faktor 1.0 (Standard)</td><td>wTagRepeat: 1.5, wIngredient: 0.3, wRecent: 1.0, wDuplicate: 2.0</td></tr>
<tr><td>Hoch</td><td>Faktor 1.5 × Standard-Gewicht</td><td>wTagRepeat: 2.25, wIngredient: 0.45, wRecent: 1.5, wDuplicate: 3.0</td></tr>
<tr class="grp"><td colspan="3">Individuell-Chip</td></tr>
<tr><td>Trigger</td><td>Wenn gespeicherter Config ≠ Omnivor, Vegetarisch, oder Vegan Preset</td><td>Lila Border + Hintergrund</td></tr>
<tr><td>Symbol</td><td>✦ (U+2726)</td><td>Statt Emoji</td></tr>
<tr><td>Label</td><td>Individuell</td><td>Nicht anklickbar — nur Status-Indikator</td></tr>
<tr class="grp"><td colspan="3">Simulation-Debounce</td></tr>
<tr><td>Delay</td><td>300ms</td><td>Nach letzter Segmented-Control-Interaktion</td></tr>
<tr><td>Während Laden</td><td>Score-Wert zeigt Spinner (CSS animation)</td><td>Kein Skeleton — nur val-Bereich</td></tr>
</tbody></table>
</div>
</div>
<!-- S4: Reset confirmation -->
<div class="scr">
<div class="scr-head"><h3>S4 · Reset-Bestätigung</h3><span class="scr-id">E4</span></div>
<div class="scr-desc">Planer tippt "Auf Standard zurücksetzen". Ein Dialog erscheint und benennt explizit, was zurückgesetzt wird. Bestätigung löscht den Custom-Config-Eintrag (DELETE) und stellt die Omnivor-Defaults wieder her. Kein Backdrop-Dismiss — der Planer muss explizit wählen.</div>
<div class="scr-var"><strong>S4</strong> · Modal über S2-Zustand · Backdrop nicht anklickbar · Mobile: Bottom Sheet</div>
<div class="previews">
<div class="prev-col">
<div class="bp-lbl">Mobile · 320px (Bottom Sheet)</div>
<div class="phone">
<div class="pst"><b>9:41</b><span>●●●</span></div>
<div class="pb">
<!-- Blurred background state -->
<div class="mtb"><div class="mtb-back">← Einstellungen</div><div class="mtb-t">Vielfalt</div></div>
<div style="padding:16px;flex:1;overflow-y:auto;opacity:.35;pointer-events:none;">
<div class="ctx-chips">
<div class="ctx-chip sel"><div class="ctx-em">🥦</div><div class="ctx-name">Vegetarisch</div></div>
</div>
</div>
<!-- Bottom sheet -->
<div style="background:var(--color-page);border-radius:20px 20px 0 0;padding:20px;border-top:1px solid var(--color-border);box-shadow:0 -4px 24px rgba(0,0,0,.12);">
<div style="width:36px;height:4px;background:var(--color-border);border-radius:2px;margin:0 auto 16px;"></div>
<div style="font-family:var(--font-display);font-size:18px;font-weight:500;margin-bottom:8px;">Auf Standard zurücksetzen?</div>
<div style="font-size:12px;color:var(--color-text-muted);line-height:1.6;margin-bottom:16px;">Alle individuellen Einstellungen werden gelöscht. Der Algorithmus verwendet dann wieder:<br><br>• Protein: Aktiv<br>• Küche: Aktiv<br>• Alle Gewichte: Mittel</div>
<div class="btn-dest" style="margin-bottom:8px;">Zurücksetzen</div>
<div class="btn-ghost">Abbrechen</div>
</div>
<div class="mbt">
<div class="mt-i"><div class="mt-ic">📅</div><div class="mt-l">Plan</div></div>
<div class="mt-i"><div class="mt-ic">🛒</div><div class="mt-l">Einkauf</div></div>
<div class="mt-i"><div class="mt-ic">🍳</div><div class="mt-l">Rezepte</div></div>
<div class="mt-i a"><div class="mt-ic">⚙️</div><div class="mt-l">Einstellungen</div></div>
</div>
</div>
</div>
</div>
<div class="prev-col" style="flex:1;min-width:600px;">
<div class="bp-lbl">Desktop · 1040px (Centered Modal)</div>
<div class="desk overlay">
<div class="dsb" style="opacity:.35;">
<div class="dsb-logo"><div class="dsb-lm"><div class="dsb-ic">🥦</div><div class="dsb-nm">Mealprep</div></div></div>
</div>
<div class="dm" style="opacity:.35;">
<div class="dtb"><div class="dtb-t">Vielfalt-Einstellungen</div></div>
<div class="dmc"><div class="ctx-chips"><div class="ctx-chip sel"><div class="ctx-em">🥦</div><div class="ctx-name">Vegetarisch</div></div></div></div>
</div>
<div class="modal-backdrop">
<div class="modal">
<div class="modal-title">Auf Standard zurücksetzen?</div>
<div class="modal-body">Alle individuellen Einstellungen werden gelöscht. Der Algorithmus verwendet dann wieder die Standard-Werte:<br><br>
<strong>Protein-Prüfung:</strong> Aktiv<br>
<strong>Küchen-Vielfalt:</strong> Aktiv<br>
<strong>Alle Gewichte:</strong> Mittel</div>
<div class="modal-acts">
<div class="btn-dest">Zurücksetzen</div>
<div class="btn-ghost">Abbrechen</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="agent">
<h4>E4 · S4 Reset-Bestätigung</h4>
<pre>/* Reset-Link Tap → Dialog öffnet (kein Backdrop-Dismiss, kein Escape-Dismiss).
* "Zurücksetzen" → DELETE /v1/households/mine/variety-config
* On success: optimistic reset von UI zu S1 (Omnivor), Score-Banner zeigt echten Score.
* On error: Toast "Fehler beim Zurücksetzen".
* Mobile: Bottom Sheet (position:fixed, bottom 0, border-radius 20px 20px 0 0).
* Desktop: centered modal, backdrop rgba(28,28,24,0.4), max-width 380px. */</pre>
<table class="at"><thead><tr><th>Element</th><th>Wert</th><th>Notizen</th></tr></thead><tbody>
<tr class="grp"><td colspan="3">Dialog-Inhalt</td></tr>
<tr><td>Titel</td><td>"Auf Standard zurücksetzen?"</td><td>Fraunces 18px (Mobile), 20px (Desktop)</td></tr>
<tr><td>Body</td><td>Auflistung der zurückgesetzten Werte</td><td>Muss konkret benennen: Protein aktiv, Küche aktiv, alle Gewichte Mittel</td></tr>
<tr><td>Primär-Aktion</td><td>"Zurücksetzen" → DELETE</td><td>Hintergrund: --red, Text: weiß</td></tr>
<tr><td>Sekundär-Aktion</td><td>"Abbrechen"</td><td>Ghost-Button, schließt Dialog</td></tr>
<tr class="grp"><td colspan="3">API</td></tr>
<tr><td>Endpoint</td><td>DELETE /v1/households/mine/variety-config</td><td>Löscht Custom-Config-Row; Backend fällt auf Defaults zurück</td></tr>
<tr><td>On Success</td><td>UI reset zu S1</td><td>Omnivor chip selected, Score-Banner: echter Score</td></tr>
</tbody></table>
</div>
</div>
</div>
<!-- ════════════════════════════════════════
LLM / AGENT REGION
═════════════════════════════════════════ -->
<div class="llm">
<h2>Maschinenlesbare Spezifikation — E4 Vielfalt-Einstellungen</h2>
<h3>Screens</h3>
<table>
<thead><tr><th>Screen</th><th>Route</th><th>Zugriff</th><th>Zweck</th></tr></thead>
<tbody>
<tr><td>E1 (Update)</td><td>/settings</td><td>Planer</td><td>Settings-Hub: dritte Kachel "Vielfalt-Einstellungen" mit aktuellem Score</td></tr>
<tr><td>E4</td><td>/settings/variety</td><td>Planer only</td><td>Vielfalt-Algorithmus per Kontext-Preset und Feineinstellungen konfigurieren</td></tr>
</tbody>
</table>
<h3>States</h3>
<table>
<thead><tr><th>State</th><th>Trigger</th><th>Beschreibung</th></tr></thead>
<tbody>
<tr><td>S0</td><td>E1 load</td><td>Settings-Hub zeigt Score-Kachel (lila Kennzahl)</td></tr>
<tr><td>S1</td><td>E4 load, kein Custom-Config</td><td>Omnivor chip selected, Score = aktueller echter Score, Reset-Link = deaktiviert/neutral</td></tr>
<tr><td>S2</td><td>Preset-Chip tap</td><td>Chip wechselt, PATCH, Score-Simulation lädt und zeigt Delta</td></tr>
<tr><td>S3</td><td>Accordion öffnen + Gewicht ändern</td><td>Individuell-Chip erscheint, Score-Simulation mit Debounce 300ms</td></tr>
<tr><td>S4</td><td>Reset-Link tap</td><td>Modal/Bottom Sheet — Bestätigung vor DELETE</td></tr>
</tbody>
</table>
<h3>API-Endpoints (neu + bestehend)</h3>
<table>
<thead><tr><th>Method</th><th>Endpoint</th><th>Neu?</th><th>Zweck</th></tr></thead>
<tbody>
<tr><td>GET</td><td>/v1/households/mine/variety-config</td><td>Neu</td><td>Aktuellen Config laden; 404 = Defaults verwenden</td></tr>
<tr><td>PATCH</td><td>/v1/households/mine/variety-config</td><td>Neu</td><td>Config speichern (auto-save bei jedem Preset/Gewicht-Wechsel)</td></tr>
<tr><td>DELETE</td><td>/v1/households/mine/variety-config</td><td>Neu</td><td>Custom-Config löschen, Backend fällt auf Defaults zurück</td></tr>
<tr><td>POST</td><td>/v1/week-plans/{id}/variety-score/simulate</td><td>Neu</td><td>Score simulieren mit temporärem Config-Body (nicht persistiert)</td></tr>
<tr><td>GET</td><td>/v1/week-plans/{id}/variety-score</td><td>Bestehend</td><td>Aktuellen Score laden (für S1 Banner + E1 Kachel)</td></tr>
</tbody>
</table>
<h3>Kontext-Preset Mapping</h3>
<table>
<thead><tr><th>Preset</th><th>repeatTagTypes</th><th>wTagRepeat</th><th>wIngredientOverlap</th><th>wRecentRepeat</th><th>wPlanDuplicate</th></tr></thead>
<tbody>
<tr><td>Omnivor (Default)</td><td>["protein","cuisine"]</td><td>1.5</td><td>0.3</td><td>1.0</td><td>2.0</td></tr>
<tr><td>Vegetarisch</td><td>["cuisine"]</td><td>1.5</td><td>0.3</td><td>1.0</td><td>2.0</td></tr>
<tr><td>Vegan</td><td>["cuisine"]</td><td>1.5</td><td>0.3</td><td>1.0</td><td>2.0</td></tr>
<tr><td>Individuell</td><td>Beliebig (≠ obige Presets)</td><td>Beliebig</td><td>Beliebig</td><td>Beliebig</td><td>Beliebig</td></tr>
</tbody>
</table>
<h3>Gewicht-Preset Mapping</h3>
<table>
<thead><tr><th>Stufe</th><th>Faktor</th><th>wTagRepeat</th><th>wIngredientOverlap</th><th>wRecentRepeat</th><th>wPlanDuplicate</th></tr></thead>
<tbody>
<tr><td>Niedrig</td><td>×0.5</td><td>0.75</td><td>0.15</td><td>0.5</td><td>1.0</td></tr>
<tr><td>Mittel</td><td>×1.0</td><td>1.5</td><td>0.3</td><td>1.0</td><td>2.0</td></tr>
<tr><td>Hoch</td><td>×1.5</td><td>2.25</td><td>0.45</td><td>1.5</td><td>3.0</td></tr>
</tbody>
</table>
<h3>Implementierungsregeln (für Agenten)</h3>
<ul>
<li>E4 ist nur für <code>rolle === 'planer'</code> zugänglich. Mitglieder werden auf E1 redirected.</li>
<li>Auto-Save auf jede Preset- oder Gewicht-Änderung. Kein expliziter Speichern-Button.</li>
<li>Optimistic Update: UI wechselt sofort; Rollback mit Toast bei API-Fehler.</li>
<li>Score-Simulation: Debounce 300ms. Während Laden: Spinner im Score-Wert-Bereich (nicht Skeleton).</li>
<li>"Individuell"-Chip ist nicht anklickbar — er ist ein reiner Status-Indikator.</li>
<li>Reset-Bestätigung: Backdrop-Dismiss deaktiviert (nicht schließbar durch Klick/Tap auf Overlay).</li>
<li>Mobile Reset: Bottom Sheet mit Handle-Bar (36×4px, --color-border, border-radius 2px). Kein Backdrop-Dismiss.</li>
<li>Desktop Reset: Zentriertes Modal, max-width 380px. Backdrop rgba(28,28,24,0.4).</li>
<li>E1 Vielfalt-Kachel: Score < 6.0 Kennzahl in --orange; Score 6.0 Kennzahl in --purple.</li>
<li>E4-Route: <code>(app)/settings/variety/+page.svelte</code>. Load-Funktion: <code>+page.server.ts</code> → Promise.all([GET variety-config, GET variety-score]).</li>
</ul>
</div>
</div>
</body>
</html>