What To Cook (WTC) v4.5: Print 256mm Safe-Height fuer Apple/Android, Echtzeit-Rezeptsuche, Kaffee & Kuchen

This commit is contained in:
2026-10-14 20:48:00 +02:00
parent c01d2d7639
commit d4e8a4dc6b
3 changed files with 679 additions and 339 deletions
+3 -2
View File
@@ -24,6 +24,7 @@ Live-Instanz: [wtc.dev.waiswuaschd.de](https://wtc.dev.waiswuaschd.de)
* **Handgezeichnete Kapitel-Illustrationen:** Hochauflösende Doodles auf jeder Kapitel-Trennseite (sowohl auf dem Bildschirm als auch im Druck).
* **2-Spalten-Layout:** Links Bild und Zutaten, rechts nummerierte Zubereitungsschritte und persönliche Notizen.
* **Intelligente Portionstabelle:** Automatische 2 / 4 / 6 / 8 Portionen-Berechnung (z. B. für Waffeln, Pfannkuchen und Teige).
* **Echtzeit-Titelsuche:** Schnelle Live-Suche in der oberen Navigationsleiste, die Rezepte sofort beim Tippen filtert und leere Kapitel automatisch ausblendet.
* **Rezept-Management:** Schnelles Hinzufügen, Bearbeiten, Löschen und Foto-Upload mit automatischer Bildoptimierung und Komprimierung (WebP/JPEG).
### 🎲 Shuffle-Generator (Essensauslosung)
@@ -43,7 +44,7 @@ Live-Instanz: [wtc.dev.waiswuaschd.de](https://wtc.dev.waiswuaschd.de)
* **Abwechselnde Seitenzahlen:**
- Gerade Seiten (links im Buch): Seitenzahl links unten
- Ungerade Seiten (rechts im Buch): Seitenzahl rechts unten
* **Millimetergenaue 1-Seiten-Garantie:** Jedes Rezept und jede Kapitelseite ist so optimiert (282mm Druckhöhe), dass auch unter Apple AirPrint (iOS Safari) und Android Chrome keine ungewollten 2. Seiten entstehen.
* **Millimetergenaue 1-Seiten-Garantie (256mm Safe-Height):** Universell abgestimmte Seitenhöhe, die sowohl unter Apple AirPrint (iOS Safari, iPhone/iPad) als auch unter Android Chrome und Desktop garantiert exakt 1 A4-Seite pro Rezept erzeugt – ohne ungewollte Leerseiten und ohne abgeschnittene Fußzeilen.
---
@@ -60,7 +61,7 @@ Live-Instanz: [wtc.dev.waiswuaschd.de](https://wtc.dev.waiswuaschd.de)
### 1. Repository klonen
```bash
git clone https://gitea.sp13l.de/kobold-ai/wtc.waiswuaschd.de.git /home/maxi/Projekt/wtc.waiswuaschd.de
git clone https://gitea.sp13l.de/kobold-ai/cookbook.git /home/maxi/Projekt/wtc.waiswuaschd.de
cd /home/maxi/Projekt/wtc.waiswuaschd.de
```
+267 -249
View File
@@ -81,6 +81,91 @@
white-space: nowrap;
}
/* Recipe Search Bar */
.cb-search-box {
display: flex;
align-items: center;
position: relative;
flex: 0 1 240px;
max-width: 280px;
min-width: 130px;
background: rgba(250, 246, 240, 0.18);
border: 1.5px solid rgba(250, 246, 240, 0.45);
border-radius: 20px;
padding: 3px 10px;
transition: all 0.2s ease;
margin: 0 6px;
}
.cb-search-box:focus-within {
background: var(--creme);
border-color: var(--creme);
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.35);
}
.cb-search-icon {
font-size: 0.95rem;
margin-right: 6px;
opacity: 0.85;
user-select: none;
}
.cb-search-box:focus-within .cb-search-icon {
filter: brightness(0.2);
}
.cb-search-input {
background: transparent;
border: none;
outline: none;
color: var(--creme);
font-family: var(--font-hand);
font-size: 1rem;
width: 100%;
}
.cb-search-box:focus-within .cb-search-input {
color: var(--schwarz);
}
.cb-search-input::placeholder {
color: rgba(250, 246, 240, 0.7);
}
.cb-search-box:focus-within .cb-search-input::placeholder {
color: rgba(34, 34, 34, 0.55);
}
.cb-search-clear {
background: none;
border: none;
color: inherit;
cursor: pointer;
padding: 0 4px;
font-size: 0.85rem;
opacity: 0.75;
line-height: 1;
}
.cb-search-clear:hover {
opacity: 1;
}
.recipe-page.search-hidden,
.divider.search-hidden {
display: none !important;
}
#search-empty-state {
text-align: center;
padding: 40px 20px;
background: rgba(255, 255, 255, 0.7);
border: 2px dashed rgba(34, 34, 34, 0.25);
border-radius: 12px;
margin: 20px auto;
max-width: 500px;
}
.cb-nav-actions {
display: flex;
align-items: center;
@@ -661,228 +746,8 @@
}
}
/* iOS Safari AirPrint Anpassung: Verhindert Seitenüberlauf und Stauchung */
@supports (-webkit-touch-callout: none) {
@media print {
html, body.cookbook-body {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: auto !important;
overflow: visible !important;
background-color: var(--creme) !important;
}
.book-wrapper {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
margin: 0 !important;
padding: 0 !important;
}
.page {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: auto !important;
max-height: none !important;
box-sizing: border-box !important;
background-color: var(--creme) !important;
overflow: hidden !important;
page-break-after: always !important;
break-after: page !important;
page-break-inside: avoid !important;
break-inside: avoid !important;
}
.cover {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: 220mm !important;
min-height: auto !important;
max-height: 220mm !important;
background-size: 100% 100% !important;
background-position: 0 0 !important;
background-repeat: no-repeat !important;
padding: 16mm 10mm !important;
box-sizing: border-box !important;
overflow: hidden !important;
page-break-after: always !important;
break-after: page !important;
page-break-inside: avoid !important;
break-inside: avoid !important;
}
.cover-box {
padding: 16mm 14mm !important;
max-width: 85% !important;
}
.divider {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: 220mm !important;
min-height: auto !important;
max-height: 220mm !important;
padding: 18mm 10mm !important;
box-sizing: border-box !important;
overflow: hidden !important;
page-break-after: always !important;
break-after: page !important;
page-break-inside: avoid !important;
break-inside: avoid !important;
}
.recipe-page {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: auto !important;
max-height: 225mm !important;
padding: 6mm 10mm !important;
box-sizing: border-box !important;
overflow: hidden !important;
page-break-after: always !important;
break-after: page !important;
page-break-inside: avoid !important;
break-inside: avoid !important;
}
.recipe-grid {
grid-template-columns: 55mm 1fr !important;
gap: 8mm !important;
width: 100% !important;
min-width: 0 !important;
}
.page:last-child {
page-break-after: auto !important;
break-after: auto !important;
}
}
}
/* Einheitliche Druck-Architektur ohne gerätespezifische Stauchungs-Hacks */
/* Fallback-Klasse falls JS is-ios gesetzt hat */
@media print {
html.is-ios,
body.is-ios.cookbook-body {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: auto !important;
overflow: visible !important;
background-color: var(--creme) !important;
}
.is-ios .book-wrapper {
display: block !important;
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
margin: 0 !important;
padding: 0 !important;
gap: 0 !important;
}
.is-ios .page {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: auto !important;
max-height: none !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
background-color: var(--creme) !important;
overflow: hidden !important;
page-break-after: always !important;
break-after: page !important;
page-break-inside: avoid !important;
break-inside: avoid !important;
}
.is-ios .cover {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: 220mm !important;
min-height: auto !important;
max-height: 220mm !important;
background-size: 100% 100% !important;
background-position: 0 0 !important;
background-repeat: no-repeat !important;
padding: 16mm 10mm !important;
box-sizing: border-box !important;
overflow: hidden !important;
page-break-after: always !important;
break-after: page !important;
page-break-inside: avoid !important;
break-inside: avoid !important;
}
.is-ios .cover-box {
padding: 16mm 14mm !important;
max-width: 85% !important;
}
.is-ios .divider {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: 220mm !important;
min-height: auto !important;
max-height: 220mm !important;
padding: 18mm 10mm !important;
box-sizing: border-box !important;
overflow: hidden !important;
page-break-after: always !important;
break-after: page !important;
page-break-inside: avoid !important;
break-inside: avoid !important;
}
.is-ios .recipe-page {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: auto !important;
max-height: 225mm !important;
padding: 6mm 10mm !important;
box-sizing: border-box !important;
overflow: hidden !important;
page-break-after: always !important;
break-after: page !important;
page-break-inside: avoid !important;
break-inside: avoid !important;
}
.is-ios .recipe-grid {
grid-template-columns: 55mm 1fr !important;
gap: 8mm !important;
width: 100% !important;
min-width: 0 !important;
}
.is-ios .notes-box-empty {
display: block !important;
padding: 4px 8px !important;
margin-top: 3px !important;
background: #FFFDF0 !important;
border: 1px dashed #D4C165 !important;
}
.is-ios .notes-blank-lines {
display: flex !important;
flex-direction: column !important;
gap: 8px !important;
margin-top: 3px !important;
}
.is-ios .notes-blank-line {
border-bottom: 1.5px dotted rgba(80, 70, 50, 0.45) !important;
height: 12px !important;
width: 100% !important;
display: block !important;
}
.is-ios .print-only {
display: block !important;
}
.is-ios .page:last-child {
page-break-after: auto !important;
break-after: auto !important;
}
}
/* --- Cover Gestaltung --- */
.cover {
@@ -2665,8 +2530,13 @@ body.modal-open {
box-shadow: 2px 2px 0px rgba(0, 0, 0, 0.15);
}
/* --- Druck-Spezifische Optimierungen (Exakte A4-Höhe 297mm & Seitenzahlen millimetergenau am Fuß) --- */
/* --- Druck-Spezifische Optimierungen (Exakte A4-Höhe 256mm & abwechselnde Seitenzahlen am Fuß) --- */
@media print {
@page {
size: A4 portrait;
margin: 0;
}
/* Titelseite, Inhaltsverzeichnis und Seitenzahlen IM DRUCK SICHTBAR */
.page.cover {
display: flex !important;
@@ -2676,14 +2546,14 @@ body.modal-open {
display: flex !important;
}
/* A4 Druck: 282mm Höhe passt exakt in AirPrint & Standard-Drucker ohne 2. Seite für Seitenzahl */
/* A4 Druck: 256mm Höhe passt absolut sicher in AirPrint (267mm) & Android Chrome ohne 2. Seite oder Abschneiden */
.page, .cover, .toc-page, .divider, .recipe-page {
width: 210mm !important;
max-width: 210mm !important;
min-width: 210mm !important;
height: 282mm !important;
min-height: 282mm !important;
max-height: 282mm !important;
height: 256mm !important;
min-height: 256mm !important;
max-height: 256mm !important;
box-sizing: border-box !important;
overflow: hidden !important;
page-break-after: always !important;
@@ -2701,23 +2571,40 @@ body.modal-open {
position: relative !important;
bottom: auto !important;
border: none !important;
padding: 3mm 0 2mm 0 !important;
padding: 1.5mm 0 1mm 0 !important;
width: 100% !important;
box-sizing: border-box !important;
z-index: 100 !important;
}
.divider {
padding: 14mm 10mm !important;
padding: 10mm 10mm 2mm 10mm !important;
justify-content: center !important;
align-items: center !important;
position: relative !important;
}
.divider .chapter-number {
font-family: var(--font-hand) !important;
font-size: 2.8rem !important;
color: var(--altrosa) !important;
margin-bottom: -6px !important;
}
.divider h2 {
font-family: var(--font-hand) !important;
font-size: 3.4rem !important;
color: var(--tannengruen) !important;
margin: 0 0 15px 0 !important;
line-height: 1.15 !important;
}
.doodle-placeholder {
width: 140mm !important;
height: 140mm !important;
max-width: 140mm !important;
max-height: 140mm !important;
margin: 6mm auto 0 auto !important;
width: 120mm !important;
height: 120mm !important;
max-width: 120mm !important;
max-height: 120mm !important;
margin: 4mm auto !important;
}
.doodle-placeholder img {
@@ -2726,12 +2613,20 @@ body.modal-open {
object-fit: contain !important;
}
.divider .page-footer {
position: absolute !important;
bottom: 2mm !important;
left: 0 !important;
right: 0 !important;
padding: 0 10mm !important;
}
.page-footer.page-even {
left: auto !important;
right: auto !important;
justify-content: flex-start !important;
text-align: left !important;
padding-left: 4mm !important;
padding-left: 3mm !important;
padding-right: 0 !important;
}
@@ -2740,57 +2635,103 @@ body.modal-open {
left: auto !important;
justify-content: flex-end !important;
text-align: right !important;
padding-right: 4mm !important;
padding-right: 3mm !important;
padding-left: 0 !important;
}
.page-footer .page-number {
font-size: 0.95rem !important;
font-family: var(--font-hand), 'Caveat', cursive !important;
font-size: 1.15rem !important;
font-weight: 700 !important;
color: var(--tannengruen) !important;
line-height: 1 !important;
}
.recipe-page {
padding: 6mm 10mm !important;
padding: 4mm 8mm 2mm 8mm !important;
overflow: hidden !important;
}
.recipe-header {
margin-bottom: 2.5mm !important;
}
.recipe-title {
font-size: 1.65rem !important;
line-height: 1.15 !important;
margin: 0 0 1.5mm 0 !important;
}
.recipe-meta-row {
display: flex !important;
flex-wrap: wrap !important;
gap: 2mm 5mm !important;
font-size: 0.82rem !important;
margin-bottom: 1.5mm !important;
}
.recipe-source-line {
display: none !important;
}
.recipe-grid {
display: grid !important;
grid-template-columns: 58mm 1fr !important;
gap: 6mm !important;
width: 100% !important;
min-width: 0 !important;
flex: 1 1 auto !important;
margin-bottom: 1.5mm !important;
}
.ingredients-box {
padding: 6px 8px !important;
padding: 4px 6px !important;
}
.ingredients-list {
gap: 2px !important;
display: flex !important;
flex-direction: column !important;
gap: 1.5px !important;
}
.ingredients-list li {
font-size: 0.80rem !important;
line-height: 1.25 !important;
font-size: 0.76rem !important;
line-height: 1.2 !important;
}
.ingredients-list li.ing-subheading {
font-size: 0.84rem !important;
margin-top: 3px !important;
font-size: 0.80rem !important;
font-weight: 700 !important;
margin-top: 2px !important;
padding-bottom: 1px !important;
}
.recipe-photo-box {
height: 38mm !important;
max-height: 38mm !important;
height: 32mm !important;
max-height: 32mm !important;
margin-bottom: 2mm !important;
}
.recipe-photo-box img {
width: 100% !important;
height: 32mm !important;
max-height: 32mm !important;
object-fit: cover !important;
border-radius: 6px !important;
}
.recipe-photo-empty {
display: none !important;
}
.portion-matrix-table {
font-size: 0.72rem !important;
line-height: 1.2 !important;
font-size: 0.70rem !important;
line-height: 1.18 !important;
}
.portion-matrix-table th {
padding: 1px 2px !important;
font-size: 0.7rem !important;
font-size: 0.68rem !important;
}
.portion-matrix-table td {
@@ -2799,7 +2740,84 @@ body.modal-open {
.recipe-grid:has(.has-portion-matrix) {
grid-template-columns: 68mm 1fr !important;
gap: 8mm !important;
gap: 6mm !important;
}
.instructions-steps {
display: flex !important;
flex-direction: column !important;
gap: 2.5px !important;
}
.step-card {
padding: 2.5px 5px !important;
margin-bottom: 2px !important;
font-size: 0.80rem !important;
line-height: 1.22 !important;
display: flex !important;
gap: 6px !important;
align-items: flex-start !important;
}
.step-badge {
width: 16px !important;
height: 16px !important;
font-size: 0.72rem !important;
flex-shrink: 0 !important;
}
.step-text {
flex: 1 1 auto !important;
}
.notes-box {
margin-top: 2mm !important;
padding: 3px 6px !important;
font-size: 0.76rem !important;
line-height: 1.2 !important;
background: #FFFDF0 !important;
border: 1px dashed #D4C165 !important;
border-radius: 6px !important;
}
.notes-box-title {
font-weight: 700 !important;
font-size: 0.78rem !important;
margin-bottom: 2px !important;
}
.notes-box-empty {
display: block !important;
padding: 3px 6px !important;
margin-top: 2mm !important;
background: #FFFDF0 !important;
border: 1px dashed #D4C165 !important;
}
.notes-blank-lines {
display: flex !important;
flex-direction: column !important;
gap: 6px !important;
margin-top: 2px !important;
}
.notes-blank-line {
border-bottom: 1px dotted rgba(100, 90, 70, 0.4) !important;
height: 8px !important;
width: 100% !important;
}
.print-only {
display: block !important;
}
.no-print {
display: none !important;
}
.page:last-child {
page-break-after: auto !important;
break-after: auto !important;
}
}
+409 -88
View File
@@ -16,17 +16,47 @@
}
}
/* Im Druck: Millimetergenaue DIN A4 Seitenhöhe (297mm) auf Apple, Android & Desktop */
/* Im Druck: Millimetergenaue DIN A4 Seitenhöhe (256mm) auf Apple, Android & Desktop */
@media print {
@page {
size: A4 portrait;
margin: 0;
}
* {
-webkit-print-color-adjust: exact !important;
print-color-adjust: exact !important;
color-adjust: exact !important;
box-sizing: border-box !important;
}
html, body.cookbook-body {
width: 100% !important;
max-width: 100% !important;
min-width: 0 !important;
height: auto !important;
min-height: auto !important;
margin: 0 !important;
padding: 0 !important;
overflow: visible !important;
background-color: var(--creme) !important;
}
.cb-nav,
.cb-filter-bar,
.no-print,
.desktop-nav-actions,
.mobile-nav-wrapper,
#search-empty-state,
.modal-backdrop,
.cb-toast {
display: none !important;
visibility: hidden !important;
height: 0 !important;
margin: 0 !important;
padding: 0 !important;
}
.book-wrapper {
display: block !important;
width: 100% !important;
@@ -36,76 +66,127 @@
padding: 0 !important;
gap: 0 !important;
}
/* Universelle 1-Seiten-Garantie: 256mm Höhe passt absolut sicher in iOS AirPrint (267mm) & Android Chrome ohne 2. Seite oder Abschneiden */
.page {
width: 100% !important;
max-width: 100% !important;
max-width: 210mm !important;
min-width: 0 !important;
height: 282mm !important;
min-height: 282mm !important;
max-height: 282mm !important;
margin: 0 !important;
padding: 0 !important;
height: 256mm !important;
min-height: 256mm !important;
max-height: 256mm !important;
margin: 0 auto !important;
padding: 4mm 8mm 2mm 8mm !important;
box-sizing: border-box !important;
background-color: var(--creme) !important;
overflow: hidden !important;
page-break-after: always !important;
break-after: page !important;
page-break-inside: avoid !important;
break-inside: avoid !important;
display: flex !important;
flex-direction: column !important;
justify-content: space-between !important;
position: relative !important;
overflow: hidden !important;
}
.page.cover {
display: flex !important;
flex-direction: column !important;
justify-content: center !important;
align-items: center !important;
width: 100% !important;
max-width: 100% !important;
max-width: 210mm !important;
min-width: 0 !important;
height: 282mm !important;
min-height: 282mm !important;
max-height: 282mm !important;
padding: 16mm 10mm !important;
height: 256mm !important;
min-height: 256mm !important;
max-height: 256mm !important;
padding: 10mm 10mm !important;
box-sizing: border-box !important;
overflow: hidden !important;
page-break-after: always !important;
break-after: page !important;
page-break-inside: avoid !important;
break-inside: avoid !important;
overflow: hidden !important;
}
.cover-box {
padding: 16mm 14mm !important;
max-width: 85% !important;
padding: 18mm 14mm !important;
max-width: 82% !important;
border: 3.5px solid var(--schwarz) !important;
background-color: var(--creme) !important;
transform: rotate(-1deg) !important;
box-sizing: border-box !important;
margin: auto !important;
}
.cover-box h1 {
font-family: var(--font-hand) !important;
font-size: 3.2rem !important;
line-height: 1.15 !important;
margin: 0 !important;
}
.cover-box p {
font-family: var(--font-hand) !important;
font-size: 1.5rem !important;
color: var(--tannengruen) !important;
margin-top: 10px !important;
margin-bottom: 0 !important;
}
.page.toc-page {
display: flex !important;
flex-direction: column !important;
justify-content: space-between !important;
width: 100% !important;
max-width: 100% !important;
max-width: 210mm !important;
min-width: 0 !important;
height: 282mm !important;
min-height: 282mm !important;
max-height: 282mm !important;
padding: 12mm 10mm !important;
height: 256mm !important;
min-height: 256mm !important;
max-height: 256mm !important;
padding: 8mm 10mm 2mm 10mm !important;
box-sizing: border-box !important;
overflow: hidden !important;
page-break-after: always !important;
break-after: page !important;
page-break-inside: avoid !important;
break-inside: avoid !important;
overflow: hidden !important;
}
.toc-header {
margin-bottom: 4mm !important;
}
.toc-columns {
column-count: 2 !important;
column-gap: 8mm !important;
flex: 1 1 auto !important;
overflow: hidden !important;
margin-bottom: 2mm !important;
}
.toc-chapter-group {
break-inside: avoid !important;
margin-bottom: 3mm !important;
}
.toc-recipe-item {
margin-bottom: 2px !important;
font-size: 0.82rem !important;
line-height: 1.2 !important;
}
.divider {
width: 100% !important;
max-width: 100% !important;
max-width: 210mm !important;
min-width: 0 !important;
height: 282mm !important;
min-height: 282mm !important;
max-height: 282mm !important;
padding: 14mm 10mm !important;
height: 256mm !important;
min-height: 256mm !important;
max-height: 256mm !important;
padding: 10mm 10mm 2mm 10mm !important;
box-sizing: border-box !important;
position: relative !important;
overflow: hidden !important;
page-break-after: always !important;
break-after: page !important;
page-break-inside: avoid !important;
@@ -114,37 +195,63 @@
flex-direction: column !important;
justify-content: center !important;
align-items: center !important;
overflow: hidden !important;
}
.divider .chapter-number {
font-family: var(--font-hand) !important;
font-size: 2.8rem !important;
color: var(--altrosa) !important;
margin-bottom: -6px !important;
}
.divider h2 {
font-family: var(--font-hand) !important;
font-size: 3.4rem !important;
color: var(--tannengruen) !important;
margin: 0 0 15px 0 !important;
line-height: 1.15 !important;
}
.doodle-placeholder {
width: 140mm !important;
height: 140mm !important;
max-width: 140mm !important;
max-height: 140mm !important;
margin: 6mm auto 0 auto !important;
width: 120mm !important;
height: 120mm !important;
max-width: 120mm !important;
max-height: 120mm !important;
margin: 4mm auto !important;
border: none !important;
background: transparent !important;
display: flex !important;
justify-content: center !important;
align-items: center !important;
}
.doodle-placeholder img {
width: 100% !important;
height: 100% !important;
max-width: 100% !important;
max-height: 100% !important;
max-width: 120mm !important;
max-height: 120mm !important;
object-fit: contain !important;
}
.divider .page-footer {
position: absolute !important;
bottom: 2mm !important;
left: 0 !important;
right: 0 !important;
padding: 0 10mm !important;
}
.recipe-page {
width: 100% !important;
max-width: 100% !important;
max-width: 210mm !important;
min-width: 0 !important;
height: 282mm !important;
min-height: 282mm !important;
max-height: 282mm !important;
padding: 6mm 10mm !important;
height: 256mm !important;
min-height: 256mm !important;
max-height: 256mm !important;
padding: 4mm 8mm 2mm 8mm !important;
box-sizing: border-box !important;
position: relative !important;
overflow: hidden !important;
page-break-after: always !important;
break-after: page !important;
page-break-inside: avoid !important;
@@ -152,98 +259,222 @@
display: flex !important;
flex-direction: column !important;
justify-content: flex-start !important;
overflow: hidden !important;
}
.recipe-header {
margin-bottom: 2.5mm !important;
}
.recipe-title {
font-size: 1.65rem !important;
line-height: 1.15 !important;
margin: 0 0 1.5mm 0 !important;
}
.recipe-meta-row {
display: flex !important;
flex-wrap: wrap !important;
gap: 2mm 5mm !important;
font-size: 0.82rem !important;
margin-bottom: 1.5mm !important;
}
.recipe-header-top {
display: none !important;
}
.recipe-source-line {
display: none !important;
}
.notes-box-empty {
display: block !important;
padding: 4px 8px !important;
margin-top: 3px !important;
background: #FFFDF0 !important;
border: 1px dashed #D4C165 !important;
}
.notes-blank-lines {
display: flex !important;
flex-direction: column !important;
gap: 8px !important;
margin-top: 3px !important;
}
.notes-blank-line {
border-bottom: 1px dotted rgba(100, 90, 70, 0.4) !important;
height: 10px !important;
width: 100% !important;
}
.print-only {
display: block !important;
}
.no-print {
display: none !important;
}
.recipe-grid {
display: grid !important;
grid-template-columns: 58mm 1fr !important;
gap: 8mm !important;
gap: 6mm !important;
width: 100% !important;
min-width: 0 !important;
flex: 1 1 auto !important;
margin-bottom: 1.5mm !important;
}
.recipe-grid:has(.has-portion-matrix) {
grid-template-columns: 68mm 1fr !important;
gap: 6mm !important;
}
.recipe-photo-box {
height: 32mm !important;
max-height: 32mm !important;
margin-bottom: 2mm !important;
}
.recipe-photo-box img {
width: 100% !important;
height: 32mm !important;
max-height: 32mm !important;
object-fit: cover !important;
border-radius: 6px !important;
}
.recipe-photo-empty {
display: none !important;
}
.ingredients-box {
padding: 4px 6px !important;
}
.ingredients-list {
display: flex !important;
flex-direction: column !important;
gap: 1.5px !important;
}
.ingredients-list li {
font-size: 0.76rem !important;
line-height: 1.2 !important;
}
.ingredients-list li.ing-subheading {
font-size: 0.80rem !important;
font-weight: 700 !important;
margin-top: 2px !important;
padding-bottom: 1px !important;
}
.portion-matrix-table {
font-size: 0.70rem !important;
line-height: 1.18 !important;
}
.portion-matrix-table th {
padding: 1px 2px !important;
font-size: 0.68rem !important;
}
.portion-matrix-table td {
padding: 1px 2px !important;
}
.instructions-steps {
display: flex !important;
flex-direction: column !important;
gap: 2.5px !important;
}
.step-card {
padding: 2.5px 5px !important;
margin-bottom: 2px !important;
font-size: 0.80rem !important;
line-height: 1.22 !important;
display: flex !important;
gap: 6px !important;
align-items: flex-start !important;
}
.step-badge {
width: 16px !important;
height: 16px !important;
font-size: 0.72rem !important;
flex-shrink: 0 !important;
}
.step-text {
flex: 1 1 auto !important;
}
.notes-box {
margin-top: 2mm !important;
padding: 3px 6px !important;
font-size: 0.76rem !important;
line-height: 1.2 !important;
background: #FFFDF0 !important;
border: 1px dashed #D4C165 !important;
border-radius: 6px !important;
}
.notes-box-title {
font-weight: 700 !important;
font-size: 0.78rem !important;
margin-bottom: 2px !important;
}
.notes-box-empty {
display: block !important;
padding: 3px 6px !important;
margin-top: 2mm !important;
background: #FFFDF0 !important;
border: 1px dashed #D4C165 !important;
}
.notes-blank-lines {
display: flex !important;
flex-direction: column !important;
gap: 6px !important;
margin-top: 2px !important;
}
.notes-blank-line {
border-bottom: 1px dotted rgba(100, 90, 70, 0.4) !important;
height: 8px !important;
width: 100% !important;
}
.print-only {
display: block !important;
}
.no-print {
display: none !important;
}
.page-footer {
display: flex !important;
margin-top: auto !important;
position: relative !important;
bottom: auto !important;
border: none !important;
padding: 3mm 0 2mm 0 !important;
padding: 1.5mm 0 1mm 0 !important;
width: 100% !important;
box-sizing: border-box !important;
z-index: 100 !important;
}
.page-footer.page-even {
left: auto !important;
right: auto !important;
justify-content: flex-start !important;
text-align: left !important;
padding-left: 4mm !important;
padding-left: 3mm !important;
padding-right: 0 !important;
}
.page-footer.page-odd {
right: auto !important;
left: auto !important;
justify-content: flex-end !important;
text-align: right !important;
padding-right: 4mm !important;
padding-right: 3mm !important;
padding-left: 0 !important;
}
.page-footer .page-number {
font-size: 0.95rem !important;
font-family: var(--font-hand), 'Caveat', cursive !important;
font-size: 1.15rem !important;
font-weight: 700 !important;
color: var(--tannengruen) !important;
line-height: 1 !important;
}
.page:last-child {
page-break-after: auto !important;
break-after: auto !important;
}
}
</style>
<script>
(function() {
var isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) ||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1) ||
(window.CSS && CSS.supports && CSS.supports('-webkit-touch-callout', 'none'));
if (isIOS) {
document.documentElement.classList.add('is-ios');
if (document.body) document.body.classList.add('is-ios');
document.addEventListener('DOMContentLoaded', function() {
if (document.body) document.body.classList.add('is-ios');
});
}
})();
</script>
</head>
<body class="cookbook-body {% if is_ios %}is-ios{% endif %}">
<body class="cookbook-body">
<!-- Navigation Bar -->
<header class="cb-nav">
@@ -252,6 +483,13 @@
<h1 class="cb-nav-title">Kochbuch</h1>
</a>
<!-- Rezept-Titel Live-Suche -->
<div class="cb-search-box no-print">
<span class="cb-search-icon">🔍</span>
<input type="search" id="cb-recipe-search" class="cb-search-input" placeholder="Rezept suchen..." oninput="filterRecipesByTitle(this.value)" autocomplete="off">
<button type="button" id="cb-search-clear" class="cb-search-clear" onclick="clearRecipeSearch()" style="display: none;" title="Suche leeren">✕</button>
</div>
<!-- Desktop Buttons (auf Bildschirmen > 768px) -->
<div class="cb-nav-actions desktop-nav-actions">
<button type="button" onclick="openMealPlanModal(event)" class="cb-nav-btn" title="Wochenmenü-Plan öffnen">
@@ -314,6 +552,16 @@
<!-- Virtual Book Container -->
<main class="book-wrapper">
<!-- Leerer Suchergebnis-Zustand -->
<div id="search-empty-state" class="no-print" style="display: none;">
<div style="font-size: 2.2rem; margin-bottom: 8px;">🔍</div>
<h3 style="font-family: var(--font-hand); font-size: 1.6rem; color: var(--tannengruen); margin: 0 0 6px 0;">Kein passendes Rezept gefunden</h3>
<p style="color: #666; font-size: 0.95rem; margin: 0 0 14px 0;">Es gibt leider kein Rezept mit dem Titel &bdquo;<span id="search-empty-term" style="font-weight: bold; color: var(--schwarz);"></span>&ldquo;.</p>
<button type="button" onclick="clearRecipeSearch()" class="cb-btn cb-btn-creme" style="background: var(--tannengruen); color: var(--creme); font-size: 0.9rem;">
Alle Rezepte anzeigen
</button>
</div>
<!-- SEITE 1: COVER -->
{% if current_chapter is none or current_chapter == 1 %}
<div class="page cover" id="page-cover">
@@ -415,7 +663,7 @@
<div class="doodle-placeholder {% if chap.illustration_url %}has-illustration{% endif %}">
{% if chap.illustration_url %}
<img src="{{ chap.illustration_url }}" alt="{{ chap.title }} Illustration">
<img src="{{ chap.illustration_url }}" alt="{{ chap.title }} Illustration" loading="lazy" decoding="async">
{% else %}
<span class="placeholder-text">[ {{ chap.doodle_hint }} ]</span>
{% endif %}
@@ -481,7 +729,7 @@
<aside class="recipe-side">
<div class="recipe-photo-box">
{% if recipe.image_url %}
<img src="{{ recipe.image_url }}" alt="{{ recipe.title }}">
<img src="{{ recipe.image_url }}" alt="{{ recipe.title }}" loading="lazy" decoding="async">
{% else %}
<div class="recipe-photo-empty">
<span>📸</span>
@@ -607,7 +855,7 @@
<h2>{{ chap.title }}</h2>
<div class="doodle-placeholder {% if chap.illustration_url %}has-illustration{% endif %}" style="margin: 15px auto;">
{% if chap.illustration_url %}
<img src="{{ chap.illustration_url }}" alt="{{ chap.title }} Illustration">
<img src="{{ chap.illustration_url }}" alt="{{ chap.title }} Illustration" loading="lazy" decoding="async">
{% else %}
<span class="placeholder-text">[ {{ chap.doodle_hint }} ]</span>
{% endif %}
@@ -991,6 +1239,79 @@
}
});
// ==========================================
// REZEPT-TITEL LIVE-SUCHE
// ==========================================
function filterRecipesByTitle(query) {
const q = (query || '').trim().toLowerCase();
const clearBtn = document.getElementById('cb-search-clear');
if (clearBtn) {
clearBtn.style.display = q ? 'block' : 'none';
}
const recipeCards = document.querySelectorAll('.recipe-page');
const dividers = document.querySelectorAll('.page.divider');
const emptyState = document.getElementById('search-empty-state');
if (!q) {
recipeCards.forEach(p => p.classList.remove('search-hidden'));
dividers.forEach(d => d.classList.remove('search-hidden'));
if (emptyState) emptyState.style.display = 'none';
return;
}
let matchedCount = 0;
const chaptersWithMatches = new Set();
recipeCards.forEach(card => {
const titleEl = card.querySelector('.recipe-title');
const titleText = titleEl ? titleEl.textContent.toLowerCase() : '';
const match = titleText.includes(q);
if (match) {
card.classList.remove('search-hidden');
matchedCount++;
let prev = card.previousElementSibling;
while (prev) {
if (prev.classList.contains('divider')) {
chaptersWithMatches.add(prev.id);
break;
}
prev = prev.previousElementSibling;
}
} else {
card.classList.add('search-hidden');
}
});
dividers.forEach(div => {
if (chaptersWithMatches.has(div.id)) {
div.classList.remove('search-hidden');
} else {
div.classList.add('search-hidden');
}
});
if (emptyState) {
if (matchedCount === 0) {
emptyState.style.display = 'block';
const termEl = document.getElementById('search-empty-term');
if (termEl) termEl.textContent = query;
} else {
emptyState.style.display = 'none';
}
}
}
function clearRecipeSearch() {
const searchInput = document.getElementById('cb-recipe-search');
if (searchInput) {
searchInput.value = '';
filterRecipesByTitle('');
searchInput.focus();
}
}
// ==========================================
// DRUCKMODAL
// ==========================================