"""
LinkedIn-Thumbnail-Overlay-Renderer (16:9, 1536×1024).

Bundle-Variante des Vault-Renderers. Nimmt ein Basisbild (KI-generiertes
Foto, 1536×1024) und legt eine Headline gemäß einem von 27 Warm-Navigator-
Templates obendrauf. Schriften werden via Headless-Chromium (Playwright)
gerendert.

Stefan-Lock-Generalisierung (v0.15.0 Wave G Foundation):
- Hartcodierte SVG-Tspan-Logo-Zeilen entfernt. `logo_inline` ist jetzt
  config-getrieben: optional Logo-Pfad-Argument. Ohne Pfad: leerer String.
  Mit Pfad: SVG-Inhalt der Datei wird eingebettet.
- Default-Logo-Pfad kommt vom Aufrufer (render.py CLI: `--logo-path PATH`),
  Fallback auf `_lib/designsystem/assets/logo-placeholder.svg`.
- `logo_inline`-Signatur bleibt rückwärtskompatibel zu compose_v.py.

CLI (für direkten Aufruf):
    python compose.py --photo PFAD --template T01 --headline "..." \
        [--eyebrow "..."] [--logo] [--logo-path PATH] [Override-Flags] --output PFAD

Override-Flags (alle optional, Standard = Template wie designed):
    --headline-size FLOAT    Schriftgröße der Headline in px
    --headline-x FLOAT       Headline-Verschiebung horizontal in px
    --headline-y FLOAT       Headline-Verschiebung vertikal in px
    --eyebrow-size FLOAT     Schriftgröße des Eyebrow-Labels in px
    --eyebrow-x FLOAT        Eyebrow-Verschiebung horizontal
    --eyebrow-y FLOAT        Eyebrow-Verschiebung vertikal
    --logo-scale FLOAT       Logo-Skalierungsfaktor (1.0 = Standard)
    --logo-x FLOAT           Logo-Verschiebung horizontal
    --logo-y FLOAT           Logo-Verschiebung vertikal
"""

from __future__ import annotations

import argparse
import base64
import html
import mimetypes
import re
import sys
import tempfile
from pathlib import Path

WIDTH, HEIGHT = 1536, 1024

# --- Warm-Navigator-Tokens ---------------------------------------------

C_DEEP_SEA = "#18273A"
C_OCEAN = "#2D4A5E"
C_TEAL = "#0D9488"
C_GOLD = "#D4A853"
C_CREAM = "#F8F6F2"

FONT_HEAD = "'Mona Sans', 'Inter', system-ui, sans-serif"
FONT_BODY = "'Inter', -apple-system, 'Segoe UI', Roboto, Arial, sans-serif"
FONT_MONO = "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace"

# --- gemeinsame Bausteine ----------------------------------------------

# Modul-globaler Logo-Pfad. Wird von render.py via `set_logo_path()`
# vor dem Render-Aufruf gesetzt. Default None bedeutet: kein Logo wird
# eingebettet, auch wenn ein Template `logo=True` anfordert.
_LOGO_PATH: Path | None = None


def set_logo_path(path: Path | None) -> None:
    """Setzt den Pfad zur Logo-SVG-Datei, die `logo_inline` einbettet.

    Wird von render.py vor dem Render-Aufruf gesetzt. None deaktiviert
    die Logo-Einbettung komplett.
    """
    global _LOGO_PATH
    _LOGO_PATH = path


def _read_logo_svg(path: Path) -> str:
    """Liest eine SVG-Datei und gibt den Inhalt als String zurück.

    Fehler werden propagiert (keine Try-Except-Fallbacks, Pflicht-Satz 6).
    """
    return path.read_text(encoding="utf-8")


def logo_inline(dark: bool = False, scale: float = 1.0) -> str:
    """Logo wird in einen .tn-logo-Wrapper gesetzt, damit Override per CSS möglich ist.

    Stefan-Lock-frei: SVG-Inhalt kommt aus der via `set_logo_path()` gesetzten
    Datei. Wenn kein Pfad gesetzt oder die Datei fehlt: leerer String (kein
    Logo wird gerendert). Die Argumente `dark` und `scale` werden für
    rückwärtskompatible Signatur akzeptiert; das Asset muss die Farbvarianten
    selbst tragen (z.B. via currentColor oder zwei SVG-Files vom Anwender).

    Anwender-Override:
      render.py --logo-path PATH  → set_logo_path(PATH)
      Fallback: assets/logo-placeholder.svg (vom Bundle mitgeliefert)
    """
    if _LOGO_PATH is None or not _LOGO_PATH.is_file():
        return ""
    svg = _read_logo_svg(_LOGO_PATH)
    style = (
        f"display:inline-block;transform-origin:top left;"
        f"transform:scale({scale});"
    )
    if dark:
        # Dark-Modus: heller Filter, falls das SVG nicht selbst zwei Varianten trägt.
        style += "filter:brightness(0) invert(0.94);"
    return f'<div class="tn-logo" style="{style}">{svg}</div>'


def gold_dot(size: int = 11, extra: str = "") -> str:
    return (
        f'<span style="display:inline-block;width:{size}px;height:{size}px;'
        f'border-radius:50%;background:{C_GOLD};{extra}"></span>'
    )


def accent_line(width: int = 140, height: int = 3, extra: str = "") -> str:
    return (
        f'<div style="width:{width}px;height:{height}px;border-radius:2px;'
        f"background:linear-gradient(90deg,{C_TEAL} 0%,{C_GOLD} 65%,transparent 100%);"
        f'{extra}"></div>'
    )


def eyebrow_span(text: str, color: str, font_size: int = 15,
                 letter_spacing: float = 2.8, font_weight: int = 600) -> str:
    """Eyebrow-Span mit Klasse tn-eyebrow für Overrides."""
    return (
        f'<span class="tn-eyebrow" style="font-family:{FONT_BODY};font-size:{font_size}px;'
        f'font-weight:{font_weight};letter-spacing:{letter_spacing}px;'
        f'text-transform:uppercase;color:{color};">{text}</span>'
    )


def headline_h1(text: str, **style) -> str:
    """Headline mit Klasse tn-headline. style-Args werden als CSS serialisiert."""
    css = ";".join(f"{k.replace('_','-')}:{v}" for k, v in style.items())
    return f'<h1 class="tn-headline" style="margin:0;{css};">{text}</h1>'


def _photo(photo_url: str) -> str:
    return (
        f'<img src="{photo_url}" '
        f'style="position:absolute;inset:0;width:100%;height:100%;'
        f'object-fit:cover;object-position:center;display:block;">'
    )


def _scrim(gradient: str) -> str:
    return f'<div style="position:absolute;inset:0;background:{gradient};"></div>'


# --- Templates T01–T16 (16 Original-Templates) -------------------------

def t01(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "Insight"
    logo_block = (f'<div style="position:absolute;top:56px;right:64px;">{logo_inline(dark=True)}</div>'
                  if logo else "")
    return f"""
    {_photo(photo)}
    {_scrim("linear-gradient(120deg,rgba(24,39,58,0.78) 0%,rgba(24,39,58,0.38) 35%,rgba(24,39,58,0) 60%)")}
    {logo_block}
    <div style="position:absolute;left:80px;bottom:80px;max-width:920px;color:{C_CREAM};">
      <div style="display:flex;align-items:center;gap:14px;margin-bottom:22px;">
        {gold_dot(11)}
        {eyebrow_span(eyebrow, C_GOLD, 17)}
      </div>
      {headline_h1(headline, font_size="72px", font_weight=600, line_height=1.08, letter_spacing="-1.6px", text_wrap="balance")}
      {accent_line(140, 3, "margin-top:26px;")}
    </div>
    """


def t02(photo, headline, eyebrow, logo):
    logo_block = (f'<div style="position:absolute;top:56px;right:64px;">{logo_inline(dark=True)}</div>'
                  if logo else "")
    return f"""
    {_photo(photo)}
    <div style="position:absolute;left:0;right:0;bottom:0;background:{C_DEEP_SEA};
      padding:44px 80px 48px;display:flex;align-items:center;justify-content:space-between;gap:48px;
      border-top:3px solid transparent;
      background-image:linear-gradient({C_DEEP_SEA},{C_DEEP_SEA}),linear-gradient(90deg,{C_TEAL} 0%,{C_GOLD} 60%,transparent 100%);
      background-origin:padding-box,border-box;background-clip:padding-box,border-box;">
      {headline_h1(headline, font_size="56px", font_weight=600, line_height=1.12, letter_spacing="-1px", color=C_CREAM, max_width="1100px", text_wrap="balance")}
      {gold_dot(12)}
    </div>
    {logo_block}
    """


def t03(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "Im Gespräch"
    logo_block = logo_inline(scale=1.1) if logo else ""
    return f"""
    <div style="position:absolute;inset:0;display:grid;grid-template-columns:920px 1fr;background:{C_CREAM};">
      <div style="position:relative;overflow:hidden;">
        <img src="{photo}" style="width:100%;height:100%;object-fit:cover;display:block;">
      </div>
      <div style="padding:80px 64px;display:flex;flex-direction:column;justify-content:space-between;color:{C_DEEP_SEA};">
        <div style="display:flex;align-items:center;gap:12px;">
          {gold_dot(11)}
          {eyebrow_span(eyebrow, C_TEAL, 15)}
        </div>
        <div>
          {accent_line(72, 3, "margin-bottom:24px;")}
          {headline_h1(headline, font_size="60px", font_weight=600, line_height=1.08, letter_spacing="-1.3px", text_wrap="balance")}
        </div>
        <div>{logo_block}</div>
      </div>
    </div>
    """


def t04(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "Standpunkt"
    logo_block = (f'<div style="margin-top:18px;">{logo_inline(scale=0.9)}</div>' if logo else "")
    return f"""
    {_photo(photo)}
    <div style="position:absolute;left:80px;top:80px;bottom:80px;width:560px;background:{C_CREAM};
      padding:48px 44px;display:flex;flex-direction:column;justify-content:space-between;
      box-shadow:0 16px 40px rgba(24,39,58,0.18);color:{C_DEEP_SEA};">
      <div style="display:flex;align-items:center;gap:12px;">
        {gold_dot(11)}
        {eyebrow_span(eyebrow, "rgba(24,39,58,0.7)", 15)}
      </div>
      <div>
        {headline_h1(headline, font_size="64px", font_weight=700, line_height=1.05, letter_spacing="-1.4px")}
      </div>
      <div>
        {accent_line(100, 3)}
        {logo_block}
      </div>
    </div>
    """


# T05 wurde 2026-04-28 entfernt (Critique-Refactor):
# zentriertes Bottom-Lockup ohne klaren Use-Case verletzte das Linksbündig-Prinzip.
# Für zentrierte Statements stattdessen T16 (mit Underline-Akzent) oder T19 (Zitat-Format)
# nutzen.


def t06(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "Praxis"
    logo_block = logo_inline(dark=True, scale=1.1) if logo else ""
    return f"""
    {_photo(photo)}
    {_scrim("linear-gradient(120deg,rgba(24,39,58,0.72) 0%,rgba(24,39,58,0.3) 38%,rgba(24,39,58,0) 65%)")}
    <div style="position:absolute;top:56px;right:64px;display:flex;align-items:center;gap:14px;">
      <span style="font-family:{FONT_MONO};font-size:14px;color:rgba(248,246,242,0.85);letter-spacing:1.5px;text-transform:uppercase;">Folge · Reihe</span>
      {gold_dot(9)}
    </div>
    <div style="position:absolute;left:80px;bottom:80px;max-width:920px;color:{C_CREAM};">
      <div style="display:flex;align-items:center;gap:12px;margin-bottom:22px;">
        <span style="width:26px;height:1.5px;background:{C_GOLD};"></span>
        {eyebrow_span(eyebrow, C_GOLD, 15, 3.2)}
      </div>
      {headline_h1(headline, font_size="68px", font_weight=600, line_height=1.08, letter_spacing="-1.5px", text_wrap="balance")}
      <div style="display:flex;align-items:center;gap:26px;margin-top:28px;">
        {accent_line(100, 3)}
        {logo_block}
      </div>
    </div>
    """


def t07(photo, headline, eyebrow, logo):
    """Reportage-Layout für Datenposts (Zahl + Kontext gemeinsam, nicht isoliert).
    2026-04-28 refactored: Hero-Metric-Slop-Pattern (240px-Zahl alleine oben) ersetzt durch
    integriertes Bottom-Lockup, Zahl in 140px gemeinsam mit Headline und Eyebrow."""
    eyebrow = eyebrow or "Zahl der Woche"
    m = re.match(r"\s*(\d{1,3})\s*([%€$x]?)\s*(.*)", headline)
    if m:
        big_num, big_unit, rest = m.group(1), m.group(2), m.group(3).lstrip(" ,.;:—-")
    else:
        big_num, big_unit, rest = "73", "%", headline
    logo_block = (f'<div style="position:absolute;top:56px;right:64px;">{logo_inline(dark=True, scale=0.9)}</div>'
                  if logo else "")
    return f"""
    {_photo(photo)}
    {_scrim("linear-gradient(180deg,rgba(24,39,58,0.25) 0%,rgba(24,39,58,0.1) 35%,rgba(24,39,58,0.85) 100%)")}
    {logo_block}
    <div style="position:absolute;top:80px;left:80px;display:flex;align-items:center;gap:12px;color:{C_CREAM};">
      {gold_dot(10)}
      <span class="tn-eyebrow" style="font-family:{FONT_MONO};font-size:14px;color:rgba(248,246,242,0.85);letter-spacing:1.8px;text-transform:uppercase;">{eyebrow}</span>
    </div>
    <div style="position:absolute;left:80px;right:80px;bottom:80px;color:{C_CREAM};">
      <div style="display:flex;align-items:baseline;gap:12px;margin-bottom:18px;">
        <span style="font-size:140px;font-weight:700;line-height:0.95;letter-spacing:-5px;">{big_num}<span style="color:{C_TEAL};font-size:96px;letter-spacing:-3px;">{big_unit or "%"}</span></span>
      </div>
      {headline_h1(rest or headline, font_size="48px", font_weight=600, line_height=1.15, letter_spacing="-0.8px", max_width="1100px", text_wrap="balance")}
      {accent_line(120, 3, "margin-top:22px;")}
    </div>
    """


def t08(photo, headline, eyebrow, logo):
    """Frage-Format zentriert, für Statements oder rhetorische Fragen.
    2026-04-28 refactored: Backdrop-Blur (Glassmorphism) auf der Eyebrow-Pill durch solide
    Background-Opacity ersetzt (Impeccable-Ban: Glassmorphism als Default)."""
    eyebrow = eyebrow or "Frage an die Runde"
    logo_block = (f'<div style="position:absolute;left:0;right:0;bottom:64px;display:flex;justify-content:center;">'
                  f'{logo_inline(dark=True, scale=1.05)}</div>' if logo else "")
    return f"""
    {_photo(photo)}
    {_scrim("radial-gradient(ellipse at center,rgba(24,39,58,0.35) 0%,rgba(24,39,58,0.1) 60%,rgba(24,39,58,0.55) 100%)")}
    <div style="position:absolute;top:64px;left:0;right:0;display:flex;justify-content:center;">
      <span class="tn-eyebrow" style="display:inline-flex;align-items:center;gap:12px;padding:10px 22px;
        border:1px solid rgba(248,246,242,0.7);border-radius:999px;font-family:{FONT_BODY};
        font-size:15px;font-weight:600;letter-spacing:2.8px;text-transform:uppercase;color:{C_CREAM};
        background:rgba(24,39,58,0.7);">
        {gold_dot(9)} {eyebrow}
      </span>
    </div>
    <div style="position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);text-align:center;color:{C_CREAM};padding:0 140px;">
      {headline_h1(headline, font_size="74px", font_weight=600, line_height=1.08, letter_spacing="-1.7px", text_wrap="balance", max_width="1180px", margin_inline="auto")}
      {accent_line(160, 3, "margin:30px auto 0;")}
    </div>
    {logo_block}
    """


def t09(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "Leadership · Essay"
    logo_block = logo_inline(scale=1.1) if logo else ""
    return f"""
    <div style="position:absolute;inset:0;display:grid;grid-template-columns:1fr 980px;background:{C_CREAM};">
      <div style="padding:80px 56px 80px 80px;display:flex;flex-direction:column;justify-content:space-between;color:{C_DEEP_SEA};">
        <div style="display:flex;flex-direction:column;gap:14px;">
          {eyebrow_span(eyebrow, C_TEAL, 15, 3)}
          {accent_line(72, 3)}
        </div>
        <div>
          {headline_h1(headline, font_size="54px", font_weight=700, line_height=1.1, letter_spacing="-1.2px", text_wrap="balance")}
        </div>
        <div>{logo_block}</div>
      </div>
      <div style="position:relative;overflow:hidden;">
        <img src="{photo}" style="width:100%;height:100%;object-fit:cover;display:block;">
      </div>
    </div>
    """


def t10(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "Notiz vom Navigator"
    logo_block = (f'<div style="position:absolute;right:80px;bottom:80px;">{logo_inline(dark=True, scale=0.9)}</div>'
                  if logo else "")
    return f"""
    {_photo(photo)}
    {_scrim("linear-gradient(180deg,rgba(24,39,58,0.5) 0%,rgba(24,39,58,0) 25%,rgba(24,39,58,0) 65%,rgba(24,39,58,0.78) 100%)")}
    <div style="position:absolute;top:56px;left:80px;display:flex;align-items:center;gap:12px;color:{C_CREAM};">
      {gold_dot(9)}
      {eyebrow_span(eyebrow, C_CREAM, 15, 3)}
    </div>
    <div style="position:absolute;left:80px;right:80px;bottom:80px;color:{C_CREAM};">
      {headline_h1(headline, font_size="72px", font_weight=600, line_height=1.06, letter_spacing="-1.6px", max_width="1140px", text_wrap="balance")}
      {accent_line(140, 3, "margin-top:26px;")}
    </div>
    {logo_block}
    """


def t11(photo, headline, eyebrow, logo):
    """Spiegelvariante mit Headline rechtsbündig. NUR sinnvoll, wenn das Foto eine Person
    zeigt, die nach links blickt. Dann führt das Layout das Auge in die Headline.
    Bei zentralen oder nach-rechts-blickenden Motiven stattdessen T01, T20 oder T14 nutzen.
    Brand-Regel: Linksbündig ist Default, rechtsbündig nur wenn Layout es zwingend verlangt."""
    eyebrow = eyebrow or "Mittelstand"
    logo_block = (f'<div style="position:absolute;top:56px;left:80px;">{logo_inline(dark=True, scale=1.05)}</div>'
                  if logo else "")
    return f"""
    {_photo(photo)}
    {_scrim("linear-gradient(240deg,rgba(24,39,58,0.78) 0%,rgba(24,39,58,0.35) 35%,rgba(24,39,58,0) 60%)")}
    {logo_block}
    <div class="tn-block" style="position:absolute;right:80px;bottom:80px;max-width:880px;color:{C_CREAM};text-align:right;">
      <div style="display:flex;justify-content:flex-end;align-items:center;gap:12px;margin-bottom:22px;">
        {eyebrow_span(eyebrow, C_GOLD, 15)}
        {gold_dot(11)}
      </div>
      {headline_h1(headline, font_size="70px", font_weight=600, line_height=1.08, letter_spacing="-1.6px", text_wrap="balance")}
      {accent_line(140, 3, "margin-top:26px;margin-left:auto;")}
    </div>
    """


def t12(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "Essay"
    logo_block = (f'<div style="position:absolute;right:64px;bottom:56px;">{logo_inline(dark=True, scale=0.9)}</div>'
                  if logo else "")
    return f"""
    {_photo(photo)}
    <div style="position:absolute;left:0;right:0;top:0;background:{C_CREAM};
      padding:44px 80px 40px;color:{C_DEEP_SEA};">
      <div style="display:flex;align-items:center;gap:12px;margin-bottom:18px;">
        {gold_dot(11)}
        {eyebrow_span(eyebrow, C_TEAL, 15)}
      </div>
      {headline_h1(headline, font_size="60px", font_weight=700, line_height=1.06, letter_spacing="-1.4px", text_wrap="balance", max_width="1280px")}
    </div>
    <div style="position:absolute;left:0;right:0;top:240px;height:3px;
      background:linear-gradient(90deg,{C_TEAL} 0%,{C_GOLD} 50%,transparent 100%);"></div>
    {logo_block}
    """


def t13(photo, headline, eyebrow, logo):
    """Reporting-Layout, Headline links bottom, Eyebrow links top, Logo links unten.
    Vertikaler Akzent-Stripe wurde 2026-04-28 entfernt (Side-Stripe-Border-Verbot, siehe Cards.md)."""
    eyebrow = eyebrow or "Reporting"
    logo_block = logo_inline(dark=True, scale=1.1) if logo else ""
    return f"""
    {_photo(photo)}
    {_scrim("linear-gradient(90deg,rgba(24,39,58,0.85) 0%,rgba(24,39,58,0.35) 38%,rgba(24,39,58,0) 60%)")}
    <div style="position:absolute;left:80px;top:80px;bottom:80px;display:flex;flex-direction:column;
      justify-content:space-between;color:{C_CREAM};max-width:760px;">
      <div style="display:flex;align-items:center;gap:12px;">
        {gold_dot(11)}
        {eyebrow_span(eyebrow, C_GOLD, 15)}
      </div>
      <div>
        {headline_h1(headline, font_size="70px", font_weight=600, line_height=1.08, letter_spacing="-1.6px", text_wrap="balance")}
        {accent_line(120, 3, "margin-top:24px;")}
      </div>
      <div>{logo_block}</div>
    </div>
    """


def t14(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "Strategie"
    logo_block = (f'<div style="position:absolute;top:56px;right:64px;">{logo_inline(dark=True, scale=0.9)}</div>'
                  if logo else "")
    return f"""
    {_photo(photo)}
    {_scrim("linear-gradient(180deg,rgba(24,39,58,0) 30%,rgba(24,39,58,0.4) 60%,rgba(24,39,58,0.92) 100%)")}
    {logo_block}
    <div style="position:absolute;left:80px;right:80px;bottom:80px;color:{C_CREAM};">
      <span class="tn-eyebrow" style="display:inline-flex;align-items:center;gap:12px;font-family:{FONT_BODY};font-size:16px;font-weight:600;letter-spacing:3px;text-transform:uppercase;color:{C_GOLD};margin-bottom:22px;">
        {gold_dot(10)} {eyebrow}
      </span>
      {headline_h1(headline, font_size="78px", font_weight=700, line_height=1.04, letter_spacing="-1.8px", text_wrap="balance", max_width="1240px")}
      {accent_line(160, 3, "margin-top:28px;")}
    </div>
    """


def t15(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "Standpunkt"
    logo_block = logo_inline(scale=1.1) if logo else ""
    return f"""
    <div style="position:absolute;inset:0;display:grid;grid-template-columns:720px 1fr;background:{C_CREAM};align-items:center;">
      <div style="padding:80px;">
        <div style="width:560px;height:760px;border-radius:12px;overflow:hidden;box-shadow:0 20px 50px rgba(24,39,58,0.18);">
          <img src="{photo}" style="width:100%;height:100%;object-fit:cover;display:block;">
        </div>
      </div>
      <div style="padding:80px 80px 80px 24px;display:flex;flex-direction:column;justify-content:space-between;height:calc(100% - 160px);color:{C_DEEP_SEA};">
        <div style="display:flex;align-items:center;gap:12px;">
          {gold_dot(11)}
          {eyebrow_span(eyebrow, C_TEAL, 15)}
        </div>
        <div>
          {accent_line(72, 3, "margin-bottom:24px;")}
          {headline_h1(headline, font_size="60px", font_weight=700, line_height=1.05, letter_spacing="-1.4px", text_wrap="balance")}
        </div>
        <div>{logo_block}</div>
      </div>
    </div>
    """


def t16(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "Klartext"
    logo_block = (f'<div style="position:absolute;right:80px;bottom:56px;">{logo_inline(dark=True, scale=0.85)}</div>'
                  if logo else "")
    return f"""
    {_photo(photo)}
    {_scrim("radial-gradient(ellipse at center,rgba(24,39,58,0.55) 0%,rgba(24,39,58,0.25) 50%,rgba(24,39,58,0.7) 100%)")}
    <div style="position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;color:{C_CREAM};padding:0 140px;text-align:center;">
      <span class="tn-eyebrow" style="display:inline-flex;align-items:center;gap:12px;font-family:{FONT_BODY};font-size:15px;font-weight:600;letter-spacing:3.2px;text-transform:uppercase;color:{C_GOLD};margin-bottom:30px;">
        <span style="width:28px;height:1.5px;background:{C_GOLD};"></span>
        {gold_dot(9)} {eyebrow}
        <span style="width:28px;height:1.5px;background:{C_GOLD};"></span>
      </span>
      {headline_h1(headline, font_size="84px", font_weight=700, line_height=1.02, letter_spacing="-2px", text_wrap="balance", max_width="1200px")}
      {accent_line(160, 3, "margin-top:32px;")}
    </div>
    {logo_block}
    """


# --- Templates T17–T30 (14 neue Templates) -----------------------------

def t17(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "Insight"
    logo_block = (f'<div style="position:absolute;top:56px;right:64px;">{logo_inline(dark=True, scale=1.05)}</div>'
                  if logo else "")
    return f"""
    {_photo(photo)}
    <div style="position:absolute;left:0;bottom:0;width:0;height:0;border-style:solid;
      border-width:0 0 560px 980px;border-color:transparent transparent {C_CREAM} transparent;"></div>
    <div style="position:absolute;left:80px;bottom:80px;max-width:760px;color:{C_DEEP_SEA};">
      <div style="display:flex;align-items:center;gap:12px;margin-bottom:18px;">
        {gold_dot(11)}
        {eyebrow_span(eyebrow, C_TEAL, 15)}
      </div>
      {headline_h1(headline, font_size="58px", font_weight=700, line_height=1.06, letter_spacing="-1.3px", text_wrap="balance")}
      {accent_line(120, 3, "margin-top:22px;")}
    </div>
    {logo_block}
    """


def t18(photo, headline, eyebrow, logo):
    """Split-Layout, Photo links flex / Deep-Sea-Block rechts 540px.
    Vertikaler Border-Gradient wurde 2026-04-28 entfernt (Side-Stripe-Border-Verbot, siehe Cards.md).
    Akzent jetzt über horizontale accent_line am unteren Block-Ende."""
    eyebrow = eyebrow or "Praxis"
    return f"""
    <div style="position:absolute;inset:0;display:grid;grid-template-columns:1fr 540px;background:{C_DEEP_SEA};">
      <div style="position:relative;overflow:hidden;">
        <img src="{photo}" style="width:100%;height:100%;object-fit:cover;display:block;">
      </div>
      <div style="background:{C_DEEP_SEA};padding:80px 56px;display:flex;flex-direction:column;
        justify-content:space-between;color:{C_CREAM};">
        <div style="display:flex;align-items:center;gap:12px;">
          {gold_dot(11)}
          {eyebrow_span(eyebrow, C_GOLD, 15)}
        </div>
        {headline_h1(headline, font_size="50px", font_weight=700, line_height=1.08, letter_spacing="-1.1px", text_wrap="balance")}
        {accent_line(100, 3)}
      </div>
    </div>
    """


def t19(photo, headline, eyebrow, logo):
    logo_block = logo_inline(dark=True, scale=1) if logo else ""
    return f"""
    {_photo(photo)}
    {_scrim("linear-gradient(180deg,rgba(24,39,58,0.4) 0%,rgba(24,39,58,0.15) 40%,rgba(24,39,58,0.85) 100%)")}
    <div style="position:absolute;top:80px;left:80px;font-size:280px;line-height:0.75;
      color:{C_GOLD};opacity:0.4;font-family:{FONT_HEAD};font-weight:700;user-select:none;">&ldquo;</div>
    <div style="position:absolute;left:80px;right:80px;bottom:80px;color:{C_CREAM};">
      {headline_h1(headline, font_size="64px", font_weight=500, line_height=1.1, letter_spacing="-1.4px", font_style="italic", text_wrap="balance", max_width="1240px")}
      <div style="display:flex;align-items:center;gap:18px;margin-top:24px;">
        {accent_line(80, 3)}
        {logo_block}
      </div>
    </div>
    """


def t20(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "Reihe Mittelstand"
    logo_block = (f'<div style="position:absolute;top:56px;right:64px;">{logo_inline(dark=True, scale=0.9)}</div>'
                  if logo else "")
    return f"""
    {_photo(photo)}
    {_scrim("linear-gradient(90deg,rgba(24,39,58,0.85) 0%,rgba(24,39,58,0.4) 40%,rgba(24,39,58,0) 60%)")}
    {logo_block}
    <div style="position:absolute;left:80px;top:50%;transform:translateY(-50%);color:{C_CREAM};max-width:880px;">
      <span class="tn-eyebrow" style="display:inline-flex;align-items:center;gap:12px;font-family:{FONT_BODY};font-size:16px;font-weight:600;letter-spacing:3px;text-transform:uppercase;color:{C_GOLD};margin-bottom:22px;">
        {gold_dot(10)} {eyebrow}
      </span>
      {headline_h1(headline, font_size="76px", font_weight=600, line_height=1.04, letter_spacing="-1.8px", text_wrap="balance")}
      {accent_line(140, 3, "margin-top:28px;")}
    </div>
    """


def t21(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "KI im Alltag"
    logo_block = logo_inline(dark=True, scale=1.05) if logo else ""
    return f"""
    {_photo(photo)}
    {_scrim("linear-gradient(135deg,rgba(24,39,58,0.7) 0%,rgba(24,39,58,0.2) 40%,rgba(24,39,58,0) 60%)")}
    <div style="position:absolute;top:56px;right:64px;display:flex;align-items:center;gap:14px;">
      <span style="display:inline-flex;align-items:center;gap:10px;padding:9px 20px;background:transparent;
        border:1.5px solid {C_GOLD};border-radius:999px;font-family:{FONT_BODY};font-size:14px;font-weight:700;letter-spacing:2.5px;
        text-transform:uppercase;color:{C_GOLD};">Neu</span>
      {logo_block}
    </div>
    <div style="position:absolute;left:80px;bottom:80px;color:{C_CREAM};max-width:940px;">
      <span class="tn-eyebrow" style="display:inline-flex;align-items:center;gap:12px;font-family:{FONT_BODY};font-size:15px;font-weight:600;letter-spacing:2.8px;text-transform:uppercase;color:{C_GOLD};margin-bottom:22px;">
        {gold_dot(10)} {eyebrow}
      </span>
      {headline_h1(headline, font_size="64px", font_weight=600, line_height=1.08, letter_spacing="-1.5px", text_wrap="balance")}
      {accent_line(140, 3, "margin-top:26px;")}
    </div>
    """


def t22(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "Standpunkt"
    return f"""
    {_photo(photo)}
    <div style="position:absolute;left:0;right:0;top:0;padding:32px 80px;display:flex;justify-content:space-between;align-items:center;color:{C_CREAM};background:linear-gradient(180deg,rgba(24,39,58,0.7),rgba(24,39,58,0));">
      <span style="font-family:{FONT_MONO};font-size:14px;letter-spacing:1.6px;text-transform:uppercase;opacity:0.85;">Ausgabe · 2026</span>
      <span class="tn-eyebrow" style="font-family:{FONT_BODY};font-size:15px;font-weight:600;letter-spacing:2.8px;text-transform:uppercase;color:{C_GOLD};display:inline-flex;align-items:center;gap:10px;">
        {gold_dot(9)} {eyebrow}
      </span>
    </div>
    {_scrim("linear-gradient(180deg,rgba(24,39,58,0) 35%,rgba(24,39,58,0.55) 65%,rgba(24,39,58,0.92) 100%)")}
    <div style="position:absolute;left:80px;right:80px;bottom:80px;color:{C_CREAM};">
      {headline_h1(headline, font_size="80px", font_weight=700, line_height=1.04, letter_spacing="-1.8px", text_wrap="balance", max_width="1280px")}
      {accent_line(160, 3, "margin-top:28px;")}
    </div>
    """


# T23 wurde 2026-04-28 entfernt (Critique-Refactor):
# nahezu Duplikat von T16 (Zentriertes Statement), aber ohne Underline-Akzent. Für
# zentrierte Klartext-Statements stattdessen T16 nutzen.


def t24(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "Serie Reporting"
    return f"""
    {_photo(photo)}
    {_scrim("linear-gradient(120deg,rgba(24,39,58,0.85) 0%,rgba(24,39,58,0.3) 45%,rgba(24,39,58,0) 65%)")}
    <div style="position:absolute;top:80px;left:80px;color:{C_CREAM};">
      <span style="font-family:{FONT_MONO};font-size:18px;letter-spacing:2px;color:{C_GOLD};font-weight:600;">TEIL 01 / 03</span>
    </div>
    <div style="position:absolute;left:80px;bottom:80px;color:{C_CREAM};max-width:1000px;">
      <span class="tn-eyebrow" style="display:inline-flex;align-items:center;gap:12px;font-family:{FONT_BODY};font-size:15px;font-weight:600;letter-spacing:2.8px;text-transform:uppercase;color:{C_GOLD};margin-bottom:22px;">
        {gold_dot(10)} {eyebrow}
      </span>
      {headline_h1(headline, font_size="70px", font_weight=600, line_height=1.06, letter_spacing="-1.6px", text_wrap="balance")}
      {accent_line(140, 3, "margin-top:28px;")}
    </div>
    """


def t25(photo, headline, eyebrow, logo):
    """Cream-Card-Layout. Card sitzt unten links, kompakt, mit Brand-Default-Schatten.
    2026-04-28 refactored: war zentrierte Modal-mäßige Card mit übertriebenem Schadow
    (Modal-Reflex laut Impeccable-Bans). Jetzt Bottom-Left-Anker, kleiner, ruhig."""
    eyebrow = eyebrow or "Leadership"
    logo_block = logo_inline(scale=0.95) if logo else ""
    return f"""
    {_photo(photo)}
    {_scrim("linear-gradient(180deg,rgba(24,39,58,0.2) 0%,rgba(24,39,58,0) 50%)")}
    <div style="position:absolute;left:80px;bottom:80px;background:{C_CREAM};
      padding:44px 52px;max-width:760px;color:{C_DEEP_SEA};box-shadow:0 8px 24px rgba(24,39,58,0.12);">
      <div style="display:flex;align-items:center;gap:12px;margin-bottom:20px;">
        {gold_dot(11)}
        {eyebrow_span(eyebrow, C_TEAL, 15)}
      </div>
      {headline_h1(headline, font_size="52px", font_weight=700, line_height=1.08, letter_spacing="-1.2px", text_wrap="balance")}
      <div style="display:flex;align-items:center;gap:20px;margin-top:24px;">
        {accent_line(80, 3)}
        {logo_block}
      </div>
    </div>
    """


def t26(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "Notiz"
    return f"""
    {_photo(photo)}
    <div style="position:absolute;left:0;right:0;bottom:0;height:6px;
      background:linear-gradient(90deg,{C_TEAL} 0%,{C_GOLD} 60%,transparent 100%);"></div>
    {_scrim("linear-gradient(180deg,rgba(24,39,58,0) 50%,rgba(24,39,58,0.85) 100%)")}
    <div style="position:absolute;left:80px;right:80px;bottom:70px;color:{C_CREAM};">
      <span class="tn-eyebrow" style="display:inline-flex;align-items:center;gap:12px;font-family:{FONT_BODY};font-size:15px;font-weight:600;letter-spacing:3px;text-transform:uppercase;color:{C_GOLD};margin-bottom:18px;">
        {gold_dot(10)} {eyebrow}
      </span>
      {headline_h1(headline, font_size="68px", font_weight=600, line_height=1.06, letter_spacing="-1.6px", text_wrap="balance", max_width="1240px")}
    </div>
    """


def t27(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "Finanzen · KI"
    logo_block = logo_inline(scale=1.1) if logo else ""
    return f"""
    <div style="position:absolute;inset:0;display:grid;grid-template-columns:1fr 720px;background:{C_CREAM};">
      <div style="padding:80px 64px 80px 88px;display:flex;flex-direction:column;justify-content:space-between;color:{C_DEEP_SEA};">
        <div style="display:flex;align-items:center;gap:12px;">
          {gold_dot(11)}
          {eyebrow_span(eyebrow, C_TEAL, 15)}
        </div>
        <div>
          {accent_line(80, 3, "margin-bottom:26px;")}
          {headline_h1(headline, font_size="64px", font_weight=700, line_height=1.04, letter_spacing="-1.5px", text_wrap="balance")}
        </div>
        <div>{logo_block}</div>
      </div>
      <div style="position:relative;overflow:hidden;">
        <img src="{photo}" style="width:100%;height:100%;object-fit:cover;display:block;">
      </div>
    </div>
    """


def t28(photo, headline, eyebrow, logo):
    """Listen-Layout mit 3 Punkten unten. Erste Card dominanter als die folgenden zwei,
    damit das Grid nicht in identische Card-Reihe kippt (Impeccable-Ban: Identical card grids).
    Eyebrow-Counter bleibt mit der tatsächlichen Item-Zahl konsistent."""
    eyebrow = eyebrow or "3 Lektionen"
    items = [("01", "Daten leben in Köpfen."),
             ("02", "Tools überzeugen niemanden."),
             ("03", "Kultur schlägt Dashboard.")]
    cards = "".join(
        f'<div style="border-top:2px solid rgba(248,246,242,0.4);padding-top:16px;color:{C_CREAM};">'
        f'<span style="font-family:{FONT_MONO};font-size:14px;color:{C_GOLD};letter-spacing:1.5px;font-weight:700;">{n}</span>'
        f'<p style="margin:8px 0 0 0;font-family:{FONT_HEAD};font-size:{28 if i == 0 else 22}px;font-weight:{700 if i == 0 else 600};line-height:1.22;letter-spacing:-0.4px;">{t}</p>'
        f'</div>'
        for i, (n, t) in enumerate(items)
    )
    return f"""
    {_photo(photo)}
    {_scrim("linear-gradient(180deg,rgba(24,39,58,0.55) 0%,rgba(24,39,58,0.1) 30%,rgba(24,39,58,0.85) 100%)")}
    <div style="position:absolute;left:80px;right:80px;top:80px;color:{C_CREAM};">
      <span class="tn-eyebrow" style="display:inline-flex;align-items:center;gap:12px;font-family:{FONT_BODY};font-size:15px;font-weight:600;letter-spacing:3px;text-transform:uppercase;color:{C_GOLD};margin-bottom:20px;">
        {gold_dot(10)} {eyebrow}
      </span>
      {headline_h1(headline, font_size="58px", font_weight=600, line_height=1.08, letter_spacing="-1.3px", text_wrap="balance", max_width="1100px")}
    </div>
    <div style="position:absolute;left:80px;right:80px;bottom:80px;display:grid;grid-template-columns:1.5fr 1fr 1fr;gap:28px;">
      {cards}
    </div>
    """


# T29 wurde 2026-04-28 entfernt (Critique-Refactor):
# Top-Header (Logo+URL) plus zentrierter Hook unten ergaben zu viel Symmetrie. Für
# Hook-Headlines stattdessen T01 oder T14 (linksbündig) nutzen, für zentrierte
# Statements T16.


def t30(photo, headline, eyebrow, logo):
    eyebrow = eyebrow or "Mittelstand"
    return f"""
    {_photo(photo)}
    {_scrim("linear-gradient(120deg,rgba(24,39,58,0.65) 0%,rgba(24,39,58,0.15) 40%,rgba(24,39,58,0) 60%)")}
    <div style="position:absolute;left:80px;top:80px;right:80px;color:{C_CREAM};max-width:1080px;">
      <span class="tn-eyebrow" style="display:inline-flex;align-items:center;gap:12px;font-family:{FONT_BODY};font-size:15px;font-weight:600;letter-spacing:3px;text-transform:uppercase;color:{C_GOLD};margin-bottom:22px;">
        {gold_dot(10)} {eyebrow}
      </span>
      {headline_h1(headline, font_size="76px", font_weight=700, line_height=1.04, letter_spacing="-1.8px", text_wrap="balance")}
    </div>
    <div style="position:absolute;left:0;right:0;bottom:0;padding:28px 80px;background:{C_CREAM};
      display:flex;justify-content:space-between;align-items:center;color:{C_DEEP_SEA};
      border-top:3px solid transparent;
      background-image:linear-gradient({C_CREAM},{C_CREAM}),linear-gradient(90deg,{C_TEAL},{C_GOLD} 60%,transparent);
      background-origin:padding-box,border-box;background-clip:padding-box,border-box;">
      <span style="font-family:{FONT_BODY};font-size:18px;font-weight:500;color:rgba(24,39,58,0.75);">Sondern an Menschen, Mut und Mandat.</span>
      {gold_dot(11)}
    </div>
    """


# Stand 2026-04-28: 27 aktive Templates (T05, T23, T29 wurden in der Critique-Runde entfernt).
TEMPLATES = {
    "T01": t01, "T02": t02, "T03": t03, "T04": t04,
    "T06": t06, "T07": t07, "T08": t08, "T09": t09, "T10": t10,
    "T11": t11, "T12": t12, "T13": t13, "T14": t14, "T15": t15, "T16": t16,
    "T17": t17, "T18": t18, "T19": t19, "T20": t20, "T21": t21,
    "T22": t22, "T24": t24, "T25": t25, "T26": t26,
    "T27": t27, "T28": t28, "T30": t30,
}

TEMPLATE_NAMES = {
    "T01": "Plate unten links",
    "T02": "Bottom-Bar mit Verlauf",
    "T03": "Split 60/40 · Cream-Panel rechts",
    "T04": "Cream-Card links",
    "T06": "Bottom-left + Serien-Label",
    "T07": "Reportage-Datenposting (Zahl + Kontext integriert)",
    "T08": "Center-Pill (Frage-/Statement-Format)",
    "T09": "Split 40/60 · Cream-Panel links",
    "T10": "Cinematic minimal",
    "T11": "Headline rechts unten (Spiegel, nur bei nach-links-blickenden Motiven)",
    "T12": "Cream-Headline-Bar oben",
    "T13": "Headline links (Reporting), ohne Stripe",
    "T14": "Bottom-Scrim, große Headline",
    "T15": "Foto-Card 560×760 + Headline rechts",
    "T16": "Zentriertes Statement",
    "T17": "Diagonale Cream-Ecke unten links",
    "T18": "Dunkles Sidebar-Panel rechts (ohne Side-Stripe)",
    "T19": "Anführungszeichen-Quote, italic",
    "T20": "Untertitel-Headline-Stack mittig links",
    "T21": "Outline-Pill oben rechts + Headline unten",
    "T22": "Magazin-Header-Strip + Headline",
    "T24": "Number-Stack 01/03 + Headline",
    "T25": "Cream-Card unten links",
    "T26": "Minimaler Streifen unten",
    "T27": "Split: Foto rechts, Headline links",
    "T28": "Listen-Karten unten (3 Punkte, asymmetrisches Grid)",
    "T30": "Footer-Streifen mit Subtitle + Headline oben",
}

TEMPLATE_LOGO_DEFAULT = {
    "T01": False, "T02": True, "T03": True, "T04": False,
    "T06": True, "T07": False, "T08": True, "T09": True, "T10": False,
    "T11": True, "T12": False, "T13": True, "T14": False, "T15": True, "T16": False,
    "T17": True, "T18": False, "T19": True, "T20": False, "T21": True,
    "T22": False, "T24": False, "T25": True, "T26": False,
    "T27": True, "T28": False, "T30": False,
}


# --- Override-CSS ------------------------------------------------------

def build_override_style(headline_size, headline_x, headline_y,
                         eyebrow_size, eyebrow_x, eyebrow_y,
                         logo_scale, logo_x, logo_y,
                         block_x=None, block_y=None) -> str:
    """Generiert CSS-Block, der inline-styles per !important überschreibt.

    block_x/block_y verschieben den gesamten Headline-Wrapper (Klasse tn-block),
    sodass Eyebrow, Punkt, Headline und Akzentlinie als Einheit zusammenbleiben.
    Aktuell unterstützt von T11. Andere Templates ignorieren den Block-Override
    still, weil sie die Klasse nicht tragen.
    """
    rules = []

    if block_x is not None or block_y is not None:
        bx = block_x or 0
        by = block_y or 0
        rules.append(".tn-block{transform:translate(" + f"{bx}px,{by}px" + ") !important;}")

    h_decls = []
    if headline_size is not None:
        h_decls.append(f"font-size:{headline_size}px !important")
    if headline_x is not None or headline_y is not None:
        x = headline_x or 0
        y = headline_y or 0
        h_decls.append(f"transform:translate({x}px,{y}px) !important")
    if h_decls:
        rules.append(".tn-headline{" + ";".join(h_decls) + ";}")

    e_decls = []
    if eyebrow_size is not None:
        e_decls.append(f"font-size:{eyebrow_size}px !important")
    if eyebrow_x is not None or eyebrow_y is not None:
        x = eyebrow_x or 0
        y = eyebrow_y or 0
        e_decls.append(f"transform:translate({x}px,{y}px) !important")
    if e_decls:
        rules.append(".tn-eyebrow{" + ";".join(e_decls) + ";}")

    l_decls = []
    transforms = []
    if logo_x is not None or logo_y is not None:
        x = logo_x or 0
        y = logo_y or 0
        transforms.append(f"translate({x}px,{y}px)")
    if logo_scale is not None:
        transforms.append(f"scale({logo_scale})")
    if transforms:
        l_decls.append("transform:" + " ".join(transforms) + " !important")
        l_decls.append("transform-origin:top left !important")
    if l_decls:
        rules.append(".tn-logo{" + ";".join(l_decls) + ";}")

    if not rules:
        return ""
    return "<style>\n" + "\n".join(rules) + "\n</style>"


# --- HTML-Shell + Render ----------------------------------------------

SHELL = """<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>thumbnail</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Mona+Sans:wght@400;500;600;700&family=Inter:wght@400;500;600;700&display=swap">
<style>
  html,body{{margin:0;padding:0;background:{bg};font-family:{font};}}
  #stage{{position:relative;width:{w}px;height:{h}px;overflow:hidden;background:{bg};}}
</style>
{overrides}
</head>
<body>
<div id="stage">{body}</div>
</body>
</html>
"""


def photo_to_data_uri(path: Path) -> str:
    mime, _ = mimetypes.guess_type(path.name)
    if not mime:
        mime = "image/png"
    data = base64.b64encode(path.read_bytes()).decode("ascii")
    return f"data:{mime};base64,{data}"


def build_template_html(template_id: str, photo_uri: str, headline: str,
                        eyebrow: str, logo: bool, overrides: str = "") -> str:
    if template_id not in TEMPLATES:
        raise SystemExit(f"Unknown template '{template_id}'. Allowed: {', '.join(sorted(TEMPLATES))}")
    safe_headline = html.escape(headline or "", quote=True)
    safe_eyebrow = html.escape(eyebrow or "", quote=True)
    body = TEMPLATES[template_id](photo_uri, safe_headline, safe_eyebrow, logo)
    return SHELL.format(bg=C_DEEP_SEA, font=FONT_BODY, w=WIDTH, h=HEIGHT, body=body, overrides=overrides)


def render(photo: Path, template_id: str, headline: str, eyebrow: str,
           logo: bool, output: Path, overrides: str = "") -> None:
    if not photo.is_file():
        raise SystemExit(f"Photo not found: {photo}")

    photo_uri = photo_to_data_uri(photo)
    html = build_template_html(template_id, photo_uri, headline, eyebrow, logo, overrides)

    try:
        from playwright.sync_api import sync_playwright
    except ImportError:
        raise SystemExit(
            "playwright fehlt. Installieren mit:\n"
            "  pip install playwright && python -m playwright install chromium"
        )

    with tempfile.NamedTemporaryFile("w", suffix=".html", delete=False, encoding="utf-8") as fh:
        fh.write(html)
        html_path = Path(fh.name)

    try:
        with sync_playwright() as p:
            browser = p.chromium.launch()
            ctx = browser.new_context(viewport={"width": WIDTH, "height": HEIGHT}, device_scale_factor=1)
            page = ctx.new_page()
            page.goto(html_path.as_uri())
            page.evaluate("document.fonts.ready")
            page.wait_for_load_state("networkidle")
            output.parent.mkdir(parents=True, exist_ok=True)
            page.locator("#stage").screenshot(path=str(output), type="png")
            browser.close()
    finally:
        try:
            html_path.unlink()
        except OSError:
            pass


def main() -> int:
    ap = argparse.ArgumentParser(description=__doc__)
    ap.add_argument("--photo", required=True, type=Path)
    ap.add_argument("--template", required=True, choices=sorted(TEMPLATES))
    ap.add_argument("--headline", required=True)
    ap.add_argument("--eyebrow", default="")
    ap.add_argument("--logo", action="store_true")
    ap.add_argument("--logo-path", type=Path, default=None,
                    help="Pfad zur Logo-SVG-Datei. Ohne diesen Pfad rendert --logo nichts.")
    ap.add_argument("--output", required=True, type=Path)
    ap.add_argument("--headline-size", type=float, default=None)
    ap.add_argument("--headline-x", type=float, default=None)
    ap.add_argument("--headline-y", type=float, default=None)
    ap.add_argument("--eyebrow-size", type=float, default=None)
    ap.add_argument("--eyebrow-x", type=float, default=None)
    ap.add_argument("--eyebrow-y", type=float, default=None)
    ap.add_argument("--logo-scale", type=float, default=None)
    ap.add_argument("--logo-x", type=float, default=None)
    ap.add_argument("--logo-y", type=float, default=None)
    ap.add_argument("--block-x", type=float, default=None)
    ap.add_argument("--block-y", type=float, default=None)
    args = ap.parse_args()

    if args.logo_path is not None:
        set_logo_path(args.logo_path)

    overrides = build_override_style(
        args.headline_size, args.headline_x, args.headline_y,
        args.eyebrow_size, args.eyebrow_x, args.eyebrow_y,
        args.logo_scale, args.logo_x, args.logo_y,
        args.block_x, args.block_y,
    )

    render(args.photo, args.template, args.headline, args.eyebrow,
           args.logo, args.output, overrides)
    print(f"OK: {args.output}")
    return 0


if __name__ == "__main__":
    sys.exit(main())
