This commit is contained in:
2026-06-24 14:40:43 +00:00
parent 22b05a7a1b
commit 7058970f98
80 changed files with 6383 additions and 0 deletions
+83
View File
@@ -0,0 +1,83 @@
# Anpassung des Designs
## Designauswahl je Kunde
Jeder Kunde erhält in seinem Render-Payload eine Theme-ID:
```json
{
"design": {
"theme": "forest-lodge",
"palette_mode": "theme"
}
}
```
`GET /themes` liefert alle verfügbaren IDs inklusive Beschreibung, Layoutfamilie und Farbpalette.
## Farbmodus
- `theme`: verwendet die vorkonfigurierte Farbpalette des gewählten Designs.
- `custom`: verwendet die Farben aus dem Kunden-Payload, behält aber Layout und Typografie des Designs.
- Ohne Angabe: `modern` und `classic` verwenden Kundenfarben, alle benannten Varianten ihre Theme-Palette.
Beispiel für kundenspezifische Farben:
```json
{
"design": {
"theme": "executive-blue",
"palette_mode": "custom",
"primary_color": "#173B67",
"secondary_color": "#2A6298",
"accent_color": "#37A6B8",
"text_color": "#182632",
"muted_color": "#6B7A86",
"surface_color": "#EEF3F7",
"font_family": "Arial"
}
}
```
## Was je Kunde variieren darf
- Logo
- Theme-ID
- optional Farbpalette
- Kontaktzeile
- Name und Objektbezeichnung
Global möglichst unverändert lassen:
- Seitenformat und Ränder
- Abschnittsreihenfolge
- KPI-Anzahl
- maximale Anzahl Empfehlungen
- Textlängen und Seitenumbrüche
## Logo
Am robustesten ist ein PNG oder SVG als Base64 Data URI:
```text
data:image/png;base64,iVBORw0KGgo...
```
Damit benötigt Gotenberg keinen Zugriff auf externe URLs. Große Logos vorher verkleinern.
## Eine neue Farbvariante anlegen
Für eine reine Farbvariante ist kein neues HTML nötig. In `renderer/app/theme_catalog.py` einen weiteren Eintrag mit vorhandener `layout`-Familie ergänzen und die Theme-ID im Enum von `renderer/app/schemas/report-payload.schema.json` eintragen.
## Eine neue Layoutfamilie anlegen
1. Ordner `renderer/app/templates/<layout>` erstellen.
2. `report.html.j2` anlegen; optional ein eigenes `footer.html.j2`.
3. In `renderer/app/theme_catalog.py` ein Theme mit dieser `layout`-ID registrieren.
4. Theme-ID im Report-Schema ergänzen.
5. `pytest -q` ausführen.
6. Mit `python scripts/render-theme-gallery.py` visuell prüfen.
## Textlängen
Die maximalen Textlängen werden im Claude-Schema begrenzt. Inhalte sollten gekürzt werden, statt Schriftgrößen immer weiter zu reduzieren.
+27
View File
@@ -0,0 +1,27 @@
# Datenmodell
Der komplette Render-Payload besteht aus sieben Bereichen:
- `report`: Zeitraum, Erzeugungszeit und Versionsnummern
- `customer`: feste Kundendaten und Logo
- `design`: Theme und Branding-Tokens
- `metrics`: aktuelle Kennzahlen und Monatsvergleich
- `trends`: zwei bis zwoelf historische Monatswerte
- `content`: ausschliesslich der von Claude erzeugte redaktionelle Inhalt
- `legal_note`: fester Hinweistext
## Warum drei Schemas?
`claude-output-anthropic.schema.json` enthaelt die von der rohen Messages API unterstuetzten Strukturregeln. Nicht direkt unterstuetzte Laengen- und Wertebeschraenkungen stehen dort als Beschreibungen.
`claude-output.schema.json` prueft Claudes Ergebnis danach noch einmal streng, inklusive Textlaengen, Arraygroessen und Wertebereichen.
`report-payload.schema.json` validiert das fertige Gesamtobjekt direkt vor dem Rendern. Dadurch kann Claude weder Farben noch Zahlenformate oder Layoutbereiche veraendern.
## Versionsstrategie
- `report_version`: fachliche Gesamtversion des Reportformats
- `prompt_version`: Version der Claude-Anweisungen
- `template_version`: Version des HTML/CSS-Layouts
Eine Layoutaenderung erhoeht nur `template_version`. Eine veraenderte Bewertungslogik erhoeht `prompt_version`.
+30
View File
@@ -0,0 +1,30 @@
# Produktions-Checkliste
## Vor dem ersten Einsatz
- [ ] API-Key als Secret/Credential hinterlegt
- [ ] Renderer und Gotenberg nicht ungeschuetzt aus dem Internet erreichbar
- [ ] Kundendaten und Logos validiert
- [ ] Alle Kennzahlen auf korrekte Einheiten geprueft
- [ ] Testreports mit sehr kurzen und maximal langen Texten erzeugt
- [ ] PDF auf A4, Seitenumbrueche und Umlaute kontrolliert
- [ ] Dateinamen und Speicherpfade festgelegt
- [ ] Eindeutigkeit pro Kunde, Monat und Reportversion in der DB aktiviert
## Bei jedem Reportlauf
- [ ] Eingabedaten vollstaendig
- [ ] Claude-Response erfolgreich
- [ ] JSON-Parsing und Schema-Validierung erfolgreich
- [ ] Renderer liefert HTTP 200 und `application/pdf`
- [ ] PDF ist groesser als 10 KB
- [ ] Reportlauf mit Modell-, Prompt- und Templateversion protokolliert
- [ ] Versand erst nach erfolgreicher Speicherung
## Nach Designaenderungen
- [ ] Beispielreport beider Themes rendern
- [ ] PDF visuell auf jeder Seite pruefen
- [ ] keine abgeschnittenen Karten oder Tabellenzeilen
- [ ] Footer hat ausreichend Abstand
- [ ] lange Kundennamen und lange Empfehlungen getestet
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
BASE_URL="${BASE_URL:-http://localhost:8080}"
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
mkdir -p "$ROOT_DIR/output"
curl -sS \
--request POST "$BASE_URL/render" \
--header 'Content-Type: application/json' \
--data-binary "@$ROOT_DIR/examples/sample-report.json" \
--output "$ROOT_DIR/output/sample-report.pdf"
echo "PDF: $ROOT_DIR/output/sample-report.pdf"
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -euo pipefail
BASE_URL="${BASE_URL:-http://localhost:8080}"
INPUT="${1:-examples/sample-report.json}"
OUT="${2:-output/all-themes}"
mkdir -p "$OUT"
mapfile -t THEMES < <(curl -fsS "$BASE_URL/themes" | python3 -c 'import json,sys; print("\\n".join(json.load(sys.stdin)["themes"]))')
for theme in "${THEMES[@]}"; do
tmp="$(mktemp)"
python3 - "$INPUT" "$theme" > "$tmp" <<'PY'
import json,sys
payload=json.load(open(sys.argv[1],encoding='utf-8'))
payload['design']['theme']=sys.argv[2]
payload['design'].pop('palette_mode',None)
json.dump(payload,sys.stdout,ensure_ascii=False)
PY
curl -fsS -X POST "$BASE_URL/render" -H 'Content-Type: application/json' --data-binary "@$tmp" -o "$OUT/$theme.pdf"
rm -f "$tmp"
echo "$theme.pdf"
done
+75
View File
@@ -0,0 +1,75 @@
{
"customer": {
"id": "kuestenblick-001",
"name": "Ferienapartments Kuestenblick",
"property_name": "Apartment Seestern",
"location": "Nordseekueste",
"contact_line": "reporting@kuestenblick.example",
"logo_data_uri": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+",
"logo_text": "KB"
},
"period": {
"year": 2026,
"month": 5,
"label": "Mai 2026",
"comparison_label": "April 2026"
},
"metrics": {
"currency": "EUR",
"revenue": 6840.5,
"occupancy_rate": 78.4,
"adr": 126.68,
"revpar": 99.32,
"bookings": 19,
"nights_sold": 54,
"average_stay": 3.6,
"cancellation_rate": 6.2,
"comparison": {
"revenue_delta_pct": 12.8,
"occupancy_delta_pp": 5.7,
"adr_delta_pct": 4.6,
"bookings_delta": 2
}
},
"trends": [
{
"label": "Dez 25",
"revenue": 4210.0,
"occupancy_rate": 55.2,
"adr": 112.3
},
{
"label": "Jan 26",
"revenue": 3890.0,
"occupancy_rate": 51.4,
"adr": 109.85
},
{
"label": "Feb 26",
"revenue": 4475.0,
"occupancy_rate": 59.7,
"adr": 114.2
},
{
"label": "Mär 26",
"revenue": 5360.0,
"occupancy_rate": 66.1,
"adr": 118.75
},
{
"label": "Apr 26",
"revenue": 6064.0,
"occupancy_rate": 72.7,
"adr": 121.1
},
{
"label": "Mai 26",
"revenue": 6840.5,
"occupancy_rate": 78.4,
"adr": 126.68
}
],
"context": {
"business_goal": "Umsatz steigern, ohne die Auslastung deutlich zu gefaehrden"
}
}
+62
View File
@@ -0,0 +1,62 @@
{
"summary": {
"headline": "Starker Umsatzmonat bei weiterhin gesunder Auslastung",
"text": "Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.",
"rating": "positive"
},
"developments": [
{
"title": "Umsatz gewinnt ueberproportional",
"text": "Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.",
"impact": "positive"
},
{
"title": "Auslastung erreicht ein solides Niveau",
"text": "Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.",
"impact": "positive"
},
{
"title": "Stornos bleiben ein Beobachtungspunkt",
"text": "Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.",
"impact": "neutral"
},
{
"title": "Aufenthaltsdauer bleibt kompakt",
"text": "Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.",
"impact": "neutral"
}
],
"recommendations": [
{
"priority": 1,
"category": "Preisgestaltung",
"title": "Nachfragestarke Wochenenden differenzierter bepreisen",
"reason": "Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.",
"action": "Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.",
"expected_effect": "Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat."
},
{
"priority": 2,
"category": "Verfuegbarkeit & Buchungssteuerung",
"title": "Schwache Wochentage mit Mindestaufenthalten entlasten",
"reason": "Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.",
"action": "Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.",
"expected_effect": "Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung."
},
{
"priority": 3,
"category": "Gaeste & Bewertungen",
"title": "Stornierungen nach Kanal und Vorlauf auswerten",
"reason": "Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.",
"action": "Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.",
"expected_effect": "Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle."
}
],
"outlook": {
"headline": "Gute Ausgangslage fuer den Fruehsommer",
"text": "Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren."
},
"data_quality_notes": [
"Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar."
]
}
+152
View File
@@ -0,0 +1,152 @@
{
"report": {
"report_version": "1.0",
"prompt_version": "1.0",
"template_version": "1.0",
"generated_at": "2026-06-24T14:30:00+02:00",
"publisher": "Fewo Performance Studio",
"period": {
"year": 2026,
"month": 5,
"label": "Mai 2026",
"comparison_label": "April 2026"
}
},
"customer": {
"id": "kuestenblick-001",
"name": "Ferienapartments Kuestenblick",
"property_name": "Apartment Seestern",
"location": "Nordseekueste",
"contact_line": "reporting@kuestenblick.example",
"logo_data_uri": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+",
"logo_text": "KB"
},
"design": {
"theme": "modern",
"primary_color": "#1F5D66",
"secondary_color": "#2C7C82",
"accent_color": "#DBA25D",
"text_color": "#24343A",
"muted_color": "#718087",
"surface_color": "#F2F6F5",
"font_family": "Arial"
},
"metrics": {
"currency": "EUR",
"revenue": 6840.5,
"occupancy_rate": 78.4,
"adr": 126.68,
"revpar": 99.32,
"bookings": 19,
"nights_sold": 54,
"average_stay": 3.6,
"cancellation_rate": 6.2,
"comparison": {
"revenue_delta_pct": 12.8,
"occupancy_delta_pp": 5.7,
"adr_delta_pct": 4.6,
"bookings_delta": 2
}
},
"trends": [
{
"label": "Dez 25",
"revenue": 4210.0,
"occupancy_rate": 55.2,
"adr": 112.3
},
{
"label": "Jan 26",
"revenue": 3890.0,
"occupancy_rate": 51.4,
"adr": 109.85
},
{
"label": "Feb 26",
"revenue": 4475.0,
"occupancy_rate": 59.7,
"adr": 114.2
},
{
"label": "Mär 26",
"revenue": 5360.0,
"occupancy_rate": 66.1,
"adr": 118.75
},
{
"label": "Apr 26",
"revenue": 6064.0,
"occupancy_rate": 72.7,
"adr": 121.1
},
{
"label": "Mai 26",
"revenue": 6840.5,
"occupancy_rate": 78.4,
"adr": 126.68
}
],
"content": {
"summary": {
"headline": "Starker Umsatzmonat bei weiterhin gesunder Auslastung",
"text": "Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.",
"rating": "positive"
},
"developments": [
{
"title": "Umsatz gewinnt ueberproportional",
"text": "Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.",
"impact": "positive"
},
{
"title": "Auslastung erreicht ein solides Niveau",
"text": "Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.",
"impact": "positive"
},
{
"title": "Stornos bleiben ein Beobachtungspunkt",
"text": "Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.",
"impact": "neutral"
},
{
"title": "Aufenthaltsdauer bleibt kompakt",
"text": "Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.",
"impact": "neutral"
}
],
"recommendations": [
{
"priority": 1,
"category": "Preisgestaltung",
"title": "Nachfragestarke Wochenenden differenzierter bepreisen",
"reason": "Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.",
"action": "Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.",
"expected_effect": "Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat."
},
{
"priority": 2,
"category": "Verfuegbarkeit & Buchungssteuerung",
"title": "Schwache Wochentage mit Mindestaufenthalten entlasten",
"reason": "Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.",
"action": "Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.",
"expected_effect": "Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung."
},
{
"priority": 3,
"category": "Gaeste & Bewertungen",
"title": "Stornierungen nach Kanal und Vorlauf auswerten",
"reason": "Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.",
"action": "Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.",
"expected_effect": "Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle."
}
],
"outlook": {
"headline": "Gute Ausgangslage fuer den Fruehsommer",
"text": "Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren."
},
"data_quality_notes": [
"Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar."
]
},
"legal_note": "Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse."
}
+48
View File
@@ -0,0 +1,48 @@
# n8n-Integration
## Empfohlene Node-Reihenfolge
```text
Schedule Trigger
-> PostgreSQL: aktive Kunden laden
-> Loop Over Items
-> PostgreSQL: Monatsmetriken und Verlauf laden
-> Code: Monatsdaten vorbereiten
-> Code: Claude Request bauen
-> HTTP Request: Anthropic Messages API
-> Code: Claude JSON extrahieren
-> Code: Render Payload bauen
-> HTTP Request: Report Renderer /render
-> Speicher / E-Mail / Kundenportal
-> PostgreSQL: Reportlauf protokollieren
```
## Anthropic HTTP Request
- Methode: `POST`
- URL: `https://api.anthropic.com/v1/messages`
- Header:
- `x-api-key`: aus Credential oder Secret
- `anthropic-version`: `2023-06-01`
- `content-type`: `application/json`
- Body: `={{ $json.claudeRequest }}`
- Response: JSON
## Renderer HTTP Request
- Methode: `POST`
- URL im gleichen Docker-Netz: `http://report-renderer:8080/render`
- Body Content Type: JSON
- Body: gesamtes aktuelles Item
- Response Format: File
- Binary Property: `data`
Danach kann `data` als E-Mail-Anhang, S3-Upload oder Datei verwendet werden.
## Datenschutz und Fehlerbehandlung
- Jeden Kunden im Loop als separates Item verarbeiten.
- Kunden-ID und Berichtsmonat vor jedem Node erhalten.
- Bei Claude- oder Renderfehlern keinen leeren Report versenden.
- Reportlauf erst nach erfolgreicher Ablage als `completed` markieren.
- Eindeutigen DB-Schluessel auf Kunde, Jahr und Monat setzen.
+40
View File
@@ -0,0 +1,40 @@
// n8n Code Node: "Claude Request bauen"
// Erwartet: customer, period, metrics, trends und optional context.
// Das Schema ist fuer die rohe Messages API vereinfacht. Die strengeren
// Laengen- und Wertepruefungen erfolgen anschliessend im Report Renderer.
const input = $json;
const schema = {"type": "object", "additionalProperties": false, "properties": {"summary": {"type": "object", "additionalProperties": false, "properties": {"headline": {"type": "string", "description": "Minimum characters: 8. Maximum characters: 110."}, "text": {"type": "string", "description": "Minimum characters: 80. Maximum characters: 900."}, "rating": {"type": "string", "enum": ["positive", "neutral", "watch"]}}, "required": ["headline", "text", "rating"]}, "developments": {"type": "array", "items": {"type": "object", "additionalProperties": false, "properties": {"text": {"type": "string", "description": "Minimum characters: 40. Maximum characters: 450."}, "impact": {"type": "string", "enum": ["positive", "neutral", "negative"]}}, "required": ["title", "text", "impact"]}, "description": "Minimum items: 2. Maximum items: 4."}, "recommendations": {"type": "array", "items": {"type": "object", "additionalProperties": false, "properties": {"priority": {"type": "integer", "description": "Minimum value: 1. Maximum value: 3."}, "category": {"type": "string", "description": "Minimum characters: 3. Maximum characters: 80."}, "reason": {"type": "string", "description": "Minimum characters: 40. Maximum characters: 450."}, "action": {"type": "string", "description": "Minimum characters: 30. Maximum characters: 450."}, "expected_effect": {"type": "string", "description": "Minimum characters: 20. Maximum characters: 300."}}, "required": ["priority", "category", "title", "reason", "action", "expected_effect"]}, "description": "Minimum items: 1. Maximum items: 3."}, "outlook": {"type": "object", "additionalProperties": false, "properties": {"headline": {"type": "string", "description": "Minimum characters: 5. Maximum characters: 100."}, "text": {"type": "string", "description": "Minimum characters: 60. Maximum characters: 700."}}, "required": ["headline", "text"]}, "data_quality_notes": {"type": "array", "items": {"type": "string", "description": "Minimum characters: 5. Maximum characters: 240."}, "description": "Maximum items: 4."}}, "required": ["summary", "developments", "recommendations", "outlook", "data_quality_notes"]};
const systemPrompt = `Du erstellst die redaktionellen Inhalte eines monatlichen Performance-Reports fuer Betreiber von Ferienunterkuenften.
Nutze ausschliesslich die gelieferten Daten. Erfinde keine Zahlen oder Ursachen.
Jede Empfehlung muss konkret und aus den Daten ableitbar sein.
Formuliere professionell, klar und auf Deutsch. Vermeide Marketingfloskeln und Wiederholungen.
Erzeuge 2 bis 4 Entwicklungen, 1 bis 3 Empfehlungen und hoechstens 4 Datenhinweise.
Nutze data_quality_notes fuer fehlende oder eingeschraenkte Datengrundlagen.`;
const userPrompt = `Erstelle den Monatsreport fuer diese Daten:
${JSON.stringify({
customer: input.customer,
period: input.period,
metrics: input.metrics,
trends: input.trends,
context: input.context ?? {}
}, null, 2)}`;
return [{
json: {
...input,
claudeRequest: {
model: input.claudeModel ?? 'claude-sonnet-4-6',
max_tokens: 3000,
temperature: 0.2,
system: systemPrompt,
messages: [{ role: 'user', content: userPrompt }],
output_config: {
format: { type: 'json_schema', schema }
}
}
}
}];
+26
View File
@@ -0,0 +1,26 @@
// n8n Code Node: "Render Payload bauen"
// Passe die Node-Namen unten an deinen Workflow an.
const source = $('Monatsdaten vorbereiten').first().json;
const claude = $('Claude JSON extrahieren').first().json;
const now = new Date().toISOString();
const payload = {
report: {
report_version: '1.0',
prompt_version: '1.0',
template_version: '1.0',
generated_at: now,
publisher: source.publisher ?? 'Mein Reporting',
period: source.period
},
customer: source.customer,
design: source.design,
metrics: source.metrics,
trends: source.trends,
content: claude.content,
legal_note: source.legal_note ?? 'Dieser Report ist eine datenbasierte Entscheidungshilfe und keine Garantie fuer zukuenftige Ergebnisse.'
};
return [{ json: payload }];
+37
View File
@@ -0,0 +1,37 @@
// n8n Code Node: "Claude JSON extrahieren"
// Erwartet die Antwort der Anthropic Messages API.
const response = $json;
if (response.stop_reason === 'refusal') {
throw new Error('Claude hat die Anfrage abgelehnt. Es wird kein Report erzeugt.');
}
if (response.stop_reason === 'max_tokens') {
throw new Error('Claude-Ausgabe wurde wegen max_tokens abgeschnitten. max_tokens erhoehen und erneut ausfuehren.');
}
const textBlock = Array.isArray(response.content)
? response.content.find(block => block.type === 'text')
: null;
if (!textBlock?.text) {
throw new Error('Anthropic-Antwort enthaelt keinen Textblock.');
}
let content;
try {
content = JSON.parse(textBlock.text);
} catch (error) {
throw new Error(`Claude-Ausgabe ist kein valides JSON: ${error.message}`);
}
return [{
json: {
content,
claudeMeta: {
id: response.id,
model: response.model,
stop_reason: response.stop_reason,
usage: response.usage
}
}
}];
+49
View File
@@ -0,0 +1,49 @@
// n8n Code Node: "Monatsdaten vorbereiten"
// Dieses Beispiel normalisiert eine DB-Zeile. Feldnamen an deine Tabellen anpassen.
const row = $json;
const year = Number(row.report_year);
const month = Number(row.report_month);
const monthNames = ['Januar','Februar','Maerz','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'];
if (!Number.isInteger(year) || month < 1 || month > 12) {
throw new Error('report_year/report_month ungueltig');
}
const previous = new Date(Date.UTC(year, month - 2, 1));
const previousLabel = `${monthNames[previous.getUTCMonth()]} ${previous.getUTCFullYear()}`;
return [{
json: {
publisher: row.publisher_name ?? 'Mein Reporting',
customer: {
id: row.customer_slug,
name: row.customer_name,
property_name: row.property_name,
location: row.location,
contact_line: row.contact_line ?? '',
logo_data_uri: row.logo_data_uri || undefined,
logo_text: row.logo_text ?? row.customer_name.slice(0, 2).toUpperCase()
},
design: {
theme: row.theme ?? 'modern',
primary_color: row.primary_color ?? '#1F5D66',
secondary_color: row.secondary_color ?? '#2C7C82',
accent_color: row.accent_color ?? '#DBA25D',
text_color: row.text_color ?? '#24343A',
muted_color: row.muted_color ?? '#718087',
surface_color: row.surface_color ?? '#F2F6F5',
font_family: row.font_family ?? 'Arial'
},
period: {
year,
month,
label: `${monthNames[month - 1]} ${year}`,
comparison_label: previousLabel
},
metrics: row.metrics,
trends: row.trends,
context: row.context ?? {},
legal_note: row.legal_note
}
}];
+49
View File
@@ -0,0 +1,49 @@
-- 1. Aktive Kunden laden
SELECT *
FROM report_customer_config
WHERE active = TRUE
ORDER BY customer_id;
-- 2. Noch nicht erzeugte Reports eines Monats finden
SELECT c.*
FROM report_customer_config c
WHERE c.active = TRUE
AND NOT EXISTS (
SELECT 1
FROM monthly_report_runs r
WHERE r.customer_id = c.customer_id
AND r.report_year = $1
AND r.report_month = $2
AND r.report_version = '1.0'
AND r.status = 'completed'
);
-- 3. Reportlauf reservieren
INSERT INTO monthly_report_runs (
customer_id, report_year, report_month, status,
report_version, prompt_version, template_version
)
VALUES ($1, $2, $3, 'processing', '1.0', '1.0', '1.0')
ON CONFLICT (customer_id, report_year, report_month, report_version)
DO UPDATE SET
status = 'processing',
error_message = NULL,
started_at = NOW(),
completed_at = NULL
RETURNING id;
-- 4. Erfolgreich abschliessen
UPDATE monthly_report_runs
SET status = 'completed',
storage_path = $2,
checksum_sha256 = $3,
claude_model = $4,
completed_at = NOW()
WHERE id = $1;
-- 5. Fehler protokollieren
UPDATE monthly_report_runs
SET status = 'failed',
error_message = LEFT($2, 5000),
completed_at = NOW()
WHERE id = $1;
+42
View File
@@ -0,0 +1,42 @@
CREATE TABLE IF NOT EXISTS report_customer_config (
customer_id VARCHAR(64) PRIMARY KEY,
customer_name VARCHAR(160) NOT NULL,
property_name VARCHAR(160) NOT NULL,
location VARCHAR(160) NOT NULL,
contact_line VARCHAR(180) NOT NULL DEFAULT '',
logo_data_uri TEXT,
logo_text VARCHAR(5) NOT NULL,
theme VARCHAR(20) NOT NULL DEFAULT 'modern' CHECK (theme IN ('modern', 'classic')),
primary_color CHAR(7) NOT NULL DEFAULT '#1F5D66',
secondary_color CHAR(7) NOT NULL DEFAULT '#2C7C82',
accent_color CHAR(7) NOT NULL DEFAULT '#DBA25D',
text_color CHAR(7) NOT NULL DEFAULT '#24343A',
muted_color CHAR(7) NOT NULL DEFAULT '#718087',
surface_color CHAR(7) NOT NULL DEFAULT '#F2F6F5',
font_family VARCHAR(100) NOT NULL DEFAULT 'Arial',
active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS monthly_report_runs (
id BIGSERIAL PRIMARY KEY,
customer_id VARCHAR(64) NOT NULL REFERENCES report_customer_config(customer_id),
report_year INTEGER NOT NULL CHECK (report_year BETWEEN 2020 AND 2100),
report_month INTEGER NOT NULL CHECK (report_month BETWEEN 1 AND 12),
status VARCHAR(20) NOT NULL CHECK (status IN ('queued', 'processing', 'completed', 'failed')),
report_version VARCHAR(20) NOT NULL,
prompt_version VARCHAR(20) NOT NULL,
template_version VARCHAR(20) NOT NULL,
claude_model VARCHAR(80),
storage_path TEXT,
checksum_sha256 CHAR(64),
error_message TEXT,
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
completed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (customer_id, report_year, report_month, report_version)
);
CREATE INDEX IF NOT EXISTS idx_monthly_report_runs_status
ON monthly_report_runs(status, report_year, report_month);
File diff suppressed because one or more lines are too long
View File
+67
View File
@@ -0,0 +1,67 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Alpine Sage - Ferienapartments Kuestenblick</title><style>
:root{--p:#49665B;--s:#718C7D;--a:#C99C64;--t:#26332E;--m:#78827D;--bg:#F2F3ED;--line:#d9dfdf;--pos:#27745b;--neg:#a54a4a}@page{size:A4;margin:14mm 15mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.3pt/1.52 Georgia,Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:36pt;line-height:.98;letter-spacing:-1.7px;margin:0}h2{font-size:15pt;line-height:1.15;margin-bottom:3mm}h3{font-size:10.5pt;margin-bottom:1mm}p{margin-bottom:3mm}.top{display:flex;justify-content:space-between;align-items:flex-start;border-top:1.8mm solid var(--p);padding-top:6mm;margin-bottom:12mm}.brand{display:flex;gap:3mm;align-items:center}.logo{width:11mm;height:11mm;border:1px solid var(--p);display:flex;align-items:center;justify-content:center;font-weight:800;color:var(--p);overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand strong{display:block}.micro,.kicker,.kpi-label,.category{font:700 7pt/1.2 Arial,sans-serif;text-transform:uppercase;letter-spacing:1.1px;color:var(--m)}.period{text-align:right;color:var(--p);font-weight:700}.hero{display:grid;grid-template-columns:1fr 68mm;gap:10mm;align-items:end;margin-bottom:11mm}.hero-note{border-left:1mm solid var(--a);padding-left:5mm}.hero-note h2{font-size:14pt}.hero-note p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);border-top:1px solid var(--line);border-bottom:1px solid var(--line);margin-bottom:5mm}.kpi{padding:5mm 4mm 4mm 0}.kpi+.kpi{border-left:1px solid var(--line);padding-left:4mm}.kpi-value{font-size:16pt;font-weight:700;color:var(--p);white-space:nowrap;margin:2mm 0}.kpi-delta{font-size:7.5pt;color:var(--m)}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:6mm;margin-bottom:10mm}.fact span{display:block;color:var(--m);font-size:7.3pt}.fact strong{display:block;margin-top:1mm}.section{margin-bottom:9mm}.section-title{display:grid;grid-template-columns:auto 1fr;gap:4mm;align-items:center;margin-bottom:4mm}.section-title h2{margin:0}.rule{height:1px;background:var(--line)}.trend-bars{border-top:1px solid var(--line)}.trend-row{display:grid;grid-template-columns:18mm 1fr 28mm 22mm;gap:3mm;align-items:center;padding:2.2mm 0;border-bottom:1px solid var(--line);font-size:7.7pt}.trend-label{font-weight:700}.trend-track{height:3.5mm;background:var(--bg);position:relative}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1mm;background:var(--a);position:absolute;bottom:0;left:0}.trend-num{text-align:right}.content-grid{display:grid;grid-template-columns:1fr 1.1fr;gap:9mm;break-before:page;break-inside:avoid}.developments,.recommendations{display:grid;gap:4mm}.development{display:grid;grid-template-columns:2mm 1fr;gap:3mm;break-inside:avoid}.impact{width:1.3mm;background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendation{display:grid;grid-template-columns:8mm 1fr;gap:3mm;break-inside:avoid;padding-bottom:4mm;border-bottom:1px solid var(--line)}.priority{font-size:17pt;color:var(--a);font-weight:700}.recommendation p{margin-bottom:1.5mm}.effect{color:var(--p)}.outlook{margin-top:8mm;padding:6mm 0;border-top:1.2mm solid var(--p);border-bottom:1px solid var(--line);break-inside:avoid}.outlook p{margin:0}.notes{margin-top:4mm;font-size:7pt;color:var(--m)}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.5pt;color:var(--m);margin-top:3mm}
</style></head><body>
<header class="top"><div class="brand"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div><strong>Ferienapartments Kuestenblick</strong><div class="micro">Apartment Seestern</div></div></div><div class="period">Mai 2026<div class="micro">Nordseekueste</div></div></header>
<section class="hero"><div><div class="kicker">Monatliche Performance</div><h1>Monats-<br>report</h1></div><div class="hero-note"><div class="kicker">Kurzfazit</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<section class="section"><div class="section-title"><h2>Monatsverlauf</h2><div class="rule"></div></div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div></section>
<div class="content-grid"><section><div class="section-title"><h2>Entwicklungen</h2><div class="rule"></div></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section><section><div class="section-title"><h2>Empfehlungen</h2><div class="rule"></div></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section></div>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+127
View File
@@ -0,0 +1,127 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Monatsreport Mai 2026 - Ferienapartments Kuestenblick</title>
<style>
:root {
--primary: #1F5D66;
--accent: #DBA25D;
--text: #24343A;
--muted: #718087;
--surface: #F2F6F5;
--line: #cfd6da;
--positive: #236a4f;
--negative: #9d3e3e;
}
@page { size: A4; margin: 15mm 16mm 19mm; }
* { box-sizing: border-box; }
html { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
body { margin: 0; font-family: Arial, Georgia, serif; color: var(--text); font-size: 9.5pt; line-height: 1.5; }
h1, h2, h3, p { margin-top: 0; }
h1 { font-size: 25pt; font-weight: 500; line-height: 1.12; margin-bottom: 2mm; }
h2 { font-size: 15pt; font-weight: 600; color: var(--primary); margin-bottom: 3mm; }
h3 { font-size: 10.5pt; margin-bottom: 1mm; }
p { margin-bottom: 3mm; }
.sans { font-family: Arial, sans-serif; }
.header { border-top: 2.5mm solid var(--primary); padding-top: 7mm; margin-bottom: 8mm; display: grid; grid-template-columns: 1fr auto; gap: 8mm; }
.brand { text-align: right; font-family: Arial, sans-serif; font-size: 8pt; color: var(--muted); }
.brand strong { display: block; color: var(--primary); font-size: 10pt; margin-bottom: 1mm; }
.period { font-family: Arial, sans-serif; text-transform: uppercase; letter-spacing: 1.4px; color: var(--accent); font-size: 8pt; font-weight: 700; }
.meta { display: flex; gap: 6mm; color: var(--muted); font-family: Arial, sans-serif; font-size: 7.5pt; }
.rule-heading { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 4mm; margin: 7mm 0 3mm; }
.rule-heading h2 { margin: 0; white-space: nowrap; }
.rule { height: .25mm; background: var(--line); }
.summary { padding: 5mm 0 5mm 5mm; border-left: 1.2mm solid var(--accent); break-inside: avoid; }
.summary h2 { color: var(--text); }
.summary p { margin: 0; }
.kpis { display: grid; grid-template-columns: repeat(4,1fr); border: .25mm solid var(--line); break-inside: avoid; }
.kpi { padding: 4mm; border-right: .25mm solid var(--line); min-height: 28mm; }
.kpi:last-child { border-right: 0; }
.kpi-label { font-family: Arial, sans-serif; font-size: 7pt; text-transform: uppercase; letter-spacing: .8px; color: var(--muted); }
.kpi-value { color: var(--primary); font-size: 15pt; font-weight: 600; margin: 2.5mm 0 1mm; white-space: nowrap; }
.kpi-delta { font-family: Arial, sans-serif; font-size: 7pt; color: var(--muted); }
.facts { display: grid; grid-template-columns: repeat(4,1fr); background: var(--surface); padding: 3mm 4mm; font-family: Arial, sans-serif; font-size: 7.5pt; }
.facts strong { display: block; color: var(--primary); font-size: 9pt; margin-top: .5mm; }
table { width: 100%; border-collapse: collapse; break-inside: avoid; font-family: Arial, sans-serif; font-size: 7.6pt; }
th { text-align: left; color: var(--muted); font-size: 6.8pt; text-transform: uppercase; letter-spacing: .7px; padding: 2.5mm; border-bottom: .5mm solid var(--primary); }
td { padding: 2.5mm; border-bottom: .25mm solid var(--line); }
td.num, th.num { text-align: right; }
.developments { columns: 2; column-gap: 6mm; }
.development { break-inside: avoid; padding: 0 0 3mm 4mm; margin-bottom: 3mm; border-left: .8mm solid var(--line); }
.development.positive { border-left-color: var(--positive); }
.development.negative { border-left-color: var(--negative); }
.development p { margin: 0; }
.recommendation { break-inside: avoid; display: grid; grid-template-columns: 10mm 1fr; gap: 4mm; padding: 4mm 0; border-bottom: .25mm solid var(--line); }
.recommendation:last-child { border-bottom: 0; }
.number { width: 9mm; height: 9mm; border: .4mm solid var(--primary); color: var(--primary); display: flex; align-items: center; justify-content: center; align-self: start; border-radius: 50%; font-family: Arial, sans-serif; font-weight: 700; }
.category { color: var(--accent); font-family: Arial, sans-serif; font-size: 7pt; text-transform: uppercase; letter-spacing: .8px; font-weight: 700; }
.recommendation p { margin-bottom: 1.7mm; }
.outlook { margin-top: 6mm; padding: 5mm; background: var(--surface); border-top: 1mm solid var(--primary); break-inside: avoid; }
.outlook p { margin: 0; }
.notes { font-family: Arial, sans-serif; font-size: 7pt; color: var(--muted); margin-top: 4mm; }
.notes ul { margin: 1mm 0; padding-left: 4mm; }
.legal { font-family: Arial, sans-serif; font-size: 6.6pt; color: var(--muted); margin-top: 4mm; }
</style>
</head>
<body>
<header class="header">
<div>
<div class="period">Mai 2026</div>
<h1>Monatsreport</h1>
<div class="meta"><span>Apartment Seestern</span><span>Nordseekueste</span><span>24.06.2026</span></div>
</div>
<div class="brand"><strong>Ferienapartments Kuestenblick</strong>reporting@kuestenblick.example</div>
</header>
<section class="summary">
<div class="period">Kurzfazit</div>
<h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2>
<p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p>
</section>
<div class="rule-heading"><h2>Kennzahlen</h2><div class="rule"></div></div>
<section class="kpis">
<div class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta">+12,8 %</div></div>
<div class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta">+5,7 PP</div></div>
<div class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta">+4,6 %</div></div>
<div class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta">+2 Buchungen</div></div>
</section>
<section class="facts">
<div>RevPAR<strong>99,32 €</strong></div>
<div>Verkaufte Nächte<strong>54</strong></div>
<div>Ø Aufenthalt<strong>3,6 Nächte</strong></div>
<div>Stornoquote<strong>6,2 %</strong></div>
</section>
<div class="rule-heading"><h2>Monatsverlauf</h2><div class="rule"></div></div>
<table>
<thead><tr><th>Monat</th><th class="num">Umsatz</th><th class="num">Auslastung</th><th class="num">Ø Tagespreis</th></tr></thead>
<tbody>
<tr><td>Dez 25</td><td class="num">4.210,00 €</td><td class="num">55,2 %</td><td class="num">112,30 €</td></tr><tr><td>Jan 26</td><td class="num">3.890,00 €</td><td class="num">51,4 %</td><td class="num">109,85 €</td></tr><tr><td>Feb 26</td><td class="num">4.475,00 €</td><td class="num">59,7 %</td><td class="num">114,20 €</td></tr><tr><td>Mär 26</td><td class="num">5.360,00 €</td><td class="num">66,1 %</td><td class="num">118,75 €</td></tr><tr><td>Apr 26</td><td class="num">6.064,00 €</td><td class="num">72,7 %</td><td class="num">121,10 €</td></tr><tr><td>Mai 26</td><td class="num">6.840,50 €</td><td class="num">78,4 %</td><td class="num">126,68 €</td></tr> </tbody>
</table>
<div class="rule-heading"><h2>Wichtige Entwicklungen</h2><div class="rule"></div></div>
<section class="developments">
<article class="development positive"><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></article><article class="development positive"><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></article><article class="development neutral"><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></article><article class="development neutral"><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></article> </section>
<div class="rule-heading"><h2>Empfehlungen</h2><div class="rule"></div></div>
<section>
<article class="recommendation">
<div class="number">1</div>
<div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div>
</article>
<article class="recommendation">
<div class="number">2</div>
<div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div>
</article>
<article class="recommendation">
<div class="number">3</div>
<div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div>
</article>
</section>
<section class="outlook"><div class="period">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section>
<section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section> <div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body>
</html>
+33
View File
@@ -0,0 +1,33 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Editorial Ink - Ferienapartments Kuestenblick</title><style>
:root{--p:#17222D;--s:#2E485F;--a:#3E88A8;--t:#171D22;--m:#68747E;--bg:#F0F3F5;--line:#cfcac1;--pos:#2e7259;--neg:#9a4747}@page{size:A4;margin:14mm 16mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.6pt/1.55 Georgia,Georgia,serif}h1,h2,h3,p{margin-top:0}h1{font-size:38pt;line-height:.94;font-weight:500;letter-spacing:-1.5px;margin:0}h2{font-size:17pt;font-weight:500;margin-bottom:3mm}h3{font-size:11pt;margin-bottom:1mm}p{margin-bottom:3mm}.mast{display:grid;grid-template-columns:1fr auto;align-items:center;border-top:2mm solid var(--p);border-bottom:1px solid var(--line);padding:4mm 0;margin-bottom:9mm}.brand{font:700 8pt Arial,sans-serif;text-transform:uppercase;letter-spacing:1.2px}.issue{text-align:right;font:7pt Arial,sans-serif;color:var(--m)}.issue strong{display:block;color:var(--p);font-size:10pt}.hero{display:grid;grid-template-columns:1.1fr .9fr;gap:10mm;align-items:end;margin-bottom:8mm}.logo{width:13mm;height:13mm;border:1px solid var(--p);float:left;margin-right:3mm;display:flex;align-items:center;justify-content:center;font:800 9pt Arial,sans-serif;color:var(--p);overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.deck{border-top:1mm solid var(--a);padding-top:4mm}.deck .kicker,.kicker,.kpi-label,.category{font:700 6.8pt/1.2 Arial,sans-serif;text-transform:uppercase;letter-spacing:1px;color:var(--m)}.deck h2{font-size:16pt}.deck p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);margin:8mm 0 4mm;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}.kpi{padding:4mm 4mm 4mm 0}.kpi+.kpi{border-left:1px solid var(--line);padding-left:4mm}.kpi-value{font-size:16pt;color:var(--p);margin:2mm 0;white-space:nowrap}.kpi-delta{font:7pt Arial,sans-serif}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:flex;justify-content:space-between;gap:4mm;font:7pt Arial,sans-serif;color:var(--m);margin-bottom:9mm}.fact strong{color:var(--t);margin-left:1mm}.headline{display:flex;align-items:center;gap:4mm;margin:7mm 0 4mm}.headline h2{margin:0;white-space:nowrap}.headline:after{content:"";height:1px;background:var(--line);flex:1}.trend-table{width:100%;border-collapse:collapse;font:7.5pt Arial,sans-serif;break-inside:avoid}.trend-table th{text-align:left;text-transform:uppercase;letter-spacing:.7px;color:var(--m);font-size:6.5pt;border-bottom:1mm solid var(--p);padding:2mm}.trend-table td{padding:2.2mm;border-bottom:1px solid var(--line)}.trend-table th:not(:first-child),.trend-table td:not(:first-child){text-align:right}.editorial-grid{display:grid;grid-template-columns:1fr 1fr;gap:8mm;align-items:start;break-before:page;break-inside:avoid}.developments{columns:1}.development{display:grid;grid-template-columns:2mm 1fr;gap:3mm;margin-bottom:4mm;break-inside:avoid}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendations{display:grid;gap:4mm}.recommendation{border-top:1px solid var(--line);padding-top:3mm;display:grid;grid-template-columns:8mm 1fr;gap:3mm;break-inside:avoid}.priority{font-size:20pt;color:var(--a);line-height:1}.recommendation p{margin-bottom:1.4mm}.effect{font-style:italic}.outlook{margin-top:8mm;background:var(--bg);padding:6mm;border-left:1.2mm solid var(--p);break-inside:avoid}.outlook h2{margin-bottom:2mm}.outlook p{margin:0}.notes{font:6.8pt Arial,sans-serif;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font:6.3pt Arial,sans-serif;color:var(--m);margin-top:2mm}
</style></head><body>
<header class="mast"><div class="brand">Ferienapartments Kuestenblick · Monthly Review</div><div class="issue"><strong>Mai 2026</strong>Nordseekueste</div></header>
<section class="hero"><div><div><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div class="kicker">Apartment Seestern</div></div><h1>Monatsreport</h1></div><div class="deck"><div class="kicker">Analyse des Monats</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<div class="headline"><h2>Zahlen im Verlauf</h2></div><table class="trend-table">
<thead><tr><th>Monat</th><th>Umsatz</th><th>Auslastung</th><th>Ø Tagespreis</th></tr></thead>
<tbody><tr><td>Dez 25</td><td>4.210,00 €</td><td>55,2 %</td><td>112,30 €</td></tr><tr><td>Jan 26</td><td>3.890,00 €</td><td>51,4 %</td><td>109,85 €</td></tr><tr><td>Feb 26</td><td>4.475,00 €</td><td>59,7 %</td><td>114,20 €</td></tr><tr><td>Mär 26</td><td>5.360,00 €</td><td>66,1 %</td><td>118,75 €</td></tr><tr><td>Apr 26</td><td>6.064,00 €</td><td>72,7 %</td><td>121,10 €</td></tr><tr><td>Mai 26</td><td>6.840,50 €</td><td>78,4 %</td><td>126,68 €</td></tr></tbody>
</table>
<div class="editorial-grid"><section><div class="headline"><h2>Entwicklungen</h2></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section><section><div class="headline"><h2>Empfehlungen</h2></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section></div>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+33
View File
@@ -0,0 +1,33 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Editorial Ivory - Ferienapartments Kuestenblick</title><style>
:root{--p:#33312E;--s:#6D655C;--a:#A77D45;--t:#282725;--m:#77716A;--bg:#F7F2E8;--line:#cfcac1;--pos:#2e7259;--neg:#9a4747}@page{size:A4;margin:14mm 16mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.6pt/1.55 Georgia,Georgia,serif}h1,h2,h3,p{margin-top:0}h1{font-size:38pt;line-height:.94;font-weight:500;letter-spacing:-1.5px;margin:0}h2{font-size:17pt;font-weight:500;margin-bottom:3mm}h3{font-size:11pt;margin-bottom:1mm}p{margin-bottom:3mm}.mast{display:grid;grid-template-columns:1fr auto;align-items:center;border-top:2mm solid var(--p);border-bottom:1px solid var(--line);padding:4mm 0;margin-bottom:9mm}.brand{font:700 8pt Arial,sans-serif;text-transform:uppercase;letter-spacing:1.2px}.issue{text-align:right;font:7pt Arial,sans-serif;color:var(--m)}.issue strong{display:block;color:var(--p);font-size:10pt}.hero{display:grid;grid-template-columns:1.1fr .9fr;gap:10mm;align-items:end;margin-bottom:8mm}.logo{width:13mm;height:13mm;border:1px solid var(--p);float:left;margin-right:3mm;display:flex;align-items:center;justify-content:center;font:800 9pt Arial,sans-serif;color:var(--p);overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.deck{border-top:1mm solid var(--a);padding-top:4mm}.deck .kicker,.kicker,.kpi-label,.category{font:700 6.8pt/1.2 Arial,sans-serif;text-transform:uppercase;letter-spacing:1px;color:var(--m)}.deck h2{font-size:16pt}.deck p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);margin:8mm 0 4mm;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}.kpi{padding:4mm 4mm 4mm 0}.kpi+.kpi{border-left:1px solid var(--line);padding-left:4mm}.kpi-value{font-size:16pt;color:var(--p);margin:2mm 0;white-space:nowrap}.kpi-delta{font:7pt Arial,sans-serif}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:flex;justify-content:space-between;gap:4mm;font:7pt Arial,sans-serif;color:var(--m);margin-bottom:9mm}.fact strong{color:var(--t);margin-left:1mm}.headline{display:flex;align-items:center;gap:4mm;margin:7mm 0 4mm}.headline h2{margin:0;white-space:nowrap}.headline:after{content:"";height:1px;background:var(--line);flex:1}.trend-table{width:100%;border-collapse:collapse;font:7.5pt Arial,sans-serif;break-inside:avoid}.trend-table th{text-align:left;text-transform:uppercase;letter-spacing:.7px;color:var(--m);font-size:6.5pt;border-bottom:1mm solid var(--p);padding:2mm}.trend-table td{padding:2.2mm;border-bottom:1px solid var(--line)}.trend-table th:not(:first-child),.trend-table td:not(:first-child){text-align:right}.editorial-grid{display:grid;grid-template-columns:1fr 1fr;gap:8mm;align-items:start;break-before:page;break-inside:avoid}.developments{columns:1}.development{display:grid;grid-template-columns:2mm 1fr;gap:3mm;margin-bottom:4mm;break-inside:avoid}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendations{display:grid;gap:4mm}.recommendation{border-top:1px solid var(--line);padding-top:3mm;display:grid;grid-template-columns:8mm 1fr;gap:3mm;break-inside:avoid}.priority{font-size:20pt;color:var(--a);line-height:1}.recommendation p{margin-bottom:1.4mm}.effect{font-style:italic}.outlook{margin-top:8mm;background:var(--bg);padding:6mm;border-left:1.2mm solid var(--p);break-inside:avoid}.outlook h2{margin-bottom:2mm}.outlook p{margin:0}.notes{font:6.8pt Arial,sans-serif;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font:6.3pt Arial,sans-serif;color:var(--m);margin-top:2mm}
</style></head><body>
<header class="mast"><div class="brand">Ferienapartments Kuestenblick · Monthly Review</div><div class="issue"><strong>Mai 2026</strong>Nordseekueste</div></header>
<section class="hero"><div><div><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div class="kicker">Apartment Seestern</div></div><h1>Monatsreport</h1></div><div class="deck"><div class="kicker">Analyse des Monats</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<div class="headline"><h2>Zahlen im Verlauf</h2></div><table class="trend-table">
<thead><tr><th>Monat</th><th>Umsatz</th><th>Auslastung</th><th>Ø Tagespreis</th></tr></thead>
<tbody><tr><td>Dez 25</td><td>4.210,00 €</td><td>55,2 %</td><td>112,30 €</td></tr><tr><td>Jan 26</td><td>3.890,00 €</td><td>51,4 %</td><td>109,85 €</td></tr><tr><td>Feb 26</td><td>4.475,00 €</td><td>59,7 %</td><td>114,20 €</td></tr><tr><td>Mär 26</td><td>5.360,00 €</td><td>66,1 %</td><td>118,75 €</td></tr><tr><td>Apr 26</td><td>6.064,00 €</td><td>72,7 %</td><td>121,10 €</td></tr><tr><td>Mai 26</td><td>6.840,50 €</td><td>78,4 %</td><td>126,68 €</td></tr></tbody>
</table>
<div class="editorial-grid"><section><div class="headline"><h2>Entwicklungen</h2></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section><section><div class="headline"><h2>Empfehlungen</h2></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section></div>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+33
View File
@@ -0,0 +1,33 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Editorial Rose - Ferienapartments Kuestenblick</title><style>
:root{--p:#5E3548;--s:#8A576B;--a:#D59AA7;--t:#33272C;--m:#7C6E74;--bg:#F8EFF1;--line:#cfcac1;--pos:#2e7259;--neg:#9a4747}@page{size:A4;margin:14mm 16mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.6pt/1.55 Georgia,Georgia,serif}h1,h2,h3,p{margin-top:0}h1{font-size:38pt;line-height:.94;font-weight:500;letter-spacing:-1.5px;margin:0}h2{font-size:17pt;font-weight:500;margin-bottom:3mm}h3{font-size:11pt;margin-bottom:1mm}p{margin-bottom:3mm}.mast{display:grid;grid-template-columns:1fr auto;align-items:center;border-top:2mm solid var(--p);border-bottom:1px solid var(--line);padding:4mm 0;margin-bottom:9mm}.brand{font:700 8pt Arial,sans-serif;text-transform:uppercase;letter-spacing:1.2px}.issue{text-align:right;font:7pt Arial,sans-serif;color:var(--m)}.issue strong{display:block;color:var(--p);font-size:10pt}.hero{display:grid;grid-template-columns:1.1fr .9fr;gap:10mm;align-items:end;margin-bottom:8mm}.logo{width:13mm;height:13mm;border:1px solid var(--p);float:left;margin-right:3mm;display:flex;align-items:center;justify-content:center;font:800 9pt Arial,sans-serif;color:var(--p);overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.deck{border-top:1mm solid var(--a);padding-top:4mm}.deck .kicker,.kicker,.kpi-label,.category{font:700 6.8pt/1.2 Arial,sans-serif;text-transform:uppercase;letter-spacing:1px;color:var(--m)}.deck h2{font-size:16pt}.deck p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);margin:8mm 0 4mm;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}.kpi{padding:4mm 4mm 4mm 0}.kpi+.kpi{border-left:1px solid var(--line);padding-left:4mm}.kpi-value{font-size:16pt;color:var(--p);margin:2mm 0;white-space:nowrap}.kpi-delta{font:7pt Arial,sans-serif}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:flex;justify-content:space-between;gap:4mm;font:7pt Arial,sans-serif;color:var(--m);margin-bottom:9mm}.fact strong{color:var(--t);margin-left:1mm}.headline{display:flex;align-items:center;gap:4mm;margin:7mm 0 4mm}.headline h2{margin:0;white-space:nowrap}.headline:after{content:"";height:1px;background:var(--line);flex:1}.trend-table{width:100%;border-collapse:collapse;font:7.5pt Arial,sans-serif;break-inside:avoid}.trend-table th{text-align:left;text-transform:uppercase;letter-spacing:.7px;color:var(--m);font-size:6.5pt;border-bottom:1mm solid var(--p);padding:2mm}.trend-table td{padding:2.2mm;border-bottom:1px solid var(--line)}.trend-table th:not(:first-child),.trend-table td:not(:first-child){text-align:right}.editorial-grid{display:grid;grid-template-columns:1fr 1fr;gap:8mm;align-items:start;break-before:page;break-inside:avoid}.developments{columns:1}.development{display:grid;grid-template-columns:2mm 1fr;gap:3mm;margin-bottom:4mm;break-inside:avoid}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendations{display:grid;gap:4mm}.recommendation{border-top:1px solid var(--line);padding-top:3mm;display:grid;grid-template-columns:8mm 1fr;gap:3mm;break-inside:avoid}.priority{font-size:20pt;color:var(--a);line-height:1}.recommendation p{margin-bottom:1.4mm}.effect{font-style:italic}.outlook{margin-top:8mm;background:var(--bg);padding:6mm;border-left:1.2mm solid var(--p);break-inside:avoid}.outlook h2{margin-bottom:2mm}.outlook p{margin:0}.notes{font:6.8pt Arial,sans-serif;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font:6.3pt Arial,sans-serif;color:var(--m);margin-top:2mm}
</style></head><body>
<header class="mast"><div class="brand">Ferienapartments Kuestenblick · Monthly Review</div><div class="issue"><strong>Mai 2026</strong>Nordseekueste</div></header>
<section class="hero"><div><div><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div class="kicker">Apartment Seestern</div></div><h1>Monatsreport</h1></div><div class="deck"><div class="kicker">Analyse des Monats</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<div class="headline"><h2>Zahlen im Verlauf</h2></div><table class="trend-table">
<thead><tr><th>Monat</th><th>Umsatz</th><th>Auslastung</th><th>Ø Tagespreis</th></tr></thead>
<tbody><tr><td>Dez 25</td><td>4.210,00 €</td><td>55,2 %</td><td>112,30 €</td></tr><tr><td>Jan 26</td><td>3.890,00 €</td><td>51,4 %</td><td>109,85 €</td></tr><tr><td>Feb 26</td><td>4.475,00 €</td><td>59,7 %</td><td>114,20 €</td></tr><tr><td>Mär 26</td><td>5.360,00 €</td><td>66,1 %</td><td>118,75 €</td></tr><tr><td>Apr 26</td><td>6.064,00 €</td><td>72,7 %</td><td>121,10 €</td></tr><tr><td>Mai 26</td><td>6.840,50 €</td><td>78,4 %</td><td>126,68 €</td></tr></tbody>
</table>
<div class="editorial-grid"><section><div class="headline"><h2>Entwicklungen</h2></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section><section><div class="headline"><h2>Empfehlungen</h2></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section></div>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+66
View File
@@ -0,0 +1,66 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Executive Blue - Ferienapartments Kuestenblick</title><style>
:root{--p:#173B67;--s:#2A6298;--a:#37A6B8;--t:#182632;--m:#6B7A86;--bg:#EEF3F7;--line:#d8e0e5;--pos:#25745b;--neg:#a84444}@page{size:A4;margin:12mm 13mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9pt/1.46 Arial,Arial,sans-serif;background:#fff}h1,h2,h3,p{margin-top:0}h1{font-size:24pt;margin:0;line-height:1.05}h2{font-size:13.5pt;margin-bottom:3mm}h3{font-size:10pt;margin-bottom:1mm}p{margin-bottom:2.5mm}.header{background:linear-gradient(125deg,var(--p),var(--s));color:#fff;border-radius:3mm;padding:7mm;margin-bottom:5mm;display:grid;grid-template-columns:1fr auto;gap:8mm;break-inside:avoid}.header-left{display:flex;gap:4mm;align-items:center}.logo{width:14mm;height:14mm;background:#fff;color:var(--p);border-radius:2mm;display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand{font-weight:700}.sub{font-size:7.5pt;opacity:.78}.header-right{text-align:right}.period{font-size:11pt;font-weight:800}.kicker,.kpi-label,.category{font-size:6.8pt;text-transform:uppercase;letter-spacing:.9px;font-weight:800;color:var(--m)}.header .kicker{color:#ffffffb8}.summary{display:grid;grid-template-columns:1fr 42mm;gap:4mm;margin-bottom:5mm}.summary-main{padding:5mm;border:1px solid var(--line);border-radius:2mm}.summary-main h2{font-size:15pt}.summary-score{background:var(--bg);border-radius:2mm;padding:4mm;display:flex;flex-direction:column;justify-content:center;text-align:center}.summary-score strong{font-size:20pt;color:var(--p)}.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:3mm;margin-bottom:3mm}.kpi{padding:4mm;background:var(--bg);border-top:1.2mm solid var(--p);min-height:29mm;break-inside:avoid}.kpi-value{font-size:15pt;font-weight:800;color:var(--p);margin:2mm 0;white-space:nowrap}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:3mm;margin-bottom:6mm}.fact{border:1px solid var(--line);padding:2.5mm 3mm}.fact span{display:block;font-size:6.8pt;color:var(--m)}.fact strong{display:block;margin-top:.5mm}.grid{display:grid;grid-template-columns:1.18fr .82fr;gap:5mm;align-items:start;break-before:page;break-inside:avoid}.panel{border:1px solid var(--line);border-radius:2mm;padding:4mm;margin-bottom:5mm;break-inside:avoid}.panel-head{display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid var(--line);padding-bottom:2mm;margin-bottom:3mm}.panel-head h2{margin:0}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:17mm 1fr 27mm 21mm;gap:2mm;align-items:center;font-size:7.2pt}.trend-label{font-weight:700}.trend-track{height:4mm;background:#e7ecef;position:relative;border-radius:1mm;overflow:hidden}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1.2mm;background:var(--a);position:absolute;bottom:0;left:0}.trend-num{text-align:right}.developments{display:grid;gap:2.5mm}.development{display:grid;grid-template-columns:2mm 1fr;gap:2.5mm;padding-bottom:2.5mm;border-bottom:1px solid var(--line);break-inside:avoid}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendations{display:grid;gap:3mm}.recommendation{display:grid;grid-template-columns:8mm 1fr;gap:3mm;background:var(--bg);padding:3.5mm;break-inside:avoid}.priority{width:7mm;height:7mm;border-radius:50%;background:var(--p);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800}.recommendation p{margin-bottom:1.4mm}.effect{border-top:1px solid #00000010;padding-top:1.5mm}.outlook{padding:5mm;background:var(--p);color:#fff;border-radius:2mm;break-inside:avoid}.outlook .kicker{color:#ffffffb8}.outlook h2{margin-bottom:1.5mm}.outlook p{margin:0}.notes{font-size:6.8pt;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.3pt;color:var(--m);margin-top:2mm}
</style></head><body>
<header class="header"><div class="header-left"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div><div class="brand">Ferienapartments Kuestenblick</div><div class="sub">Apartment Seestern · Nordseekueste</div></div></div><div class="header-right"><div class="kicker">Performance Dashboard</div><div class="period">Mai 2026</div><div class="sub">Erstellt 24.06.2026</div></div></header>
<section class="summary"><div class="summary-main"><div class="kicker">Management Summary</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div><div class="summary-score"><span class="kicker">Status</span><strong></strong><span>positive</span></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<div class="grid"><div><section class="panel"><div class="panel-head"><h2>Monatsverlauf</h2><span class="kicker">April 2026</span></div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div></section><section class="panel"><div class="panel-head"><h2>Wichtige Entwicklungen</h2></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section></div><div><section class="panel"><div class="panel-head"><h2>Prioritäten</h2></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section><section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section></div></div>
<section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
@@ -0,0 +1,66 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Executive Burgundy - Ferienapartments Kuestenblick</title><style>
:root{--p:#662E3A;--s:#8B4654;--a:#C08B5C;--t:#2E2527;--m:#7D7375;--bg:#F5F0EF;--line:#d8e0e5;--pos:#25745b;--neg:#a84444}@page{size:A4;margin:12mm 13mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9pt/1.46 Arial,Arial,sans-serif;background:#fff}h1,h2,h3,p{margin-top:0}h1{font-size:24pt;margin:0;line-height:1.05}h2{font-size:13.5pt;margin-bottom:3mm}h3{font-size:10pt;margin-bottom:1mm}p{margin-bottom:2.5mm}.header{background:linear-gradient(125deg,var(--p),var(--s));color:#fff;border-radius:3mm;padding:7mm;margin-bottom:5mm;display:grid;grid-template-columns:1fr auto;gap:8mm;break-inside:avoid}.header-left{display:flex;gap:4mm;align-items:center}.logo{width:14mm;height:14mm;background:#fff;color:var(--p);border-radius:2mm;display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand{font-weight:700}.sub{font-size:7.5pt;opacity:.78}.header-right{text-align:right}.period{font-size:11pt;font-weight:800}.kicker,.kpi-label,.category{font-size:6.8pt;text-transform:uppercase;letter-spacing:.9px;font-weight:800;color:var(--m)}.header .kicker{color:#ffffffb8}.summary{display:grid;grid-template-columns:1fr 42mm;gap:4mm;margin-bottom:5mm}.summary-main{padding:5mm;border:1px solid var(--line);border-radius:2mm}.summary-main h2{font-size:15pt}.summary-score{background:var(--bg);border-radius:2mm;padding:4mm;display:flex;flex-direction:column;justify-content:center;text-align:center}.summary-score strong{font-size:20pt;color:var(--p)}.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:3mm;margin-bottom:3mm}.kpi{padding:4mm;background:var(--bg);border-top:1.2mm solid var(--p);min-height:29mm;break-inside:avoid}.kpi-value{font-size:15pt;font-weight:800;color:var(--p);margin:2mm 0;white-space:nowrap}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:3mm;margin-bottom:6mm}.fact{border:1px solid var(--line);padding:2.5mm 3mm}.fact span{display:block;font-size:6.8pt;color:var(--m)}.fact strong{display:block;margin-top:.5mm}.grid{display:grid;grid-template-columns:1.18fr .82fr;gap:5mm;align-items:start;break-before:page;break-inside:avoid}.panel{border:1px solid var(--line);border-radius:2mm;padding:4mm;margin-bottom:5mm;break-inside:avoid}.panel-head{display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid var(--line);padding-bottom:2mm;margin-bottom:3mm}.panel-head h2{margin:0}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:17mm 1fr 27mm 21mm;gap:2mm;align-items:center;font-size:7.2pt}.trend-label{font-weight:700}.trend-track{height:4mm;background:#e7ecef;position:relative;border-radius:1mm;overflow:hidden}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1.2mm;background:var(--a);position:absolute;bottom:0;left:0}.trend-num{text-align:right}.developments{display:grid;gap:2.5mm}.development{display:grid;grid-template-columns:2mm 1fr;gap:2.5mm;padding-bottom:2.5mm;border-bottom:1px solid var(--line);break-inside:avoid}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendations{display:grid;gap:3mm}.recommendation{display:grid;grid-template-columns:8mm 1fr;gap:3mm;background:var(--bg);padding:3.5mm;break-inside:avoid}.priority{width:7mm;height:7mm;border-radius:50%;background:var(--p);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800}.recommendation p{margin-bottom:1.4mm}.effect{border-top:1px solid #00000010;padding-top:1.5mm}.outlook{padding:5mm;background:var(--p);color:#fff;border-radius:2mm;break-inside:avoid}.outlook .kicker{color:#ffffffb8}.outlook h2{margin-bottom:1.5mm}.outlook p{margin:0}.notes{font-size:6.8pt;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.3pt;color:var(--m);margin-top:2mm}
</style></head><body>
<header class="header"><div class="header-left"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div><div class="brand">Ferienapartments Kuestenblick</div><div class="sub">Apartment Seestern · Nordseekueste</div></div></div><div class="header-right"><div class="kicker">Performance Dashboard</div><div class="period">Mai 2026</div><div class="sub">Erstellt 24.06.2026</div></div></header>
<section class="summary"><div class="summary-main"><div class="kicker">Management Summary</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div><div class="summary-score"><span class="kicker">Status</span><strong></strong><span>positive</span></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<div class="grid"><div><section class="panel"><div class="panel-head"><h2>Monatsverlauf</h2><span class="kicker">April 2026</span></div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div></section><section class="panel"><div class="panel-head"><h2>Wichtige Entwicklungen</h2></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section></div><div><section class="panel"><div class="panel-head"><h2>Prioritäten</h2></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section><section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section></div></div>
<section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
@@ -0,0 +1,66 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Executive Charcoal - Ferienapartments Kuestenblick</title><style>
:root{--p:#252B31;--s:#48525B;--a:#4FA3D1;--t:#20272D;--m:#727C84;--bg:#F0F2F3;--line:#d8e0e5;--pos:#25745b;--neg:#a84444}@page{size:A4;margin:12mm 13mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9pt/1.46 Arial,Arial,sans-serif;background:#fff}h1,h2,h3,p{margin-top:0}h1{font-size:24pt;margin:0;line-height:1.05}h2{font-size:13.5pt;margin-bottom:3mm}h3{font-size:10pt;margin-bottom:1mm}p{margin-bottom:2.5mm}.header{background:linear-gradient(125deg,var(--p),var(--s));color:#fff;border-radius:3mm;padding:7mm;margin-bottom:5mm;display:grid;grid-template-columns:1fr auto;gap:8mm;break-inside:avoid}.header-left{display:flex;gap:4mm;align-items:center}.logo{width:14mm;height:14mm;background:#fff;color:var(--p);border-radius:2mm;display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand{font-weight:700}.sub{font-size:7.5pt;opacity:.78}.header-right{text-align:right}.period{font-size:11pt;font-weight:800}.kicker,.kpi-label,.category{font-size:6.8pt;text-transform:uppercase;letter-spacing:.9px;font-weight:800;color:var(--m)}.header .kicker{color:#ffffffb8}.summary{display:grid;grid-template-columns:1fr 42mm;gap:4mm;margin-bottom:5mm}.summary-main{padding:5mm;border:1px solid var(--line);border-radius:2mm}.summary-main h2{font-size:15pt}.summary-score{background:var(--bg);border-radius:2mm;padding:4mm;display:flex;flex-direction:column;justify-content:center;text-align:center}.summary-score strong{font-size:20pt;color:var(--p)}.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:3mm;margin-bottom:3mm}.kpi{padding:4mm;background:var(--bg);border-top:1.2mm solid var(--p);min-height:29mm;break-inside:avoid}.kpi-value{font-size:15pt;font-weight:800;color:var(--p);margin:2mm 0;white-space:nowrap}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:3mm;margin-bottom:6mm}.fact{border:1px solid var(--line);padding:2.5mm 3mm}.fact span{display:block;font-size:6.8pt;color:var(--m)}.fact strong{display:block;margin-top:.5mm}.grid{display:grid;grid-template-columns:1.18fr .82fr;gap:5mm;align-items:start;break-before:page;break-inside:avoid}.panel{border:1px solid var(--line);border-radius:2mm;padding:4mm;margin-bottom:5mm;break-inside:avoid}.panel-head{display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid var(--line);padding-bottom:2mm;margin-bottom:3mm}.panel-head h2{margin:0}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:17mm 1fr 27mm 21mm;gap:2mm;align-items:center;font-size:7.2pt}.trend-label{font-weight:700}.trend-track{height:4mm;background:#e7ecef;position:relative;border-radius:1mm;overflow:hidden}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1.2mm;background:var(--a);position:absolute;bottom:0;left:0}.trend-num{text-align:right}.developments{display:grid;gap:2.5mm}.development{display:grid;grid-template-columns:2mm 1fr;gap:2.5mm;padding-bottom:2.5mm;border-bottom:1px solid var(--line);break-inside:avoid}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendations{display:grid;gap:3mm}.recommendation{display:grid;grid-template-columns:8mm 1fr;gap:3mm;background:var(--bg);padding:3.5mm;break-inside:avoid}.priority{width:7mm;height:7mm;border-radius:50%;background:var(--p);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800}.recommendation p{margin-bottom:1.4mm}.effect{border-top:1px solid #00000010;padding-top:1.5mm}.outlook{padding:5mm;background:var(--p);color:#fff;border-radius:2mm;break-inside:avoid}.outlook .kicker{color:#ffffffb8}.outlook h2{margin-bottom:1.5mm}.outlook p{margin:0}.notes{font-size:6.8pt;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.3pt;color:var(--m);margin-top:2mm}
</style></head><body>
<header class="header"><div class="header-left"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div><div class="brand">Ferienapartments Kuestenblick</div><div class="sub">Apartment Seestern · Nordseekueste</div></div></div><div class="header-right"><div class="kicker">Performance Dashboard</div><div class="period">Mai 2026</div><div class="sub">Erstellt 24.06.2026</div></div></header>
<section class="summary"><div class="summary-main"><div class="kicker">Management Summary</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div><div class="summary-score"><span class="kicker">Status</span><strong></strong><span>positive</span></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<div class="grid"><div><section class="panel"><div class="panel-head"><h2>Monatsverlauf</h2><span class="kicker">April 2026</span></div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div></section><section class="panel"><div class="panel-head"><h2>Wichtige Entwicklungen</h2></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section></div><div><section class="panel"><div class="panel-head"><h2>Prioritäten</h2></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section><section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section></div></div>
<section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+58
View File
@@ -0,0 +1,58 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Forest Lodge - Ferienapartments Kuestenblick</title><style>
:root{--p:#284E3C;--s:#47715A;--a:#B78B55;--t:#243129;--m:#728079;--bg:#F1F4EF;--line:#d8e0df;--pos:#28765b;--neg:#a54b4b}@page{size:A4;margin:0 13mm 18mm 0}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.1pt/1.48 Georgia,Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:25pt;line-height:1.05;margin-bottom:2mm}h2{font-size:14pt;margin-bottom:3mm}h3{font-size:10.2pt;margin-bottom:1mm}p{margin-bottom:2.7mm}.page{display:grid;grid-template-columns:45mm 1fr;min-height:279mm}.side{background:linear-gradient(180deg,var(--p),var(--s));color:#fff;padding:13mm 7mm 10mm 8mm}.main{padding:13mm 0 0 9mm}.logo{width:15mm;height:15mm;background:#fff;color:var(--p);border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden;margin-bottom:5mm}.logo img{width:100%;height:100%;object-fit:contain;padding:1.3mm}.brand{font-weight:800;font-size:11pt}.side-sub{font-size:7.5pt;opacity:.78;margin-top:1mm}.side-period{margin:18mm 0 10mm}.side-period strong{font-size:18pt;display:block;line-height:1.05}.kicker,.kpi-label,.category{font:800 6.8pt/1.2 Arial,sans-serif;text-transform:uppercase;letter-spacing:1px;color:var(--m)}.side .kicker{color:#ffffffb0}.side-facts{display:grid;gap:4mm;border-top:1px solid #ffffff40;padding-top:5mm}.side-fact span{font-size:7pt;opacity:.7;display:block}.side-fact strong{font-size:11pt}.side-outlook{margin-top:13mm;border-top:1px solid #ffffff40;padding-top:5mm}.side-outlook h3{font-size:11pt}.side-outlook p{font-size:7.6pt;opacity:.88}.intro{margin-bottom:6mm}.intro h1{color:var(--p)}.summary{border-left:1.4mm solid var(--a);padding:1mm 0 1mm 5mm;margin:5mm 0 6mm}.summary h2{font-size:14.5pt}.summary p{margin:0}.kpis{display:grid;grid-template-columns:1fr 1fr;gap:3mm;margin-bottom:5mm}.kpi{background:var(--bg);padding:4mm;border-radius:2mm;break-inside:avoid}.kpi-value{font-size:17pt;font-weight:800;color:var(--p);margin:2mm 0}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:none}.section{margin:6mm 0}.section-head{display:flex;align-items:center;gap:3mm;margin-bottom:3mm}.section-head h2{margin:0;white-space:nowrap}.line{height:1px;background:var(--line);width:100%}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:16mm 1fr 27mm 21mm;gap:2mm;align-items:center;font-size:7.2pt}.trend-label{font-weight:700}.trend-track{height:3.7mm;background:var(--bg);position:relative}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1mm;background:var(--a);position:absolute;bottom:0;left:0}.trend-num{text-align:right}.developments{columns:2;column-gap:5mm}.development{display:grid;grid-template-columns:2mm 1fr;gap:2.5mm;break-inside:avoid;margin-bottom:3mm}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendations{display:grid;gap:3mm}.recommendation{display:grid;grid-template-columns:9mm 1fr;gap:3mm;padding:3.5mm 0;border-top:1px solid var(--line);break-inside:avoid}.priority{font-size:18pt;font-weight:800;color:var(--a)}.recommendation p{margin-bottom:1.3mm}.effect{color:var(--p)}.outlook{display:none}.notes{font-size:6.8pt;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.2pt;color:var(--m);margin-top:2mm}
</style></head><body><div class="page">
<aside class="side"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div class="brand">Ferienapartments Kuestenblick</div><div class="side-sub">Apartment Seestern<br>Nordseekueste</div><div class="side-period"><div class="kicker">Monatsreport</div><strong>Mai 2026</strong><div class="side-sub">Version 1.0</div></div><div class="side-facts"><div class="side-fact"><span>RevPAR</span><strong>99,32 €</strong></div><div class="side-fact"><span>Verkaufte Nächte</span><strong>54</strong></div><div class="side-fact"><span>Ø Aufenthalt</span><strong>3,6</strong></div><div class="side-fact"><span>Stornoquote</span><strong>6,2 %</strong></div></div><div class="side-outlook"><div class="kicker">Ausblick</div><h3>Gute Ausgangslage fuer den Fruehsommer</h3><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></div></aside>
<main class="main"><section class="intro"><div class="kicker">Performance & Handlungsempfehlungen</div><h1>Der Monat<br>im Überblick</h1></section><section class="summary"><div class="kicker">Kurzfazit</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></section><div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div>
<section class="section"><div class="section-head"><h2>Monatsverlauf</h2><div class="line"></div></div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div></section><section class="section"><div class="section-head"><h2>Entwicklungen</h2><div class="line"></div></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section><section class="section"><div class="section-head"><h2>Empfehlungen</h2><div class="line"></div></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div></main></div></body></html>
+29
View File
@@ -0,0 +1,29 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Ledger Blue - Ferienapartments Kuestenblick</title><style>
:root{--p:#294D73;--s:#4B7198;--a:#8AAAC2;--t:#25313C;--m:#71808D;--bg:#EFF3F6;--line:#cbd2ce;--pos:#247159;--neg:#9e4545}@page{size:A4;margin:13mm 14mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:8.7pt/1.45 Courier New,"Courier New",monospace}h1,h2,h3,p{margin-top:0}h1{font-size:24pt;letter-spacing:-1px;margin:0}h2{font-size:12pt;margin-bottom:3mm;text-transform:uppercase;letter-spacing:.6px}h3{font-size:9.3pt;margin-bottom:1mm}p{margin-bottom:2.3mm}.header{border:1px solid var(--p);display:grid;grid-template-columns:1fr 62mm;margin-bottom:5mm}.header-main{padding:5mm}.header-meta{background:var(--p);color:#fff;padding:5mm}.brandline{display:flex;align-items:center;gap:3mm;margin-bottom:4mm}.logo{width:10mm;height:10mm;border:1px solid var(--p);display:flex;align-items:center;justify-content:center;font-weight:800;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:.8mm}.label,.kicker,.kpi-label,.category{font-size:6.5pt;text-transform:uppercase;letter-spacing:.8px;color:var(--m);font-weight:700}.header-meta .label{color:#ffffffad}.header-meta strong{display:block;font-size:13pt;margin:1mm 0 4mm}.summary{border:1px solid var(--line);padding:4mm;margin-bottom:4mm;display:grid;grid-template-columns:26mm 1fr;gap:4mm}.summary-code{font-size:18pt;color:var(--a);font-weight:800}.summary h2{font-size:13pt;text-transform:none}.summary p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);border:1px solid var(--line);margin-bottom:0}.kpi{padding:3.5mm;border-right:1px solid var(--line)}.kpi:last-child{border-right:0}.kpi-value{font-size:13pt;font-weight:800;color:var(--p);margin:2mm 0;white-space:nowrap}.kpi-delta{font-size:6.7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);border:1px solid var(--line);border-top:0;margin-bottom:6mm}.fact{padding:2.5mm 3.5mm;border-right:1px solid var(--line)}.fact:last-child{border-right:0}.fact span{display:block;font-size:6.4pt;color:var(--m)}.fact strong{display:block;margin-top:.5mm}.block{margin-bottom:6mm}.block-head{display:flex;justify-content:space-between;align-items:center;background:var(--bg);border-left:1.2mm solid var(--p);padding:2.5mm 3mm;margin-bottom:2mm}.block-head h2{margin:0}.trend-table{width:100%;border-collapse:collapse;font-size:7.3pt}.trend-table th,.trend-table td{padding:2mm;border:1px solid var(--line)}.trend-table th{text-align:left;background:var(--bg);color:var(--m);font-size:6.3pt;text-transform:uppercase}.trend-table th:not(:first-child),.trend-table td:not(:first-child){text-align:right}.analysis-table{width:100%;border-collapse:collapse}.analysis-table td{border-bottom:1px solid var(--line);padding:3mm 2mm;vertical-align:top}.analysis-table td:first-child{width:7mm;font-weight:800;color:var(--a)}.analysis-table td:nth-child(2){width:42mm;font-weight:800}.analysis-table p{margin:0}.recommendations{display:grid;gap:0;border-top:1px solid var(--line)}.recommendation{display:grid;grid-template-columns:10mm 1fr;gap:3mm;border-bottom:1px solid var(--line);padding:3mm 0;break-inside:avoid}.priority{font-size:14pt;color:var(--p);font-weight:800}.recommendation p{margin-bottom:1.2mm}.effect{background:var(--bg);padding:1.5mm}.outlook{border:1px solid var(--p);padding:4mm;break-inside:avoid}.outlook h2{text-transform:none}.outlook p{margin:0}.notes{font-size:6.5pt;color:var(--m);margin-top:3mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6pt;color:var(--m);margin-top:2mm}.developments{display:none}
</style></head><body>
<header class="header"><div class="header-main"><div class="brandline"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div><strong>Ferienapartments Kuestenblick</strong><div class="label">Apartment Seestern / Nordseekueste</div></div></div><h1>MONATSREPORT</h1></div><div class="header-meta"><div class="label">Berichtsperiode</div><strong>Mai 2026</strong><div class="label">Erstellt</div><div>24.06.2026</div><div class="label" style="margin-top:3mm">Template</div><div>ledger-blue</div></div></header>
<section class="summary"><div class="summary-code">00</div><div><div class="kicker">Executive Summary</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<section class="block"><div class="block-head"><h2>01 / Monatsverlauf</h2><span class="label">Vergleich April 2026</span></div><table class="trend-table">
<thead><tr><th>Monat</th><th>Umsatz</th><th>Auslastung</th><th>Ø Tagespreis</th></tr></thead>
<tbody><tr><td>Dez 25</td><td>4.210,00 €</td><td>55,2 %</td><td>112,30 €</td></tr><tr><td>Jan 26</td><td>3.890,00 €</td><td>51,4 %</td><td>109,85 €</td></tr><tr><td>Feb 26</td><td>4.475,00 €</td><td>59,7 %</td><td>114,20 €</td></tr><tr><td>Mär 26</td><td>5.360,00 €</td><td>66,1 %</td><td>118,75 €</td></tr><tr><td>Apr 26</td><td>6.064,00 €</td><td>72,7 %</td><td>121,10 €</td></tr><tr><td>Mai 26</td><td>6.840,50 €</td><td>78,4 %</td><td>126,68 €</td></tr></tbody>
</table></section>
<section class="block"><div class="block-head"><h2>02 / Entwicklungen</h2><span class="label">Analyse</span></div><table class="analysis-table"><tr><td>01</td><td>Umsatz gewinnt ueberproportional</td><td><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></td></tr><tr><td>02</td><td>Auslastung erreicht ein solides Niveau</td><td><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></td></tr><tr><td>03</td><td>Stornos bleiben ein Beobachtungspunkt</td><td><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></td></tr><tr><td>04</td><td>Aufenthaltsdauer bleibt kompakt</td><td><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></td></tr></table></section>
<section class="block"><div class="block-head"><h2>03 / Massnahmenliste</h2><span class="label">Priorisiert</span></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+29
View File
@@ -0,0 +1,29 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Ledger Green - Ferienapartments Kuestenblick</title><style>
:root{--p:#275F4B;--s:#467A66;--a:#A4864D;--t:#26322D;--m:#748078;--bg:#F1F4F0;--line:#cbd2ce;--pos:#247159;--neg:#9e4545}@page{size:A4;margin:13mm 14mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:8.7pt/1.45 Courier New,"Courier New",monospace}h1,h2,h3,p{margin-top:0}h1{font-size:24pt;letter-spacing:-1px;margin:0}h2{font-size:12pt;margin-bottom:3mm;text-transform:uppercase;letter-spacing:.6px}h3{font-size:9.3pt;margin-bottom:1mm}p{margin-bottom:2.3mm}.header{border:1px solid var(--p);display:grid;grid-template-columns:1fr 62mm;margin-bottom:5mm}.header-main{padding:5mm}.header-meta{background:var(--p);color:#fff;padding:5mm}.brandline{display:flex;align-items:center;gap:3mm;margin-bottom:4mm}.logo{width:10mm;height:10mm;border:1px solid var(--p);display:flex;align-items:center;justify-content:center;font-weight:800;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:.8mm}.label,.kicker,.kpi-label,.category{font-size:6.5pt;text-transform:uppercase;letter-spacing:.8px;color:var(--m);font-weight:700}.header-meta .label{color:#ffffffad}.header-meta strong{display:block;font-size:13pt;margin:1mm 0 4mm}.summary{border:1px solid var(--line);padding:4mm;margin-bottom:4mm;display:grid;grid-template-columns:26mm 1fr;gap:4mm}.summary-code{font-size:18pt;color:var(--a);font-weight:800}.summary h2{font-size:13pt;text-transform:none}.summary p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);border:1px solid var(--line);margin-bottom:0}.kpi{padding:3.5mm;border-right:1px solid var(--line)}.kpi:last-child{border-right:0}.kpi-value{font-size:13pt;font-weight:800;color:var(--p);margin:2mm 0;white-space:nowrap}.kpi-delta{font-size:6.7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);border:1px solid var(--line);border-top:0;margin-bottom:6mm}.fact{padding:2.5mm 3.5mm;border-right:1px solid var(--line)}.fact:last-child{border-right:0}.fact span{display:block;font-size:6.4pt;color:var(--m)}.fact strong{display:block;margin-top:.5mm}.block{margin-bottom:6mm}.block-head{display:flex;justify-content:space-between;align-items:center;background:var(--bg);border-left:1.2mm solid var(--p);padding:2.5mm 3mm;margin-bottom:2mm}.block-head h2{margin:0}.trend-table{width:100%;border-collapse:collapse;font-size:7.3pt}.trend-table th,.trend-table td{padding:2mm;border:1px solid var(--line)}.trend-table th{text-align:left;background:var(--bg);color:var(--m);font-size:6.3pt;text-transform:uppercase}.trend-table th:not(:first-child),.trend-table td:not(:first-child){text-align:right}.analysis-table{width:100%;border-collapse:collapse}.analysis-table td{border-bottom:1px solid var(--line);padding:3mm 2mm;vertical-align:top}.analysis-table td:first-child{width:7mm;font-weight:800;color:var(--a)}.analysis-table td:nth-child(2){width:42mm;font-weight:800}.analysis-table p{margin:0}.recommendations{display:grid;gap:0;border-top:1px solid var(--line)}.recommendation{display:grid;grid-template-columns:10mm 1fr;gap:3mm;border-bottom:1px solid var(--line);padding:3mm 0;break-inside:avoid}.priority{font-size:14pt;color:var(--p);font-weight:800}.recommendation p{margin-bottom:1.2mm}.effect{background:var(--bg);padding:1.5mm}.outlook{border:1px solid var(--p);padding:4mm;break-inside:avoid}.outlook h2{text-transform:none}.outlook p{margin:0}.notes{font-size:6.5pt;color:var(--m);margin-top:3mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6pt;color:var(--m);margin-top:2mm}.developments{display:none}
</style></head><body>
<header class="header"><div class="header-main"><div class="brandline"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div><strong>Ferienapartments Kuestenblick</strong><div class="label">Apartment Seestern / Nordseekueste</div></div></div><h1>MONATSREPORT</h1></div><div class="header-meta"><div class="label">Berichtsperiode</div><strong>Mai 2026</strong><div class="label">Erstellt</div><div>24.06.2026</div><div class="label" style="margin-top:3mm">Template</div><div>ledger-green</div></div></header>
<section class="summary"><div class="summary-code">00</div><div><div class="kicker">Executive Summary</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<section class="block"><div class="block-head"><h2>01 / Monatsverlauf</h2><span class="label">Vergleich April 2026</span></div><table class="trend-table">
<thead><tr><th>Monat</th><th>Umsatz</th><th>Auslastung</th><th>Ø Tagespreis</th></tr></thead>
<tbody><tr><td>Dez 25</td><td>4.210,00 €</td><td>55,2 %</td><td>112,30 €</td></tr><tr><td>Jan 26</td><td>3.890,00 €</td><td>51,4 %</td><td>109,85 €</td></tr><tr><td>Feb 26</td><td>4.475,00 €</td><td>59,7 %</td><td>114,20 €</td></tr><tr><td>Mär 26</td><td>5.360,00 €</td><td>66,1 %</td><td>118,75 €</td></tr><tr><td>Apr 26</td><td>6.064,00 €</td><td>72,7 %</td><td>121,10 €</td></tr><tr><td>Mai 26</td><td>6.840,50 €</td><td>78,4 %</td><td>126,68 €</td></tr></tbody>
</table></section>
<section class="block"><div class="block-head"><h2>02 / Entwicklungen</h2><span class="label">Analyse</span></div><table class="analysis-table"><tr><td>01</td><td>Umsatz gewinnt ueberproportional</td><td><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></td></tr><tr><td>02</td><td>Auslastung erreicht ein solides Niveau</td><td><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></td></tr><tr><td>03</td><td>Stornos bleiben ein Beobachtungspunkt</td><td><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></td></tr><tr><td>04</td><td>Aufenthaltsdauer bleibt kompakt</td><td><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></td></tr></table></section>
<section class="block"><div class="block-head"><h2>03 / Massnahmenliste</h2><span class="label">Priorisiert</span></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+29
View File
@@ -0,0 +1,29 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Ledger Sepia - Ferienapartments Kuestenblick</title><style>
:root{--p:#664B38;--s:#8A6A51;--a:#B5784E;--t:#382E28;--m:#7F746C;--bg:#F6F0E7;--line:#cbd2ce;--pos:#247159;--neg:#9e4545}@page{size:A4;margin:13mm 14mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:8.7pt/1.45 Courier New,"Courier New",monospace}h1,h2,h3,p{margin-top:0}h1{font-size:24pt;letter-spacing:-1px;margin:0}h2{font-size:12pt;margin-bottom:3mm;text-transform:uppercase;letter-spacing:.6px}h3{font-size:9.3pt;margin-bottom:1mm}p{margin-bottom:2.3mm}.header{border:1px solid var(--p);display:grid;grid-template-columns:1fr 62mm;margin-bottom:5mm}.header-main{padding:5mm}.header-meta{background:var(--p);color:#fff;padding:5mm}.brandline{display:flex;align-items:center;gap:3mm;margin-bottom:4mm}.logo{width:10mm;height:10mm;border:1px solid var(--p);display:flex;align-items:center;justify-content:center;font-weight:800;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:.8mm}.label,.kicker,.kpi-label,.category{font-size:6.5pt;text-transform:uppercase;letter-spacing:.8px;color:var(--m);font-weight:700}.header-meta .label{color:#ffffffad}.header-meta strong{display:block;font-size:13pt;margin:1mm 0 4mm}.summary{border:1px solid var(--line);padding:4mm;margin-bottom:4mm;display:grid;grid-template-columns:26mm 1fr;gap:4mm}.summary-code{font-size:18pt;color:var(--a);font-weight:800}.summary h2{font-size:13pt;text-transform:none}.summary p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);border:1px solid var(--line);margin-bottom:0}.kpi{padding:3.5mm;border-right:1px solid var(--line)}.kpi:last-child{border-right:0}.kpi-value{font-size:13pt;font-weight:800;color:var(--p);margin:2mm 0;white-space:nowrap}.kpi-delta{font-size:6.7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);border:1px solid var(--line);border-top:0;margin-bottom:6mm}.fact{padding:2.5mm 3.5mm;border-right:1px solid var(--line)}.fact:last-child{border-right:0}.fact span{display:block;font-size:6.4pt;color:var(--m)}.fact strong{display:block;margin-top:.5mm}.block{margin-bottom:6mm}.block-head{display:flex;justify-content:space-between;align-items:center;background:var(--bg);border-left:1.2mm solid var(--p);padding:2.5mm 3mm;margin-bottom:2mm}.block-head h2{margin:0}.trend-table{width:100%;border-collapse:collapse;font-size:7.3pt}.trend-table th,.trend-table td{padding:2mm;border:1px solid var(--line)}.trend-table th{text-align:left;background:var(--bg);color:var(--m);font-size:6.3pt;text-transform:uppercase}.trend-table th:not(:first-child),.trend-table td:not(:first-child){text-align:right}.analysis-table{width:100%;border-collapse:collapse}.analysis-table td{border-bottom:1px solid var(--line);padding:3mm 2mm;vertical-align:top}.analysis-table td:first-child{width:7mm;font-weight:800;color:var(--a)}.analysis-table td:nth-child(2){width:42mm;font-weight:800}.analysis-table p{margin:0}.recommendations{display:grid;gap:0;border-top:1px solid var(--line)}.recommendation{display:grid;grid-template-columns:10mm 1fr;gap:3mm;border-bottom:1px solid var(--line);padding:3mm 0;break-inside:avoid}.priority{font-size:14pt;color:var(--p);font-weight:800}.recommendation p{margin-bottom:1.2mm}.effect{background:var(--bg);padding:1.5mm}.outlook{border:1px solid var(--p);padding:4mm;break-inside:avoid}.outlook h2{text-transform:none}.outlook p{margin:0}.notes{font-size:6.5pt;color:var(--m);margin-top:3mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6pt;color:var(--m);margin-top:2mm}.developments{display:none}
</style></head><body>
<header class="header"><div class="header-main"><div class="brandline"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div><strong>Ferienapartments Kuestenblick</strong><div class="label">Apartment Seestern / Nordseekueste</div></div></div><h1>MONATSREPORT</h1></div><div class="header-meta"><div class="label">Berichtsperiode</div><strong>Mai 2026</strong><div class="label">Erstellt</div><div>24.06.2026</div><div class="label" style="margin-top:3mm">Template</div><div>ledger-sepia</div></div></header>
<section class="summary"><div class="summary-code">00</div><div><div class="kicker">Executive Summary</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<section class="block"><div class="block-head"><h2>01 / Monatsverlauf</h2><span class="label">Vergleich April 2026</span></div><table class="trend-table">
<thead><tr><th>Monat</th><th>Umsatz</th><th>Auslastung</th><th>Ø Tagespreis</th></tr></thead>
<tbody><tr><td>Dez 25</td><td>4.210,00 €</td><td>55,2 %</td><td>112,30 €</td></tr><tr><td>Jan 26</td><td>3.890,00 €</td><td>51,4 %</td><td>109,85 €</td></tr><tr><td>Feb 26</td><td>4.475,00 €</td><td>59,7 %</td><td>114,20 €</td></tr><tr><td>Mär 26</td><td>5.360,00 €</td><td>66,1 %</td><td>118,75 €</td></tr><tr><td>Apr 26</td><td>6.064,00 €</td><td>72,7 %</td><td>121,10 €</td></tr><tr><td>Mai 26</td><td>6.840,50 €</td><td>78,4 %</td><td>126,68 €</td></tr></tbody>
</table></section>
<section class="block"><div class="block-head"><h2>02 / Entwicklungen</h2><span class="label">Analyse</span></div><table class="analysis-table"><tr><td>01</td><td>Umsatz gewinnt ueberproportional</td><td><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></td></tr><tr><td>02</td><td>Auslastung erreicht ein solides Niveau</td><td><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></td></tr><tr><td>03</td><td>Stornos bleiben ein Beobachtungspunkt</td><td><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></td></tr><tr><td>04</td><td>Aufenthaltsdauer bleibt kompakt</td><td><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></td></tr></table></section>
<section class="block"><div class="block-head"><h2>03 / Massnahmenliste</h2><span class="label">Priorisiert</span></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+67
View File
@@ -0,0 +1,67 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Magazine Citrus - Ferienapartments Kuestenblick</title><style>
:root{--p:#245443;--s:#3E8063;--a:#E6C84A;--t:#20312A;--m:#6E7C75;--bg:#F2F6E9;--line:#d7dce2;--pos:#24725a;--neg:#a24048}@page{size:A4;margin:12mm 14mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.1pt/1.47 Arial,Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:39pt;line-height:.88;letter-spacing:-2px;margin:0;text-transform:uppercase}h2{font-size:16pt;line-height:1.08;margin-bottom:3mm}h3{font-size:10.5pt;margin-bottom:1mm}p{margin-bottom:2.6mm}.cover{display:grid;grid-template-columns:1fr 53mm;min-height:73mm;margin-bottom:6mm;break-inside:avoid}.cover-main{background:var(--p);color:#fff;padding:7mm;position:relative;overflow:hidden}.cover-main:after{content:"";position:absolute;width:60mm;height:60mm;border:10mm solid #ffffff0f;border-radius:50%;right:-24mm;bottom:-30mm}.cover-side{background:var(--a);padding:6mm 5mm;display:flex;flex-direction:column;justify-content:space-between;color:var(--t)}.logo{width:14mm;height:14mm;background:#fff;color:var(--p);display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand{margin-top:4mm;font-weight:800}.location{font-size:7.5pt;opacity:.76}.cover-title{position:absolute;left:7mm;bottom:7mm;z-index:1}.cover-title .kicker{color:#ffffffb8}.issue-num{font-size:36pt;font-weight:900;line-height:1;color:var(--p)}.issue-label{font-size:7pt;text-transform:uppercase;letter-spacing:1px;font-weight:800}.kicker,.kpi-label,.category{font-size:6.7pt;text-transform:uppercase;letter-spacing:1.1px;font-weight:900;color:var(--m)}.summary{display:grid;grid-template-columns:52mm 1fr;gap:6mm;padding:5mm 0;border-bottom:1px solid var(--line);margin-bottom:5mm}.summary-mark{font-size:22pt;font-weight:900;color:var(--a);line-height:1}.summary h2{font-size:17pt}.summary p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:2mm;margin-bottom:3mm}.kpi{padding:4mm;background:var(--bg);border-bottom:1.2mm solid var(--p);min-height:29mm}.kpi:nth-child(2n){border-bottom-color:var(--a)}.kpi-value{font-size:16pt;font-weight:900;margin:2mm 0;color:var(--p);white-space:nowrap}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:2mm;margin-bottom:7mm}.fact{padding:2.2mm 3mm;border:1px solid var(--line)}.fact span{display:block;font-size:6.7pt;color:var(--m)}.fact strong{display:block;margin-top:.7mm}.section-head{display:grid;grid-template-columns:13mm 1fr;gap:3mm;align-items:center;margin:7mm 0 3mm}.section-no{font-size:18pt;font-weight:900;color:var(--a)}.section-head h2{margin:0;border-bottom:1px solid var(--line);padding-bottom:2mm}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:18mm 1fr 28mm 22mm;gap:2.5mm;align-items:center;font-size:7.4pt}.trend-label{font-weight:800}.trend-track{height:5mm;background:var(--bg);position:relative;overflow:hidden}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1.3mm;background:var(--a);position:absolute;left:0;bottom:0}.trend-num{text-align:right}.feature-grid{display:grid;grid-template-columns:1fr 1fr;gap:5mm;break-before:page;break-inside:avoid}.developments,.recommendations{display:grid;gap:3mm}.development{background:var(--bg);padding:3.5mm;break-inside:avoid;border-top:1mm solid var(--m)}.development.positive{border-top-color:var(--pos)}.development.negative{border-top-color:var(--neg)}.development{display:grid;grid-template-columns:0 1fr;gap:0}.development .impact{display:none}.development p{margin:0}.recommendation{display:grid;grid-template-columns:9mm 1fr;gap:3mm;border:1px solid var(--line);padding:3.5mm;break-inside:avoid}.priority{font-size:19pt;font-weight:900;color:var(--a)}.recommendation p{margin-bottom:1.3mm}.effect{color:var(--p);font-weight:600}.outlook{margin-top:7mm;background:linear-gradient(110deg,var(--p),var(--s));color:#fff;padding:6mm;break-inside:avoid}.outlook .kicker{color:#ffffffb8}.outlook p{margin:0}.notes{font-size:6.8pt;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.2pt;color:var(--m);margin-top:2mm}
</style></head><body>
<section class="cover"><div class="cover-main"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div class="brand">Ferienapartments Kuestenblick</div><div class="location">Apartment Seestern · Nordseekueste</div><div class="cover-title"><div class="kicker">Performance / Strategie / Ausblick</div><h1>Monats<br>report</h1></div></div><div class="cover-side"><div><div class="issue-label">Ausgabe</div><div class="issue-num">05</div></div><div><div class="issue-label">Zeitraum</div><strong>Mai 2026</strong><div class="location">24.06.2026</div></div></div></section>
<section class="summary"><div><div class="summary-mark"></div><div class="kicker">Kurzfazit</div></div><div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<div class="section-head"><div class="section-no">01</div><h2>Monatsverlauf</h2></div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div>
<div class="feature-grid"><section><div class="section-head"><div class="section-no">02</div><h2>Entwicklungen</h2></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section><section><div class="section-head"><div class="section-no">03</div><h2>Empfehlungen</h2></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section></div>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+67
View File
@@ -0,0 +1,67 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Magazine Cobalt - Ferienapartments Kuestenblick</title><style>
:root{--p:#1749A3;--s:#2F72D6;--a:#F3C342;--t:#172438;--m:#66758A;--bg:#EEF3FA;--line:#d7dce2;--pos:#24725a;--neg:#a24048}@page{size:A4;margin:12mm 14mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.1pt/1.47 Arial,Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:39pt;line-height:.88;letter-spacing:-2px;margin:0;text-transform:uppercase}h2{font-size:16pt;line-height:1.08;margin-bottom:3mm}h3{font-size:10.5pt;margin-bottom:1mm}p{margin-bottom:2.6mm}.cover{display:grid;grid-template-columns:1fr 53mm;min-height:73mm;margin-bottom:6mm;break-inside:avoid}.cover-main{background:var(--p);color:#fff;padding:7mm;position:relative;overflow:hidden}.cover-main:after{content:"";position:absolute;width:60mm;height:60mm;border:10mm solid #ffffff0f;border-radius:50%;right:-24mm;bottom:-30mm}.cover-side{background:var(--a);padding:6mm 5mm;display:flex;flex-direction:column;justify-content:space-between;color:var(--t)}.logo{width:14mm;height:14mm;background:#fff;color:var(--p);display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand{margin-top:4mm;font-weight:800}.location{font-size:7.5pt;opacity:.76}.cover-title{position:absolute;left:7mm;bottom:7mm;z-index:1}.cover-title .kicker{color:#ffffffb8}.issue-num{font-size:36pt;font-weight:900;line-height:1;color:var(--p)}.issue-label{font-size:7pt;text-transform:uppercase;letter-spacing:1px;font-weight:800}.kicker,.kpi-label,.category{font-size:6.7pt;text-transform:uppercase;letter-spacing:1.1px;font-weight:900;color:var(--m)}.summary{display:grid;grid-template-columns:52mm 1fr;gap:6mm;padding:5mm 0;border-bottom:1px solid var(--line);margin-bottom:5mm}.summary-mark{font-size:22pt;font-weight:900;color:var(--a);line-height:1}.summary h2{font-size:17pt}.summary p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:2mm;margin-bottom:3mm}.kpi{padding:4mm;background:var(--bg);border-bottom:1.2mm solid var(--p);min-height:29mm}.kpi:nth-child(2n){border-bottom-color:var(--a)}.kpi-value{font-size:16pt;font-weight:900;margin:2mm 0;color:var(--p);white-space:nowrap}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:2mm;margin-bottom:7mm}.fact{padding:2.2mm 3mm;border:1px solid var(--line)}.fact span{display:block;font-size:6.7pt;color:var(--m)}.fact strong{display:block;margin-top:.7mm}.section-head{display:grid;grid-template-columns:13mm 1fr;gap:3mm;align-items:center;margin:7mm 0 3mm}.section-no{font-size:18pt;font-weight:900;color:var(--a)}.section-head h2{margin:0;border-bottom:1px solid var(--line);padding-bottom:2mm}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:18mm 1fr 28mm 22mm;gap:2.5mm;align-items:center;font-size:7.4pt}.trend-label{font-weight:800}.trend-track{height:5mm;background:var(--bg);position:relative;overflow:hidden}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1.3mm;background:var(--a);position:absolute;left:0;bottom:0}.trend-num{text-align:right}.feature-grid{display:grid;grid-template-columns:1fr 1fr;gap:5mm;break-before:page;break-inside:avoid}.developments,.recommendations{display:grid;gap:3mm}.development{background:var(--bg);padding:3.5mm;break-inside:avoid;border-top:1mm solid var(--m)}.development.positive{border-top-color:var(--pos)}.development.negative{border-top-color:var(--neg)}.development{display:grid;grid-template-columns:0 1fr;gap:0}.development .impact{display:none}.development p{margin:0}.recommendation{display:grid;grid-template-columns:9mm 1fr;gap:3mm;border:1px solid var(--line);padding:3.5mm;break-inside:avoid}.priority{font-size:19pt;font-weight:900;color:var(--a)}.recommendation p{margin-bottom:1.3mm}.effect{color:var(--p);font-weight:600}.outlook{margin-top:7mm;background:linear-gradient(110deg,var(--p),var(--s));color:#fff;padding:6mm;break-inside:avoid}.outlook .kicker{color:#ffffffb8}.outlook p{margin:0}.notes{font-size:6.8pt;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.2pt;color:var(--m);margin-top:2mm}
</style></head><body>
<section class="cover"><div class="cover-main"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div class="brand">Ferienapartments Kuestenblick</div><div class="location">Apartment Seestern · Nordseekueste</div><div class="cover-title"><div class="kicker">Performance / Strategie / Ausblick</div><h1>Monats<br>report</h1></div></div><div class="cover-side"><div><div class="issue-label">Ausgabe</div><div class="issue-num">05</div></div><div><div class="issue-label">Zeitraum</div><strong>Mai 2026</strong><div class="location">24.06.2026</div></div></div></section>
<section class="summary"><div><div class="summary-mark"></div><div class="kicker">Kurzfazit</div></div><div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<div class="section-head"><div class="section-no">01</div><h2>Monatsverlauf</h2></div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div>
<div class="feature-grid"><section><div class="section-head"><div class="section-no">02</div><h2>Entwicklungen</h2></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section><section><div class="section-head"><div class="section-no">03</div><h2>Empfehlungen</h2></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section></div>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+67
View File
@@ -0,0 +1,67 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Magazine Plum - Ferienapartments Kuestenblick</title><style>
:root{--p:#5A2D67;--s:#814696;--a:#E8A875;--t:#302536;--m:#796D7E;--bg:#F7F0F8;--line:#d7dce2;--pos:#24725a;--neg:#a24048}@page{size:A4;margin:12mm 14mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.1pt/1.47 Arial,Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:39pt;line-height:.88;letter-spacing:-2px;margin:0;text-transform:uppercase}h2{font-size:16pt;line-height:1.08;margin-bottom:3mm}h3{font-size:10.5pt;margin-bottom:1mm}p{margin-bottom:2.6mm}.cover{display:grid;grid-template-columns:1fr 53mm;min-height:73mm;margin-bottom:6mm;break-inside:avoid}.cover-main{background:var(--p);color:#fff;padding:7mm;position:relative;overflow:hidden}.cover-main:after{content:"";position:absolute;width:60mm;height:60mm;border:10mm solid #ffffff0f;border-radius:50%;right:-24mm;bottom:-30mm}.cover-side{background:var(--a);padding:6mm 5mm;display:flex;flex-direction:column;justify-content:space-between;color:var(--t)}.logo{width:14mm;height:14mm;background:#fff;color:var(--p);display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand{margin-top:4mm;font-weight:800}.location{font-size:7.5pt;opacity:.76}.cover-title{position:absolute;left:7mm;bottom:7mm;z-index:1}.cover-title .kicker{color:#ffffffb8}.issue-num{font-size:36pt;font-weight:900;line-height:1;color:var(--p)}.issue-label{font-size:7pt;text-transform:uppercase;letter-spacing:1px;font-weight:800}.kicker,.kpi-label,.category{font-size:6.7pt;text-transform:uppercase;letter-spacing:1.1px;font-weight:900;color:var(--m)}.summary{display:grid;grid-template-columns:52mm 1fr;gap:6mm;padding:5mm 0;border-bottom:1px solid var(--line);margin-bottom:5mm}.summary-mark{font-size:22pt;font-weight:900;color:var(--a);line-height:1}.summary h2{font-size:17pt}.summary p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:2mm;margin-bottom:3mm}.kpi{padding:4mm;background:var(--bg);border-bottom:1.2mm solid var(--p);min-height:29mm}.kpi:nth-child(2n){border-bottom-color:var(--a)}.kpi-value{font-size:16pt;font-weight:900;margin:2mm 0;color:var(--p);white-space:nowrap}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:2mm;margin-bottom:7mm}.fact{padding:2.2mm 3mm;border:1px solid var(--line)}.fact span{display:block;font-size:6.7pt;color:var(--m)}.fact strong{display:block;margin-top:.7mm}.section-head{display:grid;grid-template-columns:13mm 1fr;gap:3mm;align-items:center;margin:7mm 0 3mm}.section-no{font-size:18pt;font-weight:900;color:var(--a)}.section-head h2{margin:0;border-bottom:1px solid var(--line);padding-bottom:2mm}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:18mm 1fr 28mm 22mm;gap:2.5mm;align-items:center;font-size:7.4pt}.trend-label{font-weight:800}.trend-track{height:5mm;background:var(--bg);position:relative;overflow:hidden}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1.3mm;background:var(--a);position:absolute;left:0;bottom:0}.trend-num{text-align:right}.feature-grid{display:grid;grid-template-columns:1fr 1fr;gap:5mm;break-before:page;break-inside:avoid}.developments,.recommendations{display:grid;gap:3mm}.development{background:var(--bg);padding:3.5mm;break-inside:avoid;border-top:1mm solid var(--m)}.development.positive{border-top-color:var(--pos)}.development.negative{border-top-color:var(--neg)}.development{display:grid;grid-template-columns:0 1fr;gap:0}.development .impact{display:none}.development p{margin:0}.recommendation{display:grid;grid-template-columns:9mm 1fr;gap:3mm;border:1px solid var(--line);padding:3.5mm;break-inside:avoid}.priority{font-size:19pt;font-weight:900;color:var(--a)}.recommendation p{margin-bottom:1.3mm}.effect{color:var(--p);font-weight:600}.outlook{margin-top:7mm;background:linear-gradient(110deg,var(--p),var(--s));color:#fff;padding:6mm;break-inside:avoid}.outlook .kicker{color:#ffffffb8}.outlook p{margin:0}.notes{font-size:6.8pt;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.2pt;color:var(--m);margin-top:2mm}
</style></head><body>
<section class="cover"><div class="cover-main"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div class="brand">Ferienapartments Kuestenblick</div><div class="location">Apartment Seestern · Nordseekueste</div><div class="cover-title"><div class="kicker">Performance / Strategie / Ausblick</div><h1>Monats<br>report</h1></div></div><div class="cover-side"><div><div class="issue-label">Ausgabe</div><div class="issue-num">05</div></div><div><div class="issue-label">Zeitraum</div><strong>Mai 2026</strong><div class="location">24.06.2026</div></div></div></section>
<section class="summary"><div><div class="summary-mark"></div><div class="kicker">Kurzfazit</div></div><div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<div class="section-head"><div class="section-no">01</div><h2>Monatsverlauf</h2></div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div>
<div class="feature-grid"><section><div class="section-head"><div class="section-no">02</div><h2>Entwicklungen</h2></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section><section><div class="section-head"><div class="section-no">03</div><h2>Empfehlungen</h2></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section></div>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+436
View File
@@ -0,0 +1,436 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Monatsreport Mai 2026 - Ferienapartments Kuestenblick</title>
<style>
:root {
--primary: #172A42;
--secondary: #284967;
--accent: #D2A64C;
--text: #1B2733;
--muted: #6F7C87;
--surface: #EFF2F4;
--line: #dfe5e8;
--positive: #207a5a;
--neutral: #667680;
--negative: #b14949;
--watch: #9a6815;
}
@page {
size: A4;
margin: 13mm 14mm 18mm 14mm;
}
* { box-sizing: border-box; }
html { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
body {
margin: 0;
color: var(--text);
font-family: Georgia, Arial, sans-serif;
font-size: 9.3pt;
line-height: 1.48;
background: #fff;
}
h1, h2, h3, p { margin-top: 0; }
h1 { font-size: 27pt; line-height: 1.08; letter-spacing: -0.6px; margin-bottom: 2mm; }
h2 { font-size: 14.5pt; line-height: 1.2; margin-bottom: 4mm; }
h3 { font-size: 10.8pt; line-height: 1.25; margin-bottom: 1.5mm; }
p { margin-bottom: 3mm; }
.cover {
position: relative;
overflow: hidden;
min-height: 67mm;
padding: 9mm;
border-radius: 5mm;
color: #fff;
background: linear-gradient(128deg, var(--primary), var(--secondary));
margin-bottom: 7mm;
break-inside: avoid;
}
.cover::after {
content: "";
position: absolute;
width: 92mm;
height: 92mm;
right: -27mm;
top: -42mm;
border: 12mm solid rgba(255,255,255,.08);
border-radius: 50%;
}
.cover-top { display: flex; align-items: center; justify-content: space-between; gap: 8mm; position: relative; z-index: 1; }
.brand { display: flex; align-items: center; gap: 4mm; }
.logo {
width: 15mm; height: 15mm; border-radius: 4mm;
background: rgba(255,255,255,.96); color: var(--primary);
display: flex; align-items: center; justify-content: center; font-size: 15pt; font-weight: 800;
box-shadow: 0 2mm 5mm rgba(0,0,0,.12);
overflow: hidden;
}
.logo img { width: 100%; height: 100%; object-fit: contain; padding: 1.6mm; }
.brand-name { font-size: 11pt; font-weight: 700; }
.brand-sub { font-size: 8pt; opacity: .82; }
.period-chip {
padding: 2.2mm 4mm; border-radius: 99mm;
border: .25mm solid rgba(255,255,255,.38);
background: rgba(255,255,255,.12); font-size: 8.3pt; font-weight: 700;
}
.cover-main { position: relative; z-index: 1; margin-top: 13mm; max-width: 142mm; }
.eyebrow { text-transform: uppercase; letter-spacing: 1.7px; font-size: 7.2pt; font-weight: 800; opacity: .78; margin-bottom: 2.2mm; }
.cover-meta { display: flex; flex-wrap: wrap; gap: 3mm 8mm; font-size: 8.4pt; opacity: .88; }
.section { margin-bottom: 7mm; }
.section-heading { display: flex; align-items: flex-end; justify-content: space-between; gap: 5mm; margin-bottom: 3.5mm; }
.section-heading h2 { margin: 0; }
.section-kicker { font-size: 7.3pt; font-weight: 800; color: var(--muted); text-transform: uppercase; letter-spacing: 1.2px; margin-bottom: 1mm; }
.summary {
display: grid; grid-template-columns: 10mm 1fr; gap: 4mm;
padding: 5mm; border-radius: 3mm; background: var(--surface);
border-left: 1.5mm solid var(--accent); break-inside: avoid;
}
.summary-icon {
width: 9mm; height: 9mm; border-radius: 50%;
display: flex; align-items: center; justify-content: center; align-self: start; color: #fff; font-weight: 900; margin-top: .5mm;
}
.summary-icon.positive { background: var(--positive); }
.summary-icon.neutral { background: var(--neutral); }
.summary-icon.watch { background: var(--watch); }
.summary h2 { font-size: 14pt; margin-bottom: 2mm; }
.summary p { margin-bottom: 0; }
.kpi-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 3mm; }
.kpi-card {
min-height: 31mm; padding: 4mm; border: .25mm solid var(--line);
border-radius: 3mm; break-inside: avoid; background: #fff;
}
.kpi-label { font-size: 7.3pt; text-transform: uppercase; letter-spacing: .8px; color: var(--muted); font-weight: 800; }
.kpi-value { font-size: 16pt; font-weight: 800; color: var(--primary); line-height: 1.15; margin: 3mm 0 1.5mm; white-space: nowrap; }
.kpi-delta { font-size: 7.6pt; color: var(--muted); }
.delta-positive { color: var(--positive); font-weight: 700; }
.delta-negative { color: var(--negative); font-weight: 700; }
.detail-strip {
display: grid; grid-template-columns: repeat(4, 1fr); gap: 0;
border: .25mm solid var(--line); border-radius: 3mm; overflow: hidden; margin-top: 3mm;
}
.detail-item { padding: 3mm 4mm; border-right: .25mm solid var(--line); }
.detail-item:last-child { border-right: 0; }
.detail-label { font-size: 7.2pt; color: var(--muted); }
.detail-value { font-weight: 800; margin-top: .8mm; }
.trend-panel {
border: .25mm solid var(--line); border-radius: 3mm; padding: 5mm;
break-inside: avoid;
}
.trend-legend { display: flex; gap: 5mm; font-size: 7.4pt; color: var(--muted); }
.legend-dot { width: 2.2mm; height: 2.2mm; border-radius: 50%; display: inline-block; margin-right: 1.2mm; }
.legend-revenue { background: var(--primary); }
.legend-occ { background: var(--accent); }
.trend-grid { display: block; margin-top: 3mm; }
.trend-row { display: grid; grid-template-columns: 20mm 1fr 25mm 25mm; align-items: center; gap: 2mm; margin-top: 2mm; }
.trend-label { font-weight: 700; font-size: 8pt; }
.bar-track { height: 4mm; border-radius: 99mm; background: #edf1f3; overflow: hidden; position: relative; }
.bar { height: 100%; border-radius: inherit; }
.bar-revenue { background: var(--primary); }
.bar-occ { background: var(--accent); height: 1.5mm; position: absolute; left: 0; bottom: 0; }
.trend-number { text-align: right; font-size: 7.7pt; font-variant-numeric: tabular-nums; }
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 5mm; align-items: start; }
.development-list { display: grid; gap: 3mm; }
.development {
border: .25mm solid var(--line); border-radius: 3mm; padding: 4mm;
break-inside: avoid;
}
.development-top { display: flex; align-items: center; gap: 2mm; margin-bottom: 1.5mm; }
.impact-dot { width: 2.5mm; height: 2.5mm; border-radius: 50%; flex: 0 0 auto; }
.impact-dot.positive { background: var(--positive); }
.impact-dot.neutral { background: var(--neutral); }
.impact-dot.negative { background: var(--negative); }
.development p { margin: 0; color: #35434a; }
.recommendations { display: grid; gap: 3.5mm; }
.recommendation {
display: grid; grid-template-columns: 11mm 1fr; gap: 4mm;
padding: 4.5mm; border-radius: 3mm; background: var(--surface);
border: .25mm solid #d7e1e2;
break-inside: avoid;
}
.priority {
width: 10mm; height: 10mm; border-radius: 3mm; background: var(--primary); color: #fff;
display: flex; align-items: center; justify-content: center; align-self: start; font-weight: 900; font-size: 12pt;
}
.category { color: var(--primary); font-size: 7.2pt; font-weight: 900; text-transform: uppercase; letter-spacing: .8px; }
.recommendation h3 { font-size: 11.3pt; margin: .8mm 0 2mm; }
.recommendation p { margin-bottom: 2mm; }
.recommendation p:last-child { margin-bottom: 0; }
.action-line { padding-top: 2mm; border-top: .25mm solid rgba(0,0,0,.08); }
.outlook {
padding: 5mm; color: #fff; border-radius: 3mm;
background: linear-gradient(115deg, var(--primary), var(--secondary));
break-inside: avoid;
}
.outlook h2 { margin-bottom: 2mm; }
.outlook p { margin: 0; opacity: .94; }
.notes {
margin-top: 4mm; padding: 3.5mm 4mm; border-radius: 2mm;
background: #f7f8f9; color: var(--muted); font-size: 7.5pt;
break-inside: avoid;
}
.notes ul { margin: 1.5mm 0 0; padding-left: 4mm; }
.notes li { margin-bottom: .8mm; }
.legal { margin-top: 4mm; color: var(--muted); font-size: 6.9pt; }
.page-break { break-before: page; }
.avoid { break-inside: avoid; }
@media print {
.section:last-child { margin-bottom: 0; }
}
</style>
</head>
<body>
<main>
<section class="cover">
<div class="cover-top">
<div class="brand">
<div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo">
</div>
<div>
<div class="brand-name">Ferienapartments Kuestenblick</div>
<div class="brand-sub">Apartment Seestern</div>
</div>
</div>
<div class="period-chip">Mai 2026</div>
</div>
<div class="cover-main">
<div class="eyebrow">Performance & Handlungsempfehlungen</div>
<h1>Monatsreport</h1>
<div class="cover-meta">
<span>Nordseekueste</span>
<span>Erstellt am 24.06.2026</span>
<span>Version 1.0</span>
</div>
</div>
</section>
<section class="section">
<div class="summary">
<div class="summary-icon positive">
</div>
<div>
<div class="section-kicker">Kurzfazit</div>
<h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2>
<p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p>
</div>
</div>
</section>
<section class="section">
<div class="section-heading">
<div>
<div class="section-kicker">Kennzahlen</div>
<h2>Der Monat auf einen Blick</h2>
</div>
<div class="section-kicker">Vergleich: April 2026</div>
</div>
<div class="kpi-grid">
<article class="kpi-card">
<div class="kpi-label">Umsatz</div>
<div class="kpi-value">6.840,50 €</div>
<div class="kpi-delta delta-positive">
+12,8 %
</div>
</article>
<article class="kpi-card">
<div class="kpi-label">Auslastung</div>
<div class="kpi-value">78,4 %</div>
<div class="kpi-delta delta-positive">
+5,7 PP
</div>
</article>
<article class="kpi-card">
<div class="kpi-label">Ø Tagespreis</div>
<div class="kpi-value">126,68 €</div>
<div class="kpi-delta delta-positive">
+4,6 %
</div>
</article>
<article class="kpi-card">
<div class="kpi-label">Buchungen</div>
<div class="kpi-value">19</div>
<div class="kpi-delta delta-positive">
+2 Buchungen
</div>
</article>
</div>
<div class="detail-strip">
<div class="detail-item"><div class="detail-label">RevPAR</div><div class="detail-value">99,32 €</div></div>
<div class="detail-item"><div class="detail-label">Verkaufte Nächte</div><div class="detail-value">54</div></div>
<div class="detail-item"><div class="detail-label">Ø Aufenthaltsdauer</div><div class="detail-value">3,6 Nächte</div></div>
<div class="detail-item"><div class="detail-label">Stornoquote</div><div class="detail-value">6,2 %</div></div>
</div>
</section>
<section class="section">
<div class="section-heading">
<div>
<div class="section-kicker">Verlauf</div>
<h2>Entwicklung der letzten Monate</h2>
</div>
<div class="trend-legend">
<span><i class="legend-dot legend-revenue"></i> Umsatz</span>
<span><i class="legend-dot legend-occ"></i> Auslastung</span>
</div>
</div>
<div class="trend-panel">
<div class="trend-grid">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 61.55%"></div>
<div class="bar bar-occ" style="width: 55.2%"></div>
</div>
<div class="trend-number">4.210,00 €</div>
<div class="trend-number">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 56.87%"></div>
<div class="bar bar-occ" style="width: 51.4%"></div>
</div>
<div class="trend-number">3.890,00 €</div>
<div class="trend-number">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 65.42%"></div>
<div class="bar bar-occ" style="width: 59.7%"></div>
</div>
<div class="trend-number">4.475,00 €</div>
<div class="trend-number">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 78.36%"></div>
<div class="bar bar-occ" style="width: 66.1%"></div>
</div>
<div class="trend-number">5.360,00 €</div>
<div class="trend-number">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 88.65%"></div>
<div class="bar bar-occ" style="width: 72.7%"></div>
</div>
<div class="trend-number">6.064,00 €</div>
<div class="trend-number">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 100%"></div>
<div class="bar bar-occ" style="width: 78.4%"></div>
</div>
<div class="trend-number">6.840,50 €</div>
<div class="trend-number">78,4 %</div>
</div>
</div>
</div>
</section>
<section class="section">
<div class="section-heading">
<div>
<div class="section-kicker">Analyse</div>
<h2>Wichtige Entwicklungen</h2>
</div>
</div>
<div class="two-col">
<article class="development">
<div class="development-top"><span class="impact-dot positive"></span><h3>Umsatz gewinnt ueberproportional</h3></div>
<p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p>
</article>
<article class="development">
<div class="development-top"><span class="impact-dot positive"></span><h3>Auslastung erreicht ein solides Niveau</h3></div>
<p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p>
</article>
<article class="development">
<div class="development-top"><span class="impact-dot neutral"></span><h3>Stornos bleiben ein Beobachtungspunkt</h3></div>
<p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p>
</article>
<article class="development">
<div class="development-top"><span class="impact-dot neutral"></span><h3>Aufenthaltsdauer bleibt kompakt</h3></div>
<p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p>
</article>
</div>
</section>
<section class="section">
<div class="section-heading">
<div>
<div class="section-kicker">Naechste Schritte</div>
<h2>Priorisierte Empfehlungen</h2>
</div>
</div>
<div class="recommendations">
<article class="recommendation">
<div class="priority">1</div>
<div>
<div class="category">Preisgestaltung</div>
<h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3>
<p><strong>Warum:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p>
<p class="action-line"><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p>
<p><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p>
</div>
</article>
<article class="recommendation">
<div class="priority">2</div>
<div>
<div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div>
<h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3>
<p><strong>Warum:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p>
<p class="action-line"><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p>
<p><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p>
</div>
</article>
<article class="recommendation">
<div class="priority">3</div>
<div>
<div class="category">Gaeste &amp; Bewertungen</div>
<h3>Stornierungen nach Kanal und Vorlauf auswerten</h3>
<p><strong>Warum:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p>
<p class="action-line"><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p>
<p><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p>
</div>
</article>
</div>
</section>
<section class="section">
<div class="outlook">
<div class="section-kicker" style="color: rgba(255,255,255,.7)">Ausblick</div>
<h2>Gute Ausgangslage fuer den Fruehsommer</h2>
<p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p>
</div>
<div class="notes">
<strong>Hinweise zur Datengrundlage</strong>
<ul>
<li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li> </ul>
</div>
<div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</section>
</main>
</body>
</html>
+436
View File
@@ -0,0 +1,436 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Monatsreport Mai 2026 - Ferienapartments Kuestenblick</title>
<style>
:root {
--primary: #1F5D66;
--secondary: #2C7C82;
--accent: #DBA25D;
--text: #24343A;
--muted: #718087;
--surface: #F2F6F5;
--line: #dfe5e8;
--positive: #207a5a;
--neutral: #667680;
--negative: #b14949;
--watch: #9a6815;
}
@page {
size: A4;
margin: 13mm 14mm 18mm 14mm;
}
* { box-sizing: border-box; }
html { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
body {
margin: 0;
color: var(--text);
font-family: Arial, Arial, sans-serif;
font-size: 9.3pt;
line-height: 1.48;
background: #fff;
}
h1, h2, h3, p { margin-top: 0; }
h1 { font-size: 27pt; line-height: 1.08; letter-spacing: -0.6px; margin-bottom: 2mm; }
h2 { font-size: 14.5pt; line-height: 1.2; margin-bottom: 4mm; }
h3 { font-size: 10.8pt; line-height: 1.25; margin-bottom: 1.5mm; }
p { margin-bottom: 3mm; }
.cover {
position: relative;
overflow: hidden;
min-height: 67mm;
padding: 9mm;
border-radius: 5mm;
color: #fff;
background: linear-gradient(128deg, var(--primary), var(--secondary));
margin-bottom: 7mm;
break-inside: avoid;
}
.cover::after {
content: "";
position: absolute;
width: 92mm;
height: 92mm;
right: -27mm;
top: -42mm;
border: 12mm solid rgba(255,255,255,.08);
border-radius: 50%;
}
.cover-top { display: flex; align-items: center; justify-content: space-between; gap: 8mm; position: relative; z-index: 1; }
.brand { display: flex; align-items: center; gap: 4mm; }
.logo {
width: 15mm; height: 15mm; border-radius: 4mm;
background: rgba(255,255,255,.96); color: var(--primary);
display: flex; align-items: center; justify-content: center; font-size: 15pt; font-weight: 800;
box-shadow: 0 2mm 5mm rgba(0,0,0,.12);
overflow: hidden;
}
.logo img { width: 100%; height: 100%; object-fit: contain; padding: 1.6mm; }
.brand-name { font-size: 11pt; font-weight: 700; }
.brand-sub { font-size: 8pt; opacity: .82; }
.period-chip {
padding: 2.2mm 4mm; border-radius: 99mm;
border: .25mm solid rgba(255,255,255,.38);
background: rgba(255,255,255,.12); font-size: 8.3pt; font-weight: 700;
}
.cover-main { position: relative; z-index: 1; margin-top: 13mm; max-width: 142mm; }
.eyebrow { text-transform: uppercase; letter-spacing: 1.7px; font-size: 7.2pt; font-weight: 800; opacity: .78; margin-bottom: 2.2mm; }
.cover-meta { display: flex; flex-wrap: wrap; gap: 3mm 8mm; font-size: 8.4pt; opacity: .88; }
.section { margin-bottom: 7mm; }
.section-heading { display: flex; align-items: flex-end; justify-content: space-between; gap: 5mm; margin-bottom: 3.5mm; }
.section-heading h2 { margin: 0; }
.section-kicker { font-size: 7.3pt; font-weight: 800; color: var(--muted); text-transform: uppercase; letter-spacing: 1.2px; margin-bottom: 1mm; }
.summary {
display: grid; grid-template-columns: 10mm 1fr; gap: 4mm;
padding: 5mm; border-radius: 3mm; background: var(--surface);
border-left: 1.5mm solid var(--accent); break-inside: avoid;
}
.summary-icon {
width: 9mm; height: 9mm; border-radius: 50%;
display: flex; align-items: center; justify-content: center; align-self: start; color: #fff; font-weight: 900; margin-top: .5mm;
}
.summary-icon.positive { background: var(--positive); }
.summary-icon.neutral { background: var(--neutral); }
.summary-icon.watch { background: var(--watch); }
.summary h2 { font-size: 14pt; margin-bottom: 2mm; }
.summary p { margin-bottom: 0; }
.kpi-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 3mm; }
.kpi-card {
min-height: 31mm; padding: 4mm; border: .25mm solid var(--line);
border-radius: 3mm; break-inside: avoid; background: #fff;
}
.kpi-label { font-size: 7.3pt; text-transform: uppercase; letter-spacing: .8px; color: var(--muted); font-weight: 800; }
.kpi-value { font-size: 16pt; font-weight: 800; color: var(--primary); line-height: 1.15; margin: 3mm 0 1.5mm; white-space: nowrap; }
.kpi-delta { font-size: 7.6pt; color: var(--muted); }
.delta-positive { color: var(--positive); font-weight: 700; }
.delta-negative { color: var(--negative); font-weight: 700; }
.detail-strip {
display: grid; grid-template-columns: repeat(4, 1fr); gap: 0;
border: .25mm solid var(--line); border-radius: 3mm; overflow: hidden; margin-top: 3mm;
}
.detail-item { padding: 3mm 4mm; border-right: .25mm solid var(--line); }
.detail-item:last-child { border-right: 0; }
.detail-label { font-size: 7.2pt; color: var(--muted); }
.detail-value { font-weight: 800; margin-top: .8mm; }
.trend-panel {
border: .25mm solid var(--line); border-radius: 3mm; padding: 5mm;
break-inside: avoid;
}
.trend-legend { display: flex; gap: 5mm; font-size: 7.4pt; color: var(--muted); }
.legend-dot { width: 2.2mm; height: 2.2mm; border-radius: 50%; display: inline-block; margin-right: 1.2mm; }
.legend-revenue { background: var(--primary); }
.legend-occ { background: var(--accent); }
.trend-grid { display: block; margin-top: 3mm; }
.trend-row { display: grid; grid-template-columns: 20mm 1fr 25mm 25mm; align-items: center; gap: 2mm; margin-top: 2mm; }
.trend-label { font-weight: 700; font-size: 8pt; }
.bar-track { height: 4mm; border-radius: 99mm; background: #edf1f3; overflow: hidden; position: relative; }
.bar { height: 100%; border-radius: inherit; }
.bar-revenue { background: var(--primary); }
.bar-occ { background: var(--accent); height: 1.5mm; position: absolute; left: 0; bottom: 0; }
.trend-number { text-align: right; font-size: 7.7pt; font-variant-numeric: tabular-nums; }
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 5mm; align-items: start; }
.development-list { display: grid; gap: 3mm; }
.development {
border: .25mm solid var(--line); border-radius: 3mm; padding: 4mm;
break-inside: avoid;
}
.development-top { display: flex; align-items: center; gap: 2mm; margin-bottom: 1.5mm; }
.impact-dot { width: 2.5mm; height: 2.5mm; border-radius: 50%; flex: 0 0 auto; }
.impact-dot.positive { background: var(--positive); }
.impact-dot.neutral { background: var(--neutral); }
.impact-dot.negative { background: var(--negative); }
.development p { margin: 0; color: #35434a; }
.recommendations { display: grid; gap: 3.5mm; }
.recommendation {
display: grid; grid-template-columns: 11mm 1fr; gap: 4mm;
padding: 4.5mm; border-radius: 3mm; background: var(--surface);
border: .25mm solid #d7e1e2;
break-inside: avoid;
}
.priority {
width: 10mm; height: 10mm; border-radius: 3mm; background: var(--primary); color: #fff;
display: flex; align-items: center; justify-content: center; align-self: start; font-weight: 900; font-size: 12pt;
}
.category { color: var(--primary); font-size: 7.2pt; font-weight: 900; text-transform: uppercase; letter-spacing: .8px; }
.recommendation h3 { font-size: 11.3pt; margin: .8mm 0 2mm; }
.recommendation p { margin-bottom: 2mm; }
.recommendation p:last-child { margin-bottom: 0; }
.action-line { padding-top: 2mm; border-top: .25mm solid rgba(0,0,0,.08); }
.outlook {
padding: 5mm; color: #fff; border-radius: 3mm;
background: linear-gradient(115deg, var(--primary), var(--secondary));
break-inside: avoid;
}
.outlook h2 { margin-bottom: 2mm; }
.outlook p { margin: 0; opacity: .94; }
.notes {
margin-top: 4mm; padding: 3.5mm 4mm; border-radius: 2mm;
background: #f7f8f9; color: var(--muted); font-size: 7.5pt;
break-inside: avoid;
}
.notes ul { margin: 1.5mm 0 0; padding-left: 4mm; }
.notes li { margin-bottom: .8mm; }
.legal { margin-top: 4mm; color: var(--muted); font-size: 6.9pt; }
.page-break { break-before: page; }
.avoid { break-inside: avoid; }
@media print {
.section:last-child { margin-bottom: 0; }
}
</style>
</head>
<body>
<main>
<section class="cover">
<div class="cover-top">
<div class="brand">
<div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo">
</div>
<div>
<div class="brand-name">Ferienapartments Kuestenblick</div>
<div class="brand-sub">Apartment Seestern</div>
</div>
</div>
<div class="period-chip">Mai 2026</div>
</div>
<div class="cover-main">
<div class="eyebrow">Performance & Handlungsempfehlungen</div>
<h1>Monatsreport</h1>
<div class="cover-meta">
<span>Nordseekueste</span>
<span>Erstellt am 24.06.2026</span>
<span>Version 1.0</span>
</div>
</div>
</section>
<section class="section">
<div class="summary">
<div class="summary-icon positive">
</div>
<div>
<div class="section-kicker">Kurzfazit</div>
<h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2>
<p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p>
</div>
</div>
</section>
<section class="section">
<div class="section-heading">
<div>
<div class="section-kicker">Kennzahlen</div>
<h2>Der Monat auf einen Blick</h2>
</div>
<div class="section-kicker">Vergleich: April 2026</div>
</div>
<div class="kpi-grid">
<article class="kpi-card">
<div class="kpi-label">Umsatz</div>
<div class="kpi-value">6.840,50 €</div>
<div class="kpi-delta delta-positive">
+12,8 %
</div>
</article>
<article class="kpi-card">
<div class="kpi-label">Auslastung</div>
<div class="kpi-value">78,4 %</div>
<div class="kpi-delta delta-positive">
+5,7 PP
</div>
</article>
<article class="kpi-card">
<div class="kpi-label">Ø Tagespreis</div>
<div class="kpi-value">126,68 €</div>
<div class="kpi-delta delta-positive">
+4,6 %
</div>
</article>
<article class="kpi-card">
<div class="kpi-label">Buchungen</div>
<div class="kpi-value">19</div>
<div class="kpi-delta delta-positive">
+2 Buchungen
</div>
</article>
</div>
<div class="detail-strip">
<div class="detail-item"><div class="detail-label">RevPAR</div><div class="detail-value">99,32 €</div></div>
<div class="detail-item"><div class="detail-label">Verkaufte Nächte</div><div class="detail-value">54</div></div>
<div class="detail-item"><div class="detail-label">Ø Aufenthaltsdauer</div><div class="detail-value">3,6 Nächte</div></div>
<div class="detail-item"><div class="detail-label">Stornoquote</div><div class="detail-value">6,2 %</div></div>
</div>
</section>
<section class="section">
<div class="section-heading">
<div>
<div class="section-kicker">Verlauf</div>
<h2>Entwicklung der letzten Monate</h2>
</div>
<div class="trend-legend">
<span><i class="legend-dot legend-revenue"></i> Umsatz</span>
<span><i class="legend-dot legend-occ"></i> Auslastung</span>
</div>
</div>
<div class="trend-panel">
<div class="trend-grid">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 61.55%"></div>
<div class="bar bar-occ" style="width: 55.2%"></div>
</div>
<div class="trend-number">4.210,00 €</div>
<div class="trend-number">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 56.87%"></div>
<div class="bar bar-occ" style="width: 51.4%"></div>
</div>
<div class="trend-number">3.890,00 €</div>
<div class="trend-number">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 65.42%"></div>
<div class="bar bar-occ" style="width: 59.7%"></div>
</div>
<div class="trend-number">4.475,00 €</div>
<div class="trend-number">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 78.36%"></div>
<div class="bar bar-occ" style="width: 66.1%"></div>
</div>
<div class="trend-number">5.360,00 €</div>
<div class="trend-number">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 88.65%"></div>
<div class="bar bar-occ" style="width: 72.7%"></div>
</div>
<div class="trend-number">6.064,00 €</div>
<div class="trend-number">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 100%"></div>
<div class="bar bar-occ" style="width: 78.4%"></div>
</div>
<div class="trend-number">6.840,50 €</div>
<div class="trend-number">78,4 %</div>
</div>
</div>
</div>
</section>
<section class="section">
<div class="section-heading">
<div>
<div class="section-kicker">Analyse</div>
<h2>Wichtige Entwicklungen</h2>
</div>
</div>
<div class="two-col">
<article class="development">
<div class="development-top"><span class="impact-dot positive"></span><h3>Umsatz gewinnt ueberproportional</h3></div>
<p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p>
</article>
<article class="development">
<div class="development-top"><span class="impact-dot positive"></span><h3>Auslastung erreicht ein solides Niveau</h3></div>
<p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p>
</article>
<article class="development">
<div class="development-top"><span class="impact-dot neutral"></span><h3>Stornos bleiben ein Beobachtungspunkt</h3></div>
<p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p>
</article>
<article class="development">
<div class="development-top"><span class="impact-dot neutral"></span><h3>Aufenthaltsdauer bleibt kompakt</h3></div>
<p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p>
</article>
</div>
</section>
<section class="section">
<div class="section-heading">
<div>
<div class="section-kicker">Naechste Schritte</div>
<h2>Priorisierte Empfehlungen</h2>
</div>
</div>
<div class="recommendations">
<article class="recommendation">
<div class="priority">1</div>
<div>
<div class="category">Preisgestaltung</div>
<h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3>
<p><strong>Warum:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p>
<p class="action-line"><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p>
<p><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p>
</div>
</article>
<article class="recommendation">
<div class="priority">2</div>
<div>
<div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div>
<h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3>
<p><strong>Warum:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p>
<p class="action-line"><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p>
<p><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p>
</div>
</article>
<article class="recommendation">
<div class="priority">3</div>
<div>
<div class="category">Gaeste &amp; Bewertungen</div>
<h3>Stornierungen nach Kanal und Vorlauf auswerten</h3>
<p><strong>Warum:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p>
<p class="action-line"><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p>
<p><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p>
</div>
</article>
</div>
</section>
<section class="section">
<div class="outlook">
<div class="section-kicker" style="color: rgba(255,255,255,.7)">Ausblick</div>
<h2>Gute Ausgangslage fuer den Fruehsommer</h2>
<p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p>
</div>
<div class="notes">
<strong>Hinweise zur Datengrundlage</strong>
<ul>
<li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li> </ul>
</div>
<div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</section>
</main>
</body>
</html>
+67
View File
@@ -0,0 +1,67 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Nordic Light - Ferienapartments Kuestenblick</title><style>
:root{--p:#294C60;--s:#6D98A6;--a:#E7B45A;--t:#1F2D33;--m:#75858B;--bg:#F1F5F5;--line:#d9dfdf;--pos:#27745b;--neg:#a54a4a}@page{size:A4;margin:14mm 15mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.3pt/1.52 Arial,Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:36pt;line-height:.98;letter-spacing:-1.7px;margin:0}h2{font-size:15pt;line-height:1.15;margin-bottom:3mm}h3{font-size:10.5pt;margin-bottom:1mm}p{margin-bottom:3mm}.top{display:flex;justify-content:space-between;align-items:flex-start;border-top:1.8mm solid var(--p);padding-top:6mm;margin-bottom:12mm}.brand{display:flex;gap:3mm;align-items:center}.logo{width:11mm;height:11mm;border:1px solid var(--p);display:flex;align-items:center;justify-content:center;font-weight:800;color:var(--p);overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand strong{display:block}.micro,.kicker,.kpi-label,.category{font:700 7pt/1.2 Arial,sans-serif;text-transform:uppercase;letter-spacing:1.1px;color:var(--m)}.period{text-align:right;color:var(--p);font-weight:700}.hero{display:grid;grid-template-columns:1fr 68mm;gap:10mm;align-items:end;margin-bottom:11mm}.hero-note{border-left:1mm solid var(--a);padding-left:5mm}.hero-note h2{font-size:14pt}.hero-note p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);border-top:1px solid var(--line);border-bottom:1px solid var(--line);margin-bottom:5mm}.kpi{padding:5mm 4mm 4mm 0}.kpi+.kpi{border-left:1px solid var(--line);padding-left:4mm}.kpi-value{font-size:16pt;font-weight:700;color:var(--p);white-space:nowrap;margin:2mm 0}.kpi-delta{font-size:7.5pt;color:var(--m)}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:6mm;margin-bottom:10mm}.fact span{display:block;color:var(--m);font-size:7.3pt}.fact strong{display:block;margin-top:1mm}.section{margin-bottom:9mm}.section-title{display:grid;grid-template-columns:auto 1fr;gap:4mm;align-items:center;margin-bottom:4mm}.section-title h2{margin:0}.rule{height:1px;background:var(--line)}.trend-bars{border-top:1px solid var(--line)}.trend-row{display:grid;grid-template-columns:18mm 1fr 28mm 22mm;gap:3mm;align-items:center;padding:2.2mm 0;border-bottom:1px solid var(--line);font-size:7.7pt}.trend-label{font-weight:700}.trend-track{height:3.5mm;background:var(--bg);position:relative}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1mm;background:var(--a);position:absolute;bottom:0;left:0}.trend-num{text-align:right}.content-grid{display:grid;grid-template-columns:1fr 1.1fr;gap:9mm;break-before:page;break-inside:avoid}.developments,.recommendations{display:grid;gap:4mm}.development{display:grid;grid-template-columns:2mm 1fr;gap:3mm;break-inside:avoid}.impact{width:1.3mm;background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendation{display:grid;grid-template-columns:8mm 1fr;gap:3mm;break-inside:avoid;padding-bottom:4mm;border-bottom:1px solid var(--line)}.priority{font-size:17pt;color:var(--a);font-weight:700}.recommendation p{margin-bottom:1.5mm}.effect{color:var(--p)}.outlook{margin-top:8mm;padding:6mm 0;border-top:1.2mm solid var(--p);border-bottom:1px solid var(--line);break-inside:avoid}.outlook p{margin:0}.notes{margin-top:4mm;font-size:7pt;color:var(--m)}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.5pt;color:var(--m);margin-top:3mm}
</style></head><body>
<header class="top"><div class="brand"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div><strong>Ferienapartments Kuestenblick</strong><div class="micro">Apartment Seestern</div></div></div><div class="period">Mai 2026<div class="micro">Nordseekueste</div></div></header>
<section class="hero"><div><div class="kicker">Monatliche Performance</div><h1>Monats-<br>report</h1></div><div class="hero-note"><div class="kicker">Kurzfazit</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<section class="section"><div class="section-title"><h2>Monatsverlauf</h2><div class="rule"></div></div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div></section>
<div class="content-grid"><section><div class="section-title"><h2>Entwicklungen</h2><div class="rule"></div></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section><section><div class="section-title"><h2>Empfehlungen</h2><div class="rule"></div></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section></div>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+67
View File
@@ -0,0 +1,67 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Nordic Night - Ferienapartments Kuestenblick</title><style>
:root{--p:#182B36;--s:#2F5668;--a:#8FD3E6;--t:#162329;--m:#6E7F86;--bg:#EDF3F4;--line:#d9dfdf;--pos:#27745b;--neg:#a54a4a}@page{size:A4;margin:14mm 15mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.3pt/1.52 Arial,Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:36pt;line-height:.98;letter-spacing:-1.7px;margin:0}h2{font-size:15pt;line-height:1.15;margin-bottom:3mm}h3{font-size:10.5pt;margin-bottom:1mm}p{margin-bottom:3mm}.top{display:flex;justify-content:space-between;align-items:flex-start;border-top:1.8mm solid var(--p);padding-top:6mm;margin-bottom:12mm}.brand{display:flex;gap:3mm;align-items:center}.logo{width:11mm;height:11mm;border:1px solid var(--p);display:flex;align-items:center;justify-content:center;font-weight:800;color:var(--p);overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand strong{display:block}.micro,.kicker,.kpi-label,.category{font:700 7pt/1.2 Arial,sans-serif;text-transform:uppercase;letter-spacing:1.1px;color:var(--m)}.period{text-align:right;color:var(--p);font-weight:700}.hero{display:grid;grid-template-columns:1fr 68mm;gap:10mm;align-items:end;margin-bottom:11mm}.hero-note{border-left:1mm solid var(--a);padding-left:5mm}.hero-note h2{font-size:14pt}.hero-note p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);border-top:1px solid var(--line);border-bottom:1px solid var(--line);margin-bottom:5mm}.kpi{padding:5mm 4mm 4mm 0}.kpi+.kpi{border-left:1px solid var(--line);padding-left:4mm}.kpi-value{font-size:16pt;font-weight:700;color:var(--p);white-space:nowrap;margin:2mm 0}.kpi-delta{font-size:7.5pt;color:var(--m)}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:6mm;margin-bottom:10mm}.fact span{display:block;color:var(--m);font-size:7.3pt}.fact strong{display:block;margin-top:1mm}.section{margin-bottom:9mm}.section-title{display:grid;grid-template-columns:auto 1fr;gap:4mm;align-items:center;margin-bottom:4mm}.section-title h2{margin:0}.rule{height:1px;background:var(--line)}.trend-bars{border-top:1px solid var(--line)}.trend-row{display:grid;grid-template-columns:18mm 1fr 28mm 22mm;gap:3mm;align-items:center;padding:2.2mm 0;border-bottom:1px solid var(--line);font-size:7.7pt}.trend-label{font-weight:700}.trend-track{height:3.5mm;background:var(--bg);position:relative}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1mm;background:var(--a);position:absolute;bottom:0;left:0}.trend-num{text-align:right}.content-grid{display:grid;grid-template-columns:1fr 1.1fr;gap:9mm;break-before:page;break-inside:avoid}.developments,.recommendations{display:grid;gap:4mm}.development{display:grid;grid-template-columns:2mm 1fr;gap:3mm;break-inside:avoid}.impact{width:1.3mm;background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendation{display:grid;grid-template-columns:8mm 1fr;gap:3mm;break-inside:avoid;padding-bottom:4mm;border-bottom:1px solid var(--line)}.priority{font-size:17pt;color:var(--a);font-weight:700}.recommendation p{margin-bottom:1.5mm}.effect{color:var(--p)}.outlook{margin-top:8mm;padding:6mm 0;border-top:1.2mm solid var(--p);border-bottom:1px solid var(--line);break-inside:avoid}.outlook p{margin:0}.notes{margin-top:4mm;font-size:7pt;color:var(--m)}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.5pt;color:var(--m);margin-top:3mm}
</style></head><body>
<header class="top"><div class="brand"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div><strong>Ferienapartments Kuestenblick</strong><div class="micro">Apartment Seestern</div></div></div><div class="period">Mai 2026<div class="micro">Nordseekueste</div></div></header>
<section class="hero"><div><div class="kicker">Monatliche Performance</div><h1>Monats-<br>report</h1></div><div class="hero-note"><div class="kicker">Kurzfazit</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<section class="section"><div class="section-title"><h2>Monatsverlauf</h2><div class="rule"></div></div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div></section>
<div class="content-grid"><section><div class="section-title"><h2>Entwicklungen</h2><div class="rule"></div></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section><section><div class="section-title"><h2>Empfehlungen</h2><div class="rule"></div></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section></div>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+58
View File
@@ -0,0 +1,58 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Ocean Breeze - Ferienapartments Kuestenblick</title><style>
:root{--p:#075B6C;--s:#18859A;--a:#58C6C7;--t:#17353B;--m:#69858A;--bg:#EDF8F8;--line:#d8e0df;--pos:#28765b;--neg:#a54b4b}@page{size:A4;margin:0 13mm 18mm 0}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.1pt/1.48 Arial,Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:25pt;line-height:1.05;margin-bottom:2mm}h2{font-size:14pt;margin-bottom:3mm}h3{font-size:10.2pt;margin-bottom:1mm}p{margin-bottom:2.7mm}.page{display:grid;grid-template-columns:45mm 1fr;min-height:279mm}.side{background:linear-gradient(180deg,var(--p),var(--s));color:#fff;padding:13mm 7mm 10mm 8mm}.main{padding:13mm 0 0 9mm}.logo{width:15mm;height:15mm;background:#fff;color:var(--p);border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden;margin-bottom:5mm}.logo img{width:100%;height:100%;object-fit:contain;padding:1.3mm}.brand{font-weight:800;font-size:11pt}.side-sub{font-size:7.5pt;opacity:.78;margin-top:1mm}.side-period{margin:18mm 0 10mm}.side-period strong{font-size:18pt;display:block;line-height:1.05}.kicker,.kpi-label,.category{font:800 6.8pt/1.2 Arial,sans-serif;text-transform:uppercase;letter-spacing:1px;color:var(--m)}.side .kicker{color:#ffffffb0}.side-facts{display:grid;gap:4mm;border-top:1px solid #ffffff40;padding-top:5mm}.side-fact span{font-size:7pt;opacity:.7;display:block}.side-fact strong{font-size:11pt}.side-outlook{margin-top:13mm;border-top:1px solid #ffffff40;padding-top:5mm}.side-outlook h3{font-size:11pt}.side-outlook p{font-size:7.6pt;opacity:.88}.intro{margin-bottom:6mm}.intro h1{color:var(--p)}.summary{border-left:1.4mm solid var(--a);padding:1mm 0 1mm 5mm;margin:5mm 0 6mm}.summary h2{font-size:14.5pt}.summary p{margin:0}.kpis{display:grid;grid-template-columns:1fr 1fr;gap:3mm;margin-bottom:5mm}.kpi{background:var(--bg);padding:4mm;border-radius:2mm;break-inside:avoid}.kpi-value{font-size:17pt;font-weight:800;color:var(--p);margin:2mm 0}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:none}.section{margin:6mm 0}.section-head{display:flex;align-items:center;gap:3mm;margin-bottom:3mm}.section-head h2{margin:0;white-space:nowrap}.line{height:1px;background:var(--line);width:100%}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:16mm 1fr 27mm 21mm;gap:2mm;align-items:center;font-size:7.2pt}.trend-label{font-weight:700}.trend-track{height:3.7mm;background:var(--bg);position:relative}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1mm;background:var(--a);position:absolute;bottom:0;left:0}.trend-num{text-align:right}.developments{columns:2;column-gap:5mm}.development{display:grid;grid-template-columns:2mm 1fr;gap:2.5mm;break-inside:avoid;margin-bottom:3mm}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendations{display:grid;gap:3mm}.recommendation{display:grid;grid-template-columns:9mm 1fr;gap:3mm;padding:3.5mm 0;border-top:1px solid var(--line);break-inside:avoid}.priority{font-size:18pt;font-weight:800;color:var(--a)}.recommendation p{margin-bottom:1.3mm}.effect{color:var(--p)}.outlook{display:none}.notes{font-size:6.8pt;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.2pt;color:var(--m);margin-top:2mm}
</style></head><body><div class="page">
<aside class="side"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div class="brand">Ferienapartments Kuestenblick</div><div class="side-sub">Apartment Seestern<br>Nordseekueste</div><div class="side-period"><div class="kicker">Monatsreport</div><strong>Mai 2026</strong><div class="side-sub">Version 1.0</div></div><div class="side-facts"><div class="side-fact"><span>RevPAR</span><strong>99,32 €</strong></div><div class="side-fact"><span>Verkaufte Nächte</span><strong>54</strong></div><div class="side-fact"><span>Ø Aufenthalt</span><strong>3,6</strong></div><div class="side-fact"><span>Stornoquote</span><strong>6,2 %</strong></div></div><div class="side-outlook"><div class="kicker">Ausblick</div><h3>Gute Ausgangslage fuer den Fruehsommer</h3><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></div></aside>
<main class="main"><section class="intro"><div class="kicker">Performance & Handlungsempfehlungen</div><h1>Der Monat<br>im Überblick</h1></section><section class="summary"><div class="kicker">Kurzfazit</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></section><div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div>
<section class="section"><div class="section-head"><h2>Monatsverlauf</h2><div class="line"></div></div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div></section><section class="section"><div class="section-head"><h2>Entwicklungen</h2><div class="line"></div></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section><section class="section"><div class="section-head"><h2>Empfehlungen</h2><div class="line"></div></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div></main></div></body></html>
+67
View File
@@ -0,0 +1,67 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Poster Mono - Ferienapartments Kuestenblick</title><style>
:root{--p:#111111;--s:#444444;--a:#A3A3A3;--t:#171717;--m:#737373;--bg:#F3F3F3;--line:#d6d6d6;--pos:#25745a;--neg:#a43d43}@page{size:A4;margin:11mm 13mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9pt/1.42 Arial,Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:43pt;line-height:.8;letter-spacing:-2.8px;text-transform:uppercase;margin:0}h2{font-size:17pt;line-height:1.05;margin-bottom:3mm}h3{font-size:10pt;margin-bottom:1mm}p{margin-bottom:2.5mm}.cover{background:var(--p);color:#fff;min-height:79mm;padding:7mm;position:relative;overflow:hidden;margin-bottom:4mm;break-inside:avoid}.cover:after{content:"05";position:absolute;right:-4mm;bottom:-17mm;font-size:90pt;line-height:1;font-weight:900;color:#ffffff10}.top{display:flex;justify-content:space-between;align-items:flex-start;position:relative;z-index:1}.brand{display:flex;gap:3mm;align-items:center}.logo{width:13mm;height:13mm;background:#fff;color:var(--p);display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand-name{font-weight:900}.small{font-size:7pt;opacity:.74}.period{background:var(--a);color:var(--t);padding:2.5mm 4mm;font-weight:900}.title{position:absolute;left:7mm;bottom:7mm;z-index:1}.kicker,.kpi-label,.category{font-size:6.6pt;text-transform:uppercase;letter-spacing:1px;font-weight:900;color:var(--m)}.cover .kicker{color:#ffffffad}.summary{display:grid;grid-template-columns:48mm 1fr;background:var(--a);padding:5mm;margin-bottom:4mm}.summary-label{font-size:22pt;font-weight:900;text-transform:uppercase;line-height:.9}.summary h2{font-size:16pt}.summary p{margin:0}.kpis{display:grid;grid-template-columns:1fr 1fr;gap:3mm;margin-bottom:3mm}.kpi{min-height:34mm;padding:4mm;border:1px solid var(--t);position:relative}.kpi:nth-child(1),.kpi:nth-child(4){background:var(--t);color:#fff}.kpi:nth-child(1) .kpi-label,.kpi:nth-child(4) .kpi-label{color:#ffffffaa}.kpi-value{font-size:25pt;font-weight:900;line-height:1;color:var(--p);margin:2mm 0}.kpi:nth-child(1) .kpi-value,.kpi:nth-child(4) .kpi-value{color:var(--a)}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:0;background:var(--bg);margin-bottom:6mm}.fact{padding:3mm;border-right:1px solid var(--line)}.fact:last-child{border-right:0}.fact span{display:block;font-size:6.5pt;color:var(--m)}.fact strong{display:block;margin-top:.5mm}.section-title{display:flex;align-items:baseline;gap:4mm;border-bottom:2mm solid var(--p);margin:7mm 0 3mm}.section-title .num{font-size:24pt;font-weight:900;color:var(--a)}.section-title h2{margin:0 0 1mm;text-transform:uppercase}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:17mm 1fr 28mm 22mm;gap:2.5mm;align-items:center;font-size:7.2pt}.trend-label{font-weight:900}.trend-track{height:5mm;background:var(--bg);position:relative;border:1px solid var(--t)}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1.4mm;background:var(--a);position:absolute;left:0;bottom:0}.trend-num{text-align:right}.content{display:grid;grid-template-columns:1fr 1fr;gap:5mm;break-before:page;break-inside:avoid}.developments,.recommendations{display:grid;gap:3mm}.development{display:grid;grid-template-columns:3mm 1fr;gap:3mm;border-bottom:1px solid var(--line);padding-bottom:3mm;break-inside:avoid}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendation{display:grid;grid-template-columns:10mm 1fr;gap:3mm;border:1px solid var(--t);padding:3mm;break-inside:avoid}.priority{font-size:22pt;font-weight:900;color:var(--a)}.recommendation p{margin-bottom:1.2mm}.effect{border-top:1px solid var(--line);padding-top:1.3mm}.outlook{margin-top:6mm;background:var(--t);color:#fff;padding:5mm;break-inside:avoid}.outlook .kicker{color:var(--a)}.outlook p{margin:0}.notes{font-size:6.7pt;color:var(--m);margin-top:3mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.1pt;color:var(--m);margin-top:2mm}
</style></head><body>
<section class="cover"><div class="top"><div class="brand"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div><div class="brand-name">Ferienapartments Kuestenblick</div><div class="small">Apartment Seestern · Nordseekueste</div></div></div><div class="period">Mai 2026</div></div><div class="title"><div class="kicker">Performance / Analyse / Aktionen</div><h1>Monats<br>report</h1></div></section>
<section class="summary"><div class="summary-label">Der<br>Monat</div><div><div class="kicker">Kurzfazit</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<div class="section-title"><span class="num">01</span><h2>Monatsverlauf</h2></div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div>
<div class="content"><section><div class="section-title"><span class="num">02</span><h2>Entwicklungen</h2></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section><section><div class="section-title"><span class="num">03</span><h2>Aktionen</h2></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section></div>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+67
View File
@@ -0,0 +1,67 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Poster Red - Ferienapartments Kuestenblick</title><style>
:root{--p:#B3202A;--s:#D53B42;--a:#F2B84B;--t:#1F1D1D;--m:#6D6767;--bg:#F7F2F0;--line:#d6d6d6;--pos:#25745a;--neg:#a43d43}@page{size:A4;margin:11mm 13mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9pt/1.42 Arial,Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:43pt;line-height:.8;letter-spacing:-2.8px;text-transform:uppercase;margin:0}h2{font-size:17pt;line-height:1.05;margin-bottom:3mm}h3{font-size:10pt;margin-bottom:1mm}p{margin-bottom:2.5mm}.cover{background:var(--p);color:#fff;min-height:79mm;padding:7mm;position:relative;overflow:hidden;margin-bottom:4mm;break-inside:avoid}.cover:after{content:"05";position:absolute;right:-4mm;bottom:-17mm;font-size:90pt;line-height:1;font-weight:900;color:#ffffff10}.top{display:flex;justify-content:space-between;align-items:flex-start;position:relative;z-index:1}.brand{display:flex;gap:3mm;align-items:center}.logo{width:13mm;height:13mm;background:#fff;color:var(--p);display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand-name{font-weight:900}.small{font-size:7pt;opacity:.74}.period{background:var(--a);color:var(--t);padding:2.5mm 4mm;font-weight:900}.title{position:absolute;left:7mm;bottom:7mm;z-index:1}.kicker,.kpi-label,.category{font-size:6.6pt;text-transform:uppercase;letter-spacing:1px;font-weight:900;color:var(--m)}.cover .kicker{color:#ffffffad}.summary{display:grid;grid-template-columns:48mm 1fr;background:var(--a);padding:5mm;margin-bottom:4mm}.summary-label{font-size:22pt;font-weight:900;text-transform:uppercase;line-height:.9}.summary h2{font-size:16pt}.summary p{margin:0}.kpis{display:grid;grid-template-columns:1fr 1fr;gap:3mm;margin-bottom:3mm}.kpi{min-height:34mm;padding:4mm;border:1px solid var(--t);position:relative}.kpi:nth-child(1),.kpi:nth-child(4){background:var(--t);color:#fff}.kpi:nth-child(1) .kpi-label,.kpi:nth-child(4) .kpi-label{color:#ffffffaa}.kpi-value{font-size:25pt;font-weight:900;line-height:1;color:var(--p);margin:2mm 0}.kpi:nth-child(1) .kpi-value,.kpi:nth-child(4) .kpi-value{color:var(--a)}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:0;background:var(--bg);margin-bottom:6mm}.fact{padding:3mm;border-right:1px solid var(--line)}.fact:last-child{border-right:0}.fact span{display:block;font-size:6.5pt;color:var(--m)}.fact strong{display:block;margin-top:.5mm}.section-title{display:flex;align-items:baseline;gap:4mm;border-bottom:2mm solid var(--p);margin:7mm 0 3mm}.section-title .num{font-size:24pt;font-weight:900;color:var(--a)}.section-title h2{margin:0 0 1mm;text-transform:uppercase}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:17mm 1fr 28mm 22mm;gap:2.5mm;align-items:center;font-size:7.2pt}.trend-label{font-weight:900}.trend-track{height:5mm;background:var(--bg);position:relative;border:1px solid var(--t)}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1.4mm;background:var(--a);position:absolute;left:0;bottom:0}.trend-num{text-align:right}.content{display:grid;grid-template-columns:1fr 1fr;gap:5mm;break-before:page;break-inside:avoid}.developments,.recommendations{display:grid;gap:3mm}.development{display:grid;grid-template-columns:3mm 1fr;gap:3mm;border-bottom:1px solid var(--line);padding-bottom:3mm;break-inside:avoid}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendation{display:grid;grid-template-columns:10mm 1fr;gap:3mm;border:1px solid var(--t);padding:3mm;break-inside:avoid}.priority{font-size:22pt;font-weight:900;color:var(--a)}.recommendation p{margin-bottom:1.2mm}.effect{border-top:1px solid var(--line);padding-top:1.3mm}.outlook{margin-top:6mm;background:var(--t);color:#fff;padding:5mm;break-inside:avoid}.outlook .kicker{color:var(--a)}.outlook p{margin:0}.notes{font-size:6.7pt;color:var(--m);margin-top:3mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.1pt;color:var(--m);margin-top:2mm}
</style></head><body>
<section class="cover"><div class="top"><div class="brand"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div><div class="brand-name">Ferienapartments Kuestenblick</div><div class="small">Apartment Seestern · Nordseekueste</div></div></div><div class="period">Mai 2026</div></div><div class="title"><div class="kicker">Performance / Analyse / Aktionen</div><h1>Monats<br>report</h1></div></section>
<section class="summary"><div class="summary-label">Der<br>Monat</div><div><div class="kicker">Kurzfazit</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<div class="section-title"><span class="num">01</span><h2>Monatsverlauf</h2></div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div>
<div class="content"><section><div class="section-title"><span class="num">02</span><h2>Entwicklungen</h2></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section><section><div class="section-title"><span class="num">03</span><h2>Aktionen</h2></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section></div>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+67
View File
@@ -0,0 +1,67 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Poster Yellow - Ferienapartments Kuestenblick</title><style>
:root{--p:#171717;--s:#3B3B3B;--a:#F1C928;--t:#181818;--m:#707070;--bg:#F7F5E8;--line:#d6d6d6;--pos:#25745a;--neg:#a43d43}@page{size:A4;margin:11mm 13mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9pt/1.42 Arial,Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:43pt;line-height:.8;letter-spacing:-2.8px;text-transform:uppercase;margin:0}h2{font-size:17pt;line-height:1.05;margin-bottom:3mm}h3{font-size:10pt;margin-bottom:1mm}p{margin-bottom:2.5mm}.cover{background:var(--p);color:#fff;min-height:79mm;padding:7mm;position:relative;overflow:hidden;margin-bottom:4mm;break-inside:avoid}.cover:after{content:"05";position:absolute;right:-4mm;bottom:-17mm;font-size:90pt;line-height:1;font-weight:900;color:#ffffff10}.top{display:flex;justify-content:space-between;align-items:flex-start;position:relative;z-index:1}.brand{display:flex;gap:3mm;align-items:center}.logo{width:13mm;height:13mm;background:#fff;color:var(--p);display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand-name{font-weight:900}.small{font-size:7pt;opacity:.74}.period{background:var(--a);color:var(--t);padding:2.5mm 4mm;font-weight:900}.title{position:absolute;left:7mm;bottom:7mm;z-index:1}.kicker,.kpi-label,.category{font-size:6.6pt;text-transform:uppercase;letter-spacing:1px;font-weight:900;color:var(--m)}.cover .kicker{color:#ffffffad}.summary{display:grid;grid-template-columns:48mm 1fr;background:var(--a);padding:5mm;margin-bottom:4mm}.summary-label{font-size:22pt;font-weight:900;text-transform:uppercase;line-height:.9}.summary h2{font-size:16pt}.summary p{margin:0}.kpis{display:grid;grid-template-columns:1fr 1fr;gap:3mm;margin-bottom:3mm}.kpi{min-height:34mm;padding:4mm;border:1px solid var(--t);position:relative}.kpi:nth-child(1),.kpi:nth-child(4){background:var(--t);color:#fff}.kpi:nth-child(1) .kpi-label,.kpi:nth-child(4) .kpi-label{color:#ffffffaa}.kpi-value{font-size:25pt;font-weight:900;line-height:1;color:var(--p);margin:2mm 0}.kpi:nth-child(1) .kpi-value,.kpi:nth-child(4) .kpi-value{color:var(--a)}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:0;background:var(--bg);margin-bottom:6mm}.fact{padding:3mm;border-right:1px solid var(--line)}.fact:last-child{border-right:0}.fact span{display:block;font-size:6.5pt;color:var(--m)}.fact strong{display:block;margin-top:.5mm}.section-title{display:flex;align-items:baseline;gap:4mm;border-bottom:2mm solid var(--p);margin:7mm 0 3mm}.section-title .num{font-size:24pt;font-weight:900;color:var(--a)}.section-title h2{margin:0 0 1mm;text-transform:uppercase}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:17mm 1fr 28mm 22mm;gap:2.5mm;align-items:center;font-size:7.2pt}.trend-label{font-weight:900}.trend-track{height:5mm;background:var(--bg);position:relative;border:1px solid var(--t)}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1.4mm;background:var(--a);position:absolute;left:0;bottom:0}.trend-num{text-align:right}.content{display:grid;grid-template-columns:1fr 1fr;gap:5mm;break-before:page;break-inside:avoid}.developments,.recommendations{display:grid;gap:3mm}.development{display:grid;grid-template-columns:3mm 1fr;gap:3mm;border-bottom:1px solid var(--line);padding-bottom:3mm;break-inside:avoid}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendation{display:grid;grid-template-columns:10mm 1fr;gap:3mm;border:1px solid var(--t);padding:3mm;break-inside:avoid}.priority{font-size:22pt;font-weight:900;color:var(--a)}.recommendation p{margin-bottom:1.2mm}.effect{border-top:1px solid var(--line);padding-top:1.3mm}.outlook{margin-top:6mm;background:var(--t);color:#fff;padding:5mm;break-inside:avoid}.outlook .kicker{color:var(--a)}.outlook p{margin:0}.notes{font-size:6.7pt;color:var(--m);margin-top:3mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.1pt;color:var(--m);margin-top:2mm}
</style></head><body>
<section class="cover"><div class="top"><div class="brand"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div><div class="brand-name">Ferienapartments Kuestenblick</div><div class="small">Apartment Seestern · Nordseekueste</div></div></div><div class="period">Mai 2026</div></div><div class="title"><div class="kicker">Performance / Analyse / Aktionen</div><h1>Monats<br>report</h1></div></section>
<section class="summary"><div class="summary-label">Der<br>Monat</div><div><div class="kicker">Kurzfazit</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<div class="section-title"><span class="num">01</span><h2>Monatsverlauf</h2></div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div>
<div class="content"><section><div class="section-title"><span class="num">02</span><h2>Entwicklungen</h2></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section><section><div class="section-title"><span class="num">03</span><h2>Aktionen</h2></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section></div>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+436
View File
@@ -0,0 +1,436 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Monatsreport Mai 2026 - Ferienapartments Kuestenblick</title>
<style>
:root {
--primary: #67558B;
--secondary: #8B76B3;
--accent: #D5A6B8;
--text: #302B38;
--muted: #7D7485;
--surface: #F5F0F8;
--line: #dfe5e8;
--positive: #207a5a;
--neutral: #667680;
--negative: #b14949;
--watch: #9a6815;
}
@page {
size: A4;
margin: 13mm 14mm 18mm 14mm;
}
* { box-sizing: border-box; }
html { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
body {
margin: 0;
color: var(--text);
font-family: Arial, Arial, sans-serif;
font-size: 9.3pt;
line-height: 1.48;
background: #fff;
}
h1, h2, h3, p { margin-top: 0; }
h1 { font-size: 27pt; line-height: 1.08; letter-spacing: -0.6px; margin-bottom: 2mm; }
h2 { font-size: 14.5pt; line-height: 1.2; margin-bottom: 4mm; }
h3 { font-size: 10.8pt; line-height: 1.25; margin-bottom: 1.5mm; }
p { margin-bottom: 3mm; }
.cover {
position: relative;
overflow: hidden;
min-height: 67mm;
padding: 9mm;
border-radius: 5mm;
color: #fff;
background: linear-gradient(128deg, var(--primary), var(--secondary));
margin-bottom: 7mm;
break-inside: avoid;
}
.cover::after {
content: "";
position: absolute;
width: 92mm;
height: 92mm;
right: -27mm;
top: -42mm;
border: 12mm solid rgba(255,255,255,.08);
border-radius: 50%;
}
.cover-top { display: flex; align-items: center; justify-content: space-between; gap: 8mm; position: relative; z-index: 1; }
.brand { display: flex; align-items: center; gap: 4mm; }
.logo {
width: 15mm; height: 15mm; border-radius: 4mm;
background: rgba(255,255,255,.96); color: var(--primary);
display: flex; align-items: center; justify-content: center; font-size: 15pt; font-weight: 800;
box-shadow: 0 2mm 5mm rgba(0,0,0,.12);
overflow: hidden;
}
.logo img { width: 100%; height: 100%; object-fit: contain; padding: 1.6mm; }
.brand-name { font-size: 11pt; font-weight: 700; }
.brand-sub { font-size: 8pt; opacity: .82; }
.period-chip {
padding: 2.2mm 4mm; border-radius: 99mm;
border: .25mm solid rgba(255,255,255,.38);
background: rgba(255,255,255,.12); font-size: 8.3pt; font-weight: 700;
}
.cover-main { position: relative; z-index: 1; margin-top: 13mm; max-width: 142mm; }
.eyebrow { text-transform: uppercase; letter-spacing: 1.7px; font-size: 7.2pt; font-weight: 800; opacity: .78; margin-bottom: 2.2mm; }
.cover-meta { display: flex; flex-wrap: wrap; gap: 3mm 8mm; font-size: 8.4pt; opacity: .88; }
.section { margin-bottom: 7mm; }
.section-heading { display: flex; align-items: flex-end; justify-content: space-between; gap: 5mm; margin-bottom: 3.5mm; }
.section-heading h2 { margin: 0; }
.section-kicker { font-size: 7.3pt; font-weight: 800; color: var(--muted); text-transform: uppercase; letter-spacing: 1.2px; margin-bottom: 1mm; }
.summary {
display: grid; grid-template-columns: 10mm 1fr; gap: 4mm;
padding: 5mm; border-radius: 3mm; background: var(--surface);
border-left: 1.5mm solid var(--accent); break-inside: avoid;
}
.summary-icon {
width: 9mm; height: 9mm; border-radius: 50%;
display: flex; align-items: center; justify-content: center; align-self: start; color: #fff; font-weight: 900; margin-top: .5mm;
}
.summary-icon.positive { background: var(--positive); }
.summary-icon.neutral { background: var(--neutral); }
.summary-icon.watch { background: var(--watch); }
.summary h2 { font-size: 14pt; margin-bottom: 2mm; }
.summary p { margin-bottom: 0; }
.kpi-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 3mm; }
.kpi-card {
min-height: 31mm; padding: 4mm; border: .25mm solid var(--line);
border-radius: 3mm; break-inside: avoid; background: #fff;
}
.kpi-label { font-size: 7.3pt; text-transform: uppercase; letter-spacing: .8px; color: var(--muted); font-weight: 800; }
.kpi-value { font-size: 16pt; font-weight: 800; color: var(--primary); line-height: 1.15; margin: 3mm 0 1.5mm; white-space: nowrap; }
.kpi-delta { font-size: 7.6pt; color: var(--muted); }
.delta-positive { color: var(--positive); font-weight: 700; }
.delta-negative { color: var(--negative); font-weight: 700; }
.detail-strip {
display: grid; grid-template-columns: repeat(4, 1fr); gap: 0;
border: .25mm solid var(--line); border-radius: 3mm; overflow: hidden; margin-top: 3mm;
}
.detail-item { padding: 3mm 4mm; border-right: .25mm solid var(--line); }
.detail-item:last-child { border-right: 0; }
.detail-label { font-size: 7.2pt; color: var(--muted); }
.detail-value { font-weight: 800; margin-top: .8mm; }
.trend-panel {
border: .25mm solid var(--line); border-radius: 3mm; padding: 5mm;
break-inside: avoid;
}
.trend-legend { display: flex; gap: 5mm; font-size: 7.4pt; color: var(--muted); }
.legend-dot { width: 2.2mm; height: 2.2mm; border-radius: 50%; display: inline-block; margin-right: 1.2mm; }
.legend-revenue { background: var(--primary); }
.legend-occ { background: var(--accent); }
.trend-grid { display: block; margin-top: 3mm; }
.trend-row { display: grid; grid-template-columns: 20mm 1fr 25mm 25mm; align-items: center; gap: 2mm; margin-top: 2mm; }
.trend-label { font-weight: 700; font-size: 8pt; }
.bar-track { height: 4mm; border-radius: 99mm; background: #edf1f3; overflow: hidden; position: relative; }
.bar { height: 100%; border-radius: inherit; }
.bar-revenue { background: var(--primary); }
.bar-occ { background: var(--accent); height: 1.5mm; position: absolute; left: 0; bottom: 0; }
.trend-number { text-align: right; font-size: 7.7pt; font-variant-numeric: tabular-nums; }
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 5mm; align-items: start; }
.development-list { display: grid; gap: 3mm; }
.development {
border: .25mm solid var(--line); border-radius: 3mm; padding: 4mm;
break-inside: avoid;
}
.development-top { display: flex; align-items: center; gap: 2mm; margin-bottom: 1.5mm; }
.impact-dot { width: 2.5mm; height: 2.5mm; border-radius: 50%; flex: 0 0 auto; }
.impact-dot.positive { background: var(--positive); }
.impact-dot.neutral { background: var(--neutral); }
.impact-dot.negative { background: var(--negative); }
.development p { margin: 0; color: #35434a; }
.recommendations { display: grid; gap: 3.5mm; }
.recommendation {
display: grid; grid-template-columns: 11mm 1fr; gap: 4mm;
padding: 4.5mm; border-radius: 3mm; background: var(--surface);
border: .25mm solid #d7e1e2;
break-inside: avoid;
}
.priority {
width: 10mm; height: 10mm; border-radius: 3mm; background: var(--primary); color: #fff;
display: flex; align-items: center; justify-content: center; align-self: start; font-weight: 900; font-size: 12pt;
}
.category { color: var(--primary); font-size: 7.2pt; font-weight: 900; text-transform: uppercase; letter-spacing: .8px; }
.recommendation h3 { font-size: 11.3pt; margin: .8mm 0 2mm; }
.recommendation p { margin-bottom: 2mm; }
.recommendation p:last-child { margin-bottom: 0; }
.action-line { padding-top: 2mm; border-top: .25mm solid rgba(0,0,0,.08); }
.outlook {
padding: 5mm; color: #fff; border-radius: 3mm;
background: linear-gradient(115deg, var(--primary), var(--secondary));
break-inside: avoid;
}
.outlook h2 { margin-bottom: 2mm; }
.outlook p { margin: 0; opacity: .94; }
.notes {
margin-top: 4mm; padding: 3.5mm 4mm; border-radius: 2mm;
background: #f7f8f9; color: var(--muted); font-size: 7.5pt;
break-inside: avoid;
}
.notes ul { margin: 1.5mm 0 0; padding-left: 4mm; }
.notes li { margin-bottom: .8mm; }
.legal { margin-top: 4mm; color: var(--muted); font-size: 6.9pt; }
.page-break { break-before: page; }
.avoid { break-inside: avoid; }
@media print {
.section:last-child { margin-bottom: 0; }
}
</style>
</head>
<body>
<main>
<section class="cover">
<div class="cover-top">
<div class="brand">
<div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo">
</div>
<div>
<div class="brand-name">Ferienapartments Kuestenblick</div>
<div class="brand-sub">Apartment Seestern</div>
</div>
</div>
<div class="period-chip">Mai 2026</div>
</div>
<div class="cover-main">
<div class="eyebrow">Performance & Handlungsempfehlungen</div>
<h1>Monatsreport</h1>
<div class="cover-meta">
<span>Nordseekueste</span>
<span>Erstellt am 24.06.2026</span>
<span>Version 1.0</span>
</div>
</div>
</section>
<section class="section">
<div class="summary">
<div class="summary-icon positive">
</div>
<div>
<div class="section-kicker">Kurzfazit</div>
<h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2>
<p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p>
</div>
</div>
</section>
<section class="section">
<div class="section-heading">
<div>
<div class="section-kicker">Kennzahlen</div>
<h2>Der Monat auf einen Blick</h2>
</div>
<div class="section-kicker">Vergleich: April 2026</div>
</div>
<div class="kpi-grid">
<article class="kpi-card">
<div class="kpi-label">Umsatz</div>
<div class="kpi-value">6.840,50 €</div>
<div class="kpi-delta delta-positive">
+12,8 %
</div>
</article>
<article class="kpi-card">
<div class="kpi-label">Auslastung</div>
<div class="kpi-value">78,4 %</div>
<div class="kpi-delta delta-positive">
+5,7 PP
</div>
</article>
<article class="kpi-card">
<div class="kpi-label">Ø Tagespreis</div>
<div class="kpi-value">126,68 €</div>
<div class="kpi-delta delta-positive">
+4,6 %
</div>
</article>
<article class="kpi-card">
<div class="kpi-label">Buchungen</div>
<div class="kpi-value">19</div>
<div class="kpi-delta delta-positive">
+2 Buchungen
</div>
</article>
</div>
<div class="detail-strip">
<div class="detail-item"><div class="detail-label">RevPAR</div><div class="detail-value">99,32 €</div></div>
<div class="detail-item"><div class="detail-label">Verkaufte Nächte</div><div class="detail-value">54</div></div>
<div class="detail-item"><div class="detail-label">Ø Aufenthaltsdauer</div><div class="detail-value">3,6 Nächte</div></div>
<div class="detail-item"><div class="detail-label">Stornoquote</div><div class="detail-value">6,2 %</div></div>
</div>
</section>
<section class="section">
<div class="section-heading">
<div>
<div class="section-kicker">Verlauf</div>
<h2>Entwicklung der letzten Monate</h2>
</div>
<div class="trend-legend">
<span><i class="legend-dot legend-revenue"></i> Umsatz</span>
<span><i class="legend-dot legend-occ"></i> Auslastung</span>
</div>
</div>
<div class="trend-panel">
<div class="trend-grid">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 61.55%"></div>
<div class="bar bar-occ" style="width: 55.2%"></div>
</div>
<div class="trend-number">4.210,00 €</div>
<div class="trend-number">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 56.87%"></div>
<div class="bar bar-occ" style="width: 51.4%"></div>
</div>
<div class="trend-number">3.890,00 €</div>
<div class="trend-number">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 65.42%"></div>
<div class="bar bar-occ" style="width: 59.7%"></div>
</div>
<div class="trend-number">4.475,00 €</div>
<div class="trend-number">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 78.36%"></div>
<div class="bar bar-occ" style="width: 66.1%"></div>
</div>
<div class="trend-number">5.360,00 €</div>
<div class="trend-number">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 88.65%"></div>
<div class="bar bar-occ" style="width: 72.7%"></div>
</div>
<div class="trend-number">6.064,00 €</div>
<div class="trend-number">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: 100%"></div>
<div class="bar bar-occ" style="width: 78.4%"></div>
</div>
<div class="trend-number">6.840,50 €</div>
<div class="trend-number">78,4 %</div>
</div>
</div>
</div>
</section>
<section class="section">
<div class="section-heading">
<div>
<div class="section-kicker">Analyse</div>
<h2>Wichtige Entwicklungen</h2>
</div>
</div>
<div class="two-col">
<article class="development">
<div class="development-top"><span class="impact-dot positive"></span><h3>Umsatz gewinnt ueberproportional</h3></div>
<p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p>
</article>
<article class="development">
<div class="development-top"><span class="impact-dot positive"></span><h3>Auslastung erreicht ein solides Niveau</h3></div>
<p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p>
</article>
<article class="development">
<div class="development-top"><span class="impact-dot neutral"></span><h3>Stornos bleiben ein Beobachtungspunkt</h3></div>
<p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p>
</article>
<article class="development">
<div class="development-top"><span class="impact-dot neutral"></span><h3>Aufenthaltsdauer bleibt kompakt</h3></div>
<p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p>
</article>
</div>
</section>
<section class="section">
<div class="section-heading">
<div>
<div class="section-kicker">Naechste Schritte</div>
<h2>Priorisierte Empfehlungen</h2>
</div>
</div>
<div class="recommendations">
<article class="recommendation">
<div class="priority">1</div>
<div>
<div class="category">Preisgestaltung</div>
<h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3>
<p><strong>Warum:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p>
<p class="action-line"><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p>
<p><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p>
</div>
</article>
<article class="recommendation">
<div class="priority">2</div>
<div>
<div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div>
<h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3>
<p><strong>Warum:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p>
<p class="action-line"><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p>
<p><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p>
</div>
</article>
<article class="recommendation">
<div class="priority">3</div>
<div>
<div class="category">Gaeste &amp; Bewertungen</div>
<h3>Stornierungen nach Kanal und Vorlauf auswerten</h3>
<p><strong>Warum:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p>
<p class="action-line"><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p>
<p><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p>
</div>
</article>
</div>
</section>
<section class="section">
<div class="outlook">
<div class="section-kicker" style="color: rgba(255,255,255,.7)">Ausblick</div>
<h2>Gute Ausgangslage fuer den Fruehsommer</h2>
<p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p>
</div>
<div class="notes">
<strong>Hinweise zur Datengrundlage</strong>
<ul>
<li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li> </ul>
</div>
<div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</section>
</main>
</body>
</html>
+67
View File
@@ -0,0 +1,67 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Split Teal - Ferienapartments Kuestenblick</title><style>
:root{--p:#095B61;--s:#2E8E8B;--a:#9ED8CB;--t:#183334;--m:#698281;--bg:#EEF7F5;--line:#d9dfdf;--pos:#28745a;--neg:#a74646}@page{size:A4;margin:12mm 14mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.2pt/1.48 Arial,Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:31pt;line-height:.98;margin:0}h2{font-size:15pt;margin-bottom:3mm}h3{font-size:10.3pt;margin-bottom:1mm}p{margin-bottom:2.6mm}.cover{display:grid;grid-template-columns:1fr 1fr;min-height:68mm;margin-bottom:6mm;break-inside:avoid}.cover-left{background:var(--p);color:#fff;padding:7mm;display:flex;flex-direction:column;justify-content:space-between}.cover-right{background:var(--bg);padding:7mm;display:flex;flex-direction:column;justify-content:space-between}.brand{display:flex;align-items:center;gap:3mm}.logo{width:13mm;height:13mm;background:#fff;color:var(--p);display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand-name{font-weight:800}.small{font-size:7.3pt;opacity:.76}.kicker,.kpi-label,.category{font-size:6.7pt;text-transform:uppercase;letter-spacing:1px;font-weight:800;color:var(--m)}.cover-left .kicker{color:#ffffffb8}.period{font-size:18pt;color:var(--p);font-weight:800}.summary h2{font-size:15pt}.summary p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:3mm;margin-bottom:3mm}.kpi{padding:4mm;border-left:1mm solid var(--p);background:#fff;border-top:1px solid var(--line);border-right:1px solid var(--line);border-bottom:1px solid var(--line)}.kpi:nth-child(even){border-left-color:var(--a)}.kpi-value{font-size:15.5pt;font-weight:800;color:var(--p);margin:2mm 0;white-space:nowrap}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);background:var(--bg);padding:3mm 4mm;margin-bottom:7mm}.fact span{display:block;font-size:6.7pt;color:var(--m)}.fact strong{display:block;margin-top:.5mm}.band{display:grid;grid-template-columns:40mm 1fr;gap:6mm;margin:7mm 0;break-inside:avoid}.band-title{background:var(--p);color:#fff;padding:5mm;min-height:30mm}.band-title.alt{background:var(--a);color:var(--t)}.band-title h2{margin:0}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:18mm 1fr 28mm 22mm;gap:2.5mm;align-items:center;font-size:7.3pt}.trend-label{font-weight:700}.trend-track{height:4mm;background:var(--bg);position:relative}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1.2mm;background:var(--a);position:absolute;bottom:0;left:0}.trend-num{text-align:right}.developments{display:grid;grid-template-columns:1fr 1fr;gap:3mm}.development{display:grid;grid-template-columns:2mm 1fr;gap:3mm;border:1px solid var(--line);padding:3.5mm;break-inside:avoid}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendations{display:grid;gap:3mm}.recommendation{display:grid;grid-template-columns:9mm 1fr;gap:3mm;border-bottom:1px solid var(--line);padding:0 0 3mm;break-inside:avoid}.priority{font-size:18pt;font-weight:800;color:var(--a)}.recommendation p{margin-bottom:1.3mm}.effect{color:var(--p)}.outlook{margin-top:7mm;display:grid;grid-template-columns:38mm 1fr;background:var(--bg);padding:5mm;break-inside:avoid}.outlook .kicker{align-self:start;color:var(--p)}.outlook h2{margin-bottom:2mm}.outlook p{margin:0}.notes{font-size:6.8pt;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.2pt;color:var(--m);margin-top:2mm}
</style></head><body>
<section class="cover"><div class="cover-left"><div class="brand"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div><div class="brand-name">Ferienapartments Kuestenblick</div><div class="small">Apartment Seestern</div></div></div><div><div class="kicker">Performance & Strategie</div><h1>Monatsreport</h1></div></div><div class="cover-right"><div><div class="kicker">Berichtszeitraum</div><div class="period">Mai 2026</div><div class="small">Nordseekueste · 24.06.2026</div></div><div class="summary"><div class="kicker">Kurzfazit</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<section class="band"><div class="band-title"><div class="kicker">01</div><h2>Monatsverlauf</h2></div><div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div></div></section>
<section class="band"><div class="band-title alt"><div class="kicker">02</div><h2>Entwicklungen</h2></div><div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></div></section>
<section class="band"><div class="band-title"><div class="kicker">03</div><h2>Empfehlungen</h2></div><div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></div></section>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
@@ -0,0 +1,67 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Split Terracotta - Ferienapartments Kuestenblick</title><style>
:root{--p:#8B4938;--s:#B26950;--a:#E3B68F;--t:#3B2D29;--m:#84756F;--bg:#FAF1EA;--line:#d9dfdf;--pos:#28745a;--neg:#a74646}@page{size:A4;margin:12mm 14mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.2pt/1.48 Georgia,Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:31pt;line-height:.98;margin:0}h2{font-size:15pt;margin-bottom:3mm}h3{font-size:10.3pt;margin-bottom:1mm}p{margin-bottom:2.6mm}.cover{display:grid;grid-template-columns:1fr 1fr;min-height:68mm;margin-bottom:6mm;break-inside:avoid}.cover-left{background:var(--p);color:#fff;padding:7mm;display:flex;flex-direction:column;justify-content:space-between}.cover-right{background:var(--bg);padding:7mm;display:flex;flex-direction:column;justify-content:space-between}.brand{display:flex;align-items:center;gap:3mm}.logo{width:13mm;height:13mm;background:#fff;color:var(--p);display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand-name{font-weight:800}.small{font-size:7.3pt;opacity:.76}.kicker,.kpi-label,.category{font-size:6.7pt;text-transform:uppercase;letter-spacing:1px;font-weight:800;color:var(--m)}.cover-left .kicker{color:#ffffffb8}.period{font-size:18pt;color:var(--p);font-weight:800}.summary h2{font-size:15pt}.summary p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:3mm;margin-bottom:3mm}.kpi{padding:4mm;border-left:1mm solid var(--p);background:#fff;border-top:1px solid var(--line);border-right:1px solid var(--line);border-bottom:1px solid var(--line)}.kpi:nth-child(even){border-left-color:var(--a)}.kpi-value{font-size:15.5pt;font-weight:800;color:var(--p);margin:2mm 0;white-space:nowrap}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);background:var(--bg);padding:3mm 4mm;margin-bottom:7mm}.fact span{display:block;font-size:6.7pt;color:var(--m)}.fact strong{display:block;margin-top:.5mm}.band{display:grid;grid-template-columns:40mm 1fr;gap:6mm;margin:7mm 0;break-inside:avoid}.band-title{background:var(--p);color:#fff;padding:5mm;min-height:30mm}.band-title.alt{background:var(--a);color:var(--t)}.band-title h2{margin:0}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:18mm 1fr 28mm 22mm;gap:2.5mm;align-items:center;font-size:7.3pt}.trend-label{font-weight:700}.trend-track{height:4mm;background:var(--bg);position:relative}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1.2mm;background:var(--a);position:absolute;bottom:0;left:0}.trend-num{text-align:right}.developments{display:grid;grid-template-columns:1fr 1fr;gap:3mm}.development{display:grid;grid-template-columns:2mm 1fr;gap:3mm;border:1px solid var(--line);padding:3.5mm;break-inside:avoid}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendations{display:grid;gap:3mm}.recommendation{display:grid;grid-template-columns:9mm 1fr;gap:3mm;border-bottom:1px solid var(--line);padding:0 0 3mm;break-inside:avoid}.priority{font-size:18pt;font-weight:800;color:var(--a)}.recommendation p{margin-bottom:1.3mm}.effect{color:var(--p)}.outlook{margin-top:7mm;display:grid;grid-template-columns:38mm 1fr;background:var(--bg);padding:5mm;break-inside:avoid}.outlook .kicker{align-self:start;color:var(--p)}.outlook h2{margin-bottom:2mm}.outlook p{margin:0}.notes{font-size:6.8pt;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.2pt;color:var(--m);margin-top:2mm}
</style></head><body>
<section class="cover"><div class="cover-left"><div class="brand"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div><div class="brand-name">Ferienapartments Kuestenblick</div><div class="small">Apartment Seestern</div></div></div><div><div class="kicker">Performance & Strategie</div><h1>Monatsreport</h1></div></div><div class="cover-right"><div><div class="kicker">Berichtszeitraum</div><div class="period">Mai 2026</div><div class="small">Nordseekueste · 24.06.2026</div></div><div class="summary"><div class="kicker">Kurzfazit</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<section class="band"><div class="band-title"><div class="kicker">01</div><h2>Monatsverlauf</h2></div><div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div></div></section>
<section class="band"><div class="band-title alt"><div class="kicker">02</div><h2>Entwicklungen</h2></div><div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></div></section>
<section class="band"><div class="band-title"><div class="kicker">03</div><h2>Empfehlungen</h2></div><div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></div></section>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+67
View File
@@ -0,0 +1,67 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Split Violet - Ferienapartments Kuestenblick</title><style>
:root{--p:#513A75;--s:#7557A0;--a:#BFA8E2;--t:#302A38;--m:#787080;--bg:#F4F0FA;--line:#d9dfdf;--pos:#28745a;--neg:#a74646}@page{size:A4;margin:12mm 14mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.2pt/1.48 Arial,Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:31pt;line-height:.98;margin:0}h2{font-size:15pt;margin-bottom:3mm}h3{font-size:10.3pt;margin-bottom:1mm}p{margin-bottom:2.6mm}.cover{display:grid;grid-template-columns:1fr 1fr;min-height:68mm;margin-bottom:6mm;break-inside:avoid}.cover-left{background:var(--p);color:#fff;padding:7mm;display:flex;flex-direction:column;justify-content:space-between}.cover-right{background:var(--bg);padding:7mm;display:flex;flex-direction:column;justify-content:space-between}.brand{display:flex;align-items:center;gap:3mm}.logo{width:13mm;height:13mm;background:#fff;color:var(--p);display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand-name{font-weight:800}.small{font-size:7.3pt;opacity:.76}.kicker,.kpi-label,.category{font-size:6.7pt;text-transform:uppercase;letter-spacing:1px;font-weight:800;color:var(--m)}.cover-left .kicker{color:#ffffffb8}.period{font-size:18pt;color:var(--p);font-weight:800}.summary h2{font-size:15pt}.summary p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:3mm;margin-bottom:3mm}.kpi{padding:4mm;border-left:1mm solid var(--p);background:#fff;border-top:1px solid var(--line);border-right:1px solid var(--line);border-bottom:1px solid var(--line)}.kpi:nth-child(even){border-left-color:var(--a)}.kpi-value{font-size:15.5pt;font-weight:800;color:var(--p);margin:2mm 0;white-space:nowrap}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);background:var(--bg);padding:3mm 4mm;margin-bottom:7mm}.fact span{display:block;font-size:6.7pt;color:var(--m)}.fact strong{display:block;margin-top:.5mm}.band{display:grid;grid-template-columns:40mm 1fr;gap:6mm;margin:7mm 0;break-inside:avoid}.band-title{background:var(--p);color:#fff;padding:5mm;min-height:30mm}.band-title.alt{background:var(--a);color:var(--t)}.band-title h2{margin:0}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:18mm 1fr 28mm 22mm;gap:2.5mm;align-items:center;font-size:7.3pt}.trend-label{font-weight:700}.trend-track{height:4mm;background:var(--bg);position:relative}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1.2mm;background:var(--a);position:absolute;bottom:0;left:0}.trend-num{text-align:right}.developments{display:grid;grid-template-columns:1fr 1fr;gap:3mm}.development{display:grid;grid-template-columns:2mm 1fr;gap:3mm;border:1px solid var(--line);padding:3.5mm;break-inside:avoid}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendations{display:grid;gap:3mm}.recommendation{display:grid;grid-template-columns:9mm 1fr;gap:3mm;border-bottom:1px solid var(--line);padding:0 0 3mm;break-inside:avoid}.priority{font-size:18pt;font-weight:800;color:var(--a)}.recommendation p{margin-bottom:1.3mm}.effect{color:var(--p)}.outlook{margin-top:7mm;display:grid;grid-template-columns:38mm 1fr;background:var(--bg);padding:5mm;break-inside:avoid}.outlook .kicker{align-self:start;color:var(--p)}.outlook h2{margin-bottom:2mm}.outlook p{margin:0}.notes{font-size:6.8pt;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.2pt;color:var(--m);margin-top:2mm}
</style></head><body>
<section class="cover"><div class="cover-left"><div class="brand"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div><div class="brand-name">Ferienapartments Kuestenblick</div><div class="small">Apartment Seestern</div></div></div><div><div class="kicker">Performance & Strategie</div><h1>Monatsreport</h1></div></div><div class="cover-right"><div><div class="kicker">Berichtszeitraum</div><div class="period">Mai 2026</div><div class="small">Nordseekueste · 24.06.2026</div></div><div class="summary"><div class="kicker">Kurzfazit</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></div></div></section>
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div><div class="facts">
<div class="fact"><span>RevPAR</span><strong>99,32 €</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>54</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>3,6 Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>6,2 %</strong></div>
</div>
<section class="band"><div class="band-title"><div class="kicker">01</div><h2>Monatsverlauf</h2></div><div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div></div></section>
<section class="band"><div class="band-title alt"><div class="kicker">02</div><h2>Entwicklungen</h2></div><div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></div></section>
<section class="band"><div class="band-title"><div class="kicker">03</div><h2>Empfehlungen</h2></div><div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></div></section>
<section class="outlook"><div class="kicker">Ausblick</div><h2>Gute Ausgangslage fuer den Fruehsommer</h2><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div>
</body></html>
+58
View File
@@ -0,0 +1,58 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Sunset Coral - Ferienapartments Kuestenblick</title><style>
:root{--p:#A9474E;--s:#D06B62;--a:#F0B66D;--t:#382B30;--m:#82747A;--bg:#FBF1ED;--line:#d8e0df;--pos:#28765b;--neg:#a54b4b}@page{size:A4;margin:0 13mm 18mm 0}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.1pt/1.48 Arial,Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:25pt;line-height:1.05;margin-bottom:2mm}h2{font-size:14pt;margin-bottom:3mm}h3{font-size:10.2pt;margin-bottom:1mm}p{margin-bottom:2.7mm}.page{display:grid;grid-template-columns:45mm 1fr;min-height:279mm}.side{background:linear-gradient(180deg,var(--p),var(--s));color:#fff;padding:13mm 7mm 10mm 8mm}.main{padding:13mm 0 0 9mm}.logo{width:15mm;height:15mm;background:#fff;color:var(--p);border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden;margin-bottom:5mm}.logo img{width:100%;height:100%;object-fit:contain;padding:1.3mm}.brand{font-weight:800;font-size:11pt}.side-sub{font-size:7.5pt;opacity:.78;margin-top:1mm}.side-period{margin:18mm 0 10mm}.side-period strong{font-size:18pt;display:block;line-height:1.05}.kicker,.kpi-label,.category{font:800 6.8pt/1.2 Arial,sans-serif;text-transform:uppercase;letter-spacing:1px;color:var(--m)}.side .kicker{color:#ffffffb0}.side-facts{display:grid;gap:4mm;border-top:1px solid #ffffff40;padding-top:5mm}.side-fact span{font-size:7pt;opacity:.7;display:block}.side-fact strong{font-size:11pt}.side-outlook{margin-top:13mm;border-top:1px solid #ffffff40;padding-top:5mm}.side-outlook h3{font-size:11pt}.side-outlook p{font-size:7.6pt;opacity:.88}.intro{margin-bottom:6mm}.intro h1{color:var(--p)}.summary{border-left:1.4mm solid var(--a);padding:1mm 0 1mm 5mm;margin:5mm 0 6mm}.summary h2{font-size:14.5pt}.summary p{margin:0}.kpis{display:grid;grid-template-columns:1fr 1fr;gap:3mm;margin-bottom:5mm}.kpi{background:var(--bg);padding:4mm;border-radius:2mm;break-inside:avoid}.kpi-value{font-size:17pt;font-weight:800;color:var(--p);margin:2mm 0}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:none}.section{margin:6mm 0}.section-head{display:flex;align-items:center;gap:3mm;margin-bottom:3mm}.section-head h2{margin:0;white-space:nowrap}.line{height:1px;background:var(--line);width:100%}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:16mm 1fr 27mm 21mm;gap:2mm;align-items:center;font-size:7.2pt}.trend-label{font-weight:700}.trend-track{height:3.7mm;background:var(--bg);position:relative}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1mm;background:var(--a);position:absolute;bottom:0;left:0}.trend-num{text-align:right}.developments{columns:2;column-gap:5mm}.development{display:grid;grid-template-columns:2mm 1fr;gap:2.5mm;break-inside:avoid;margin-bottom:3mm}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendations{display:grid;gap:3mm}.recommendation{display:grid;grid-template-columns:9mm 1fr;gap:3mm;padding:3.5mm 0;border-top:1px solid var(--line);break-inside:avoid}.priority{font-size:18pt;font-weight:800;color:var(--a)}.recommendation p{margin-bottom:1.3mm}.effect{color:var(--p)}.outlook{display:none}.notes{font-size:6.8pt;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.2pt;color:var(--m);margin-top:2mm}
</style></head><body><div class="page">
<aside class="side"><div class="logo">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjAgMTYwJz48cmVjdCB3aWR0aD0nMTYwJyBoZWlnaHQ9JzE2MCcgcng9JzM1JyBmaWxsPScjZmZmZmZmJy8+PHBhdGggZD0nTTI4IDEwNWMyOC0xMCA1NC0xMCAxMDQgMCcgc3Ryb2tlPScjMWY1ZDY2JyBzdHJva2Utd2lkdGg9JzknIGZpbGw9J25vbmUnIHN0cm9rZS1saW5lY2FwPSdyb3VuZCcvPjxjaXJjbGUgY3g9JzgwJyBjeT0nNjInIHI9JzI4JyBmaWxsPScjZGJhMjVkJy8+PHBhdGggZD0nTTQ4IDYyaDY0JyBzdHJva2U9JyMxZjVkNjYnIHN0cm9rZS13aWR0aD0nOCcgc3Ryb2tlLWxpbmVjYXA9J3JvdW5kJy8+PC9zdmc+" alt="Logo"></div><div class="brand">Ferienapartments Kuestenblick</div><div class="side-sub">Apartment Seestern<br>Nordseekueste</div><div class="side-period"><div class="kicker">Monatsreport</div><strong>Mai 2026</strong><div class="side-sub">Version 1.0</div></div><div class="side-facts"><div class="side-fact"><span>RevPAR</span><strong>99,32 €</strong></div><div class="side-fact"><span>Verkaufte Nächte</span><strong>54</strong></div><div class="side-fact"><span>Ø Aufenthalt</span><strong>3,6</strong></div><div class="side-fact"><span>Stornoquote</span><strong>6,2 %</strong></div></div><div class="side-outlook"><div class="kicker">Ausblick</div><h3>Gute Ausgangslage fuer den Fruehsommer</h3><p>Die Kombination aus stabiler Nachfrage und verbessertem Tagespreis schafft eine robuste Basis fuer Juni. Entscheidend ist, Preiserhoehungen nur an Tagen mit erkennbar hoher Nachfrage einzusetzen und freie Randtage nicht versehentlich mit zu strengen Aufenthaltsregeln zu blockieren.</p></div></aside>
<main class="main"><section class="intro"><div class="kicker">Performance & Handlungsempfehlungen</div><h1>Der Monat<br>im Überblick</h1></section><section class="summary"><div class="kicker">Kurzfazit</div><h2>Starker Umsatzmonat bei weiterhin gesunder Auslastung</h2><p>Der Mai verbindet eine hohe Auslastung mit einem gestiegenen durchschnittlichen Tagespreis. Dadurch liegt der Umsatz klar ueber dem Vormonat, ohne dass die Buchungszahl im gleichen Umfang wachsen musste. Die Stornoquote bleibt beherrschbar. Fuer die kommenden Wochen sollte der Fokus deshalb auf einer feineren Preissteuerung an besonders nachgefragten Tagen liegen.</p></section><div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">6.840,50 €</div><div class="kpi-delta up">+12,8 %</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">78,4 %</div><div class="kpi-delta up">+5,7 PP</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">126,68 €</div><div class="kpi-delta up">+4,6 %</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">19</div><div class="kpi-delta up">+2 Buchungen</div></article>
</div>
<section class="section"><div class="section-head"><h2>Monatsverlauf</h2><div class="line"></div></div><div class="trend-bars">
<div class="trend-row">
<div class="trend-label">Dez 25</div>
<div class="trend-track"><div class="trend-revenue" style="width:61.55%"></div><div class="trend-occ" style="width:55.2%"></div></div>
<div class="trend-num">4.210,00 €</div>
<div class="trend-num">55,2 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Jan 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:56.87%"></div><div class="trend-occ" style="width:51.4%"></div></div>
<div class="trend-num">3.890,00 €</div>
<div class="trend-num">51,4 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Feb 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:65.42%"></div><div class="trend-occ" style="width:59.7%"></div></div>
<div class="trend-num">4.475,00 €</div>
<div class="trend-num">59,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mär 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:78.36%"></div><div class="trend-occ" style="width:66.1%"></div></div>
<div class="trend-num">5.360,00 €</div>
<div class="trend-num">66,1 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Apr 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:88.65%"></div><div class="trend-occ" style="width:72.7%"></div></div>
<div class="trend-num">6.064,00 €</div>
<div class="trend-num">72,7 %</div>
</div>
<div class="trend-row">
<div class="trend-label">Mai 26</div>
<div class="trend-track"><div class="trend-revenue" style="width:100%"></div><div class="trend-occ" style="width:78.4%"></div></div>
<div class="trend-num">6.840,50 €</div>
<div class="trend-num">78,4 %</div>
</div>
</div></section><section class="section"><div class="section-head"><h2>Entwicklungen</h2><div class="line"></div></div><div class="developments">
<article class="development positive"><div class="impact"></div><div><h3>Umsatz gewinnt ueberproportional</h3><p>Der Umsatz steigt staerker als die Buchungszahl. Das spricht dafuer, dass der hoehere Tagespreis und eine bessere Belegung der verfuegbaren Naechte den Monat getragen haben.</p></div></article>
<article class="development positive"><div class="impact"></div><div><h3>Auslastung erreicht ein solides Niveau</h3><p>Mit 78,4 Prozent ist ein grosser Teil der verfuegbaren Kapazitaet verkauft. Gleichzeitig verbleibt genug Spielraum, um einzelne schwache Wochentage gezielt zu stimulieren.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Stornos bleiben ein Beobachtungspunkt</h3><p>Die Stornoquote ist nicht kritisch, sollte aber nach Buchungskanal und Vorlaufzeit beobachtet werden. So laesst sich erkennen, ob bestimmte Tarife oder Plattformen ueberdurchschnittlich betroffen sind.</p></div></article>
<article class="development neutral"><div class="impact"></div><div><h3>Aufenthaltsdauer bleibt kompakt</h3><p>Die durchschnittliche Aufenthaltsdauer von 3,6 Naechten sorgt fuer regelmaessige Gaestewechsel. Das kann Umsatzchancen schaffen, erhoeht jedoch zugleich den operativen Aufwand je belegter Nacht.</p></div></article>
</div></section><section class="section"><div class="section-head"><h2>Empfehlungen</h2><div class="line"></div></div><div class="recommendations">
<article class="recommendation"><div class="priority">1</div><div><div class="category">Preisgestaltung</div><h3>Nachfragestarke Wochenenden differenzierter bepreisen</h3><p><strong>Begründung:</strong> Umsatz, Tagespreis und Auslastung entwickeln sich gleichzeitig positiv. Dadurch besteht an stark nachgefragten Terminen Spielraum, den Preis vorsichtig weiter auszureizen.</p><p><strong>Massnahme:</strong> Fuer Freitage, Samstage und lokale Spitzentermine einen Preisaufschlag von zunaechst 5 Prozent testen und die Buchungsgeschwindigkeit wochenweise kontrollieren.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Hoeherer Umsatz pro verfuegbarer Nacht ohne pauschale Preiserhoehung fuer den gesamten Monat.</p></div></article>
<article class="recommendation"><div class="priority">2</div><div><div class="category">Verfuegbarkeit &amp; Buchungssteuerung</div><h3>Schwache Wochentage mit Mindestaufenthalten entlasten</h3><p><strong>Begründung:</strong> Die Auslastung ist insgesamt gut, dennoch koennen einzelne Luecken zwischen kurzen Aufenthalten entstehen und wertvolle Naechte blockieren.</p><p><strong>Massnahme:</strong> Fuer ausgewaehlte Anreisetage flexible Mindestaufenthalte einsetzen und kurze Restluecken gezielt fuer Zwei-Nacht-Buchungen freigeben.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Weniger unverkaeufliche Einzelnächte und eine gleichmaessigere Belegung.</p></div></article>
<article class="recommendation"><div class="priority">3</div><div><div class="category">Gaeste &amp; Bewertungen</div><h3>Stornierungen nach Kanal und Vorlauf auswerten</h3><p><strong>Begründung:</strong> Die aktuelle Stornoquote ist tragbar, liefert ohne Segmentierung aber noch keinen Hinweis auf die eigentliche Ursache.</p><p><strong>Massnahme:</strong> Stornos kuenftig nach Buchungskanal, Tarifart und Tagen bis zur Anreise gruppieren und im naechsten Report separat vergleichen.</p><p class="effect"><strong>Erwarteter Effekt:</strong> Gezieltere Tarifregeln und weniger vermeidbare kurzfristige Ausfaelle.</p></div></article>
</div></section><section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul><li>Die Bewertung basiert auf Monatsaggregaten; Unterschiede zwischen Wochentagen und Buchungskanaelen sind darin noch nicht getrennt sichtbar.</li></ul></section><div class="legal">Dieser Report ist eine datenbasierte Entscheidungshilfe. Prognosen und erwartete Effekte sind keine Garantie fuer zukuenftige Ergebnisse.</div></main></div></body></html>
File diff suppressed because one or more lines are too long
+156
View File
@@ -0,0 +1,156 @@
%PDF-1.4
%“Œ‹ž ReportLab Generated PDF document (opensource)
1 0 obj
<<
/F1 2 0 R /F2 3 0 R /F3 4 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
>>
endobj
4 0 obj
<<
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
>>
endobj
5 0 obj
<<
/Contents 13 0 R /MediaBox [ 0 0 841.8898 595.2756 ] /Parent 12 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
6 0 obj
<<
/Contents 14 0 R /MediaBox [ 0 0 841.8898 595.2756 ] /Parent 12 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
7 0 obj
<<
/Contents 15 0 R /MediaBox [ 0 0 841.8898 595.2756 ] /Parent 12 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
8 0 obj
<<
/Contents 16 0 R /MediaBox [ 0 0 841.8898 595.2756 ] /Parent 12 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
9 0 obj
<<
/Contents 17 0 R /MediaBox [ 0 0 841.8898 595.2756 ] /Parent 12 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
10 0 obj
<<
/PageMode /UseNone /Pages 12 0 R /Type /Catalog
>>
endobj
11 0 obj
<<
/Author (anonymous) /CreationDate (D:20260624142554+00'00') /Creator (anonymous) /Keywords () /ModDate (D:20260624142554+00'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (unspecified) /Title (untitled) /Trapped /False
>>
endobj
12 0 obj
<<
/Count 5 /Kids [ 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R ] /Type /Pages
>>
endobj
13 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2039
>>
stream
GauI88TWWE'Z]\A'KEOhQmFWl36#+T);@<mReG/;AO/4iMXk`.dSJa*!X)%3A.k@F4(AHB>6s0#TDsEr9&U``5Aq&<?#7l++#(P7D>"7AKV?X*HG;K+h^=6Pmutu1T;3sU.RONfQq62$E%))\opp*=/io,NB-\XPB4u?O^K_k]p:gH^53g0uh4i)er=s2K7@R@B'h53QJi&TW-C,"\-q[SG?NMN925qdf=;E[.pml;[];e.c"l[g.rq4pOqts9TKs!mZk@X;TpG8=Yo_GTRK2Z?6+-=DtO]%1q/()UE,/Ka!PXrVML)1fZ6p]rS*k)YJ"h%0*Ar0tj+Uj!,UPi1b"8jPpMSUfU.O?JA'`=g!a-\)F]dkE@#LZO0$g'U>'#B3r`aKAfWfNc#B<O(sbgm):=\=IiKLLFY[pBeIAj#[!R(H$@4Guhj5Q+4.Qo#c5&As8!TijQp^t?S5(^:(;-3hB7(q<2_&n),<-E/Xu`[I^4iP:Jhj-^(jVZh`0Nd/]5"aqflQX[!goFHMQ3uiIUY"l$_4Dbqf#hZ[a9c/bEnjkM_q7&.QGkAF[g>h-K$Unr*4pQ'89^Nm!!Qf:3LIadmp_5E6lEK5'+.lFs3/>:t<Br:$IUaT/paEtJm@CDlC8Y9q0(Z[)eSFfDY04K42\3sL4bD#,^=EJAl$ZDD]&)RG31%X]g?8-0=37s,B1gn=V/iMKB)]@3_nrQ>P8Sa]2S?4XlQteSQaH^_A?PN/3npkfT(,ut++i$JWpa<u,E<-b,)'_`)eG$G$tE^ZB6j[D9)GHk45:WqeebbM`Sh/N_.0DMe$=C*-<2H&Mu3%q.\=`j@OPj^#[Xbb@JAu5LbZpm6Su5ZZ,E=I4j]!@I.EjT:9Y18$FWko"l$hk@(RV]GXcPs"^9`JH.*J:CZ3F6S1s929sQ7U6DcKJAu>0IFG2P]Ibj5!f^#R9qKTZRo6m<>UV/90NNN\kWZT74>ea5]IiK-?li@Q:#`8jl-!kU,DBDT&&RgjsOKbl[/\*M,A;8'dlZ[(cP):&i++cqOAJW"R_T&E0"1'9i:G[5n_A>3jXHa0;U8#`%&>L^ik0n7I-mBuVa:GsT+u5]+%)\3YS/TIK<>9#>T"9YG3TPgKZ@b#7'I>^aqt!qY!(^21h>NOi`UcM49h4B(W_[V@`_sHC8eF'Uo7nqkh7Q3g[r70dh72JQXC-r-3dk?:N\3S![7=L_14:X&rdX7.C$N>m9M%'FlrHgm66f4lSi#Eoag8_2]pO[=.>t2o\C\HiE=c&)?41U\e5Y5hLXah3f]1N3*._"T,aP<6*Hhngq'(A*?(U8ZDfNiV,;?c;mXaIu4Z,kWYG[sXU_$foeNG:!$FTt4_03u#OfaSpY(s+J]D-#Y.qFUSld,7^(%O`u<io"KT50%`G?sl<C=GB,eZPkA:IT>OYL*U%8tU6?Ba2B,!m(!7]m9A``)e_-R[NK(ObSb2!DD'mF../Gmr"8b)Ck0t*JL9kTX*Z8ePJ%E>NeGXTq5%9cqph<jm'ApM@]\6"=*?YCmN:0oIRZ;X@LD>B6]P@mef0uP]+fQU'U1")%fV"T70-eiH-8jr6XaRN$n?uIM`L7jF55^<t\8)gHSIn@4k#.2s$epkM5-BH9L);g$%QWmk^ImOUNn,9pgmFI-g8e/\sQlXY.nG=`i-0&^Hund([sdWq*U!WuO*@S_"B"B=;JZ>EQkSco;]$1i0=#$td-&MkmkHYa^ed(2#<m!o";T;VZ&]@uNm748k71H4aAo7[bRGE6g_<LDa&'+XbPp;pid'C;*0$\%`KOqIUK]?JdjI*'X3)+'s_m0I5<1Vftc]3!m%Sl.sdVAF[D^-[<2c)X,5=Z$b6dc2I@'f=TQZc3,rl^ZaFT/NuH`Phes-$(8fCd6jf&D'[R;11u30b;-9[N-:anJ@>W:R.GO>JssG<27bE#\cIWi`.:oIH7+RJ"Y/(@iOU\rhnq'C-[4?SD(9VdY3'n5B#D/3&b`Y]WcD]B[*Xe=j[<C0jZhG^mj_ikV#@nE7'kKf7B7"A/L3CS+*B&?DZ~>endstream
endobj
14 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2052
>>
stream
GauHMgN)%,&:O:SlslNA=Q2f3O)\pDSKr&"ekB^;IA%oWAkeC:01kN6mfFU4;C7gMf#78a#.4[@QeeD=Qp?Jb`;JI5!A<!ndkq.m@D)o_!tOY+E4*D6cRD]^S4;pl&1/Pl+p^`XAVdNh`%g@M*AiFk^!dfd6j"o-"R@<1n?+=2g\`,LWt/dl^mhG$&_@!!qLt[gOI-W56/49d:r]"k^a&c?&;X.]9ec+Y1L^/n<G.)]L9/2Yi,*dI[`q!!ApL82!U\Z9hZ%U^!WeoG$I_".D!+<E#n,`P)*H+$js#Tn/J8=uaT]KsgT0`GoJ[93FMoH0+;RI5_Kc1c)jQ#u(YAuPR%Oc+=2C)^T&:LGisnk@!5]_?E"V)sE#*F]EKs']M3&4e'Brp^e>PO)&l+8$3@BP482PP2Ks<aNrE+%c0F'//J4-kZhXq6fLCDcZ_-r%03GkB>l5,WAY.CK:6Q<i:.%kMT!'s*UI8^Amko'_'B2KY%/mgVOKUM2CD8G2!R@\"&M$/Wrq_Ym#l`<p*%KB6u]j4h!DT]??SRsI%>W;bX\:ZuG#UU9"'7;nXT'tsNg9s`L;8MSQ[+^g[IS.SPS!kRrh*Np0LJ/m:R3Iff-W3+TC-+dN!&MVm7?39\8VKEm,f6S"R\XQ%-cj5VlkNQLPs/a'9=W+7NN/X'G516o8FoQI[]j]?=eiF7794>F<Mp@M0J(\L"P8S`mPCC!T.V"\??HqmL;B!Y,_9pcTjfp4@Q%kOL`m(B?AplX`a'%/A-TG<9U$eYTWaIe:-5G"Q?_UkZb=RR#hN4:WJ"cZDI3XY3=XB8^qih(k(pt`hI5TC7!Hci,*q<.p[1I=E,tNn$AX]8qVl#*,3*1HeG.ZPlA^UemIYa_N[()lT$+Q'@"$n(7sR5O[/=`PfUa][SoL\pJ%&FY[Wf2phPan]C:GgqSP%Y_E6K6qPZC:sKK&:R]rKMm#?<T*nX1g87l=T,U6@-d5Rm!W!0K!=6;":!Xp8QSbX.M($+a)r&Wo`5YI#u?Pg?WhPfQGp$2\kN)NDA04.:]I*bFJL=#EOEc2I(<pFrs5Bp0TMk1q\8(b/#c`&4)STlE%!kaR3TGT79ee\a()aS_NDV`&7#eYKX5EuGnnB_>ncCfOZSAYmn/3hLP'iP=06RUW[mUj/JFU%*X;kE%P.DY3BA='=@XQZ,X!XN?KiY@q./;AI>VR=/Xo9*MNuCX^h7a83'*g4l$$M0]SQ%EEdeXa,c1!`<lBVGXGD$u&d!OB/l]H'q,RQ'$5Ce#72*0@/&Uk<e=\K60c0m-ud&[^S9d=@9YG9=d;6/^1;Z3",<\2=\B'a&_4g=F@3:(EY`iQpGON&UQ^PnK3>>9635U:jB.d9%=B`/U)t+$'46eWmBPkXR[g31O,4J"Kg.I:rNHp9CWYOQ"=gNk1;A<BZe15R]]YUWFBGqpcWKJ$5Mi$(#tM,6=kE$anhn2l34Z2:B`Yh+QtE$1fP+$VumE;^.p6'N#""0UU)XM(F6@AggESA<!spsr.t\JOksA_lc.^ceHp%C5<@G![VjqhUDSOrDQjciB'.o&=;V[2%#A[[LI0)GT#NX9!$0nE\E921$tdi[ZS4eg!EiXVWe&c5FjA_X_?]h.[@p]>V^S-L@0dn#r2!1Hn4'bFb+*OA9^VA?oB.1^b7RGUb)#^D$=EAJGaReZ<VT)S.BDmji\6OYV>N6<B1\`RUS9RPKVQ!--ip[MmX358W^"9iU*i0qZh6%/W.eF'5%\D[hr8.;,p(?hbXi(_='PWce*aN`nAo-bU(a=q^R=:L-hPZ<*F^l#YdF.?_i7C%>IFIub,WG5!6sej1I+a_,1l]WOdo9/OX2)B*oH^^.$TdhO7.G@.9>jMFJN#?]<!H^/Bt;/WP3Y$'/Yk)chcD:Z9%^hc:Gh-N)nUGeJYI88BTecL\)`?d]1D!qG:4(HZVa@`6u:aOb0srpQmj@3PMmug"6F%(<XGm9^;cKcY_Ko8,"^Ns-\U2[e^*_rHjAnXd(:5B1Bf$Mp^4M8S#U.-bK:VGq<NCs/h!gR?'XTr2#$'KT#j2k;>VI~>endstream
endobj
15 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2112
>>
stream
GauHMgN)%,&:O:SlslMV=Q7?DA)*lJNh)S3U?P#m09cpfX=;:ZOj2Ncho19L8V'QOWNe6k!:AbGMqu8QLd6p67/ssR!F2ec[m(-0$EFUI*cY:f_u%u<m\`<m5>>C4'^%3m'8T2rdhn]VA/XLUCm>C5UXKW>66hqV"BIVZjl='mn#AnQ/0FR[$Wgp:/$/`$eLLkn+P/E*UT?uFELLkO&PqmDKh0,h.Y,GNO+cnEnka5i"-bYQ#M6rT^2#[HY,k5u%q+R$o(g0,M$/4<W:f("2hUQA,:q!CI*bs2Q]!7ZDimDOV-FRZQr2B^TRLmlH6ALdj2A5KauRe!@&&j'q$P/-5:1'hnL8](dtp:Vs31<Q,(MB1l;kaN%mEos%^Al/>=]AI=Ies0(5?)j_"%VQQM\IdXW,85k6*pkb14FMja!RYbY/kEGg-!f@lQ3*E5J)GpfXcR1S=LlAhh2rjtZj*mthpG-2h]m9F]TQ)ds.7*uX]FD]n8bTPl:^)mCS[<Q)0kG"L"?,>>!X"qIQ/=$02GOpDURpE=m5>IOF+/1UEe0nEonSE<!u0#*3=bQFK,"B1M@!$KTU#k61:IYu"X0$@[")e>g%/n1M2ckpK`1#+88PfFUDdYJg+`5+-n;B^",SKM%\<:=f,7gs@Ngt[<.R]"cA.dL,%=5UlC<Aa7HQW;GLVNVJ1ZBd@1FR,rS.M$BA\@KNNomVB4"Uk8WheS4pZIG0U=9!(`&euAp$WW=%.Qi#MN*"#2]P*od(+XCsLb'+$)6]l7U*QB$q@VlKe?[=jr1aVDN&&:;/BJN^bGLT3D:"SNB[Of(&/MJSrZ2lDc&$J1CH:Mi1:<O_kf9'#,bCo9iq!pYXQ2nGga"kIoGRYu[[sA/m?jreX_02'HUc^%#r@55<:4e*1BdDsIuri%0TQpFYpP"nEZXgc,;O%mDI%.B]Pq/1-F;I0^9=d$D7>hU(5WHCAIE^/UcmD<B\U>WHIoQ1]cE6gI+d!j4NnVYZ4+'8N`ctK+qY\qEp_O';4L/lXm(W\f0!D\>q4*PUl209-ESs9-V5g\dNGO^mgZ9@N\aIMmDrdl<"d"-Z`s5ilD^N0bsGtPMu2;oM*5-Bc+#:>#k;WHl%nBd/&f1IbR:H&>I7J.6+o/Il$)b89h/s?24^83=ZeJ'Rfe:ZClk2fD_XGSZB)u5GXBra)/Ek'8#:WkfOC'bTh5$-^FlO]"3o$N(5iF\R=6#lDLs:7#qenfO*&p"AXm[B9iG+3D2h0R2/JBu%h_p(&,U3BCe>qlMSnIl-eh+K0)2rkm4&uQ?(pQ2i04CF(N)Ce.dp#[k_6#elnr-V7Wlt#/JOFI?"'pLWNMG`af2F'Jg*@OS+;AKU3>6OpWD`'1hGu)[C\]Ki[1ig+tRF]E0\Q8h!R[-<(]pHfIUGk3VEO&ntW,'Z>%0_hU]$#[iJE#^buSQSr_G"48c!RRthFD>M1pjiQPbIL?*q_B2E(_VL)sPf8$6@j._]BIr!iAXOb:AAL5s6^-t5e;5J,klIpF"E(f<UOb4oG-`Oo:^'pgi$u=,=kWk$M\B\0P;dqC-4]Glqqhk<J8kemVe)R99BR=c\\<3Ju&gN?"KAn^joEXuDcRCTcdogk#)Vc@f#?M#kO9ueXJ.e@IoK,[(`$6;aRSIN.1:eBF9lE9e=(ACY-7+Ctpk_V%LbunHT;ldQ4rm*P%8bPA!95mN7d'j8dfq\]:;2Itb'bSj<bnhH%o%>UD[eY]2mR,?IjJ@Y8$[%)?-$H%7U.>XI7p"&AMuRjReud!bVKk68lEe^lni'E7X<7'/JO:E?=C$M.Ber6a=4;Q66\>)p/3SB/Wrhu8NOL8bM4l>)>\R^"4`]J(0JZe2X.Q2Upi3RASg]/-FPot[WR!3>7qHaWS""bC.j_"gG&qY>FHSedf2U"NAtWPXCYBHqS6QrWKO_pfpl>:NO\4VA"_>5UG&7b+e_C'ACg<`)o=UfIN!9,;okm-J-sH;<7[?6P"gAbG$bu>K0Bt:i3Ku*]>J,h=)SURV7">.Bq^4XSRdff/44D/Jab\I9jsrq:E9PX9EpJfdgTHK)_4#u,&K'T>%?A&FR?t1g#aC!i\\p(f8VbY^-e,r.tJ-r#T*LAn&h%Y~>endstream
endobj
16 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1954
>>
stream
GauHM?#SIU'Re<2\;sk!B]>@L^'<EickH`uUB?7aW"'JVOl\i/>-,JfQQMqM=n:;!WtRmpHk-`PmQEau$0:kKgu%c?i+`G1r_@u?=?QZC)2Ha"r3j1UpF/p_T,-sGQKt()!]!YmRH'P>V'q,md6^CfSLP0Sc);<[XL@WILL&AGl@7aC4R^u6hH/OZYkf;>D^#nsm7*1MWb:>%<1H7o$[bOe6uJu9R!:>>@Jd1[=-(TIWWp(flgg\(9D;8#X1C&\6G#(<gNOGZ'Cb+XELeoQ45YW6/5o.gpM.4Ma:tA&L.k/k#[Vn^[MQ/43*b&IPJi*@.Pf8Z#(hic^ssCj"*%"2c1*9ncKPJX&?c/,&-7GQ-n4L<6,kH-noKrR&:5,C3^G2&HE_cWe$ueAU^_8_U+Z:6'/#$:SZ`FZ\Ols5EsSH7.%kJg!K<$?qW8@)q'_nS%KU#qaOmj#+a],@g8%VL*n-Hs7[Qgq^Kbs]A=?Jn&0Q!WAC[^XAEpaBX8R>HIo4G0g>"o]G+-DBY`LV,EH-ab,FE"8bRee@#/Y0-4^?MjB$.q49I_eoD>+]B^hmQ#,Z9ab#+5u1IKGk.Af(fpN-^L.Ot\5^&D4V'$&<dq?,"XhLkOl,[GH";%tBn7g,-4<79c-\Fnl(lbrsja2jJYBm:0A7A8-0-a_T):PRNDnm;L']]:$SIY2<eT=H??r!@8:&EGLFS1t#>"b0A$08r!St/qrf[2qXm]?9ips>&YAoiZue,XRB^d3=siH(QPuGeHGUbmD(4ES:cD!c6i9P$2:]]R)IXVU;Y\M=,,@a\A[#c@YWNlcG\@$D2-]"jMY/?34Et/O!m>m5?*4Yl^SI@RHLS4Nt;a_1MX:hj*A<X%:#kZrDC"-SC:4.>a]cK.GOEm_tLP(r&gN&h<suBq=N2oh+3eHC*jQ6(Dr1oX748f?'t]3l9#-5W-XgqR?\5XX;pp\#bb@n8"`/01*,"i!\K3j#5q"e6Z[O9VkHN(.T7C-bUs\m5isod&11p'EF+gqb=]#hW3k/Ba>'4Y^5XS[Tn[hp"5:0Gh]::`kI1('ioJDY.2*f@L8NQ2)kcb!JBAB(e2T^a9hF+F,u7G=m^^=gGNuHBs.7]S0M831.oY$^ZS*k*I(gR!AN)tqRX:_X+aI]];q7Fi<RmN6Te=T9A"6BNR',8q:+8(Lb@V-_(XkQJqiP&%b@=%3fhCoJ+-h\5&ukOi'/P\!]H"o=Q&51=->"<AXCA8fR7D[lM)e-QU)@*sMBJ`5oc&cHYs48oJI_l./9-oqA:qAtTD+8L_6q3B>`Lcj*CK9NE@GF=00#"0X7F0\Z(NAIC*rY%g+n':r<RrlfFCpDA$rA^!RlnnA4CB!cgmUBSW#DgUM7@*WN>&5LsJ7I_Q_'-5Ln'Dc?8s92#!jg.F,2=)#.^$3eZM`K[Wa;F(/&0U!g,X&UI8S9>ncD/EkEB!fS2^ocf&1KfcB_YOs<<a%q@9W,bB+A4LesKcN]Z:j3rL3q\(.8.gV=j&$TKr==rUnr^g4j0P$"e7'+WMJ3(PUB&H_VBbeU&=;=qGSD@_TgrhOEkUeM1S&G(%B!.pkS@l-o.,J@<,O<aQK/jl2Oggu_G]Bc#BV?_`?'Eb6eOYkk)2N>Bh$fr/>M#71#5pJaEN:pE<U/K9^L+2[ka!OeXB&OSVbH5Q[.)cg9GO,Ja7[<b"6Uc%EFWFaA<3'I.b*d1RmJa&MQDE_6Nc!$fZ46_NX&H1u2@&'38#$N/gD15NW5aiS:VXkTBMgb9MrR]IQ(M`KR\_nn1(!rst/F7\tRo38iBCT@kQM.c&G3Z9;_YK1QmpqFt6ZQ!O&#c,&eM]=_?dYdV;Q#,>Q:.!r:7iN_5+pSNN9VJ3cU-a9@t?d,[k.kHoaVug^tJ>HTS-!k#RL6kgnHA)N5In&rk"NrL-$F@g&$RQhk9dqWinmD6$D_?;E*X.*Bb6Spa!YYh?f)~>endstream
endobj
17 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1465
>>
stream
GauHLgMZ%0&:Ml+b[VUAWd#3!a"H*46aFZT2Gb+OM`.GLF`g8%H.2-3GBgA</!?!3gtG%".@`EZE6cj.#fQKame9'Ln88=mh@LeD2EN$DiiotG?T)!R4pC6>e"jSt`B#>,JVYRV`]-ki']i0[D$UI$W</4/Le<fFVL\,!<+UEtTAeWh<cneZ=o1?ure/O=#=Uni'uZ4q+n8Yac62*QIO%<*[SRW.4R&!tqIe8fqm(dS`,osb5$,dJQPN_qR;r9h\!-^`=!SFJFB,p59`*lS.)I1)o\a$cl`3Qb[*T@5aT]MsB=1mXIW;nN&X1-<0pP.qEt&7*C'3q-0aG]Q5rH\[E#mD)4MuCYiX$2^=;Q;;`G"mDZ:DuF>?D:N*T1JDWN82_/k',J8V`S[>f9a"87KE&^^>re--S$m7OH>Ll55akkO/2RQm@i<2(FKqL>n^8k)L7EJH`Dl+QHrYM#\.ZIR39XD,"H](B0uZ*04+KRX3agoOVB"KOTN06RR<j0@@9JD#^8'&&4SrYF``^%)SSs%'!=O&;7ThN0m!e15-n3*lDo)ofS's5Xs7u,TR;'OpWa)dg8nUM*bJU:>gp/cMHMhPh'4#=DhQ,6qR!`aZmW0L`7nn^U#-/%=H9d,;-pMD4];`PI8dPF'c:Ol0t('Ti\f'nJr0<Hd9^qdHI>>Ru(>62&_[h.%E]1WEa"r<>oqs4@BcE'D37nEuO9>-:2csatcKQ+F9f&J_!Hp*N_?rYRBMeR&0usFYrr+GO_#t\A4=]p]&;*%W[Hnpro`j6hML4K($Y]bdXplLDj(i[ON6ff+G&s)@67JrFW@4=o!h!'Nkh2o4,23dp:Ne*)$Ale`UF`:A`][.sp1lmY?nOkX1I6$_^5l.(!:feZR;-4M&mmaJI6b51O?uht0mG6r)1&@oH7Z:[WjonLE1Z!QOsi)Y^6Je;b1dYuFmf&qg>gHL`X]Tu"S;5-+nSY,D<R=26b@:f?)*cRJ,#*t^>Fh5.MKIY*I'-Cc[n'@cg\ePE]*CLDPbm&P:q8;_.tlLL*mJPe0(\kBf*Er/b;^>1KIG[PY5`)u+W(iM2=<"3ftBt:ReELYO].<F[MXgnqrbC>$][+;_kB.6Y]$<3)`W_(OTA#Z4D,\7WG%(#FD^b-@-J3WJI1JC<0=I00V5`q;B[g^_O9B<@D@0Z#S=GAc67;!M#1h6O0D!3fiPTt:)p'msUL0fOGriCKd/Wl+c1R9;^ce]%di+-rUMa]k>f9CaP\ZcM)Wen9Qe!U-N2\_^A[4/CknR#s(%lb8n&)"D8p4jF?=8DR,[cL2*M?($;:B4\9\=?.:-8R__SmTs%6i/<.O3XZU*N#ID>#4?g>"htc&e5ZQ)H4,u*\Vt'mb0^;Vr([TpsHuTZ95dA7+AqNi)YGsS_KJKJY8=YSJHprT=^F-6(6tIB3lo0:Id-#o2i?+Pfj#i"1(#Xa*0`M@SfS)q?KK;%]'~>endstream
endobj
xref
0 18
0000000000 65535 f
0000000061 00000 n
0000000112 00000 n
0000000219 00000 n
0000000331 00000 n
0000000436 00000 n
0000000641 00000 n
0000000846 00000 n
0000001051 00000 n
0000001256 00000 n
0000001461 00000 n
0000001531 00000 n
0000001793 00000 n
0000001877 00000 n
0000004008 00000 n
0000006152 00000 n
0000008356 00000 n
0000010402 00000 n
trailer
<<
/ID
[<bd6b9c6ec5d587c63e157c6e0dcc86fa><bd6b9c6ec5d587c63e157c6e0dcc86fa>]
% ReportLab generated PDF document -- digest (opensource)
/Info 11 0 R
/Root 10 0 R
/Size 18
>>
startxref
11959
%%EOF
+148
View File
@@ -0,0 +1,148 @@
{
"model": "claude-sonnet-4-6",
"max_tokens": 3000,
"temperature": 0.2,
"system": "{{SYSTEM_PROMPT}}",
"messages": [
{
"role": "user",
"content": "{{USER_PROMPT}}"
}
],
"output_config": {
"format": {
"type": "json_schema",
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"summary": {
"type": "object",
"additionalProperties": false,
"properties": {
"headline": {
"type": "string",
"description": "Minimum characters: 8. Maximum characters: 110."
},
"text": {
"type": "string",
"description": "Minimum characters: 80. Maximum characters: 900."
},
"rating": {
"type": "string",
"enum": [
"positive",
"neutral",
"watch"
]
}
},
"required": [
"headline",
"text",
"rating"
]
},
"developments": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"text": {
"type": "string",
"description": "Minimum characters: 40. Maximum characters: 450."
},
"impact": {
"type": "string",
"enum": [
"positive",
"neutral",
"negative"
]
}
},
"required": [
"title",
"text",
"impact"
]
},
"description": "Minimum items: 2. Maximum items: 4."
},
"recommendations": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"priority": {
"type": "integer",
"description": "Minimum value: 1. Maximum value: 3."
},
"category": {
"type": "string",
"description": "Minimum characters: 3. Maximum characters: 80."
},
"reason": {
"type": "string",
"description": "Minimum characters: 40. Maximum characters: 450."
},
"action": {
"type": "string",
"description": "Minimum characters: 30. Maximum characters: 450."
},
"expected_effect": {
"type": "string",
"description": "Minimum characters: 20. Maximum characters: 300."
}
},
"required": [
"priority",
"category",
"title",
"reason",
"action",
"expected_effect"
]
},
"description": "Minimum items: 1. Maximum items: 3."
},
"outlook": {
"type": "object",
"additionalProperties": false,
"properties": {
"headline": {
"type": "string",
"description": "Minimum characters: 5. Maximum characters: 100."
},
"text": {
"type": "string",
"description": "Minimum characters: 60. Maximum characters: 700."
}
},
"required": [
"headline",
"text"
]
},
"data_quality_notes": {
"type": "array",
"items": {
"type": "string",
"description": "Minimum characters: 5. Maximum characters: 240."
},
"description": "Maximum items: 4."
}
},
"required": [
"summary",
"developments",
"recommendations",
"outlook",
"data_quality_notes"
]
}
}
}
}
+24
View File
@@ -0,0 +1,24 @@
Du erstellst die redaktionellen Inhalte eines monatlichen Performance-Reports fuer Betreiber von Ferienunterkuenften.
Ziel:
- Die gelieferten Kennzahlen sachlich erklaeren.
- Auffaellige Entwicklungen priorisieren.
- Maximal drei konkrete, umsetzbare Empfehlungen ableiten.
- Einen realistischen Ausblick formulieren.
Verbindliche Regeln:
1. Nutze ausschliesslich die gelieferten Daten.
2. Erfinde keine Zahlen, Ursachen, Ereignisse oder Vergleichswerte.
3. Unterscheide klar zwischen beobachteter Entwicklung und moeglicher Interpretation.
4. Formuliere professionell, klar und ohne Marketingfloskeln.
5. Nenne keine Prozentwerte, die nicht in den Eingangsdaten enthalten oder daraus eindeutig berechenbar sind.
6. Jede Empfehlung muss auf mindestens einer gelieferten Kennzahl oder Entwicklung beruhen.
7. Empfehlungen muessen konkrete Handlungen enthalten, keine allgemeinen Appelle.
8. Bei fehlenden oder zweifelhaften Daten nutze data_quality_notes.
9. Vermeide Wiederholungen zwischen Zusammenfassung, Entwicklungen und Empfehlungen.
10. Die Ausgabe wird durch ein JSON-Schema erzwungen. Gib keine Einleitung, kein Markdown und keinen zusaetzlichen Text aus.
Bewertung fuer summary.rating:
- positive: Die wichtigsten Kennzahlen entwickeln sich insgesamt guenstig.
- neutral: Das Gesamtbild ist stabil oder gemischt, ohne akuten Handlungsdruck.
- watch: Wesentliche Kennzahlen verschlechtern sich oder verlangen zeitnahe Aufmerksamkeit.
+18
View File
@@ -0,0 +1,18 @@
Erstelle den Monatsreport fuer den folgenden Kunden und Zeitraum.
Kunde:
{{CUSTOMER_JSON}}
Zeitraum:
{{PERIOD_JSON}}
Aktuelle Kennzahlen:
{{METRICS_JSON}}
Vergleichswerte und Verlauf:
{{TRENDS_JSON}}
Zusaetzlicher Kontext, sofern vorhanden:
{{CONTEXT_JSON}}
Priorisiere die wichtigsten Erkenntnisse. Formuliere alle Texte auf Deutsch.
+16
View File
@@ -0,0 +1,16 @@
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PYTHONPATH=/app
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app ./app
EXPOSE 8080
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8080"]
View File
+66
View File
@@ -0,0 +1,66 @@
from __future__ import annotations
from datetime import datetime
from typing import Any
def _group_thousands(value: str) -> str:
parts = []
while value:
parts.append(value[-3:])
value = value[:-3]
return ".".join(reversed(parts))
def number_de(value: Any, decimals: int = 1) -> str:
if value is None:
return "-"
try:
numeric = float(value)
except (TypeError, ValueError):
return "-"
sign = "-" if numeric < 0 else ""
numeric = abs(numeric)
raw = f"{numeric:.{decimals}f}"
integer, _, fraction = raw.partition(".")
grouped = _group_thousands(integer)
return f"{sign}{grouped},{fraction}" if decimals else f"{sign}{grouped}"
def currency_de(value: Any, currency: str = "EUR") -> str:
symbol = {"EUR": "", "USD": "$", "GBP": "£"}.get(currency, currency)
return f"{number_de(value, 2)} {symbol}"
def percent_de(value: Any, decimals: int = 1) -> str:
return f"{number_de(value, decimals)} %"
def delta_de(value: Any, decimals: int = 1, suffix: str = "%") -> str:
if value is None:
return "-"
numeric = float(value)
prefix = "+" if numeric > 0 else ""
return f"{prefix}{number_de(numeric, decimals)} {suffix}".strip()
def date_de(value: Any) -> str:
if not value:
return "-"
if isinstance(value, datetime):
dt = value
else:
try:
dt = datetime.fromisoformat(str(value).replace("Z", "+00:00"))
except ValueError:
return str(value)
return dt.strftime("%d.%m.%Y")
def clamp(value: Any, lower: float = 0, upper: float = 100) -> float:
try:
number = float(value)
except (TypeError, ValueError):
return lower
return max(lower, min(upper, number))
+75
View File
@@ -0,0 +1,75 @@
from __future__ import annotations
import os
from typing import Any
from fastapi import FastAPI, HTTPException, Request, Response
from fastapi.responses import HTMLResponse, JSONResponse
from .renderer import ALLOWED_THEMES, pdf_filename, render_documents, render_pdf_with_gotenberg
from .theme_catalog import public_theme_catalog
from .validation import validate_report
app = FastAPI(
title="Monthly Report Renderer",
version="2.0.0",
description="Validiert Report-Payloads, rendert feste HTML-Templates und erzeugt PDFs via Gotenberg.",
)
@app.middleware("http")
async def limit_request_size(request: Request, call_next):
max_bytes = int(os.getenv("MAX_PAYLOAD_BYTES", "2097152"))
content_length = request.headers.get("content-length")
if content_length and int(content_length) > max_bytes:
return JSONResponse(status_code=413, content={"detail": "Payload too large"})
return await call_next(request)
@app.get("/health")
def health() -> dict[str, Any]:
return {"status": "ok", "service": "monthly-report-renderer", "version": "2.0.0", "theme_count": len(ALLOWED_THEMES)}
@app.get("/themes")
def themes() -> dict[str, Any]:
return {"themes": sorted(ALLOWED_THEMES), "catalog": public_theme_catalog()}
@app.post("/validate")
def validate(payload: dict[str, Any]) -> dict[str, Any]:
errors = validate_report(payload)
return {"valid": not errors, "errors": errors}
def _ensure_valid(payload: dict[str, Any]) -> None:
errors = validate_report(payload)
if errors:
raise HTTPException(status_code=422, detail={"message": "Invalid report payload", "errors": errors})
@app.post("/preview/html", response_class=HTMLResponse)
def preview_html(payload: dict[str, Any]) -> HTMLResponse:
_ensure_valid(payload)
html, _ = render_documents(payload)
return HTMLResponse(content=html, status_code=200)
@app.post("/render")
def render(payload: dict[str, Any]) -> Response:
_ensure_valid(payload)
try:
pdf = render_pdf_with_gotenberg(payload)
except Exception as exc:
raise HTTPException(status_code=502, detail=f"PDF rendering failed: {exc}") from exc
filename = pdf_filename(payload)
return Response(
content=pdf,
media_type="application/pdf",
headers={
"Content-Disposition": f'attachment; filename="{filename}"',
"X-Report-Version": payload["report"]["report_version"],
"X-Template-Version": payload["report"]["template_version"],
},
)
+112
View File
@@ -0,0 +1,112 @@
from __future__ import annotations
import json
import os
from copy import deepcopy
from pathlib import Path
from tempfile import NamedTemporaryFile
from typing import Any
import requests
from jinja2 import Environment, FileSystemLoader, select_autoescape
from .formatting import clamp, currency_de, date_de, delta_de, number_de, percent_de
from .theme_catalog import THEMES, get_theme
BASE_DIR = Path(__file__).resolve().parent
TEMPLATE_DIR = BASE_DIR / "templates"
ALLOWED_THEMES = set(THEMES)
jinja = Environment(
loader=FileSystemLoader(str(TEMPLATE_DIR)),
autoescape=select_autoescape(["html", "xml", "j2"]),
trim_blocks=True,
lstrip_blocks=True,
)
jinja.filters["number_de"] = number_de
jinja.filters["currency_de"] = currency_de
jinja.filters["percent_de"] = percent_de
jinja.filters["delta_de"] = delta_de
jinja.filters["date_de"] = date_de
jinja.filters["clamp"] = clamp
def _prepare_trends(payload: dict[str, Any]) -> dict[str, Any]:
result = deepcopy(payload)
trends = result.get("trends", [])
max_revenue = max((float(item.get("revenue", 0)) for item in trends), default=1) or 1
for item in trends:
item["revenue_bar"] = round(clamp(float(item.get("revenue", 0)) / max_revenue * 100), 2)
item["occupancy_bar"] = round(clamp(item.get("occupancy_rate", 0)), 2)
return result
def render_documents(payload: dict[str, Any]) -> tuple[str, str]:
prepared = _prepare_trends(payload)
theme_id = prepared.get("design", {}).get("theme", "modern")
theme = get_theme(theme_id)
design = prepared.setdefault("design", {})
palette_mode = design.get("palette_mode")
if not palette_mode:
palette_mode = "custom" if theme.get("custom_palette_default") else "theme"
if palette_mode not in {"theme", "custom"}:
raise ValueError(f"Unknown palette mode: {palette_mode}")
if palette_mode == "theme":
design.update(theme["palette"])
design["palette_mode"] = palette_mode
prepared["_theme"] = theme
prepared["_theme"]["palette_mode"] = palette_mode
layout = theme["layout"]
context = {"data": prepared}
report_template = jinja.get_template(f"{layout}/report.html.j2")
local_footer = TEMPLATE_DIR / layout / "footer.html.j2"
footer_name = f"{layout}/footer.html.j2" if local_footer.exists() else "_shared/footer.html.j2"
footer_template = jinja.get_template(footer_name)
return report_template.render(**context), footer_template.render(**context)
def pdf_filename(payload: dict[str, Any]) -> str:
customer = payload["customer"]["id"].strip().lower().replace(" ", "-")
period = payload["report"]["period"]
return f"monatsreport-{customer}-{period['year']}-{period['month']:02d}.pdf"
def render_pdf_with_gotenberg(payload: dict[str, Any]) -> bytes:
index_html, footer_html = render_documents(payload)
gotenberg_url = os.getenv("GOTENBERG_URL", "http://gotenberg:3000").rstrip("/")
timeout = int(os.getenv("RENDER_TIMEOUT_SECONDS", "60"))
metadata = {
"Title": f"Monatsreport {payload['report']['period']['label']} - {payload['customer']['name']}",
"Author": payload["report"].get("publisher", "Monthly Report Kit"),
"Creator": "Monthly Report Kit / Gotenberg",
"Subject": "Automatisch erzeugter Monatsreport",
"Keywords": ["Monatsreport", payload["customer"]["id"], payload["report"]["period"]["label"]],
}
files = [
("files", ("index.html", index_html.encode("utf-8"), "text/html")),
("files", ("footer.html", footer_html.encode("utf-8"), "text/html")),
]
form = {
"printBackground": "true",
"preferCssPageSize": "true",
"generateDocumentOutline": "true",
"generateTaggedPdf": "true",
"failOnResourceLoadingFailed": "true",
"metadata": json.dumps(metadata, ensure_ascii=False),
}
response = requests.post(
f"{gotenberg_url}/forms/chromium/convert/html",
files=files,
data=form,
timeout=timeout,
)
if response.status_code != 200:
detail = response.text[:1000]
raise RuntimeError(f"Gotenberg returned HTTP {response.status_code}: {detail}")
return response.content
@@ -0,0 +1,131 @@
{
"type": "object",
"additionalProperties": false,
"properties": {
"summary": {
"type": "object",
"additionalProperties": false,
"properties": {
"headline": {
"type": "string",
"description": "Minimum characters: 8. Maximum characters: 110."
},
"text": {
"type": "string",
"description": "Minimum characters: 80. Maximum characters: 900."
},
"rating": {
"type": "string",
"enum": [
"positive",
"neutral",
"watch"
]
}
},
"required": [
"headline",
"text",
"rating"
]
},
"developments": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"text": {
"type": "string",
"description": "Minimum characters: 40. Maximum characters: 450."
},
"impact": {
"type": "string",
"enum": [
"positive",
"neutral",
"negative"
]
}
},
"required": [
"title",
"text",
"impact"
]
},
"description": "Minimum items: 2. Maximum items: 4."
},
"recommendations": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"priority": {
"type": "integer",
"description": "Minimum value: 1. Maximum value: 3."
},
"category": {
"type": "string",
"description": "Minimum characters: 3. Maximum characters: 80."
},
"reason": {
"type": "string",
"description": "Minimum characters: 40. Maximum characters: 450."
},
"action": {
"type": "string",
"description": "Minimum characters: 30. Maximum characters: 450."
},
"expected_effect": {
"type": "string",
"description": "Minimum characters: 20. Maximum characters: 300."
}
},
"required": [
"priority",
"category",
"title",
"reason",
"action",
"expected_effect"
]
},
"description": "Minimum items: 1. Maximum items: 3."
},
"outlook": {
"type": "object",
"additionalProperties": false,
"properties": {
"headline": {
"type": "string",
"description": "Minimum characters: 5. Maximum characters: 100."
},
"text": {
"type": "string",
"description": "Minimum characters: 60. Maximum characters: 700."
}
},
"required": [
"headline",
"text"
]
},
"data_quality_notes": {
"type": "array",
"items": {
"type": "string",
"description": "Minimum characters: 5. Maximum characters: 240."
},
"description": "Maximum items: 4."
}
},
"required": [
"summary",
"developments",
"recommendations",
"outlook",
"data_quality_notes"
]
}
@@ -0,0 +1,157 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.invalid/schemas/claude-output.schema.json",
"title": "Claude Monthly Report Content",
"type": "object",
"additionalProperties": false,
"properties": {
"summary": {
"type": "object",
"additionalProperties": false,
"properties": {
"headline": {
"type": "string",
"minLength": 8,
"maxLength": 110
},
"text": {
"type": "string",
"minLength": 80,
"maxLength": 900
},
"rating": {
"type": "string",
"enum": [
"positive",
"neutral",
"watch"
]
}
},
"required": [
"headline",
"text",
"rating"
]
},
"developments": {
"type": "array",
"minItems": 2,
"maxItems": 4,
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"title": {
"type": "string",
"minLength": 4,
"maxLength": 80
},
"text": {
"type": "string",
"minLength": 40,
"maxLength": 450
},
"impact": {
"type": "string",
"enum": [
"positive",
"neutral",
"negative"
]
}
},
"required": [
"title",
"text",
"impact"
]
}
},
"recommendations": {
"type": "array",
"minItems": 1,
"maxItems": 3,
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"priority": {
"type": "integer",
"minimum": 1,
"maximum": 3
},
"category": {
"type": "string",
"minLength": 3,
"maxLength": 80
},
"title": {
"type": "string",
"minLength": 5,
"maxLength": 100
},
"reason": {
"type": "string",
"minLength": 40,
"maxLength": 450
},
"action": {
"type": "string",
"minLength": 30,
"maxLength": 450
},
"expected_effect": {
"type": "string",
"minLength": 20,
"maxLength": 300
}
},
"required": [
"priority",
"category",
"title",
"reason",
"action",
"expected_effect"
]
}
},
"outlook": {
"type": "object",
"additionalProperties": false,
"properties": {
"headline": {
"type": "string",
"minLength": 5,
"maxLength": 100
},
"text": {
"type": "string",
"minLength": 60,
"maxLength": 700
}
},
"required": [
"headline",
"text"
]
},
"data_quality_notes": {
"type": "array",
"maxItems": 4,
"items": {
"type": "string",
"minLength": 5,
"maxLength": 240
}
}
},
"required": [
"summary",
"developments",
"recommendations",
"outlook",
"data_quality_notes"
]
}
@@ -0,0 +1,508 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.invalid/schemas/report-payload.schema.json",
"title": "Monthly Report Render Payload",
"type": "object",
"additionalProperties": false,
"properties": {
"report": {
"type": "object",
"additionalProperties": false,
"properties": {
"report_version": {
"type": "string",
"pattern": "^[0-9]+\\.[0-9]+$"
},
"prompt_version": {
"type": "string",
"pattern": "^[0-9]+\\.[0-9]+$"
},
"template_version": {
"type": "string",
"pattern": "^[0-9]+\\.[0-9]+$"
},
"generated_at": {
"type": "string",
"format": "date-time"
},
"publisher": {
"type": "string",
"minLength": 2,
"maxLength": 120
},
"period": {
"type": "object",
"additionalProperties": false,
"properties": {
"year": {
"type": "integer",
"minimum": 2020,
"maximum": 2100
},
"month": {
"type": "integer",
"minimum": 1,
"maximum": 12
},
"label": {
"type": "string",
"minLength": 4,
"maxLength": 40
},
"comparison_label": {
"type": "string",
"minLength": 4,
"maxLength": 60
}
},
"required": [
"year",
"month",
"label",
"comparison_label"
]
}
},
"required": [
"report_version",
"prompt_version",
"template_version",
"generated_at",
"publisher",
"period"
]
},
"customer": {
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"pattern": "^[a-zA-Z0-9_-]{2,64}$"
},
"name": {
"type": "string",
"minLength": 2,
"maxLength": 160
},
"property_name": {
"type": "string",
"minLength": 2,
"maxLength": 160
},
"location": {
"type": "string",
"minLength": 2,
"maxLength": 160
},
"contact_line": {
"type": "string",
"minLength": 0,
"maxLength": 180
},
"logo_data_uri": {
"type": "string",
"pattern": "^data:image/(png|jpeg|svg\\+xml);base64,"
},
"logo_text": {
"type": "string",
"minLength": 1,
"maxLength": 5
}
},
"required": [
"id",
"name",
"property_name",
"location",
"contact_line",
"logo_text"
]
},
"design": {
"type": "object",
"additionalProperties": false,
"properties": {
"theme": {
"type": "string",
"enum": [
"alpine-sage",
"classic",
"editorial-ink",
"editorial-ivory",
"editorial-rose",
"executive-blue",
"executive-burgundy",
"executive-charcoal",
"forest-lodge",
"ledger-blue",
"ledger-green",
"ledger-sepia",
"magazine-citrus",
"magazine-cobalt",
"magazine-plum",
"midnight-gold",
"modern",
"nordic-light",
"nordic-night",
"ocean-breeze",
"poster-mono",
"poster-red",
"poster-yellow",
"soft-lavender",
"split-teal",
"split-terracotta",
"split-violet",
"sunset-coral"
]
},
"primary_color": {
"type": "string",
"pattern": "^#[0-9A-Fa-f]{6}$"
},
"secondary_color": {
"type": "string",
"pattern": "^#[0-9A-Fa-f]{6}$"
},
"accent_color": {
"type": "string",
"pattern": "^#[0-9A-Fa-f]{6}$"
},
"text_color": {
"type": "string",
"pattern": "^#[0-9A-Fa-f]{6}$"
},
"muted_color": {
"type": "string",
"pattern": "^#[0-9A-Fa-f]{6}$"
},
"surface_color": {
"type": "string",
"pattern": "^#[0-9A-Fa-f]{6}$"
},
"font_family": {
"type": "string",
"minLength": 3,
"maxLength": 100,
"pattern": "^[A-Za-z0-9 _,-]+$"
},
"palette_mode": {
"type": "string",
"enum": [
"theme",
"custom"
],
"description": "theme nutzt die feste Theme-Palette; custom nutzt die mitgelieferten Designfarben."
}
},
"required": [
"theme",
"primary_color",
"secondary_color",
"accent_color",
"text_color",
"muted_color",
"surface_color",
"font_family"
]
},
"metrics": {
"type": "object",
"additionalProperties": false,
"properties": {
"currency": {
"type": "string",
"enum": [
"EUR",
"USD",
"GBP"
]
},
"revenue": {
"type": "number",
"minimum": 0
},
"occupancy_rate": {
"type": "number",
"minimum": 0,
"maximum": 100
},
"adr": {
"type": "number",
"minimum": 0
},
"revpar": {
"type": "number",
"minimum": 0
},
"bookings": {
"type": "integer",
"minimum": 0
},
"nights_sold": {
"type": "integer",
"minimum": 0
},
"average_stay": {
"type": "number",
"minimum": 0
},
"cancellation_rate": {
"type": "number",
"minimum": 0,
"maximum": 100
},
"comparison": {
"type": "object",
"additionalProperties": false,
"properties": {
"revenue_delta_pct": {
"type": "number",
"minimum": -1000,
"maximum": 1000
},
"occupancy_delta_pp": {
"type": "number",
"minimum": -100,
"maximum": 100
},
"adr_delta_pct": {
"type": "number",
"minimum": -1000,
"maximum": 1000
},
"bookings_delta": {
"type": "integer",
"minimum": -100000,
"maximum": 100000
}
},
"required": [
"revenue_delta_pct",
"occupancy_delta_pp",
"adr_delta_pct",
"bookings_delta"
]
}
},
"required": [
"currency",
"revenue",
"occupancy_rate",
"adr",
"revpar",
"bookings",
"nights_sold",
"average_stay",
"cancellation_rate",
"comparison"
]
},
"trends": {
"type": "array",
"minItems": 2,
"maxItems": 12,
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"label": {
"type": "string",
"minLength": 2,
"maxLength": 20
},
"revenue": {
"type": "number",
"minimum": 0
},
"occupancy_rate": {
"type": "number",
"minimum": 0,
"maximum": 100
},
"adr": {
"type": "number",
"minimum": 0
}
},
"required": [
"label",
"revenue",
"occupancy_rate",
"adr"
]
}
},
"content": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.invalid/schemas/claude-output.schema.json",
"title": "Claude Monthly Report Content",
"type": "object",
"additionalProperties": false,
"properties": {
"summary": {
"type": "object",
"additionalProperties": false,
"properties": {
"headline": {
"type": "string",
"minLength": 8,
"maxLength": 110
},
"text": {
"type": "string",
"minLength": 80,
"maxLength": 900
},
"rating": {
"type": "string",
"enum": [
"positive",
"neutral",
"watch"
]
}
},
"required": [
"headline",
"text",
"rating"
]
},
"developments": {
"type": "array",
"minItems": 2,
"maxItems": 4,
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"title": {
"type": "string",
"minLength": 4,
"maxLength": 80
},
"text": {
"type": "string",
"minLength": 40,
"maxLength": 450
},
"impact": {
"type": "string",
"enum": [
"positive",
"neutral",
"negative"
]
}
},
"required": [
"title",
"text",
"impact"
]
}
},
"recommendations": {
"type": "array",
"minItems": 1,
"maxItems": 3,
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"priority": {
"type": "integer",
"minimum": 1,
"maximum": 3
},
"category": {
"type": "string",
"minLength": 3,
"maxLength": 80
},
"title": {
"type": "string",
"minLength": 5,
"maxLength": 100
},
"reason": {
"type": "string",
"minLength": 40,
"maxLength": 450
},
"action": {
"type": "string",
"minLength": 30,
"maxLength": 450
},
"expected_effect": {
"type": "string",
"minLength": 20,
"maxLength": 300
}
},
"required": [
"priority",
"category",
"title",
"reason",
"action",
"expected_effect"
]
}
},
"outlook": {
"type": "object",
"additionalProperties": false,
"properties": {
"headline": {
"type": "string",
"minLength": 5,
"maxLength": 100
},
"text": {
"type": "string",
"minLength": 60,
"maxLength": 700
}
},
"required": [
"headline",
"text"
]
},
"data_quality_notes": {
"type": "array",
"maxItems": 4,
"items": {
"type": "string",
"minLength": 5,
"maxLength": 240
}
}
},
"required": [
"summary",
"developments",
"recommendations",
"outlook",
"data_quality_notes"
]
},
"legal_note": {
"type": "string",
"minLength": 10,
"maxLength": 500
}
},
"required": [
"report",
"customer",
"design",
"metrics",
"trends",
"content",
"legal_note"
]
}
@@ -0,0 +1,3 @@
<!doctype html><html lang="de"><head><meta charset="utf-8"><style>
html{font-family:Arial,sans-serif;font-size:8px;color:{{ data.design.muted_color }};margin:0 14mm;-webkit-print-color-adjust:exact}body{margin:0}.footer{border-top:1px solid {{ data.design.primary_color }}33;padding-top:2.5mm;display:flex;justify-content:space-between}.page{font-weight:700;color:{{ data.design.primary_color }}}
</style></head><body><div class="footer"><span>{{ data.customer.name }} · {{ data.report.period.label }} · {{ data._theme.name }}</span><span class="page">Seite <span class="pageNumber"></span> / <span class="totalPages"></span></span></div></body></html>
@@ -0,0 +1,68 @@
{% macro logo(data, class_name='logo') -%}
<div class="{{ class_name }}">
{% if data.customer.logo_data_uri %}<img src="{{ data.customer.logo_data_uri }}" alt="Logo">{% else %}{{ data.customer.logo_text }}{% endif %}
</div>
{%- endmacro %}
{% macro kpis(data) -%}
<div class="kpis">
<article class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">{{ data.metrics.revenue|currency_de(data.metrics.currency) }}</div><div class="kpi-delta {{ 'up' if data.metrics.comparison.revenue_delta_pct >= 0 else 'down' }}">{{ data.metrics.comparison.revenue_delta_pct|delta_de(1, '%') }}</div></article>
<article class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">{{ data.metrics.occupancy_rate|percent_de }}</div><div class="kpi-delta {{ 'up' if data.metrics.comparison.occupancy_delta_pp >= 0 else 'down' }}">{{ data.metrics.comparison.occupancy_delta_pp|delta_de(1, 'PP') }}</div></article>
<article class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">{{ data.metrics.adr|currency_de(data.metrics.currency) }}</div><div class="kpi-delta {{ 'up' if data.metrics.comparison.adr_delta_pct >= 0 else 'down' }}">{{ data.metrics.comparison.adr_delta_pct|delta_de(1, '%') }}</div></article>
<article class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">{{ data.metrics.bookings|number_de(0) }}</div><div class="kpi-delta {{ 'up' if data.metrics.comparison.bookings_delta >= 0 else 'down' }}">{{ data.metrics.comparison.bookings_delta|delta_de(0, '') }} Buchungen</div></article>
</div>
{%- endmacro %}
{% macro facts(data) -%}
<div class="facts">
<div class="fact"><span>RevPAR</span><strong>{{ data.metrics.revpar|currency_de(data.metrics.currency) }}</strong></div>
<div class="fact"><span>Verkaufte Nächte</span><strong>{{ data.metrics.nights_sold|number_de(0) }}</strong></div>
<div class="fact"><span>Ø Aufenthalt</span><strong>{{ data.metrics.average_stay|number_de(1) }} Nächte</strong></div>
<div class="fact"><span>Stornoquote</span><strong>{{ data.metrics.cancellation_rate|percent_de }}</strong></div>
</div>
{%- endmacro %}
{% macro trend_bars(data) -%}
<div class="trend-bars">
{% for item in data.trends %}
<div class="trend-row">
<div class="trend-label">{{ item.label }}</div>
<div class="trend-track"><div class="trend-revenue" style="width:{{ item.revenue_bar }}%"></div><div class="trend-occ" style="width:{{ item.occupancy_bar }}%"></div></div>
<div class="trend-num">{{ item.revenue|currency_de(data.metrics.currency) }}</div>
<div class="trend-num">{{ item.occupancy_rate|percent_de }}</div>
</div>
{% endfor %}
</div>
{%- endmacro %}
{% macro trend_table(data) -%}
<table class="trend-table">
<thead><tr><th>Monat</th><th>Umsatz</th><th>Auslastung</th><th>Ø Tagespreis</th></tr></thead>
<tbody>{% for item in data.trends %}<tr><td>{{ item.label }}</td><td>{{ item.revenue|currency_de(data.metrics.currency) }}</td><td>{{ item.occupancy_rate|percent_de }}</td><td>{{ item.adr|currency_de(data.metrics.currency) }}</td></tr>{% endfor %}</tbody>
</table>
{%- endmacro %}
{% macro developments(data) -%}
<div class="developments">
{% for item in data.content.developments %}
<article class="development {{ item.impact }}"><div class="impact"></div><div><h3>{{ item.title }}</h3><p>{{ item.text }}</p></div></article>
{% endfor %}
</div>
{%- endmacro %}
{% macro recommendations(data) -%}
<div class="recommendations">
{% for item in data.content.recommendations|sort(attribute='priority') %}
<article class="recommendation"><div class="priority">{{ item.priority }}</div><div><div class="category">{{ item.category }}</div><h3>{{ item.title }}</h3><p><strong>Begründung:</strong> {{ item.reason }}</p><p><strong>Massnahme:</strong> {{ item.action }}</p><p class="effect"><strong>Erwarteter Effekt:</strong> {{ item.expected_effect }}</p></div></article>
{% endfor %}
</div>
{%- endmacro %}
{% macro outlook(data) -%}
<section class="outlook"><div class="kicker">Ausblick</div><h2>{{ data.content.outlook.headline }}</h2><p>{{ data.content.outlook.text }}</p></section>
{%- endmacro %}
{% macro notes(data) -%}
{% if data.content.data_quality_notes %}<section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul>{% for note in data.content.data_quality_notes %}<li>{{ note }}</li>{% endfor %}</ul></section>{% endif %}
<div class="legal">{{ data.legal_note }}</div>
{%- endmacro %}
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<style>
html { font-family: Arial, sans-serif; font-size: 8px; color: #737b80; margin: 0 16mm; -webkit-print-color-adjust: exact; }
body { margin: 0; }
.footer { border-top: 1px solid #cfd6da; padding-top: 3mm; display: flex; justify-content: space-between; }
.page { color: {{ data.design.primary_color }}; font-weight: 700; }
</style>
</head>
<body><div class="footer"><span>{{ data.customer.name }} · Vertraulich</span><span class="page">{{ data.report.period.label }} · <span class="pageNumber"></span>/<span class="totalPages"></span></span></div></body>
</html>
@@ -0,0 +1,124 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Monatsreport {{ data.report.period.label }} - {{ data.customer.name }}</title>
<style>
:root {
--primary: {{ data.design.primary_color }};
--accent: {{ data.design.accent_color }};
--text: {{ data.design.text_color }};
--muted: {{ data.design.muted_color }};
--surface: {{ data.design.surface_color }};
--line: #cfd6da;
--positive: #236a4f;
--negative: #9d3e3e;
}
@page { size: A4; margin: 15mm 16mm 19mm; }
* { box-sizing: border-box; }
html { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
body { margin: 0; font-family: {{ data.design.font_family }}, Georgia, serif; color: var(--text); font-size: 9.5pt; line-height: 1.5; }
h1, h2, h3, p { margin-top: 0; }
h1 { font-size: 25pt; font-weight: 500; line-height: 1.12; margin-bottom: 2mm; }
h2 { font-size: 15pt; font-weight: 600; color: var(--primary); margin-bottom: 3mm; }
h3 { font-size: 10.5pt; margin-bottom: 1mm; }
p { margin-bottom: 3mm; }
.sans { font-family: Arial, sans-serif; }
.header { border-top: 2.5mm solid var(--primary); padding-top: 7mm; margin-bottom: 8mm; display: grid; grid-template-columns: 1fr auto; gap: 8mm; }
.brand { text-align: right; font-family: Arial, sans-serif; font-size: 8pt; color: var(--muted); }
.brand strong { display: block; color: var(--primary); font-size: 10pt; margin-bottom: 1mm; }
.period { font-family: Arial, sans-serif; text-transform: uppercase; letter-spacing: 1.4px; color: var(--accent); font-size: 8pt; font-weight: 700; }
.meta { display: flex; gap: 6mm; color: var(--muted); font-family: Arial, sans-serif; font-size: 7.5pt; }
.rule-heading { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 4mm; margin: 7mm 0 3mm; }
.rule-heading h2 { margin: 0; white-space: nowrap; }
.rule { height: .25mm; background: var(--line); }
.summary { padding: 5mm 0 5mm 5mm; border-left: 1.2mm solid var(--accent); break-inside: avoid; }
.summary h2 { color: var(--text); }
.summary p { margin: 0; }
.kpis { display: grid; grid-template-columns: repeat(4,1fr); border: .25mm solid var(--line); break-inside: avoid; }
.kpi { padding: 4mm; border-right: .25mm solid var(--line); min-height: 28mm; }
.kpi:last-child { border-right: 0; }
.kpi-label { font-family: Arial, sans-serif; font-size: 7pt; text-transform: uppercase; letter-spacing: .8px; color: var(--muted); }
.kpi-value { color: var(--primary); font-size: 15pt; font-weight: 600; margin: 2.5mm 0 1mm; white-space: nowrap; }
.kpi-delta { font-family: Arial, sans-serif; font-size: 7pt; color: var(--muted); }
.facts { display: grid; grid-template-columns: repeat(4,1fr); background: var(--surface); padding: 3mm 4mm; font-family: Arial, sans-serif; font-size: 7.5pt; }
.facts strong { display: block; color: var(--primary); font-size: 9pt; margin-top: .5mm; }
table { width: 100%; border-collapse: collapse; break-inside: avoid; font-family: Arial, sans-serif; font-size: 7.6pt; }
th { text-align: left; color: var(--muted); font-size: 6.8pt; text-transform: uppercase; letter-spacing: .7px; padding: 2.5mm; border-bottom: .5mm solid var(--primary); }
td { padding: 2.5mm; border-bottom: .25mm solid var(--line); }
td.num, th.num { text-align: right; }
.developments { columns: 2; column-gap: 6mm; }
.development { break-inside: avoid; padding: 0 0 3mm 4mm; margin-bottom: 3mm; border-left: .8mm solid var(--line); }
.development.positive { border-left-color: var(--positive); }
.development.negative { border-left-color: var(--negative); }
.development p { margin: 0; }
.recommendation { break-inside: avoid; display: grid; grid-template-columns: 10mm 1fr; gap: 4mm; padding: 4mm 0; border-bottom: .25mm solid var(--line); }
.recommendation:last-child { border-bottom: 0; }
.number { width: 9mm; height: 9mm; border: .4mm solid var(--primary); color: var(--primary); display: flex; align-items: center; justify-content: center; align-self: start; border-radius: 50%; font-family: Arial, sans-serif; font-weight: 700; }
.category { color: var(--accent); font-family: Arial, sans-serif; font-size: 7pt; text-transform: uppercase; letter-spacing: .8px; font-weight: 700; }
.recommendation p { margin-bottom: 1.7mm; }
.outlook { margin-top: 6mm; padding: 5mm; background: var(--surface); border-top: 1mm solid var(--primary); break-inside: avoid; }
.outlook p { margin: 0; }
.notes { font-family: Arial, sans-serif; font-size: 7pt; color: var(--muted); margin-top: 4mm; }
.notes ul { margin: 1mm 0; padding-left: 4mm; }
.legal { font-family: Arial, sans-serif; font-size: 6.6pt; color: var(--muted); margin-top: 4mm; }
</style>
</head>
<body>
<header class="header">
<div>
<div class="period">{{ data.report.period.label }}</div>
<h1>Monatsreport</h1>
<div class="meta"><span>{{ data.customer.property_name }}</span><span>{{ data.customer.location }}</span><span>{{ data.report.generated_at|date_de }}</span></div>
</div>
<div class="brand"><strong>{{ data.customer.name }}</strong>{{ data.customer.contact_line }}</div>
</header>
<section class="summary">
<div class="period">Kurzfazit</div>
<h2>{{ data.content.summary.headline }}</h2>
<p>{{ data.content.summary.text }}</p>
</section>
<div class="rule-heading"><h2>Kennzahlen</h2><div class="rule"></div></div>
<section class="kpis">
<div class="kpi"><div class="kpi-label">Umsatz</div><div class="kpi-value">{{ data.metrics.revenue|currency_de(data.metrics.currency) }}</div><div class="kpi-delta">{{ data.metrics.comparison.revenue_delta_pct|delta_de(1, '%') }}</div></div>
<div class="kpi"><div class="kpi-label">Auslastung</div><div class="kpi-value">{{ data.metrics.occupancy_rate|percent_de }}</div><div class="kpi-delta">{{ data.metrics.comparison.occupancy_delta_pp|delta_de(1, 'PP') }}</div></div>
<div class="kpi"><div class="kpi-label">Ø Tagespreis</div><div class="kpi-value">{{ data.metrics.adr|currency_de(data.metrics.currency) }}</div><div class="kpi-delta">{{ data.metrics.comparison.adr_delta_pct|delta_de(1, '%') }}</div></div>
<div class="kpi"><div class="kpi-label">Buchungen</div><div class="kpi-value">{{ data.metrics.bookings|number_de(0) }}</div><div class="kpi-delta">{{ data.metrics.comparison.bookings_delta|delta_de(0, '') }} Buchungen</div></div>
</section>
<section class="facts">
<div>RevPAR<strong>{{ data.metrics.revpar|currency_de(data.metrics.currency) }}</strong></div>
<div>Verkaufte Nächte<strong>{{ data.metrics.nights_sold|number_de(0) }}</strong></div>
<div>Ø Aufenthalt<strong>{{ data.metrics.average_stay|number_de(1) }} Nächte</strong></div>
<div>Stornoquote<strong>{{ data.metrics.cancellation_rate|percent_de }}</strong></div>
</section>
<div class="rule-heading"><h2>Monatsverlauf</h2><div class="rule"></div></div>
<table>
<thead><tr><th>Monat</th><th class="num">Umsatz</th><th class="num">Auslastung</th><th class="num">Ø Tagespreis</th></tr></thead>
<tbody>
{% for item in data.trends %}<tr><td>{{ item.label }}</td><td class="num">{{ item.revenue|currency_de(data.metrics.currency) }}</td><td class="num">{{ item.occupancy_rate|percent_de }}</td><td class="num">{{ item.adr|currency_de(data.metrics.currency) }}</td></tr>{% endfor %}
</tbody>
</table>
<div class="rule-heading"><h2>Wichtige Entwicklungen</h2><div class="rule"></div></div>
<section class="developments">
{% for item in data.content.developments %}<article class="development {{ item.impact }}"><h3>{{ item.title }}</h3><p>{{ item.text }}</p></article>{% endfor %}
</section>
<div class="rule-heading"><h2>Empfehlungen</h2><div class="rule"></div></div>
<section>
{% for item in data.content.recommendations|sort(attribute='priority') %}
<article class="recommendation">
<div class="number">{{ item.priority }}</div>
<div><div class="category">{{ item.category }}</div><h3>{{ item.title }}</h3><p><strong>Begründung:</strong> {{ item.reason }}</p><p><strong>Massnahme:</strong> {{ item.action }}</p><p><strong>Erwarteter Effekt:</strong> {{ item.expected_effect }}</p></div>
</article>
{% endfor %}
</section>
<section class="outlook"><div class="period">Ausblick</div><h2>{{ data.content.outlook.headline }}</h2><p>{{ data.content.outlook.text }}</p></section>
{% if data.content.data_quality_notes %}<section class="notes"><strong>Hinweise zur Datengrundlage</strong><ul>{% for note in data.content.data_quality_notes %}<li>{{ note }}</li>{% endfor %}</ul></section>{% endif %}
<div class="legal">{{ data.legal_note }}</div>
</body>
</html>
@@ -0,0 +1,10 @@
{% import '_shared/macros.html.j2' as ui %}
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>{{ data._theme.name }} - {{ data.customer.name }}</title><style>
:root{--p:{{data.design.primary_color}};--s:{{data.design.secondary_color}};--a:{{data.design.accent_color}};--t:{{data.design.text_color}};--m:{{data.design.muted_color}};--bg:{{data.design.surface_color}};--line:#d8e0e5;--pos:#25745b;--neg:#a84444}@page{size:A4;margin:12mm 13mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9pt/1.46 {{data.design.font_family}},Arial,sans-serif;background:#fff}h1,h2,h3,p{margin-top:0}h1{font-size:24pt;margin:0;line-height:1.05}h2{font-size:13.5pt;margin-bottom:3mm}h3{font-size:10pt;margin-bottom:1mm}p{margin-bottom:2.5mm}.header{background:linear-gradient(125deg,var(--p),var(--s));color:#fff;border-radius:3mm;padding:7mm;margin-bottom:5mm;display:grid;grid-template-columns:1fr auto;gap:8mm;break-inside:avoid}.header-left{display:flex;gap:4mm;align-items:center}.logo{width:14mm;height:14mm;background:#fff;color:var(--p);border-radius:2mm;display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand{font-weight:700}.sub{font-size:7.5pt;opacity:.78}.header-right{text-align:right}.period{font-size:11pt;font-weight:800}.kicker,.kpi-label,.category{font-size:6.8pt;text-transform:uppercase;letter-spacing:.9px;font-weight:800;color:var(--m)}.header .kicker{color:#ffffffb8}.summary{display:grid;grid-template-columns:1fr 42mm;gap:4mm;margin-bottom:5mm}.summary-main{padding:5mm;border:1px solid var(--line);border-radius:2mm}.summary-main h2{font-size:15pt}.summary-score{background:var(--bg);border-radius:2mm;padding:4mm;display:flex;flex-direction:column;justify-content:center;text-align:center}.summary-score strong{font-size:20pt;color:var(--p)}.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:3mm;margin-bottom:3mm}.kpi{padding:4mm;background:var(--bg);border-top:1.2mm solid var(--p);min-height:29mm;break-inside:avoid}.kpi-value{font-size:15pt;font-weight:800;color:var(--p);margin:2mm 0;white-space:nowrap}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:3mm;margin-bottom:6mm}.fact{border:1px solid var(--line);padding:2.5mm 3mm}.fact span{display:block;font-size:6.8pt;color:var(--m)}.fact strong{display:block;margin-top:.5mm}.grid{display:grid;grid-template-columns:1.18fr .82fr;gap:5mm;align-items:start;break-before:page;break-inside:avoid}.panel{border:1px solid var(--line);border-radius:2mm;padding:4mm;margin-bottom:5mm;break-inside:avoid}.panel-head{display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid var(--line);padding-bottom:2mm;margin-bottom:3mm}.panel-head h2{margin:0}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:17mm 1fr 27mm 21mm;gap:2mm;align-items:center;font-size:7.2pt}.trend-label{font-weight:700}.trend-track{height:4mm;background:#e7ecef;position:relative;border-radius:1mm;overflow:hidden}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1.2mm;background:var(--a);position:absolute;bottom:0;left:0}.trend-num{text-align:right}.developments{display:grid;gap:2.5mm}.development{display:grid;grid-template-columns:2mm 1fr;gap:2.5mm;padding-bottom:2.5mm;border-bottom:1px solid var(--line);break-inside:avoid}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendations{display:grid;gap:3mm}.recommendation{display:grid;grid-template-columns:8mm 1fr;gap:3mm;background:var(--bg);padding:3.5mm;break-inside:avoid}.priority{width:7mm;height:7mm;border-radius:50%;background:var(--p);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800}.recommendation p{margin-bottom:1.4mm}.effect{border-top:1px solid #00000010;padding-top:1.5mm}.outlook{padding:5mm;background:var(--p);color:#fff;border-radius:2mm;break-inside:avoid}.outlook .kicker{color:#ffffffb8}.outlook h2{margin-bottom:1.5mm}.outlook p{margin:0}.notes{font-size:6.8pt;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.3pt;color:var(--m);margin-top:2mm}
</style></head><body>
<header class="header"><div class="header-left">{{ui.logo(data)}}<div><div class="brand">{{data.customer.name}}</div><div class="sub">{{data.customer.property_name}} · {{data.customer.location}}</div></div></div><div class="header-right"><div class="kicker">Performance Dashboard</div><div class="period">{{data.report.period.label}}</div><div class="sub">Erstellt {{data.report.generated_at|date_de}}</div></div></header>
<section class="summary"><div class="summary-main"><div class="kicker">Management Summary</div><h2>{{data.content.summary.headline}}</h2><p>{{data.content.summary.text}}</p></div><div class="summary-score"><span class="kicker">Status</span><strong>{% if data.content.summary.rating=='positive' %}↑{% elif data.content.summary.rating=='watch' %}!{% else %}•{% endif %}</strong><span>{{data.content.summary.rating}}</span></div></section>
{{ui.kpis(data)}}{{ui.facts(data)}}
<div class="grid"><div><section class="panel"><div class="panel-head"><h2>Monatsverlauf</h2><span class="kicker">{{data.report.period.comparison_label}}</span></div>{{ui.trend_bars(data)}}</section><section class="panel"><div class="panel-head"><h2>Wichtige Entwicklungen</h2></div>{{ui.developments(data)}}</section></div><div><section class="panel"><div class="panel-head"><h2>Prioritäten</h2></div>{{ui.recommendations(data)}}</section>{{ui.outlook(data)}}</div></div>
{{ui.notes(data)}}
</body></html>
@@ -0,0 +1,11 @@
{% import '_shared/macros.html.j2' as ui %}
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>{{ data._theme.name }} - {{ data.customer.name }}</title><style>
:root{--p:{{data.design.primary_color}};--s:{{data.design.secondary_color}};--a:{{data.design.accent_color}};--t:{{data.design.text_color}};--m:{{data.design.muted_color}};--bg:{{data.design.surface_color}};--line:#cfcac1;--pos:#2e7259;--neg:#9a4747}@page{size:A4;margin:14mm 16mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.6pt/1.55 {{data.design.font_family}},Georgia,serif}h1,h2,h3,p{margin-top:0}h1{font-size:38pt;line-height:.94;font-weight:500;letter-spacing:-1.5px;margin:0}h2{font-size:17pt;font-weight:500;margin-bottom:3mm}h3{font-size:11pt;margin-bottom:1mm}p{margin-bottom:3mm}.mast{display:grid;grid-template-columns:1fr auto;align-items:center;border-top:2mm solid var(--p);border-bottom:1px solid var(--line);padding:4mm 0;margin-bottom:9mm}.brand{font:700 8pt Arial,sans-serif;text-transform:uppercase;letter-spacing:1.2px}.issue{text-align:right;font:7pt Arial,sans-serif;color:var(--m)}.issue strong{display:block;color:var(--p);font-size:10pt}.hero{display:grid;grid-template-columns:1.1fr .9fr;gap:10mm;align-items:end;margin-bottom:8mm}.logo{width:13mm;height:13mm;border:1px solid var(--p);float:left;margin-right:3mm;display:flex;align-items:center;justify-content:center;font:800 9pt Arial,sans-serif;color:var(--p);overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.deck{border-top:1mm solid var(--a);padding-top:4mm}.deck .kicker,.kicker,.kpi-label,.category{font:700 6.8pt/1.2 Arial,sans-serif;text-transform:uppercase;letter-spacing:1px;color:var(--m)}.deck h2{font-size:16pt}.deck p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);margin:8mm 0 4mm;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}.kpi{padding:4mm 4mm 4mm 0}.kpi+.kpi{border-left:1px solid var(--line);padding-left:4mm}.kpi-value{font-size:16pt;color:var(--p);margin:2mm 0;white-space:nowrap}.kpi-delta{font:7pt Arial,sans-serif}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:flex;justify-content:space-between;gap:4mm;font:7pt Arial,sans-serif;color:var(--m);margin-bottom:9mm}.fact strong{color:var(--t);margin-left:1mm}.headline{display:flex;align-items:center;gap:4mm;margin:7mm 0 4mm}.headline h2{margin:0;white-space:nowrap}.headline:after{content:"";height:1px;background:var(--line);flex:1}.trend-table{width:100%;border-collapse:collapse;font:7.5pt Arial,sans-serif;break-inside:avoid}.trend-table th{text-align:left;text-transform:uppercase;letter-spacing:.7px;color:var(--m);font-size:6.5pt;border-bottom:1mm solid var(--p);padding:2mm}.trend-table td{padding:2.2mm;border-bottom:1px solid var(--line)}.trend-table th:not(:first-child),.trend-table td:not(:first-child){text-align:right}.editorial-grid{display:grid;grid-template-columns:1fr 1fr;gap:8mm;align-items:start;break-before:page;break-inside:avoid}.developments{columns:1}.development{display:grid;grid-template-columns:2mm 1fr;gap:3mm;margin-bottom:4mm;break-inside:avoid}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendations{display:grid;gap:4mm}.recommendation{border-top:1px solid var(--line);padding-top:3mm;display:grid;grid-template-columns:8mm 1fr;gap:3mm;break-inside:avoid}.priority{font-size:20pt;color:var(--a);line-height:1}.recommendation p{margin-bottom:1.4mm}.effect{font-style:italic}.outlook{margin-top:8mm;background:var(--bg);padding:6mm;border-left:1.2mm solid var(--p);break-inside:avoid}.outlook h2{margin-bottom:2mm}.outlook p{margin:0}.notes{font:6.8pt Arial,sans-serif;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font:6.3pt Arial,sans-serif;color:var(--m);margin-top:2mm}
</style></head><body>
<header class="mast"><div class="brand">{{data.customer.name}} · Monthly Review</div><div class="issue"><strong>{{data.report.period.label}}</strong>{{data.customer.location}}</div></header>
<section class="hero"><div><div>{{ui.logo(data)}}<div class="kicker">{{data.customer.property_name}}</div></div><h1>Monatsreport</h1></div><div class="deck"><div class="kicker">Analyse des Monats</div><h2>{{data.content.summary.headline}}</h2><p>{{data.content.summary.text}}</p></div></section>
{{ui.kpis(data)}}{{ui.facts(data)}}
<div class="headline"><h2>Zahlen im Verlauf</h2></div>{{ui.trend_table(data)}}
<div class="editorial-grid"><section><div class="headline"><h2>Entwicklungen</h2></div>{{ui.developments(data)}}</section><section><div class="headline"><h2>Empfehlungen</h2></div>{{ui.recommendations(data)}}</section></div>
{{ui.outlook(data)}}{{ui.notes(data)}}
</body></html>
@@ -0,0 +1,12 @@
{% import '_shared/macros.html.j2' as ui %}
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>{{ data._theme.name }} - {{ data.customer.name }}</title><style>
:root{--p:{{data.design.primary_color}};--s:{{data.design.secondary_color}};--a:{{data.design.accent_color}};--t:{{data.design.text_color}};--m:{{data.design.muted_color}};--bg:{{data.design.surface_color}};--line:#cbd2ce;--pos:#247159;--neg:#9e4545}@page{size:A4;margin:13mm 14mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:8.7pt/1.45 {{data.design.font_family}},"Courier New",monospace}h1,h2,h3,p{margin-top:0}h1{font-size:24pt;letter-spacing:-1px;margin:0}h2{font-size:12pt;margin-bottom:3mm;text-transform:uppercase;letter-spacing:.6px}h3{font-size:9.3pt;margin-bottom:1mm}p{margin-bottom:2.3mm}.header{border:1px solid var(--p);display:grid;grid-template-columns:1fr 62mm;margin-bottom:5mm}.header-main{padding:5mm}.header-meta{background:var(--p);color:#fff;padding:5mm}.brandline{display:flex;align-items:center;gap:3mm;margin-bottom:4mm}.logo{width:10mm;height:10mm;border:1px solid var(--p);display:flex;align-items:center;justify-content:center;font-weight:800;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:.8mm}.label,.kicker,.kpi-label,.category{font-size:6.5pt;text-transform:uppercase;letter-spacing:.8px;color:var(--m);font-weight:700}.header-meta .label{color:#ffffffad}.header-meta strong{display:block;font-size:13pt;margin:1mm 0 4mm}.summary{border:1px solid var(--line);padding:4mm;margin-bottom:4mm;display:grid;grid-template-columns:26mm 1fr;gap:4mm}.summary-code{font-size:18pt;color:var(--a);font-weight:800}.summary h2{font-size:13pt;text-transform:none}.summary p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);border:1px solid var(--line);margin-bottom:0}.kpi{padding:3.5mm;border-right:1px solid var(--line)}.kpi:last-child{border-right:0}.kpi-value{font-size:13pt;font-weight:800;color:var(--p);margin:2mm 0;white-space:nowrap}.kpi-delta{font-size:6.7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);border:1px solid var(--line);border-top:0;margin-bottom:6mm}.fact{padding:2.5mm 3.5mm;border-right:1px solid var(--line)}.fact:last-child{border-right:0}.fact span{display:block;font-size:6.4pt;color:var(--m)}.fact strong{display:block;margin-top:.5mm}.block{margin-bottom:6mm}.block-head{display:flex;justify-content:space-between;align-items:center;background:var(--bg);border-left:1.2mm solid var(--p);padding:2.5mm 3mm;margin-bottom:2mm}.block-head h2{margin:0}.trend-table{width:100%;border-collapse:collapse;font-size:7.3pt}.trend-table th,.trend-table td{padding:2mm;border:1px solid var(--line)}.trend-table th{text-align:left;background:var(--bg);color:var(--m);font-size:6.3pt;text-transform:uppercase}.trend-table th:not(:first-child),.trend-table td:not(:first-child){text-align:right}.analysis-table{width:100%;border-collapse:collapse}.analysis-table td{border-bottom:1px solid var(--line);padding:3mm 2mm;vertical-align:top}.analysis-table td:first-child{width:7mm;font-weight:800;color:var(--a)}.analysis-table td:nth-child(2){width:42mm;font-weight:800}.analysis-table p{margin:0}.recommendations{display:grid;gap:0;border-top:1px solid var(--line)}.recommendation{display:grid;grid-template-columns:10mm 1fr;gap:3mm;border-bottom:1px solid var(--line);padding:3mm 0;break-inside:avoid}.priority{font-size:14pt;color:var(--p);font-weight:800}.recommendation p{margin-bottom:1.2mm}.effect{background:var(--bg);padding:1.5mm}.outlook{border:1px solid var(--p);padding:4mm;break-inside:avoid}.outlook h2{text-transform:none}.outlook p{margin:0}.notes{font-size:6.5pt;color:var(--m);margin-top:3mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6pt;color:var(--m);margin-top:2mm}.developments{display:none}
</style></head><body>
<header class="header"><div class="header-main"><div class="brandline">{{ui.logo(data)}}<div><strong>{{data.customer.name}}</strong><div class="label">{{data.customer.property_name}} / {{data.customer.location}}</div></div></div><h1>MONATSREPORT</h1></div><div class="header-meta"><div class="label">Berichtsperiode</div><strong>{{data.report.period.label}}</strong><div class="label">Erstellt</div><div>{{data.report.generated_at|date_de}}</div><div class="label" style="margin-top:3mm">Template</div><div>{{data._theme.id}}</div></div></header>
<section class="summary"><div class="summary-code">00</div><div><div class="kicker">Executive Summary</div><h2>{{data.content.summary.headline}}</h2><p>{{data.content.summary.text}}</p></div></section>
{{ui.kpis(data)}}{{ui.facts(data)}}
<section class="block"><div class="block-head"><h2>01 / Monatsverlauf</h2><span class="label">Vergleich {{data.report.period.comparison_label}}</span></div>{{ui.trend_table(data)}}</section>
<section class="block"><div class="block-head"><h2>02 / Entwicklungen</h2><span class="label">Analyse</span></div><table class="analysis-table">{% for item in data.content.developments %}<tr><td>{{'%02d'|format(loop.index)}}</td><td>{{item.title}}</td><td><p>{{item.text}}</p></td></tr>{% endfor %}</table></section>
<section class="block"><div class="block-head"><h2>03 / Massnahmenliste</h2><span class="label">Priorisiert</span></div>{{ui.recommendations(data)}}</section>
{{ui.outlook(data)}}{{ui.notes(data)}}
</body></html>
@@ -0,0 +1,11 @@
{% import '_shared/macros.html.j2' as ui %}
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>{{ data._theme.name }} - {{ data.customer.name }}</title><style>
:root{--p:{{data.design.primary_color}};--s:{{data.design.secondary_color}};--a:{{data.design.accent_color}};--t:{{data.design.text_color}};--m:{{data.design.muted_color}};--bg:{{data.design.surface_color}};--line:#d7dce2;--pos:#24725a;--neg:#a24048}@page{size:A4;margin:12mm 14mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.1pt/1.47 {{data.design.font_family}},Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:39pt;line-height:.88;letter-spacing:-2px;margin:0;text-transform:uppercase}h2{font-size:16pt;line-height:1.08;margin-bottom:3mm}h3{font-size:10.5pt;margin-bottom:1mm}p{margin-bottom:2.6mm}.cover{display:grid;grid-template-columns:1fr 53mm;min-height:73mm;margin-bottom:6mm;break-inside:avoid}.cover-main{background:var(--p);color:#fff;padding:7mm;position:relative;overflow:hidden}.cover-main:after{content:"";position:absolute;width:60mm;height:60mm;border:10mm solid #ffffff0f;border-radius:50%;right:-24mm;bottom:-30mm}.cover-side{background:var(--a);padding:6mm 5mm;display:flex;flex-direction:column;justify-content:space-between;color:var(--t)}.logo{width:14mm;height:14mm;background:#fff;color:var(--p);display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand{margin-top:4mm;font-weight:800}.location{font-size:7.5pt;opacity:.76}.cover-title{position:absolute;left:7mm;bottom:7mm;z-index:1}.cover-title .kicker{color:#ffffffb8}.issue-num{font-size:36pt;font-weight:900;line-height:1;color:var(--p)}.issue-label{font-size:7pt;text-transform:uppercase;letter-spacing:1px;font-weight:800}.kicker,.kpi-label,.category{font-size:6.7pt;text-transform:uppercase;letter-spacing:1.1px;font-weight:900;color:var(--m)}.summary{display:grid;grid-template-columns:52mm 1fr;gap:6mm;padding:5mm 0;border-bottom:1px solid var(--line);margin-bottom:5mm}.summary-mark{font-size:22pt;font-weight:900;color:var(--a);line-height:1}.summary h2{font-size:17pt}.summary p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:2mm;margin-bottom:3mm}.kpi{padding:4mm;background:var(--bg);border-bottom:1.2mm solid var(--p);min-height:29mm}.kpi:nth-child(2n){border-bottom-color:var(--a)}.kpi-value{font-size:16pt;font-weight:900;margin:2mm 0;color:var(--p);white-space:nowrap}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:2mm;margin-bottom:7mm}.fact{padding:2.2mm 3mm;border:1px solid var(--line)}.fact span{display:block;font-size:6.7pt;color:var(--m)}.fact strong{display:block;margin-top:.7mm}.section-head{display:grid;grid-template-columns:13mm 1fr;gap:3mm;align-items:center;margin:7mm 0 3mm}.section-no{font-size:18pt;font-weight:900;color:var(--a)}.section-head h2{margin:0;border-bottom:1px solid var(--line);padding-bottom:2mm}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:18mm 1fr 28mm 22mm;gap:2.5mm;align-items:center;font-size:7.4pt}.trend-label{font-weight:800}.trend-track{height:5mm;background:var(--bg);position:relative;overflow:hidden}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1.3mm;background:var(--a);position:absolute;left:0;bottom:0}.trend-num{text-align:right}.feature-grid{display:grid;grid-template-columns:1fr 1fr;gap:5mm;break-before:page;break-inside:avoid}.developments,.recommendations{display:grid;gap:3mm}.development{background:var(--bg);padding:3.5mm;break-inside:avoid;border-top:1mm solid var(--m)}.development.positive{border-top-color:var(--pos)}.development.negative{border-top-color:var(--neg)}.development{display:grid;grid-template-columns:0 1fr;gap:0}.development .impact{display:none}.development p{margin:0}.recommendation{display:grid;grid-template-columns:9mm 1fr;gap:3mm;border:1px solid var(--line);padding:3.5mm;break-inside:avoid}.priority{font-size:19pt;font-weight:900;color:var(--a)}.recommendation p{margin-bottom:1.3mm}.effect{color:var(--p);font-weight:600}.outlook{margin-top:7mm;background:linear-gradient(110deg,var(--p),var(--s));color:#fff;padding:6mm;break-inside:avoid}.outlook .kicker{color:#ffffffb8}.outlook p{margin:0}.notes{font-size:6.8pt;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.2pt;color:var(--m);margin-top:2mm}
</style></head><body>
<section class="cover"><div class="cover-main">{{ui.logo(data)}}<div class="brand">{{data.customer.name}}</div><div class="location">{{data.customer.property_name}} · {{data.customer.location}}</div><div class="cover-title"><div class="kicker">Performance / Strategie / Ausblick</div><h1>Monats<br>report</h1></div></div><div class="cover-side"><div><div class="issue-label">Ausgabe</div><div class="issue-num">{{'%02d'|format(data.report.period.month)}}</div></div><div><div class="issue-label">Zeitraum</div><strong>{{data.report.period.label}}</strong><div class="location">{{data.report.generated_at|date_de}}</div></div></div></section>
<section class="summary"><div><div class="summary-mark">“</div><div class="kicker">Kurzfazit</div></div><div><h2>{{data.content.summary.headline}}</h2><p>{{data.content.summary.text}}</p></div></section>
{{ui.kpis(data)}}{{ui.facts(data)}}
<div class="section-head"><div class="section-no">01</div><h2>Monatsverlauf</h2></div>{{ui.trend_bars(data)}}
<div class="feature-grid"><section><div class="section-head"><div class="section-no">02</div><h2>Entwicklungen</h2></div>{{ui.developments(data)}}</section><section><div class="section-head"><div class="section-no">03</div><h2>Empfehlungen</h2></div>{{ui.recommendations(data)}}</section></div>
{{ui.outlook(data)}}{{ui.notes(data)}}
</body></html>
@@ -0,0 +1,11 @@
{% import '_shared/macros.html.j2' as ui %}
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>{{ data._theme.name }} - {{ data.customer.name }}</title><style>
:root{--p:{{data.design.primary_color}};--s:{{data.design.secondary_color}};--a:{{data.design.accent_color}};--t:{{data.design.text_color}};--m:{{data.design.muted_color}};--bg:{{data.design.surface_color}};--line:#d9dfdf;--pos:#27745b;--neg:#a54a4a}@page{size:A4;margin:14mm 15mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.3pt/1.52 {{data.design.font_family}},Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:36pt;line-height:.98;letter-spacing:-1.7px;margin:0}h2{font-size:15pt;line-height:1.15;margin-bottom:3mm}h3{font-size:10.5pt;margin-bottom:1mm}p{margin-bottom:3mm}.top{display:flex;justify-content:space-between;align-items:flex-start;border-top:1.8mm solid var(--p);padding-top:6mm;margin-bottom:12mm}.brand{display:flex;gap:3mm;align-items:center}.logo{width:11mm;height:11mm;border:1px solid var(--p);display:flex;align-items:center;justify-content:center;font-weight:800;color:var(--p);overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand strong{display:block}.micro,.kicker,.kpi-label,.category{font:700 7pt/1.2 Arial,sans-serif;text-transform:uppercase;letter-spacing:1.1px;color:var(--m)}.period{text-align:right;color:var(--p);font-weight:700}.hero{display:grid;grid-template-columns:1fr 68mm;gap:10mm;align-items:end;margin-bottom:11mm}.hero-note{border-left:1mm solid var(--a);padding-left:5mm}.hero-note h2{font-size:14pt}.hero-note p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);border-top:1px solid var(--line);border-bottom:1px solid var(--line);margin-bottom:5mm}.kpi{padding:5mm 4mm 4mm 0}.kpi+.kpi{border-left:1px solid var(--line);padding-left:4mm}.kpi-value{font-size:16pt;font-weight:700;color:var(--p);white-space:nowrap;margin:2mm 0}.kpi-delta{font-size:7.5pt;color:var(--m)}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:6mm;margin-bottom:10mm}.fact span{display:block;color:var(--m);font-size:7.3pt}.fact strong{display:block;margin-top:1mm}.section{margin-bottom:9mm}.section-title{display:grid;grid-template-columns:auto 1fr;gap:4mm;align-items:center;margin-bottom:4mm}.section-title h2{margin:0}.rule{height:1px;background:var(--line)}.trend-bars{border-top:1px solid var(--line)}.trend-row{display:grid;grid-template-columns:18mm 1fr 28mm 22mm;gap:3mm;align-items:center;padding:2.2mm 0;border-bottom:1px solid var(--line);font-size:7.7pt}.trend-label{font-weight:700}.trend-track{height:3.5mm;background:var(--bg);position:relative}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1mm;background:var(--a);position:absolute;bottom:0;left:0}.trend-num{text-align:right}.content-grid{display:grid;grid-template-columns:1fr 1.1fr;gap:9mm;break-before:page;break-inside:avoid}.developments,.recommendations{display:grid;gap:4mm}.development{display:grid;grid-template-columns:2mm 1fr;gap:3mm;break-inside:avoid}.impact{width:1.3mm;background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendation{display:grid;grid-template-columns:8mm 1fr;gap:3mm;break-inside:avoid;padding-bottom:4mm;border-bottom:1px solid var(--line)}.priority{font-size:17pt;color:var(--a);font-weight:700}.recommendation p{margin-bottom:1.5mm}.effect{color:var(--p)}.outlook{margin-top:8mm;padding:6mm 0;border-top:1.2mm solid var(--p);border-bottom:1px solid var(--line);break-inside:avoid}.outlook p{margin:0}.notes{margin-top:4mm;font-size:7pt;color:var(--m)}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.5pt;color:var(--m);margin-top:3mm}
</style></head><body>
<header class="top"><div class="brand">{{ui.logo(data)}}<div><strong>{{data.customer.name}}</strong><div class="micro">{{data.customer.property_name}}</div></div></div><div class="period">{{data.report.period.label}}<div class="micro">{{data.customer.location}}</div></div></header>
<section class="hero"><div><div class="kicker">Monatliche Performance</div><h1>Monats-<br>report</h1></div><div class="hero-note"><div class="kicker">Kurzfazit</div><h2>{{data.content.summary.headline}}</h2><p>{{data.content.summary.text}}</p></div></section>
{{ui.kpis(data)}}{{ui.facts(data)}}
<section class="section"><div class="section-title"><h2>Monatsverlauf</h2><div class="rule"></div></div>{{ui.trend_bars(data)}}</section>
<div class="content-grid"><section><div class="section-title"><h2>Entwicklungen</h2><div class="rule"></div></div>{{ui.developments(data)}}</section><section><div class="section-title"><h2>Empfehlungen</h2><div class="rule"></div></div>{{ui.recommendations(data)}}</section></div>
{{ui.outlook(data)}}{{ui.notes(data)}}
</body></html>
@@ -0,0 +1,18 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<style>
html { font-family: Arial, sans-serif; font-size: 8px; color: #718087; margin: 0 14mm; -webkit-print-color-adjust: exact; }
body { margin: 0; }
.footer { width: 100%; padding-top: 3mm; border-top: 1px solid #dfe5e8; display: flex; justify-content: space-between; align-items: center; }
.page { font-weight: 700; color: {{ data.design.primary_color }}; }
</style>
</head>
<body>
<div class="footer">
<span>{{ data.customer.name }} · {{ data.report.period.label }} · Template {{ data.report.template_version }}</span>
<span class="page">Seite <span class="pageNumber"></span> / <span class="totalPages"></span></span>
</div>
</body>
</html>
@@ -0,0 +1,373 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Monatsreport {{ data.report.period.label }} - {{ data.customer.name }}</title>
<style>
:root {
--primary: {{ data.design.primary_color }};
--secondary: {{ data.design.secondary_color }};
--accent: {{ data.design.accent_color }};
--text: {{ data.design.text_color }};
--muted: {{ data.design.muted_color }};
--surface: {{ data.design.surface_color }};
--line: #dfe5e8;
--positive: #207a5a;
--neutral: #667680;
--negative: #b14949;
--watch: #9a6815;
}
@page {
size: A4;
margin: 13mm 14mm 18mm 14mm;
}
* { box-sizing: border-box; }
html { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
body {
margin: 0;
color: var(--text);
font-family: {{ data.design.font_family }}, Arial, sans-serif;
font-size: 9.3pt;
line-height: 1.48;
background: #fff;
}
h1, h2, h3, p { margin-top: 0; }
h1 { font-size: 27pt; line-height: 1.08; letter-spacing: -0.6px; margin-bottom: 2mm; }
h2 { font-size: 14.5pt; line-height: 1.2; margin-bottom: 4mm; }
h3 { font-size: 10.8pt; line-height: 1.25; margin-bottom: 1.5mm; }
p { margin-bottom: 3mm; }
.cover {
position: relative;
overflow: hidden;
min-height: 67mm;
padding: 9mm;
border-radius: 5mm;
color: #fff;
background: linear-gradient(128deg, var(--primary), var(--secondary));
margin-bottom: 7mm;
break-inside: avoid;
}
.cover::after {
content: "";
position: absolute;
width: 92mm;
height: 92mm;
right: -27mm;
top: -42mm;
border: 12mm solid rgba(255,255,255,.08);
border-radius: 50%;
}
.cover-top { display: flex; align-items: center; justify-content: space-between; gap: 8mm; position: relative; z-index: 1; }
.brand { display: flex; align-items: center; gap: 4mm; }
.logo {
width: 15mm; height: 15mm; border-radius: 4mm;
background: rgba(255,255,255,.96); color: var(--primary);
display: flex; align-items: center; justify-content: center; font-size: 15pt; font-weight: 800;
box-shadow: 0 2mm 5mm rgba(0,0,0,.12);
overflow: hidden;
}
.logo img { width: 100%; height: 100%; object-fit: contain; padding: 1.6mm; }
.brand-name { font-size: 11pt; font-weight: 700; }
.brand-sub { font-size: 8pt; opacity: .82; }
.period-chip {
padding: 2.2mm 4mm; border-radius: 99mm;
border: .25mm solid rgba(255,255,255,.38);
background: rgba(255,255,255,.12); font-size: 8.3pt; font-weight: 700;
}
.cover-main { position: relative; z-index: 1; margin-top: 13mm; max-width: 142mm; }
.eyebrow { text-transform: uppercase; letter-spacing: 1.7px; font-size: 7.2pt; font-weight: 800; opacity: .78; margin-bottom: 2.2mm; }
.cover-meta { display: flex; flex-wrap: wrap; gap: 3mm 8mm; font-size: 8.4pt; opacity: .88; }
.section { margin-bottom: 7mm; }
.section-heading { display: flex; align-items: flex-end; justify-content: space-between; gap: 5mm; margin-bottom: 3.5mm; }
.section-heading h2 { margin: 0; }
.section-kicker { font-size: 7.3pt; font-weight: 800; color: var(--muted); text-transform: uppercase; letter-spacing: 1.2px; margin-bottom: 1mm; }
.summary {
display: grid; grid-template-columns: 10mm 1fr; gap: 4mm;
padding: 5mm; border-radius: 3mm; background: var(--surface);
border-left: 1.5mm solid var(--accent); break-inside: avoid;
}
.summary-icon {
width: 9mm; height: 9mm; border-radius: 50%;
display: flex; align-items: center; justify-content: center; align-self: start; color: #fff; font-weight: 900; margin-top: .5mm;
}
.summary-icon.positive { background: var(--positive); }
.summary-icon.neutral { background: var(--neutral); }
.summary-icon.watch { background: var(--watch); }
.summary h2 { font-size: 14pt; margin-bottom: 2mm; }
.summary p { margin-bottom: 0; }
.kpi-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 3mm; }
.kpi-card {
min-height: 31mm; padding: 4mm; border: .25mm solid var(--line);
border-radius: 3mm; break-inside: avoid; background: #fff;
}
.kpi-label { font-size: 7.3pt; text-transform: uppercase; letter-spacing: .8px; color: var(--muted); font-weight: 800; }
.kpi-value { font-size: 16pt; font-weight: 800; color: var(--primary); line-height: 1.15; margin: 3mm 0 1.5mm; white-space: nowrap; }
.kpi-delta { font-size: 7.6pt; color: var(--muted); }
.delta-positive { color: var(--positive); font-weight: 700; }
.delta-negative { color: var(--negative); font-weight: 700; }
.detail-strip {
display: grid; grid-template-columns: repeat(4, 1fr); gap: 0;
border: .25mm solid var(--line); border-radius: 3mm; overflow: hidden; margin-top: 3mm;
}
.detail-item { padding: 3mm 4mm; border-right: .25mm solid var(--line); }
.detail-item:last-child { border-right: 0; }
.detail-label { font-size: 7.2pt; color: var(--muted); }
.detail-value { font-weight: 800; margin-top: .8mm; }
.trend-panel {
border: .25mm solid var(--line); border-radius: 3mm; padding: 5mm;
break-inside: avoid;
}
.trend-legend { display: flex; gap: 5mm; font-size: 7.4pt; color: var(--muted); }
.legend-dot { width: 2.2mm; height: 2.2mm; border-radius: 50%; display: inline-block; margin-right: 1.2mm; }
.legend-revenue { background: var(--primary); }
.legend-occ { background: var(--accent); }
.trend-grid { display: block; margin-top: 3mm; }
.trend-row { display: grid; grid-template-columns: 20mm 1fr 25mm 25mm; align-items: center; gap: 2mm; margin-top: 2mm; }
.trend-label { font-weight: 700; font-size: 8pt; }
.bar-track { height: 4mm; border-radius: 99mm; background: #edf1f3; overflow: hidden; position: relative; }
.bar { height: 100%; border-radius: inherit; }
.bar-revenue { background: var(--primary); }
.bar-occ { background: var(--accent); height: 1.5mm; position: absolute; left: 0; bottom: 0; }
.trend-number { text-align: right; font-size: 7.7pt; font-variant-numeric: tabular-nums; }
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 5mm; align-items: start; }
.development-list { display: grid; gap: 3mm; }
.development {
border: .25mm solid var(--line); border-radius: 3mm; padding: 4mm;
break-inside: avoid;
}
.development-top { display: flex; align-items: center; gap: 2mm; margin-bottom: 1.5mm; }
.impact-dot { width: 2.5mm; height: 2.5mm; border-radius: 50%; flex: 0 0 auto; }
.impact-dot.positive { background: var(--positive); }
.impact-dot.neutral { background: var(--neutral); }
.impact-dot.negative { background: var(--negative); }
.development p { margin: 0; color: #35434a; }
.recommendations { display: grid; gap: 3.5mm; }
.recommendation {
display: grid; grid-template-columns: 11mm 1fr; gap: 4mm;
padding: 4.5mm; border-radius: 3mm; background: var(--surface);
border: .25mm solid #d7e1e2;
break-inside: avoid;
}
.priority {
width: 10mm; height: 10mm; border-radius: 3mm; background: var(--primary); color: #fff;
display: flex; align-items: center; justify-content: center; align-self: start; font-weight: 900; font-size: 12pt;
}
.category { color: var(--primary); font-size: 7.2pt; font-weight: 900; text-transform: uppercase; letter-spacing: .8px; }
.recommendation h3 { font-size: 11.3pt; margin: .8mm 0 2mm; }
.recommendation p { margin-bottom: 2mm; }
.recommendation p:last-child { margin-bottom: 0; }
.action-line { padding-top: 2mm; border-top: .25mm solid rgba(0,0,0,.08); }
.outlook {
padding: 5mm; color: #fff; border-radius: 3mm;
background: linear-gradient(115deg, var(--primary), var(--secondary));
break-inside: avoid;
}
.outlook h2 { margin-bottom: 2mm; }
.outlook p { margin: 0; opacity: .94; }
.notes {
margin-top: 4mm; padding: 3.5mm 4mm; border-radius: 2mm;
background: #f7f8f9; color: var(--muted); font-size: 7.5pt;
break-inside: avoid;
}
.notes ul { margin: 1.5mm 0 0; padding-left: 4mm; }
.notes li { margin-bottom: .8mm; }
.legal { margin-top: 4mm; color: var(--muted); font-size: 6.9pt; }
.page-break { break-before: page; }
.avoid { break-inside: avoid; }
@media print {
.section:last-child { margin-bottom: 0; }
}
</style>
</head>
<body>
<main>
<section class="cover">
<div class="cover-top">
<div class="brand">
<div class="logo">
{% if data.customer.logo_data_uri %}
<img src="{{ data.customer.logo_data_uri }}" alt="Logo">
{% else %}
{{ data.customer.logo_text }}
{% endif %}
</div>
<div>
<div class="brand-name">{{ data.customer.name }}</div>
<div class="brand-sub">{{ data.customer.property_name }}</div>
</div>
</div>
<div class="period-chip">{{ data.report.period.label }}</div>
</div>
<div class="cover-main">
<div class="eyebrow">Performance & Handlungsempfehlungen</div>
<h1>Monatsreport</h1>
<div class="cover-meta">
<span>{{ data.customer.location }}</span>
<span>Erstellt am {{ data.report.generated_at|date_de }}</span>
<span>Version {{ data.report.report_version }}</span>
</div>
</div>
</section>
<section class="section">
<div class="summary">
<div class="summary-icon {{ data.content.summary.rating }}">
{% if data.content.summary.rating == 'positive' %}↑{% elif data.content.summary.rating == 'watch' %}!{% else %}•{% endif %}
</div>
<div>
<div class="section-kicker">Kurzfazit</div>
<h2>{{ data.content.summary.headline }}</h2>
<p>{{ data.content.summary.text }}</p>
</div>
</div>
</section>
<section class="section">
<div class="section-heading">
<div>
<div class="section-kicker">Kennzahlen</div>
<h2>Der Monat auf einen Blick</h2>
</div>
<div class="section-kicker">Vergleich: {{ data.report.period.comparison_label }}</div>
</div>
<div class="kpi-grid">
<article class="kpi-card">
<div class="kpi-label">Umsatz</div>
<div class="kpi-value">{{ data.metrics.revenue|currency_de(data.metrics.currency) }}</div>
<div class="kpi-delta {% if data.metrics.comparison.revenue_delta_pct >= 0 %}delta-positive{% else %}delta-negative{% endif %}">
{{ data.metrics.comparison.revenue_delta_pct|delta_de(1, '%') }}
</div>
</article>
<article class="kpi-card">
<div class="kpi-label">Auslastung</div>
<div class="kpi-value">{{ data.metrics.occupancy_rate|percent_de }}</div>
<div class="kpi-delta {% if data.metrics.comparison.occupancy_delta_pp >= 0 %}delta-positive{% else %}delta-negative{% endif %}">
{{ data.metrics.comparison.occupancy_delta_pp|delta_de(1, 'PP') }}
</div>
</article>
<article class="kpi-card">
<div class="kpi-label">Ø Tagespreis</div>
<div class="kpi-value">{{ data.metrics.adr|currency_de(data.metrics.currency) }}</div>
<div class="kpi-delta {% if data.metrics.comparison.adr_delta_pct >= 0 %}delta-positive{% else %}delta-negative{% endif %}">
{{ data.metrics.comparison.adr_delta_pct|delta_de(1, '%') }}
</div>
</article>
<article class="kpi-card">
<div class="kpi-label">Buchungen</div>
<div class="kpi-value">{{ data.metrics.bookings|number_de(0) }}</div>
<div class="kpi-delta {% if data.metrics.comparison.bookings_delta >= 0 %}delta-positive{% else %}delta-negative{% endif %}">
{{ data.metrics.comparison.bookings_delta|delta_de(0, '') }} Buchungen
</div>
</article>
</div>
<div class="detail-strip">
<div class="detail-item"><div class="detail-label">RevPAR</div><div class="detail-value">{{ data.metrics.revpar|currency_de(data.metrics.currency) }}</div></div>
<div class="detail-item"><div class="detail-label">Verkaufte Nächte</div><div class="detail-value">{{ data.metrics.nights_sold|number_de(0) }}</div></div>
<div class="detail-item"><div class="detail-label">Ø Aufenthaltsdauer</div><div class="detail-value">{{ data.metrics.average_stay|number_de(1) }} Nächte</div></div>
<div class="detail-item"><div class="detail-label">Stornoquote</div><div class="detail-value">{{ data.metrics.cancellation_rate|percent_de }}</div></div>
</div>
</section>
<section class="section">
<div class="section-heading">
<div>
<div class="section-kicker">Verlauf</div>
<h2>Entwicklung der letzten Monate</h2>
</div>
<div class="trend-legend">
<span><i class="legend-dot legend-revenue"></i> Umsatz</span>
<span><i class="legend-dot legend-occ"></i> Auslastung</span>
</div>
</div>
<div class="trend-panel">
<div class="trend-grid">
{% for item in data.trends %}
<div class="trend-row">
<div class="trend-label">{{ item.label }}</div>
<div class="bar-track">
<div class="bar bar-revenue" style="width: {{ item.revenue_bar }}%"></div>
<div class="bar bar-occ" style="width: {{ item.occupancy_bar }}%"></div>
</div>
<div class="trend-number">{{ item.revenue|currency_de(data.metrics.currency) }}</div>
<div class="trend-number">{{ item.occupancy_rate|percent_de }}</div>
</div>
{% endfor %}
</div>
</div>
</section>
<section class="section">
<div class="section-heading">
<div>
<div class="section-kicker">Analyse</div>
<h2>Wichtige Entwicklungen</h2>
</div>
</div>
<div class="two-col">
{% for item in data.content.developments %}
<article class="development">
<div class="development-top"><span class="impact-dot {{ item.impact }}"></span><h3>{{ item.title }}</h3></div>
<p>{{ item.text }}</p>
</article>
{% endfor %}
</div>
</section>
<section class="section">
<div class="section-heading">
<div>
<div class="section-kicker">Naechste Schritte</div>
<h2>Priorisierte Empfehlungen</h2>
</div>
</div>
<div class="recommendations">
{% for item in data.content.recommendations|sort(attribute='priority') %}
<article class="recommendation">
<div class="priority">{{ item.priority }}</div>
<div>
<div class="category">{{ item.category }}</div>
<h3>{{ item.title }}</h3>
<p><strong>Warum:</strong> {{ item.reason }}</p>
<p class="action-line"><strong>Massnahme:</strong> {{ item.action }}</p>
<p><strong>Erwarteter Effekt:</strong> {{ item.expected_effect }}</p>
</div>
</article>
{% endfor %}
</div>
</section>
<section class="section">
<div class="outlook">
<div class="section-kicker" style="color: rgba(255,255,255,.7)">Ausblick</div>
<h2>{{ data.content.outlook.headline }}</h2>
<p>{{ data.content.outlook.text }}</p>
</div>
{% if data.content.data_quality_notes %}
<div class="notes">
<strong>Hinweise zur Datengrundlage</strong>
<ul>
{% for note in data.content.data_quality_notes %}<li>{{ note }}</li>{% endfor %}
</ul>
</div>
{% endif %}
<div class="legal">{{ data.legal_note }}</div>
</section>
</main>
</body>
</html>
@@ -0,0 +1,11 @@
{% import '_shared/macros.html.j2' as ui %}
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>{{ data._theme.name }} - {{ data.customer.name }}</title><style>
:root{--p:{{data.design.primary_color}};--s:{{data.design.secondary_color}};--a:{{data.design.accent_color}};--t:{{data.design.text_color}};--m:{{data.design.muted_color}};--bg:{{data.design.surface_color}};--line:#d6d6d6;--pos:#25745a;--neg:#a43d43}@page{size:A4;margin:11mm 13mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9pt/1.42 {{data.design.font_family}},Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:43pt;line-height:.8;letter-spacing:-2.8px;text-transform:uppercase;margin:0}h2{font-size:17pt;line-height:1.05;margin-bottom:3mm}h3{font-size:10pt;margin-bottom:1mm}p{margin-bottom:2.5mm}.cover{background:var(--p);color:#fff;min-height:79mm;padding:7mm;position:relative;overflow:hidden;margin-bottom:4mm;break-inside:avoid}.cover:after{content:"{{'%02d'|format(data.report.period.month)}}";position:absolute;right:-4mm;bottom:-17mm;font-size:90pt;line-height:1;font-weight:900;color:#ffffff10}.top{display:flex;justify-content:space-between;align-items:flex-start;position:relative;z-index:1}.brand{display:flex;gap:3mm;align-items:center}.logo{width:13mm;height:13mm;background:#fff;color:var(--p);display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand-name{font-weight:900}.small{font-size:7pt;opacity:.74}.period{background:var(--a);color:var(--t);padding:2.5mm 4mm;font-weight:900}.title{position:absolute;left:7mm;bottom:7mm;z-index:1}.kicker,.kpi-label,.category{font-size:6.6pt;text-transform:uppercase;letter-spacing:1px;font-weight:900;color:var(--m)}.cover .kicker{color:#ffffffad}.summary{display:grid;grid-template-columns:48mm 1fr;background:var(--a);padding:5mm;margin-bottom:4mm}.summary-label{font-size:22pt;font-weight:900;text-transform:uppercase;line-height:.9}.summary h2{font-size:16pt}.summary p{margin:0}.kpis{display:grid;grid-template-columns:1fr 1fr;gap:3mm;margin-bottom:3mm}.kpi{min-height:34mm;padding:4mm;border:1px solid var(--t);position:relative}.kpi:nth-child(1),.kpi:nth-child(4){background:var(--t);color:#fff}.kpi:nth-child(1) .kpi-label,.kpi:nth-child(4) .kpi-label{color:#ffffffaa}.kpi-value{font-size:25pt;font-weight:900;line-height:1;color:var(--p);margin:2mm 0}.kpi:nth-child(1) .kpi-value,.kpi:nth-child(4) .kpi-value{color:var(--a)}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:0;background:var(--bg);margin-bottom:6mm}.fact{padding:3mm;border-right:1px solid var(--line)}.fact:last-child{border-right:0}.fact span{display:block;font-size:6.5pt;color:var(--m)}.fact strong{display:block;margin-top:.5mm}.section-title{display:flex;align-items:baseline;gap:4mm;border-bottom:2mm solid var(--p);margin:7mm 0 3mm}.section-title .num{font-size:24pt;font-weight:900;color:var(--a)}.section-title h2{margin:0 0 1mm;text-transform:uppercase}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:17mm 1fr 28mm 22mm;gap:2.5mm;align-items:center;font-size:7.2pt}.trend-label{font-weight:900}.trend-track{height:5mm;background:var(--bg);position:relative;border:1px solid var(--t)}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1.4mm;background:var(--a);position:absolute;left:0;bottom:0}.trend-num{text-align:right}.content{display:grid;grid-template-columns:1fr 1fr;gap:5mm;break-before:page;break-inside:avoid}.developments,.recommendations{display:grid;gap:3mm}.development{display:grid;grid-template-columns:3mm 1fr;gap:3mm;border-bottom:1px solid var(--line);padding-bottom:3mm;break-inside:avoid}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendation{display:grid;grid-template-columns:10mm 1fr;gap:3mm;border:1px solid var(--t);padding:3mm;break-inside:avoid}.priority{font-size:22pt;font-weight:900;color:var(--a)}.recommendation p{margin-bottom:1.2mm}.effect{border-top:1px solid var(--line);padding-top:1.3mm}.outlook{margin-top:6mm;background:var(--t);color:#fff;padding:5mm;break-inside:avoid}.outlook .kicker{color:var(--a)}.outlook p{margin:0}.notes{font-size:6.7pt;color:var(--m);margin-top:3mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.1pt;color:var(--m);margin-top:2mm}
</style></head><body>
<section class="cover"><div class="top"><div class="brand">{{ui.logo(data)}}<div><div class="brand-name">{{data.customer.name}}</div><div class="small">{{data.customer.property_name}} · {{data.customer.location}}</div></div></div><div class="period">{{data.report.period.label}}</div></div><div class="title"><div class="kicker">Performance / Analyse / Aktionen</div><h1>Monats<br>report</h1></div></section>
<section class="summary"><div class="summary-label">Der<br>Monat</div><div><div class="kicker">Kurzfazit</div><h2>{{data.content.summary.headline}}</h2><p>{{data.content.summary.text}}</p></div></section>
{{ui.kpis(data)}}{{ui.facts(data)}}
<div class="section-title"><span class="num">01</span><h2>Monatsverlauf</h2></div>{{ui.trend_bars(data)}}
<div class="content"><section><div class="section-title"><span class="num">02</span><h2>Entwicklungen</h2></div>{{ui.developments(data)}}</section><section><div class="section-title"><span class="num">03</span><h2>Aktionen</h2></div>{{ui.recommendations(data)}}</section></div>
{{ui.outlook(data)}}{{ui.notes(data)}}
</body></html>
@@ -0,0 +1,7 @@
{% import '_shared/macros.html.j2' as ui %}
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>{{ data._theme.name }} - {{ data.customer.name }}</title><style>
:root{--p:{{data.design.primary_color}};--s:{{data.design.secondary_color}};--a:{{data.design.accent_color}};--t:{{data.design.text_color}};--m:{{data.design.muted_color}};--bg:{{data.design.surface_color}};--line:#d8e0df;--pos:#28765b;--neg:#a54b4b}@page{size:A4;margin:0 13mm 18mm 0}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.1pt/1.48 {{data.design.font_family}},Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:25pt;line-height:1.05;margin-bottom:2mm}h2{font-size:14pt;margin-bottom:3mm}h3{font-size:10.2pt;margin-bottom:1mm}p{margin-bottom:2.7mm}.page{display:grid;grid-template-columns:45mm 1fr;min-height:279mm}.side{background:linear-gradient(180deg,var(--p),var(--s));color:#fff;padding:13mm 7mm 10mm 8mm}.main{padding:13mm 0 0 9mm}.logo{width:15mm;height:15mm;background:#fff;color:var(--p);border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden;margin-bottom:5mm}.logo img{width:100%;height:100%;object-fit:contain;padding:1.3mm}.brand{font-weight:800;font-size:11pt}.side-sub{font-size:7.5pt;opacity:.78;margin-top:1mm}.side-period{margin:18mm 0 10mm}.side-period strong{font-size:18pt;display:block;line-height:1.05}.kicker,.kpi-label,.category{font:800 6.8pt/1.2 Arial,sans-serif;text-transform:uppercase;letter-spacing:1px;color:var(--m)}.side .kicker{color:#ffffffb0}.side-facts{display:grid;gap:4mm;border-top:1px solid #ffffff40;padding-top:5mm}.side-fact span{font-size:7pt;opacity:.7;display:block}.side-fact strong{font-size:11pt}.side-outlook{margin-top:13mm;border-top:1px solid #ffffff40;padding-top:5mm}.side-outlook h3{font-size:11pt}.side-outlook p{font-size:7.6pt;opacity:.88}.intro{margin-bottom:6mm}.intro h1{color:var(--p)}.summary{border-left:1.4mm solid var(--a);padding:1mm 0 1mm 5mm;margin:5mm 0 6mm}.summary h2{font-size:14.5pt}.summary p{margin:0}.kpis{display:grid;grid-template-columns:1fr 1fr;gap:3mm;margin-bottom:5mm}.kpi{background:var(--bg);padding:4mm;border-radius:2mm;break-inside:avoid}.kpi-value{font-size:17pt;font-weight:800;color:var(--p);margin:2mm 0}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:none}.section{margin:6mm 0}.section-head{display:flex;align-items:center;gap:3mm;margin-bottom:3mm}.section-head h2{margin:0;white-space:nowrap}.line{height:1px;background:var(--line);width:100%}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:16mm 1fr 27mm 21mm;gap:2mm;align-items:center;font-size:7.2pt}.trend-label{font-weight:700}.trend-track{height:3.7mm;background:var(--bg);position:relative}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1mm;background:var(--a);position:absolute;bottom:0;left:0}.trend-num{text-align:right}.developments{columns:2;column-gap:5mm}.development{display:grid;grid-template-columns:2mm 1fr;gap:2.5mm;break-inside:avoid;margin-bottom:3mm}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendations{display:grid;gap:3mm}.recommendation{display:grid;grid-template-columns:9mm 1fr;gap:3mm;padding:3.5mm 0;border-top:1px solid var(--line);break-inside:avoid}.priority{font-size:18pt;font-weight:800;color:var(--a)}.recommendation p{margin-bottom:1.3mm}.effect{color:var(--p)}.outlook{display:none}.notes{font-size:6.8pt;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.2pt;color:var(--m);margin-top:2mm}
</style></head><body><div class="page">
<aside class="side">{{ui.logo(data)}}<div class="brand">{{data.customer.name}}</div><div class="side-sub">{{data.customer.property_name}}<br>{{data.customer.location}}</div><div class="side-period"><div class="kicker">Monatsreport</div><strong>{{data.report.period.label}}</strong><div class="side-sub">Version {{data.report.report_version}}</div></div><div class="side-facts"><div class="side-fact"><span>RevPAR</span><strong>{{data.metrics.revpar|currency_de(data.metrics.currency)}}</strong></div><div class="side-fact"><span>Verkaufte Nächte</span><strong>{{data.metrics.nights_sold|number_de(0)}}</strong></div><div class="side-fact"><span>Ø Aufenthalt</span><strong>{{data.metrics.average_stay|number_de(1)}}</strong></div><div class="side-fact"><span>Stornoquote</span><strong>{{data.metrics.cancellation_rate|percent_de}}</strong></div></div><div class="side-outlook"><div class="kicker">Ausblick</div><h3>{{data.content.outlook.headline}}</h3><p>{{data.content.outlook.text}}</p></div></aside>
<main class="main"><section class="intro"><div class="kicker">Performance & Handlungsempfehlungen</div><h1>Der Monat<br>im Überblick</h1></section><section class="summary"><div class="kicker">Kurzfazit</div><h2>{{data.content.summary.headline}}</h2><p>{{data.content.summary.text}}</p></section>{{ui.kpis(data)}}
<section class="section"><div class="section-head"><h2>Monatsverlauf</h2><div class="line"></div></div>{{ui.trend_bars(data)}}</section><section class="section"><div class="section-head"><h2>Entwicklungen</h2><div class="line"></div></div>{{ui.developments(data)}}</section><section class="section"><div class="section-head"><h2>Empfehlungen</h2><div class="line"></div></div>{{ui.recommendations(data)}}</section>{{ui.notes(data)}}</main></div></body></html>
@@ -0,0 +1,11 @@
{% import '_shared/macros.html.j2' as ui %}
<!doctype html><html lang="de"><head><meta charset="utf-8"><title>{{ data._theme.name }} - {{ data.customer.name }}</title><style>
:root{--p:{{data.design.primary_color}};--s:{{data.design.secondary_color}};--a:{{data.design.accent_color}};--t:{{data.design.text_color}};--m:{{data.design.muted_color}};--bg:{{data.design.surface_color}};--line:#d9dfdf;--pos:#28745a;--neg:#a74646}@page{size:A4;margin:12mm 14mm 19mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;color:var(--t);font:9.2pt/1.48 {{data.design.font_family}},Arial,sans-serif}h1,h2,h3,p{margin-top:0}h1{font-size:31pt;line-height:.98;margin:0}h2{font-size:15pt;margin-bottom:3mm}h3{font-size:10.3pt;margin-bottom:1mm}p{margin-bottom:2.6mm}.cover{display:grid;grid-template-columns:1fr 1fr;min-height:68mm;margin-bottom:6mm;break-inside:avoid}.cover-left{background:var(--p);color:#fff;padding:7mm;display:flex;flex-direction:column;justify-content:space-between}.cover-right{background:var(--bg);padding:7mm;display:flex;flex-direction:column;justify-content:space-between}.brand{display:flex;align-items:center;gap:3mm}.logo{width:13mm;height:13mm;background:#fff;color:var(--p);display:flex;align-items:center;justify-content:center;font-weight:900;overflow:hidden}.logo img{width:100%;height:100%;object-fit:contain;padding:1mm}.brand-name{font-weight:800}.small{font-size:7.3pt;opacity:.76}.kicker,.kpi-label,.category{font-size:6.7pt;text-transform:uppercase;letter-spacing:1px;font-weight:800;color:var(--m)}.cover-left .kicker{color:#ffffffb8}.period{font-size:18pt;color:var(--p);font-weight:800}.summary h2{font-size:15pt}.summary p{margin:0}.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:3mm;margin-bottom:3mm}.kpi{padding:4mm;border-left:1mm solid var(--p);background:#fff;border-top:1px solid var(--line);border-right:1px solid var(--line);border-bottom:1px solid var(--line)}.kpi:nth-child(even){border-left-color:var(--a)}.kpi-value{font-size:15.5pt;font-weight:800;color:var(--p);margin:2mm 0;white-space:nowrap}.kpi-delta{font-size:7pt}.up{color:var(--pos)}.down{color:var(--neg)}.facts{display:grid;grid-template-columns:repeat(4,1fr);background:var(--bg);padding:3mm 4mm;margin-bottom:7mm}.fact span{display:block;font-size:6.7pt;color:var(--m)}.fact strong{display:block;margin-top:.5mm}.band{display:grid;grid-template-columns:40mm 1fr;gap:6mm;margin:7mm 0;break-inside:avoid}.band-title{background:var(--p);color:#fff;padding:5mm;min-height:30mm}.band-title.alt{background:var(--a);color:var(--t)}.band-title h2{margin:0}.trend-bars{display:grid;gap:2mm}.trend-row{display:grid;grid-template-columns:18mm 1fr 28mm 22mm;gap:2.5mm;align-items:center;font-size:7.3pt}.trend-label{font-weight:700}.trend-track{height:4mm;background:var(--bg);position:relative}.trend-revenue{height:100%;background:var(--p)}.trend-occ{height:1.2mm;background:var(--a);position:absolute;bottom:0;left:0}.trend-num{text-align:right}.developments{display:grid;grid-template-columns:1fr 1fr;gap:3mm}.development{display:grid;grid-template-columns:2mm 1fr;gap:3mm;border:1px solid var(--line);padding:3.5mm;break-inside:avoid}.impact{background:var(--m)}.positive .impact{background:var(--pos)}.negative .impact{background:var(--neg)}.development p{margin:0}.recommendations{display:grid;gap:3mm}.recommendation{display:grid;grid-template-columns:9mm 1fr;gap:3mm;border-bottom:1px solid var(--line);padding:0 0 3mm;break-inside:avoid}.priority{font-size:18pt;font-weight:800;color:var(--a)}.recommendation p{margin-bottom:1.3mm}.effect{color:var(--p)}.outlook{margin-top:7mm;display:grid;grid-template-columns:38mm 1fr;background:var(--bg);padding:5mm;break-inside:avoid}.outlook .kicker{align-self:start;color:var(--p)}.outlook h2{margin-bottom:2mm}.outlook p{margin:0}.notes{font-size:6.8pt;color:var(--m);margin-top:4mm}.notes ul{margin:1mm 0;padding-left:4mm}.legal{font-size:6.2pt;color:var(--m);margin-top:2mm}
</style></head><body>
<section class="cover"><div class="cover-left"><div class="brand">{{ui.logo(data)}}<div><div class="brand-name">{{data.customer.name}}</div><div class="small">{{data.customer.property_name}}</div></div></div><div><div class="kicker">Performance & Strategie</div><h1>Monatsreport</h1></div></div><div class="cover-right"><div><div class="kicker">Berichtszeitraum</div><div class="period">{{data.report.period.label}}</div><div class="small">{{data.customer.location}} · {{data.report.generated_at|date_de}}</div></div><div class="summary"><div class="kicker">Kurzfazit</div><h2>{{data.content.summary.headline}}</h2><p>{{data.content.summary.text}}</p></div></div></section>
{{ui.kpis(data)}}{{ui.facts(data)}}
<section class="band"><div class="band-title"><div class="kicker">01</div><h2>Monatsverlauf</h2></div><div>{{ui.trend_bars(data)}}</div></section>
<section class="band"><div class="band-title alt"><div class="kicker">02</div><h2>Entwicklungen</h2></div><div>{{ui.developments(data)}}</div></section>
<section class="band"><div class="band-title"><div class="kicker">03</div><h2>Empfehlungen</h2></div><div>{{ui.recommendations(data)}}</div></section>
{{ui.outlook(data)}}{{ui.notes(data)}}
</body></html>
+196
View File
@@ -0,0 +1,196 @@
from __future__ import annotations
from copy import deepcopy
from typing import Any
def _theme(
theme_id: str,
name: str,
layout: str,
category: str,
description: str,
primary: str,
secondary: str,
accent: str,
text: str,
muted: str,
surface: str,
font: str = "Arial",
*,
custom_palette_default: bool = False,
) -> dict[str, Any]:
return {
"id": theme_id,
"name": name,
"layout": layout,
"category": category,
"description": description,
"custom_palette_default": custom_palette_default,
"palette": {
"primary_color": primary,
"secondary_color": secondary,
"accent_color": accent,
"text_color": text,
"muted_color": muted,
"surface_color": surface,
"font_family": font,
},
}
THEMES: dict[str, dict[str, Any]] = {
"modern": _theme(
"modern", "Modern Custom", "modern", "Flexibel",
"Abgerundete Karten, Verlaufskopf und frei definierbare Kundenfarben.",
"#1F5D66", "#2C7C82", "#DBA25D", "#24343A", "#718087", "#F2F6F5",
custom_palette_default=True,
),
"classic": _theme(
"classic", "Classic Custom", "classic", "Flexibel",
"Serifentypografie, feine Linien und frei definierbare Kundenfarben.",
"#243B53", "#486581", "#C3913C", "#25313A", "#76838C", "#F4F1EA", "Georgia",
custom_palette_default=True,
),
"nordic-light": _theme(
"nordic-light", "Nordic Light", "minimal", "Minimal",
"Helles, luftiges Layout mit kuehlen Blautoenen und viel Weissraum.",
"#294C60", "#6D98A6", "#E7B45A", "#1F2D33", "#75858B", "#F1F5F5", "Arial",
),
"nordic-night": _theme(
"nordic-night", "Nordic Night", "minimal", "Minimal",
"Dunkle skandinavische Farbwelt mit eisblauem Akzent.",
"#182B36", "#2F5668", "#8FD3E6", "#162329", "#6E7F86", "#EDF3F4", "Arial",
),
"alpine-sage": _theme(
"alpine-sage", "Alpine Sage", "minimal", "Minimal",
"Ruhige Salbei- und Steinfarben fuer naturnahe Marken.",
"#49665B", "#718C7D", "#C99C64", "#26332E", "#78827D", "#F2F3ED", "Georgia",
),
"executive-blue": _theme(
"executive-blue", "Executive Blue", "dashboard", "Business",
"Klares Management-Dashboard in serioesem Marineblau.",
"#173B67", "#2A6298", "#37A6B8", "#182632", "#6B7A86", "#EEF3F7", "Arial",
),
"executive-charcoal": _theme(
"executive-charcoal", "Executive Charcoal", "dashboard", "Business",
"Anthrazit, Silber und Signalblau fuer technische Reports.",
"#252B31", "#48525B", "#4FA3D1", "#20272D", "#727C84", "#F0F2F3", "Arial",
),
"executive-burgundy": _theme(
"executive-burgundy", "Executive Burgundy", "dashboard", "Business",
"Zurueckhaltendes Bordeaux mit warmem Kupferakzent.",
"#662E3A", "#8B4654", "#C08B5C", "#2E2527", "#7D7375", "#F5F0EF", "Arial",
),
"ocean-breeze": _theme(
"ocean-breeze", "Ocean Breeze", "sidebar", "Sidebar",
"Breite Seitenleiste, maritime Blautoene und frischer Aqua-Akzent.",
"#075B6C", "#18859A", "#58C6C7", "#17353B", "#69858A", "#EDF8F8", "Arial",
),
"forest-lodge": _theme(
"forest-lodge", "Forest Lodge", "sidebar", "Sidebar",
"Tannengruen, Moos und Holzton fuer Ferien- und Naturmarken.",
"#284E3C", "#47715A", "#B78B55", "#243129", "#728079", "#F1F4EF", "Georgia",
),
"sunset-coral": _theme(
"sunset-coral", "Sunset Coral", "sidebar", "Sidebar",
"Warme Koralle mit tiefem Pflaumenton und freundlicher Flaechenwirkung.",
"#A9474E", "#D06B62", "#F0B66D", "#382B30", "#82747A", "#FBF1ED", "Arial",
),
"editorial-ivory": _theme(
"editorial-ivory", "Editorial Ivory", "editorial", "Editorial",
"Magazinartige Serifengestaltung auf warmem Elfenbein.",
"#33312E", "#6D655C", "#A77D45", "#282725", "#77716A", "#F7F2E8", "Georgia",
),
"editorial-ink": _theme(
"editorial-ink", "Editorial Ink", "editorial", "Editorial",
"Schwarz, Tinte und klares Blau fuer einen publizistischen Look.",
"#17222D", "#2E485F", "#3E88A8", "#171D22", "#68747E", "#F0F3F5", "Georgia",
),
"editorial-rose": _theme(
"editorial-rose", "Editorial Rose", "editorial", "Editorial",
"Staubiges Rosa und dunkles Aubergine mit hochwertiger Anmutung.",
"#5E3548", "#8A576B", "#D59AA7", "#33272C", "#7C6E74", "#F8EFF1", "Georgia",
),
"magazine-cobalt": _theme(
"magazine-cobalt", "Magazine Cobalt", "magazine", "Magazin",
"Kräftiges Kobaltblau, grosse Typografie und asymmetrische Module.",
"#1749A3", "#2F72D6", "#F3C342", "#172438", "#66758A", "#EEF3FA", "Arial",
),
"magazine-citrus": _theme(
"magazine-citrus", "Magazine Citrus", "magazine", "Magazin",
"Dunkles Gruen mit Zitrusgelb fuer einen lebendigen Auftritt.",
"#245443", "#3E8063", "#E6C84A", "#20312A", "#6E7C75", "#F2F6E9", "Arial",
),
"magazine-plum": _theme(
"magazine-plum", "Magazine Plum", "magazine", "Magazin",
"Pflaume, Violett und Apricot fuer kreative Kundenreports.",
"#5A2D67", "#814696", "#E8A875", "#302536", "#796D7E", "#F7F0F8", "Arial",
),
"ledger-green": _theme(
"ledger-green", "Ledger Green", "ledger", "Tabellarisch",
"Praezises Tabellenlayout in klassischem Buchhaltungsgruen.",
"#275F4B", "#467A66", "#A4864D", "#26322D", "#748078", "#F1F4F0", "Courier New",
),
"ledger-blue": _theme(
"ledger-blue", "Ledger Blue", "ledger", "Tabellarisch",
"Dichtes Zahlenlayout in Blau und Schiefergrau.",
"#294D73", "#4B7198", "#8AAAC2", "#25313C", "#71808D", "#EFF3F6", "Courier New",
),
"ledger-sepia": _theme(
"ledger-sepia", "Ledger Sepia", "ledger", "Tabellarisch",
"Warmer Papiercharakter mit Sepia und Rostakzent.",
"#664B38", "#8A6A51", "#B5784E", "#382E28", "#7F746C", "#F6F0E7", "Courier New",
),
"split-teal": _theme(
"split-teal", "Split Teal", "split", "Split",
"Geteilte Titelflaeche mit Petrol und hellem Tuerkis.",
"#095B61", "#2E8E8B", "#9ED8CB", "#183334", "#698281", "#EEF7F5", "Arial",
),
"split-violet": _theme(
"split-violet", "Split Violet", "split", "Split",
"Vertikal geteiltes Layout in Violett und Lavendel.",
"#513A75", "#7557A0", "#BFA8E2", "#302A38", "#787080", "#F4F0FA", "Arial",
),
"split-terracotta": _theme(
"split-terracotta", "Split Terracotta", "split", "Split",
"Terrakotta, Lehm und Sand fuer warme Markenwelten.",
"#8B4938", "#B26950", "#E3B68F", "#3B2D29", "#84756F", "#FAF1EA", "Georgia",
),
"poster-red": _theme(
"poster-red", "Poster Red", "poster", "Statement",
"Plakatives Rot-Schwarz-Layout mit sehr grossen Kennzahlen.",
"#B3202A", "#D53B42", "#F2B84B", "#1F1D1D", "#6D6767", "#F7F2F0", "Arial",
),
"poster-yellow": _theme(
"poster-yellow", "Poster Yellow", "poster", "Statement",
"Schwarz und Signalgelb fuer maximale visuelle Klarheit.",
"#171717", "#3B3B3B", "#F1C928", "#181818", "#707070", "#F7F5E8", "Arial",
),
"poster-mono": _theme(
"poster-mono", "Poster Mono", "poster", "Statement",
"Konsequentes Schwarz-Weiss-Design mit typografischem Fokus.",
"#111111", "#444444", "#A3A3A3", "#171717", "#737373", "#F3F3F3", "Arial",
),
"soft-lavender": _theme(
"soft-lavender", "Soft Lavender", "modern", "Soft",
"Sanftes Kartenlayout in Lavendel, Flieder und warmem Rosa.",
"#67558B", "#8B76B3", "#D5A6B8", "#302B38", "#7D7485", "#F5F0F8", "Arial",
),
"midnight-gold": _theme(
"midnight-gold", "Midnight Gold", "modern", "Premium",
"Tiefes Nachtblau mit Goldakzent fuer einen hochwertigen Auftritt.",
"#172A42", "#284967", "#D2A64C", "#1B2733", "#6F7C87", "#EFF2F4", "Georgia",
),
}
def get_theme(theme_id: str) -> dict[str, Any]:
try:
return deepcopy(THEMES[theme_id])
except KeyError as exc:
raise ValueError(f"Unknown theme: {theme_id}") from exc
def public_theme_catalog() -> list[dict[str, Any]]:
return [deepcopy(THEMES[key]) for key in sorted(THEMES)]
+50
View File
@@ -0,0 +1,50 @@
from __future__ import annotations
import json
from pathlib import Path
from typing import Any
from jsonschema import Draft202012Validator
BASE_DIR = Path(__file__).resolve().parent
SCHEMA_DIR = BASE_DIR / "schemas"
def load_schema(name: str) -> dict[str, Any]:
path = SCHEMA_DIR / name
with path.open("r", encoding="utf-8") as handle:
return json.load(handle)
REPORT_SCHEMA = load_schema("report-payload.schema.json")
CLAUDE_SCHEMA = load_schema("claude-output.schema.json")
REPORT_VALIDATOR = Draft202012Validator(REPORT_SCHEMA)
CLAUDE_VALIDATOR = Draft202012Validator(CLAUDE_SCHEMA)
def _format_path(path_parts) -> str:
path = "$"
for part in path_parts:
if isinstance(part, int):
path += f"[{part}]"
else:
path += f".{part}"
return path
def collect_errors(payload: Any, validator: Draft202012Validator) -> list[dict[str, str]]:
errors = []
for error in sorted(validator.iter_errors(payload), key=lambda item: list(item.path)):
errors.append({
"path": _format_path(error.absolute_path),
"message": error.message,
})
return errors
def validate_report(payload: Any) -> list[dict[str, str]]:
return collect_errors(payload, REPORT_VALIDATOR)
def validate_claude_output(payload: Any) -> list[dict[str, str]]:
return collect_errors(payload, CLAUDE_VALIDATOR)
+5
View File
@@ -0,0 +1,5 @@
fastapi>=0.115,<1
uvicorn[standard]>=0.34,<1
Jinja2>=3.1,<4
jsonschema>=4.23,<5
requests>=2.32,<3
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import json
import subprocess
import sys
import tempfile
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "renderer"))
from app.renderer import render_documents
from app.validation import validate_report
def main() -> int:
parser = argparse.ArgumentParser(description="Render a report with a locally installed Chromium.")
parser.add_argument("input", type=Path)
parser.add_argument("output", type=Path)
parser.add_argument("--chromium", default="chromium")
args = parser.parse_args()
payload = json.loads(args.input.read_text(encoding="utf-8"))
errors = validate_report(payload)
if errors:
print(json.dumps(errors, ensure_ascii=False, indent=2), file=sys.stderr)
return 2
html, _ = render_documents(payload)
args.output.parent.mkdir(parents=True, exist_ok=True)
with tempfile.TemporaryDirectory() as tmp:
html_path = Path(tmp) / "index.html"
html_path.write_text(html, encoding="utf-8")
subprocess.run([
args.chromium,
"--headless",
"--no-sandbox",
"--disable-gpu",
"--disable-dev-shm-usage",
f"--print-to-pdf={args.output.resolve()}",
"--print-to-pdf-no-header",
html_path.resolve().as_uri(),
], check=True)
print(args.output)
return 0
if __name__ == "__main__":
raise SystemExit(main())
+163
View File
@@ -0,0 +1,163 @@
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import base64
import json
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "renderer"))
from app.renderer import render_documents
from app.theme_catalog import THEMES
from app.validation import validate_report
def command(name: str, override: str | None = None) -> str:
value = override or shutil.which(name)
if not value:
raise SystemExit(f"Benötigtes Programm nicht gefunden: {name}")
return value
def print_pdf(engine: str, executable: str, html_path: Path, pdf_path: Path) -> None:
if engine == "weasyprint":
subprocess.run(
[executable, str(html_path), str(pdf_path)],
check=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
timeout=90,
)
return
subprocess.run(
[
executable,
"--headless=new",
"--no-sandbox",
"--disable-gpu",
"--disable-dev-shm-usage",
"--disable-background-networking",
"--disable-extensions",
"--no-first-run",
f"--user-data-dir={pdf_path.parent / ('.chrome-' + pdf_path.stem)}",
f"--print-to-pdf={pdf_path.resolve()}",
"--no-pdf-header-footer",
html_path.resolve().as_uri(),
],
check=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
timeout=90,
)
def first_page_png(pdftoppm: str, pdf_path: Path, png_path: Path) -> None:
prefix = png_path.with_suffix("")
subprocess.run(
[pdftoppm, "-f", "1", "-singlefile", "-scale-to", "760", "-png", str(pdf_path), str(prefix)],
check=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
def make_gallery(cards: list[dict[str, str]], output: Path) -> None:
blocks = []
for card in cards:
image_data = base64.b64encode(Path(card["image"]).read_bytes()).decode("ascii")
swatches = "".join(f'<span style="background:{color}"></span>' for color in card["colors"].split(","))
blocks.append(
f'''<article class="card">
<div class="preview"><img src="data:image/png;base64,{image_data}" alt="{card['name']}"></div>
<div class="meta"><div><div class="category">{card['category']} · {card['layout']}</div><h2>{card['name']}</h2><code>{card['id']}</code></div><div class="swatches">{swatches}</div></div>
<p>{card['description']}</p>
</article>'''
)
output.write_text(
'''<!doctype html><html lang="de"><head><meta charset="utf-8"><title>Monthly Report Kit - Theme-Katalog</title><style>
@page{size:A4 landscape;margin:10mm 11mm 13mm}*{box-sizing:border-box}html{-webkit-print-color-adjust:exact;print-color-adjust:exact}body{margin:0;font-family:Arial,sans-serif;color:#202a30;background:#fff}.title{display:flex;justify-content:space-between;align-items:flex-end;border-bottom:2px solid #172a42;padding-bottom:4mm;margin-bottom:5mm}.title h1{font-size:24pt;margin:0}.title p{margin:0;color:#667680}.grid{display:grid;grid-template-columns:1fr 1fr;gap:5mm}.card{display:grid;grid-template-columns:66mm 1fr;grid-template-rows:auto 1fr;column-gap:5mm;border:1px solid #d8dfe3;padding:3.5mm;min-height:83mm;break-inside:avoid}.preview{grid-row:1/3;background:#eef2f4;display:flex;align-items:flex-start;justify-content:center;overflow:hidden;height:76mm}.preview img{width:100%;height:auto}.meta{display:flex;justify-content:space-between;gap:3mm}.category{font-size:6.5pt;text-transform:uppercase;letter-spacing:.8px;color:#718087;font-weight:700}.meta h2{font-size:13pt;margin:1mm 0}.meta code{font-size:7pt;background:#f1f4f5;padding:1mm 1.5mm}.card p{font-size:8pt;line-height:1.4;color:#56656d;margin:3mm 0 0}.swatches{display:flex;gap:1mm}.swatches span{width:5mm;height:5mm;border:1px solid #00000015}.footer{margin-top:4mm;font-size:7pt;color:#718087;display:flex;justify-content:space-between}
</style></head><body><header class="title"><div><h1>Monthly Report Kit</h1><p>28 Designs in 10 Layoutfamilien</p></div><p>Auswahl über <code>design.theme</code></p></header><main class="grid">'''
+ "".join(blocks)
+ '''</main><footer class="footer"><span>Modern und Classic unterstützen standardmäßig eigene Kundenfarben.</span><span>Bei allen benannten Varianten: palette_mode = theme oder custom</span></footer></body></html>''',
encoding="utf-8",
)
def main() -> int:
parser = argparse.ArgumentParser(description="Rendert alle Themes und erzeugt einen PDF-Theme-Katalog.")
parser.add_argument("--input", type=Path, default=ROOT / "examples" / "sample-report.json")
parser.add_argument("--output-dir", type=Path, default=ROOT / "output" / "theme-catalog")
parser.add_argument("--engine", choices=["auto", "chromium", "weasyprint"], default="auto")
parser.add_argument("--chromium", default=None)
parser.add_argument("--keep-theme-pdfs", action="store_true")
parser.add_argument("--themes", nargs="*", default=None, help="Optional: nur diese Theme-IDs rendern")
args = parser.parse_args()
if args.engine == "weasyprint" or (args.engine == "auto" and shutil.which("weasyprint")):
engine = "weasyprint"
renderer = command("weasyprint")
else:
engine = "chromium"
renderer = command("chromium", args.chromium)
pdftoppm = command("pdftoppm")
payload = json.loads(args.input.read_text(encoding="utf-8"))
errors = validate_report(payload)
if errors:
print(json.dumps(errors, ensure_ascii=False, indent=2), file=sys.stderr)
return 2
args.output_dir.mkdir(parents=True, exist_ok=True)
preview_dir = args.output_dir / "previews"
preview_dir.mkdir(exist_ok=True)
pdf_dir = args.output_dir / "pdfs"
pdf_dir.mkdir(exist_ok=True)
cards: list[dict[str, str]] = []
selected = args.themes or list(THEMES)
unknown = sorted(set(selected) - set(THEMES))
if unknown:
raise SystemExit(f"Unbekannte Themes: {', '.join(unknown)}")
for theme_id in selected:
theme = THEMES[theme_id]
payload["design"]["theme"] = theme_id
payload["design"].pop("palette_mode", None)
html, _ = render_documents(payload)
html_path = args.output_dir / f"{theme_id}.html"
pdf_path = pdf_dir / f"{theme_id}.pdf"
png_path = preview_dir / f"{theme_id}.png"
html_path.write_text(html, encoding="utf-8")
print_pdf(engine, renderer, html_path, pdf_path)
first_page_png(pdftoppm, pdf_path, png_path)
palette = theme["palette"]
cards.append({
"id": theme_id,
"name": theme["name"],
"layout": theme["layout"],
"category": theme["category"],
"description": theme["description"],
"image": str(png_path),
"colors": ",".join([palette["primary_color"], palette["secondary_color"], palette["accent_color"], palette["surface_color"]]),
})
print(f"{theme_id}: OK")
if set(selected) == set(THEMES):
gallery_html = args.output_dir / "theme-gallery.html"
gallery_pdf = args.output_dir / "theme-gallery.pdf"
make_gallery(cards, gallery_html)
print_pdf(engine, renderer, gallery_html, gallery_pdf)
print(gallery_pdf)
if not args.keep_theme_pdfs and pdf_dir.exists():
shutil.rmtree(pdf_dir)
return 0
if __name__ == "__main__":
raise SystemExit(main())
+5
View File
@@ -0,0 +1,5 @@
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "renderer"))
+34
View File
@@ -0,0 +1,34 @@
import json
from pathlib import Path
from app.renderer import render_documents
from app.theme_catalog import THEMES
ROOT = Path(__file__).resolve().parents[1]
def test_html_contains_customer_and_period():
payload = json.loads((ROOT / "examples" / "sample-report.json").read_text(encoding="utf-8"))
html, footer = render_documents(payload)
assert payload["customer"]["name"] in html
assert payload["report"]["period"]["label"] in html
assert "pageNumber" in footer
def test_classic_theme_renders():
payload = json.loads((ROOT / "examples" / "sample-report.json").read_text(encoding="utf-8"))
payload["design"]["theme"] = "classic"
html, _ = render_documents(payload)
assert "Monatsverlauf" in html
def test_all_registered_themes_render():
base = json.loads((ROOT / "examples" / "sample-report.json").read_text(encoding="utf-8"))
for theme_id, theme in THEMES.items():
payload = json.loads(json.dumps(base))
payload["design"]["theme"] = theme_id
payload["design"].pop("palette_mode", None)
html, footer = render_documents(payload)
assert payload["customer"]["name"] in html, theme_id
assert theme["name"] in html or payload["report"]["period"]["label"] in html, theme_id
assert "pageNumber" in footer, theme_id
+23
View File
@@ -0,0 +1,23 @@
import json
from pathlib import Path
from app.validation import validate_claude_output, validate_report
ROOT = Path(__file__).resolve().parents[1]
def test_sample_report_is_valid():
payload = json.loads((ROOT / "examples" / "sample-report.json").read_text(encoding="utf-8"))
assert validate_report(payload) == []
def test_sample_claude_output_is_valid():
payload = json.loads((ROOT / "examples" / "sample-claude-output.json").read_text(encoding="utf-8"))
assert validate_claude_output(payload) == []
def test_unknown_design_property_is_rejected():
payload = json.loads((ROOT / "examples" / "sample-report.json").read_text(encoding="utf-8"))
payload["design"]["surprise_layout"] = True
errors = validate_report(payload)
assert errors