<?php
declare(strict_types=1);

function app_config(): array
{
    static $config = null;
    if ($config === null) {
        $path = __DIR__ . '/../../config/config.php';
        if (!is_file($path)) {
            return [
                'app' => ['name' => 'TripTale', 'language' => 'de'],
                'database' => [],
            ];
        }
        $config = require $path;
    }
    return $config;
}

/** Erzeugt eine vollständige öffentliche Adresse auf Basis der Installationsadresse. */
function triptale_public_url(string $path = ''): string
{
    $baseUrl = rtrim((string)(app_config()['app']['base_url'] ?? ''), '/');
    if ($baseUrl === '') {
        $secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || (int)($_SERVER['SERVER_PORT'] ?? 0) === 443;
        $host = preg_replace('/[^A-Za-z0-9.:-]/', '', (string)($_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost')) ?: 'localhost';
        $baseUrl = ($secure ? 'https://' : 'http://') . $host;
    }
    return $baseUrl . '/' . ltrim($path, '/');
}

/** Alle installierten Sprachdateien erkennen. Für eine neue Sprache genügt eine neue Datei in /lang. */
function triptale_available_languages(): array
{
    static $languages = null;
    if ($languages !== null) { return $languages; }
    $languages = [];
    foreach (glob(__DIR__ . '/../../lang/[a-z][a-z].php') ?: [] as $file) {
        $code = basename($file, '.php');
        $translationSet = require $file;
        $languages[$code] = (string)($translationSet['language.self'] ?? $translationSet['language.' . $code] ?? strtoupper($code));
    }
    if (!isset($languages['de'])) { $languages['de'] = 'Deutsch'; }
    ksort($languages);
    return $languages;
}

function language(): string
{
    start_session();
    $language = $_SESSION['language'] ?? app_config()['app']['language'] ?? 'de';
    return array_key_exists($language, triptale_available_languages()) ? $language : 'de';
}

function translations(): array
{
    static $translations = null;
    if ($translations === null) {
        $translations = require __DIR__ . '/../../lang/' . language() . '.php';
    }
    return $translations;
}

function t(string $key): string
{
    return translations()[$key] ?? $key;
}

/** Übersetzung für einen bestimmten Empfänger, ohne die Sprache der aktuellen Sitzung zu verändern. */
function t_in_language(string $key, string $locale): string
{
    $locale = array_key_exists($locale, triptale_available_languages()) ? $locale : 'de';
    static $sets = [];
    if (!isset($sets[$locale])) {
        $sets[$locale] = require __DIR__ . '/../../lang/' . $locale . '.php';
    }
    return $sets[$locale][$key] ?? $key;
}

/** Sichere Ausgabe eines übersetzten Textes innerhalb von JavaScript. */
function tjs(string $key): string
{
    return (string)json_encode(t($key), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
}

function localized_date(string $date, bool $withWeekday = false): string
{
    $timestamp = strtotime($date);
    if ($timestamp === false) {
        return '';
    }
    $day = (int)date('j', $timestamp);
    $month = (int)date('n', $timestamp);
    $year = date('Y', $timestamp);
    $dayName = t('weekday.' . date('N', $timestamp));
    $monthName = t('month.' . $month);
    $result = language() !== 'de' ? $monthName . ' ' . $day . ', ' . $year : $day . '. ' . $monthName . ' ' . $year;
    return $withWeekday ? $dayName . ', ' . $result : $result;
}

/** Accept only browser colour-picker values; settings remain safe CSS values. */
function triptale_theme_color(string $value, string $fallback): string
{
    return preg_match('/^#[0-9a-fA-F]{6}$/', $value) ? strtolower($value) : $fallback;
}

/** Farben für Seiten vor der Anmeldung, die keinen Benutzerkopf erhalten. */
function triptale_public_theme_css(): string
{
    $primary = '#126e82';
    $accent = '#e3ebee';
    try {
        $settings = db()->query("SELECT setting_key, setting_value FROM " . table('settings') . " WHERE setting_key IN ('site_primary_color','site_accent_color')")->fetchAll(PDO::FETCH_KEY_PAIR);
        $primary = triptale_theme_color((string)($settings['site_primary_color'] ?? ''), $primary);
        $accent = triptale_theme_color((string)($settings['site_accent_color'] ?? ''), $accent);
    } catch (Throwable $exception) {
        // Die Standardfarben sorgen auch bei einer noch nicht eingerichteten App für eine gute Ansicht.
    }
    return '<style>:root{--triptale-primary:' . $primary . ';--triptale-accent:' . $accent . ';}'
        . 'body{background:color-mix(in srgb,var(--triptale-accent) 34%,#fff)!important}'
        . 'main{border-top:5px solid var(--triptale-primary)!important}'
        . 'button,.button{background:var(--triptale-primary)!important;border-color:var(--triptale-primary)!important;font:inherit!important;font-size:1rem!important}'
        . '.admin-button,.back{background:var(--triptale-accent)!important;color:var(--triptale-primary)!important;border:1px solid var(--triptale-primary)!important}'
        . 'input:focus{outline:2px solid var(--triptale-primary)!important;outline-offset:1px!important;border-color:var(--triptale-primary)!important}'
        . '</style>';
}

function sanitize_rich_text(string $html): string
{
    $clean = strip_tags($html, '<p><br><strong><b><em><i><h2><h3><ul><ol><li><a><blockquote><div>');
    // Contenteditable erzeugt beim Drücken von Enter häufig DIV-Container.
    // Auch ein einzelnes DIV nach formatiertem Text ist ein echter, bewusst
    // eingegebener Zeilenwechsel und darf deshalb nicht entfernt werden.
    $clean = preg_replace('/<div\b[^>]*>/i', '<br>', $clean) ?? $clean;
    $clean = preg_replace('/<\/div\s*>/i', '', $clean) ?? $clean;
    // Ein führender DIV-Container ist lediglich die Hülle des gesamten Editors,
    // nicht eine zusätzliche Leerzeile.
    $clean = preg_replace('/^(?:\s*<br>\s*)+/', '', $clean) ?? $clean;
    // Gleiches gilt für unvollständige P-Container aus contenteditable. Zwei
    // echte aufeinanderfolgende Absätze bleiben als Abstand erhalten.
    $clean = preg_replace('/<\/p>\s*<p\b[^>]*>/i', '<br><br>', $clean) ?? $clean;
    $clean = preg_replace('/<\/?p\b[^>]*>/i', '', $clean) ?? $clean;
    $clean = preg_replace_callback('/<a\b([^>]*)>/i', static function (array $match): string {
        if (!preg_match('/href\s*=\s*(["\'])(.*?)\1/i', $match[1], $hrefMatch)) {
            return '<a>';
        }
        $url = html_entity_decode($hrefMatch[2], ENT_QUOTES, 'UTF-8');
        $scheme = strtolower((string)parse_url($url, PHP_URL_SCHEME));
        if (!in_array($scheme, ['http', 'https'], true)) {
            return '<a>';
        }
        return '<a href="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '" target="_blank" rel="noopener noreferrer">';
    }, $clean) ?? '';
    $clean = preg_replace('/<(p|br|strong|b|em|i|h2|h3|ul|ol|li|blockquote)\b[^>]*>/i', '<$1>', $clean) ?? '';
    return trim($clean);
}

function render_rich_text(?string $text): string
{
    if (!$text) {
        return '';
    }
    if (!str_contains($text, '<')) {
        return nl2br(htmlspecialchars($text, ENT_QUOTES, 'UTF-8'));
    }
    return sanitize_rich_text($text);
}

/** Liest die Dreh-Information eines JPEGs auch dann, wenn die PHP-EXIF-Erweiterung fehlt. */
function triptale_jpeg_orientation(string $file): int
{
    if (function_exists('exif_read_data')) {
        $exif = @exif_read_data($file);
        $orientation = (int)($exif['Orientation'] ?? 0);
        if ($orientation >= 1 && $orientation <= 8) {
            return $orientation;
        }
    }
    $data = @file_get_contents($file, false, null, 0, 131072);
    $marker = is_string($data) ? strpos($data, "Exif\0\0") : false;
    if ($marker === false) {
        return 1;
    }
    $tiff = $marker + 6;
    $endian = substr($data, $tiff, 2);
    if (!in_array($endian, ['II', 'MM'], true)) {
        return 1;
    }
    $u16 = static fn(int $at): int => $endian === 'II'
        ? (int)(unpack('v', substr($data, $at, 2))[1] ?? 0)
        : (int)(unpack('n', substr($data, $at, 2))[1] ?? 0);
    $u32 = static fn(int $at): int => $endian === 'II'
        ? (int)(unpack('V', substr($data, $at, 4))[1] ?? 0)
        : (int)(unpack('N', substr($data, $at, 4))[1] ?? 0);
    $ifd = $tiff + $u32($tiff + 4);
    $count = $u16($ifd);
    for ($index = 0; $index < $count; $index++) {
        $entry = $ifd + 2 + ($index * 12);
        if ($u16($entry) === 0x0112) {
            $orientation = $u16($entry + 8);
            return ($orientation >= 1 && $orientation <= 8) ? $orientation : 1;
        }
    }
    return 1;
}

function triptale_correct_jpeg_orientation($image, string $file)
{
    if (!function_exists('imagerotate')) {
        return $image;
    }
    $orientation = triptale_jpeg_orientation($file);
    $flip = static function ($source, int $mode) {
        if (function_exists('imageflip')) {
            @imageflip($source, $mode);
        }
        return $source;
    };
    $rotate = static function ($source, int $angle) {
        $rotated = @imagerotate($source, $angle, imagecolorallocate($source, 255, 255, 255));
        if ($rotated) {
            imagedestroy($source);
            return $rotated;
        }
        return $source;
    };
    return match ($orientation) {
        2 => $flip($image, IMG_FLIP_HORIZONTAL),
        3 => $rotate($image, 180),
        4 => $flip($image, IMG_FLIP_VERTICAL),
        5 => $rotate($flip($image, IMG_FLIP_HORIZONTAL), 90),
        6 => $rotate($image, -90),
        7 => $rotate($flip($image, IMG_FLIP_HORIZONTAL), -90),
        8 => $rotate($image, 90),
        default => $image,
    };
}

function db(): PDO
{
    static $pdo = null;
    if ($pdo instanceof PDO) {
        return $pdo;
    }

    $database = app_config()['database'] ?? [];
    foreach (['host', 'name', 'user', 'password'] as $key) {
        if (empty($database[$key]) || str_starts_with((string)$database[$key], 'BITTE_')) {
            throw new RuntimeException('Die Datenbankdaten in config/config.php sind noch nicht vollständig.');
        }
    }

    $pdo = new PDO(
        sprintf('mysql:host=%s;dbname=%s;charset=%s', $database['host'], $database['name'], $database['charset'] ?? 'utf8mb4'),
        $database['user'],
        $database['password'],
        [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES => false,
        ]
    );

    return $pdo;
}

function table(string $name): string
{
    $prefix = app_config()['database']['prefix'] ?? '';
    if (!preg_match('/^[A-Za-z][A-Za-z0-9_]{1,30}$/', $prefix) || !preg_match('/^[a-z_]+$/', $name)) {
        throw new RuntimeException('Ungültiger Tabellenname.');
    }
    return $prefix . $name;
}

function start_session(): void
{
    if (session_status() === PHP_SESSION_ACTIVE) {
        return;
    }

    $sessionPath = __DIR__ . '/../../storage/sessions';
    if (is_dir($sessionPath) && is_writable($sessionPath)) {
        session_save_path($sessionPath);
    }
    ini_set('session.use_strict_mode', '1');
    $secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || (int)($_SERVER['SERVER_PORT'] ?? 0) === 443;
    session_name('triptale_session');
    ini_set('session.gc_maxlifetime', (string) (14 * 24 * 60 * 60));
    session_set_cookie_params(['lifetime' => 14 * 24 * 60 * 60, 'httponly' => true, 'secure' => $secure, 'samesite' => 'Lax', 'path' => '/']);
    session_start();
}

function csrf_token(): string
{
    start_session();
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

function verify_csrf(): void
{
    start_session();
    $token = (string)($_POST['csrf_token'] ?? '');
    if (empty($_SESSION['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $token)) {
        http_response_code(403);
        exit('Ungültige Anfrage. Bitte die Seite neu laden und erneut versuchen.');
    }
}

function logged_in_user(): ?array
{
    start_session();
    $expiresAt = (int) ($_SESSION['login_expires_at'] ?? 0);
    if ($expiresAt > 0 && $expiresAt < time()) {
        $_SESSION = [];
        session_destroy();
        return null;
    }
    $id = (int)($_SESSION['user_id'] ?? 0);
    if ($id < 1) {
        return null;
    }
    try {
        $statement = db()->prepare('SELECT id, first_name, last_name, email, role, status, preferred_language FROM ' . table('users') . ' WHERE id = :id AND status = \'active\' AND deleted_at IS NULL');
        $statement->execute([':id' => $id]);
        $user = $statement->fetch() ?: null;
    } catch (Throwable $exception) {
        // Die Anwendung bleibt auch während der einmaligen SQL-Aktualisierung erreichbar.
        $statement = db()->prepare('SELECT id, first_name, last_name, email, role, status FROM ' . table('users') . ' WHERE id = :id AND status = \'active\' AND deleted_at IS NULL');
        $statement->execute([':id' => $id]);
        $user = $statement->fetch() ?: null;
    }
    if ($user !== null && array_key_exists((string)($user['preferred_language'] ?? ''), triptale_available_languages())) {
        $_SESSION['language'] = $user['preferred_language'];
    }
    if ($user !== null && $expiresAt === 0) {
        $_SESSION['login_expires_at'] = time() + (14 * 24 * 60 * 60);
    }
    return $user;
}

function require_login(): array
{
    $user = logged_in_user();
    if ($user === null) {
        header('Location: /login.php');
        exit;
    }
    return $user;
}

function triptale_mail_settings(): array
{
    $settings = [
        'from_name' => 'TripTale',
        'from_email' => '',
        'reply_to' => '',
        'transport' => 'php',
        'smtp_host' => '',
        'smtp_port' => '587',
        'smtp_security' => 'tls',
        'smtp_username' => '',
        'smtp_password' => '',
    ];
    try {
        $rows = db()->query('SELECT setting_key, setting_value FROM ' . table('settings') . " WHERE setting_key IN ('mail_from_name', 'mail_from_email', 'mail_reply_to', 'mail_transport', 'smtp_host', 'smtp_port', 'smtp_security', 'smtp_username', 'smtp_password')")->fetchAll();
        foreach ($rows as $row) {
            $key = (string)$row['setting_key'];
            $value = trim((string)$row['setting_value']);
            if ($key === 'mail_from_name' && $value !== '') { $settings['from_name'] = $value; }
            if ($key === 'mail_from_email' && filter_var($value, FILTER_VALIDATE_EMAIL)) { $settings['from_email'] = $value; }
            if ($key === 'mail_reply_to' && filter_var($value, FILTER_VALIDATE_EMAIL)) { $settings['reply_to'] = $value; }
            if ($key === 'mail_transport' && in_array($value, ['php', 'smtp'], true)) { $settings['transport'] = $value; }
            if (in_array($key, ['smtp_host', 'smtp_username', 'smtp_password'], true)) { $settings[$key] = $value; }
            if ($key === 'smtp_port' && ctype_digit($value) && (int)$value > 0 && (int)$value < 65536) { $settings['smtp_port'] = $value; }
            if ($key === 'smtp_security' && in_array($value, ['tls', 'ssl', 'none'], true)) { $settings['smtp_security'] = $value; }
        }
    } catch (Throwable $exception) {
        // Die Standardwerte ermöglichen den Betrieb auch vor der ersten Einstellung.
    }
    return $settings;
}

function triptale_mail_headers(): string
{
    $settings = triptale_mail_settings();
    $name = str_replace(["\r", "\n"], '', $settings['from_name']);
    $from = str_replace(["\r", "\n"], '', $settings['from_email']);
    $replyTo = str_replace(["\r", "\n"], '', $settings['reply_to']);
    return "MIME-Version: 1.0\r\nContent-type: text/plain; charset=UTF-8\r\nFrom: " . $name . " <" . $from . ">\r\nReply-To: " . $replyTo;
}

/** Prüft, ob die für den Versand zwingend notwendigen Angaben vorhanden sind. */
function triptale_mail_is_configured(array $settings): bool
{
    if (trim((string)($settings['from_name'] ?? '')) === '') { return false; }
    if (!filter_var((string)($settings['from_email'] ?? ''), FILTER_VALIDATE_EMAIL)) { return false; }
    if (!filter_var((string)($settings['reply_to'] ?? ''), FILTER_VALIDATE_EMAIL)) { return false; }
    if (($settings['transport'] ?? 'php') !== 'smtp') { return true; }
    return trim((string)($settings['smtp_host'] ?? '')) !== ''
        && (int)($settings['smtp_port'] ?? 0) > 0
        && trim((string)($settings['smtp_username'] ?? '')) !== ''
        && trim((string)($settings['smtp_password'] ?? '')) !== '';
}

/** Liefert bei fehlender Grundkonfiguration einen eindeutigen, übersetzten Hinweis. */
function triptale_mail_failure_message(string $fallbackKey): string
{
    return triptale_mail_is_configured(triptale_mail_settings()) ? t($fallbackKey) : t('mail.error_not_configured');
}

/** Versendet über den Server oder – falls gewählt – über den gespeicherten SMTP-Anbieter. */
function triptale_send_mail(string $to, string $subject, string $body): bool
{
    $settings = triptale_mail_settings();
    if (!triptale_mail_is_configured($settings)) { return false; }
    if (($settings['transport'] ?? 'php') !== 'smtp') {
        return @mail($to, $subject, $body, triptale_mail_headers());
    }
    $host = trim((string)($settings['smtp_host'] ?? ''));
    $port = (int)($settings['smtp_port'] ?? 0);
    if ($host === '' || $port < 1 || $port > 65535) { return false; }
    $security = (string)($settings['smtp_security'] ?? 'tls');
    $socket = @stream_socket_client(($security === 'ssl' ? 'ssl://' : 'tcp://') . $host . ':' . $port, $number, $error, 15, STREAM_CLIENT_CONNECT);
    if (!is_resource($socket)) { return false; }
    stream_set_timeout($socket, 15);
    $read = static function () use ($socket): string {
        $response = '';
        do { $line = fgets($socket, 1024); if ($line === false) { break; } $response .= $line; } while (isset($line[3]) && $line[3] === '-');
        return $response;
    };
    $command = static function (string $line) use ($socket, $read): bool { fwrite($socket, $line . "\r\n"); return preg_match('/^[23]/', $read()) === 1; };
    $serverName = preg_replace('/[^A-Za-z0-9.-]/', '', (string)($_SERVER['SERVER_NAME'] ?? 'localhost')) ?: 'localhost';
    $ok = preg_match('/^2/', $read()) === 1 && $command('EHLO ' . $serverName);
    if ($ok && $security === 'tls') {
        $crypto = defined('STREAM_CRYPTO_METHOD_TLS_CLIENT') ? STREAM_CRYPTO_METHOD_TLS_CLIENT : STREAM_CRYPTO_METHOD_SSLv23_CLIENT;
        $ok = $command('STARTTLS') && @stream_socket_enable_crypto($socket, true, $crypto) && $command('EHLO ' . $serverName);
    }
    $username = (string)($settings['smtp_username'] ?? '');
    if ($ok && $username !== '') { $ok = $command('AUTH LOGIN') && $command(base64_encode($username)) && $command(base64_encode((string)($settings['smtp_password'] ?? ''))); }
    $from = str_replace(["\r", "\n"], '', (string)$settings['from_email']);
    $safeTo = str_replace(["\r", "\n"], '', $to);
    if ($ok) { $ok = $command('MAIL FROM:<' . $from . '>') && $command('RCPT TO:<' . $safeTo . '>') && $command('DATA'); }
    if ($ok) {
        $name = str_replace(["\r", "\n"], '', (string)$settings['from_name']);
        $replyTo = str_replace(["\r", "\n"], '', (string)$settings['reply_to']);
        $encodedSubject = function_exists('mb_encode_mimeheader') ? mb_encode_mimeheader($subject, 'UTF-8') : $subject;
        $message = 'From: ' . $name . ' <' . $from . ">\r\nReply-To: " . $replyTo . "\r\nTo: " . $safeTo . "\r\nSubject: " . $encodedSubject . "\r\nMIME-Version: 1.0\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\n" . str_replace("\n.", "\n..", $body) . "\r\n.\r\n";
        fwrite($socket, $message); $ok = preg_match('/^2/', $read()) === 1;
    }
    @fwrite($socket, "QUIT\r\n"); @fclose($socket);
    return $ok;
}

function triptale_enhance_image_picker(): void
{
    $page = basename((string)($_SERVER['SCRIPT_NAME'] ?? ''));
    $headerUser = logged_in_user();
    if ($headerUser === null) {
        return;
    }
    echo <<<'HTML'
<style>
@media(max-width:600px){a.button.back{display:inline-block!important;width:auto!important;max-width:100%!important;white-space:normal!important;text-align:left!important}}
.triptale-file-picker{display:table!important;margin:10px 0 0!important;padding:10px 13px!important;background:var(--triptale-primary,#126e82)!important;color:#fff!important;border:1px solid var(--triptale-primary,#126e82)!important;border-radius:7px!important;font:inherit!important;font-weight:700!important;cursor:pointer!important;width:auto!important;text-align:center!important}.triptale-hidden-file-input{position:absolute!important;width:1px!important;height:1px!important;opacity:0!important;overflow:hidden!important}.triptale-file-name{display:block;margin-top:8px;color:#59636d;font-size:.92rem;overflow-wrap:anywhere}
@media(max-width:600px){.triptale-file-picker{display:block!important;width:100%!important}.triptale-file-picker+ .triptale-file-name{margin-bottom:4px}}
.triptale-image-selection-preview{display:flex;flex-wrap:wrap;gap:8px;margin:12px 0 4px}.triptale-image-selection-preview img{display:block;width:110px;height:90px;object-fit:contain;background:#f4f6f8;border-radius:7px;border:1px solid #d6e0e4}
.item-thumb.empty{background:var(--triptale-accent,#e7f4f1) url('/placeholder.php?type=image') center/cover no-repeat!important;border:2px solid var(--triptale-primary,#126e82)!important;box-sizing:border-box!important}
img.thumb[src^="/placeholder.php"],img.trip-cover[src^="/placeholder.php"],img.preview[src^="/placeholder.php"]{border:2px solid var(--triptale-primary,#126e82)!important;box-sizing:border-box!important;background:var(--triptale-accent,#e7f4f1)!important;object-fit:cover!important}
body:has(.triptale-server-header) main .preview[src^="/placeholder.php?type=image"]{display:block!important;width:min(100%,480px)!important;height:300px!important;max-height:none!important;object-fit:contain!important;margin:14px auto!important}
.comment-avatar{width:36px!important;height:36px!important;flex:0 0 36px!important;object-fit:cover!important;border-radius:50%!important;background:#eaf2f3!important;border:1px solid #c9dadd!important}
body:has(.preview) main>form+form{margin-top:14px!important}
body:has(.triptale-global-header){padding-top:0!important}.triptale-global-header{box-sizing:border-box;width:100vw;margin-left:calc(50% - 50vw);padding:18px 7%;background:#126e82;color:#fff;display:flex;justify-content:space-between;align-items:center;gap:12px}.triptale-global-header a{color:#fff}@media(max-width:600px){.triptale-global-header{padding:14px 16px;flex-wrap:wrap}}
body:has(.triptale-server-header)>main{margin-top:24px!important}
/* Einheitliches Desktop-Raster für alle angemeldeten Seiten. */
body:has(.triptale-server-header)>main{width:calc(100% - 48px)!important;max-width:920px!important;margin:24px auto 40px!important;padding:28px!important;box-sizing:border-box!important}
body:has(.triptale-server-header)>main:has(.top),body:has(.triptale-server-header)>main:has(.hero),body:has(.triptale-server-header)>main:has(.filters){max-width:1080px!important}
body:has(.triptale-server-header)>main>a.button.back:first-child{margin:0 0 12px!important}
body:has(.triptale-server-header)>main>a.button.back:first-child+.settings{margin-left:8px!important}
body:has(.triptale-server-header)>main :is(a.button,button){margin:6px 8px 6px 0!important;border-radius:7px!important}
body:has(.triptale-server-header)>main :is(.toolbar button,.image-delete,.image-lightbox button,.mobile-sort button){margin:0!important}
body:has(.triptale-server-header)>main .actions,body:has(.triptale-server-header)>main .member-actions,body:has(.triptale-server-header)>main .trip-note-actions{gap:10px!important}
@media(max-width:600px){body:has(.triptale-server-header)>main{width:100%!important;max-width:100%!important;margin:18px auto!important;padding-left:12px!important;padding-right:12px!important;box-sizing:border-box!important}.filters label{min-width:0!important;width:100%!important}.top>a.button,.top>div>a.button,a.button.back{width:auto!important;display:inline-block!important;max-width:100%!important;box-sizing:border-box!important;text-align:left!important}.card form{max-width:100%!important}.card form .button{max-width:100%!important}}
@media(max-width:600px){.top .resource-menu{display:inline-block!important;width:auto!important;margin:4px!important}.top .resource-menu summary{display:inline-block!important;width:auto!important;text-align:left!important}.top .resource-links{width:auto!important}.top .resource-links a{text-align:left!important}.top .resource-menu+.button{margin-left:4px!important}.top .resource-menu~.button{margin:4px 6px 10px 0!important}}
</style>
<script>
document.addEventListener('DOMContentLoaded',function(){
  var placeholder='/placeholder.php?type=image';
  document.querySelectorAll('img[src$="triptale-placeholder.png"]').forEach(function(image){image.src=placeholder;});
  document.querySelectorAll('img[src$="triptale-profile-placeholder.png"]').forEach(function(image){image.src='/placeholder.php?type=profile';});
  var currentPage=location.pathname.split('/').pop();
  var existingHeader=document.querySelector('body>header');
  if(false&& !existingHeader&&currentPage!=='login.php'){
    var top=document.createElement('header');top.className='triptale-global-header';
    top.innerHTML='<strong>TripTale</strong><span>'+String(window.triptaleHeaderName||'')+' · <a href="/profile.php">Profil</a> · <a href="/logout.php">Abmelden</a></span>';
    document.body.insertBefore(top,document.body.firstChild);
  }
  if(false&&existingHeader&&!existingHeader.querySelector('a[href="/logout.php"]')){
    var account=document.createElement('span');
    account.innerHTML=String(window.triptaleHeaderName||'')+' · <a href="/profile.php">Profil</a> · <a href="/logout.php">Abmelden</a>';
    existingHeader.append(account);
    existingHeader.classList.add('triptale-global-header');
  }
  if(currentPage==='dashboard.php'){document.querySelectorAll('a.card').forEach(function(card){if(!card.querySelector('img.thumb')){var image=document.createElement('img');image.className='thumb';image.src=placeholder;image.alt='';card.insertBefore(image,card.firstChild);}});}
  if(currentPage==='trip.php'){var hero=document.querySelector('.hero');if(hero&&!hero.querySelector('img.trip-cover')){var cover=document.createElement('img');cover.className='trip-cover';cover.src=placeholder;cover.alt='';hero.insertBefore(cover,hero.firstChild);}}
  if(['attractions.php','catalog.php','custom-points.php'].includes(currentPage)){document.querySelectorAll('.card[data-search]').forEach(function(card){if(!card.querySelector('img.thumb')){var image=document.createElement('img');image.className='thumb';image.src=placeholder;image.alt='';card.insertBefore(image,card.firstChild);}});}
  if(currentPage==='image-upload.php'){var uploadHeading=document.querySelector('main h1');if(uploadHeading&&!document.querySelector('main img')){var uploadPlaceholder=document.createElement('img');uploadPlaceholder.className='preview';uploadPlaceholder.src=placeholder;uploadPlaceholder.alt='';uploadHeading.insertAdjacentElement('afterend',uploadPlaceholder);}}
  if(currentPage==='profile.php'){var profileHeading=document.querySelector('main h1');if(profileHeading&&!document.getElementById('profile-image-link')){var profileLink=document.createElement('a');profileLink.id='profile-image-link';profileLink.className='button';profileLink.href='/profile-image.php';profileLink.textContent=String(window.triptaleProfileImageLabel||'Profilbild bearbeiten');profileHeading.insertAdjacentElement('afterend',profileLink);}}
  if(currentPage==='profile-image.php'){var profileFile=document.getElementById('file');var profilePreview=document.querySelector('img.preview');if(profileFile&&profilePreview){profileFile.addEventListener('change',function(){var selected=(profileFile.files||[])[0];if(!selected){return;}var reader=new FileReader();reader.onload=function(event){profilePreview.src=String(event.target&&event.target.result||'');};reader.readAsDataURL(selected);});}}
  if(['attraction-edit.php','catalog-edit.php','custom-point-edit.php','day-items.php','item-edit.php','attractions.php','catalog.php','custom-points.php'].includes(currentPage)){var categoryLabels=window.triptaleCategoryLabels||{};var categoryName=String(categoryLabels.name||'Kategorien'),categoryFilter=String(categoryLabels.filter||'Kategorie'),multiple=String(categoryLabels.multiple||'(mehrere möglich)'),all=String(categoryLabels.all||'Alle Kategorien'),prefix=String(categoryLabels.prefix||'Kategorien:');document.querySelectorAll('label,p.muted').forEach(function(container){var walker=document.createTreeWalker(container,NodeFilter.SHOW_TEXT);for(var node;node=walker.nextNode();){if(node.nodeValue.indexOf('Kategorien')!==-1){node.nodeValue=node.nodeValue.replace(/Kategorien/g,categoryName);}if(node.nodeValue.indexOf('Kategorie')!==-1){node.nodeValue=node.nodeValue.replace(/Kategorie/g,categoryFilter);}if(node.nodeValue.indexOf('(mehrere möglich)')!==-1){node.nodeValue=node.nodeValue.replace('(mehrere möglich)',multiple);}}});document.querySelectorAll('option').forEach(function(option){if(option.textContent.trim()==='Alle Kategorien'){option.textContent=all;}});document.querySelectorAll('p.muted').forEach(function(paragraph){if(paragraph.textContent.indexOf('Kategorien:')===0){paragraph.firstChild.nodeValue=paragraph.firstChild.nodeValue.replace('Kategorien:',prefix);}});}
  var editorLabels=window.triptaleEditorLabels||{};
  document.querySelectorAll('.toolbar button,.toolbar option').forEach(function(element){var text=element.textContent.trim(),replacement=editorLabels[text];if(replacement){element.textContent=replacement;}});
  var accountArea=document.querySelector('header span');
  var logoutLink=accountArea&&accountArea.querySelector('a[href="/logout.php"]');
  if(false&&logoutLink&&!document.querySelector('a[href="/profile.php"]')){
    var separator=document.createTextNode(' · ');
    var profileLink=document.createElement('a');
    profileLink.id='triptale-profile-link';
    profileLink.href='/profile.php';
    profileLink.textContent='Profil';
    accountArea.insertBefore(profileLink,logoutLink);
    accountArea.insertBefore(separator,logoutLink);
  }
  var input=document.getElementById('images');
  if(input&&!document.getElementById('triptale-file-picker')){
    var label=input.closest('label');
    if(label){
      var picker=document.createElement('button');
      picker.type='button';
      picker.id='triptale-file-picker';
      picker.className='triptale-file-picker';
      picker.textContent=(window.triptaleImageLabels||{}).choose||'Bilder auswählen';
      if(input.id){label.setAttribute('for',input.id);}
      label.parentNode.insertBefore(input,label.nextSibling);
      input.parentNode.insertBefore(picker,input);
      input.classList.add('triptale-hidden-file-input');
      picker.style.setProperty('background','var(--triptale-primary,#126e82)','important');
      picker.style.setProperty('border-color','var(--triptale-primary,#126e82)','important');
      picker.addEventListener('click',function(){input.click();});
      var name=document.createElement('span');
      name.className='triptale-file-name';
      name.textContent=(window.triptaleImageLabels||{}).empty||'Noch keine Bilder ausgewählt';
      picker.insertAdjacentElement('afterend',name);
      input.addEventListener('change',function(){
        var files=[].slice.call(input.files||[]);
        name.textContent=files.length?files.map(function(file){return file.name;}).join(', '):((window.triptaleImageLabels||{}).empty||'Noch keine Bilder ausgewählt');
      });
    }
  }
  document.querySelectorAll('input[type="file"][accept*="image"]').forEach(function(fileInput){
    if(fileInput.dataset.triptalePreviewBound==='1'){return;}
    fileInput.dataset.triptalePreviewBound='1';
    var existingPreview=document.querySelector('img.preview');
    var preview=null;
    if(!existingPreview){
      preview=document.createElement('div');
      preview.className='triptale-image-selection-preview';
      preview.setAttribute('aria-live','polite');
      var pickerHost=fileInput.id==='images'?document.getElementById('triptale-file-picker'):fileInput.closest('.triptale-file-picker');
      if(pickerHost){
        var fileName=pickerHost.nextElementSibling;
        if(fileName&&fileName.classList.contains('triptale-file-name')){fileName.insertAdjacentElement('afterend',preview);}
        else{pickerHost.insertAdjacentElement('afterend',preview);}
      }else{
        var host=fileInput.closest('.file-area')||fileInput.closest('label')||fileInput.parentElement;
        if(host){host.appendChild(preview);}
      }
    }
    function showSelection(){
      if(preview){preview.replaceChildren();}
      var files=[].slice.call(fileInput.files||[]);
      if(existingPreview&&files[0]){existingPreview.src=URL.createObjectURL(files[0]);}
      files.forEach(function(file){
        if(!file.type.match(/^image\//)){return;}
        if(!preview){return;}
        var image=document.createElement('img');
        image.alt='Vorschau: '+file.name;
        image.src=URL.createObjectURL(file);
        preview.appendChild(image);
      });
    }
    fileInput.addEventListener('change',showSelection);
  });
});
</script>
HTML;
    echo '<script>window.triptaleHeaderName=' . json_encode((string) $headerUser['first_name'], JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) . ';window.triptaleImageLabels=' . json_encode(['choose' => t('image_picker.choose'), 'empty' => t('image_picker.empty')], JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) . ';window.triptaleProfileImageLabel=' . json_encode(t('profile.image_edit'), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) . ';window.triptaleCategoryLabels=' . json_encode(['name' => t('category.title'), 'filter' => t('category.filter'), 'multiple' => t('category.multiple'), 'all' => t('category.all'), 'prefix' => t('category.prefix')], JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) . ';window.triptaleEditorLabels=' . json_encode(['Fett' => t('editor.bold'), 'Kursiv' => t('editor.italic'), 'Liste' => t('editor.list'), '1. Liste' => t('editor.numbered_list'), 'Link' => t('editor.link'), 'Textstil…' => t('editor.style'), 'Normal' => t('editor.normal'), 'Überschrift' => t('editor.heading'), 'Kleine Überschrift' => t('editor.small_heading')], JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) . ';</script>';
}

register_shutdown_function('triptale_enhance_image_picker');

function triptale_render_global_header(string $html): string
{
    if (!str_contains($html, '<body')) {
        if (basename((string)($_SERVER['SCRIPT_NAME'] ?? '')) !== 'trip-checklist.php') {
            return $html;
        }
        $html = preg_replace('#<!doctype html[^>]*>#i', '$0<html><head></head><body>', $html, 1) . '</body></html>';
    }
    try { $user = logged_in_user(); } catch (Throwable $exception) { return $html; }
    if ($user === null) {
        $page = basename((string)($_SERVER['SCRIPT_NAME'] ?? ''));
        if (in_array($page, ['login.php', 'admin-login.php'], true)) {
            return str_replace('</head>', triptale_public_theme_css() . '</head>', $html);
        }
        return $html;
    }
    $name = htmlspecialchars((string)$user['first_name'], ENT_QUOTES, 'UTF-8');
    $siteName = ''; $siteLogo = ''; $siteLogoPosition = 'left';
    $primaryColor = '#126e82'; $accentColor = '#e3ebee';
    try {
        $siteSettings = db()->query("SELECT setting_key, setting_value FROM " . table('settings') . " WHERE setting_key IN ('site_name','site_logo','site_logo_position','site_primary_color','site_accent_color')")->fetchAll(PDO::FETCH_KEY_PAIR);
        $siteName = (string)($siteSettings['site_name'] ?? '');
        $siteLogo = (string)($siteSettings['site_logo'] ?? '');
        $siteLogoPosition = trim((string)($siteSettings['site_logo_position'] ?? '')) === 'right' ? 'right' : 'left';
        $primaryColor = triptale_theme_color((string)($siteSettings['site_primary_color'] ?? ''), '#126e82');
        $accentColor = triptale_theme_color((string)($siteSettings['site_accent_color'] ?? ''), '#e3ebee');
    } catch (Throwable $exception) {}
    $siteName = htmlspecialchars($siteName !== '' ? $siteName : 'TripTale', ENT_QUOTES, 'UTF-8');
    $siteLogoHtml = $siteLogo !== '' ? '<a class="triptale-logo-link" href="/dashboard.php"><img class="triptale-site-logo" src="/' . htmlspecialchars(ltrim($siteLogo, '/'), ENT_QUOTES, 'UTF-8') . '" alt=""></a>' : '';
    $dayScript = '<script>document.addEventListener("DOMContentLoaded",function(){var day=' . tjs('trip.day') . ';document.querySelectorAll("details summary h2,details summary h3,details summary>span:first-child").forEach(function(el){var text=el.textContent.trim(),m=text.match(/^(?:Tag|Day)\\s+(\\d+)(?:\\s+·\\s+(.*))?$/i);if(!m)return;var suffix=(m[2]||"").trim();if(new RegExp("^(?:Tag|Day)\\\\s+"+m[1]+"$","i").test(suffix))suffix="";el.textContent=day+" "+m[1]+(suffix?" · "+suffix:"");});});</script>';
    $dayTextScript = '<script>document.addEventListener("DOMContentLoaded",function(){var day=' . tjs('trip.day') . ',trip=' . tjs('trip.to_trip') . ';document.querySelectorAll(".comment-card,.note,main>p").forEach(function(box){var walker=document.createTreeWalker(box,NodeFilter.SHOW_TEXT);for(var node;node=walker.nextNode();){node.nodeValue=node.nodeValue.replace(/^(\\s*)(?:Tag|Day)\\s+(\\d+)\\s+·\\s+/i,function(_,space,number){return space+day+" "+number+" · ";});if(node.nodeValue.trim()==="Zur Reise")node.nodeValue=node.nodeValue.replace("Zur Reise",trip);}});});</script>';
    $editorScript = '<script>document.addEventListener("DOMContentLoaded",function(){var labels={bold:' . tjs('editor.bold') . ',italic:' . tjs('editor.italic') . ',insertUnorderedList:' . tjs('editor.list') . ',insertOrderedList:' . tjs('editor.numbered_list') . ',createLink:' . tjs('editor.link') . '},styles={"":' . tjs('editor.style') . ',p:' . tjs('editor.normal') . ',h2:' . tjs('editor.heading') . ',h3:' . tjs('editor.small_heading') . '};document.querySelectorAll(".toolbar button[data-command],.editor-toolbar button[data-command]").forEach(function(button){var label=labels[button.dataset.command];if(label)button.textContent=label;});document.querySelectorAll(".toolbar #link-button,.toolbar #link,.editor-toolbar button[data-command=createLink]").forEach(function(button){button.textContent=' . tjs('editor.link') . ';});document.querySelectorAll(".toolbar select,.editor-toolbar select").forEach(function(select){Array.prototype.forEach.call(select.options,function(option){if(Object.prototype.hasOwnProperty.call(styles,option.value))option.textContent=styles[option.value];});});});</script>';
    $descriptionEditorScript = '<script>document.addEventListener("DOMContentLoaded",function(){var labels={bold:' . tjs('editor.bold') . ',italic:' . tjs('editor.italic') . ',list:' . tjs('editor.list') . ',numbered:' . tjs('editor.numbered_list') . ',link:' . tjs('editor.link') . ',style:' . tjs('editor.style') . ',normal:' . tjs('editor.normal') . ',heading:' . tjs('editor.heading') . ',smallHeading:' . tjs('editor.small_heading') . '};document.querySelectorAll("textarea[name=description]").forEach(function(textarea){if(textarea.dataset.richEditor)return;var toolbar=document.createElement("div"),editor=document.createElement("div"),form=textarea.closest("form");toolbar.className="toolbar triptale-auto-toolbar";editor.className="editor triptale-auto-editor";editor.contentEditable="true";editor.innerHTML=textarea.value;toolbar.innerHTML="";[["bold",labels.bold],["italic",labels.italic],["insertUnorderedList",labels.list],["insertOrderedList",labels.numbered]].forEach(function(item){var button=document.createElement("button");button.type="button";button.dataset.command=item[0];button.textContent=item[1];button.addEventListener("click",function(){editor.focus();document.execCommand(item[0],false,null);});toolbar.appendChild(button);});var link=document.createElement("button");link.type="button";link.textContent=labels.link;link.addEventListener("click",function(){var url=window.prompt("https://");if(url){editor.focus();document.execCommand("createLink",false,url);}});toolbar.appendChild(link);var select=document.createElement("select");[["",labels.style],["p",labels.normal],["h2",labels.heading],["h3",labels.smallHeading]].forEach(function(item){var option=document.createElement("option");option.value=item[0];option.textContent=item[1];select.appendChild(option);});select.addEventListener("change",function(){if(this.value){editor.focus();document.execCommand("formatBlock",false,"<"+this.value+">");this.value="";}});toolbar.appendChild(select);textarea.style.display="none";textarea.dataset.richEditor="1";textarea.parentNode.insertBefore(toolbar,textarea);textarea.parentNode.insertBefore(editor,textarea);if(form)form.addEventListener("submit",function(){textarea.value=editor.innerHTML;});});});</script>';
    $catalogLayoutScript = '<style>.toolbar,.editor-toolbar{display:flex!important;gap:5px!important;flex-wrap:wrap!important;margin-top:6px!important;padding:7px!important;border:1px solid #b9c1c8!important;border-bottom:0!important;border-radius:7px 7px 0 0!important;background:#edf2f3!important}.toolbar button,.toolbar select,.editor-toolbar button,.editor-toolbar select{margin:0!important;padding:6px 9px!important;background:#fff!important;color:#17202a!important;border:1px solid #b9c1c8!important;border-radius:4px!important;font:inherit!important}.toolbar button,.editor-toolbar button,.triptale-auto-toolbar button,button[data-command],button#link,button#link-button,[data-editor-toolbar] button{font-weight:700!important}.editor{min-height:130px!important;padding:11px!important;border:1px solid #b9c1c8!important;border-radius:0 0 7px 7px!important;background:#fff!important;box-sizing:border-box!important}.triptale-custom-top{display:flex!important;justify-content:space-between!important;align-items:center!important;gap:15px!important}.triptale-custom-top>div{min-width:0!important}.triptale-custom-top h1{margin-bottom:6px!important}.triptale-custom-top .muted{margin:0!important}@media(max-width:600px){.triptale-custom-top{flex-wrap:wrap!important}.triptale-custom-top>*{width:100%!important}}</style><script>document.addEventListener("DOMContentLoaded",function(){if(!/\\/custom-points\\.php$/.test(location.pathname))return;var main=document.querySelector("main"),title=main&&main.querySelector(":scope>h1"),intro=title&&title.nextElementSibling,button=main&&main.querySelector(":scope>a.button[href=\"/custom-point-edit.php\"]"),filters=main&&main.querySelector(":scope>.filters");if(!main||!title||!intro||!button||!filters)return;var top=document.createElement("div"),left=document.createElement("div");top.className="top triptale-custom-top";left.appendChild(title);left.appendChild(intro);top.appendChild(left);top.appendChild(button);main.insertBefore(top,filters);});</script>';
    $changeToolsScript = '<style>.choice:has(input:checked){border:2px solid var(--triptale-primary,#126e82)!important;background:var(--triptale-accent,#eef7f8)!important}.triptale-change-tools{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin:12px 0}.triptale-change-tools label{font-weight:700}.triptale-change-tools textarea{display:block;box-sizing:border-box;width:100%;min-height:84px;margin-top:6px;padding:10px;border:1px solid #b9c1c8;border-radius:7px;font:inherit}.triptale-change-tools small{display:block;margin-top:4px;color:#59636d;font-weight:400}.triptale-load-more{display:block;margin:12px auto 0!important}</style><script>document.addEventListener("DOMContentLoaded",function(){if(!/\\/trip-changes\\.php$/.test(location.pathname))return;var form=[].slice.call(document.forms).find(function(candidate){return candidate.querySelector("input[name=\\\"change_ids[]\\\"]");});if(!form)return;var toolbar=form.querySelector(".toolbar"),cards=[].slice.call(form.querySelectorAll("section.card"));if(!toolbar)return;var tools=document.createElement("div");tools.className="triptale-change-tools";var selectLabel=document.createElement("label"),select=document.createElement("input");select.type="checkbox";selectLabel.append(select,document.createTextNode(" "+' . tjs('changes.select_all') . '));tools.append(selectLabel);select.addEventListener("change",function(){cards.forEach(function(card){var checkbox=card.querySelector("input[name=\\\"change_ids[]\\\"]");if(checkbox)checkbox.checked=select.checked;});});if(!toolbar.querySelector("textarea[name=custom_message]")){var messageLabel=document.createElement("label");messageLabel.textContent=' . tjs('changes.custom_message') . ';var textarea=document.createElement("textarea");textarea.name="custom_message";textarea.maxLength=3000;var hint=document.createElement("small");hint.textContent=' . tjs('changes.custom_message_hint') . ';messageLabel.append(textarea,hint);tools.append(messageLabel);}toolbar.append(tools);if(cards.length>20){cards.forEach(function(card,index){if(index>=20)card.hidden=true;});var more=document.createElement("button");more.type="button";more.className="button secondary triptale-load-more";more.textContent=' . tjs('changes.load_more') . ';var shown=20;more.addEventListener("click",function(){cards.slice(shown,shown+20).forEach(function(card){card.hidden=false;});shown+=20;if(shown>=cards.length)more.remove();});form.append(more);}});</script>';
    $brandLink = '<a class="triptale-brand" href="/dashboard.php">' . $siteName . '</a>';
    $brand = $siteLogoPosition === 'right' ? $brandLink . $siteLogoHtml : $siteLogoHtml . $brandLink;
    $header = '<style>body:has(.triptale-server-header){padding:0!important}.triptale-server-header{box-sizing:border-box;width:100%;padding:18px 7%;background:#126e82;color:#fff;display:flex;justify-content:space-between;align-items:center;gap:12px}.triptale-server-header a{color:#fff}.triptale-server-header .triptale-brand-wrap{display:flex;align-items:center;gap:10px;min-width:0}.triptale-server-header .triptale-brand{color:#fff;text-decoration:none;font:inherit;font-size:2em;font-weight:700}.triptale-server-header .triptale-brand:hover,.triptale-server-header .triptale-logo-link:hover{text-decoration:none}.triptale-logo-link{display:block;line-height:0}.triptale-site-logo{display:block;max-width:280px;max-height:96px;width:auto;height:auto;object-fit:contain}@media(max-width:600px){.triptale-server-header{padding:14px 16px;flex-direction:column;align-items:flex-start}.triptale-server-header .triptale-brand-wrap{flex-direction:column;align-items:flex-start;gap:8px}.triptale-site-logo{max-width:360px;max-height:128px}.triptale-server-header>span{width:100%}}.triptale-auto-toolbar{display:flex!important;gap:5px!important;flex-wrap:wrap!important;margin-top:6px!important;padding:7px!important;border:1px solid #b9c1c8!important;border-bottom:0!important;border-radius:7px 7px 0 0!important;background:#edf2f3!important}.triptale-auto-toolbar button,.triptale-auto-toolbar select{margin:0!important;padding:6px 9px!important;background:#fff!important;color:#17202a!important;border:1px solid #b9c1c8!important;border-radius:4px!important;font:inherit!important}.triptale-auto-editor{min-height:130px!important;margin-top:0!important;padding:11px!important;border:1px solid #b9c1c8!important;border-radius:0 0 7px 7px!important;background:#fff!important;box-sizing:border-box!important}.triptale-auto-editor:focus{outline:2px solid #75aeb9!important;outline-offset:-2px!important}</style><header class="triptale-server-header"><strong class="triptale-brand-wrap">' . $brand . '</strong><span>' . $name . ' · <a href="/language.php">' . htmlspecialchars(t('nav.language'), ENT_QUOTES, 'UTF-8') . '</a> · <a href="/profile.php">' . htmlspecialchars(t('nav.profile'), ENT_QUOTES, 'UTF-8') . '</a> · <a href="/logout.php">' . htmlspecialchars(t('nav.logout'), ENT_QUOTES, 'UTF-8') . '</a></span></header>' . $dayScript . $dayTextScript . $editorScript . $descriptionEditorScript . $changeToolsScript;
    $header = str_replace('<header class="triptale-server-header">', '<header class="triptale-server-header triptale-logo-' . $siteLogoPosition . '">', $header);
    $header = str_replace('<span>' . $name . ' · ', '<span class="triptale-account"><strong class="triptale-user-name">' . $name . '</strong> · ', $header);
    if ($user['role'] === 'main_admin') {
        $header = str_replace(
            ' · <a href="/logout.php">',
            ' · <a href="/settings.php">' . htmlspecialchars(t('settings.title'), ENT_QUOTES, 'UTF-8') . '</a> · <a href="/logout.php">',
            $header
        );
    }
    $header .= '<style>:root{--triptale-primary:' . $primaryColor . ';--triptale-accent:' . $accentColor . ';}.triptale-server-header,.triptale-global-header,.triptale-footer{background:var(--triptale-primary)!important}.triptale-file-picker,.file-picker,.triptale-primary-button{background:var(--triptale-primary)!important}.triptale-light-button{background:var(--triptale-accent)!important;border:1px solid var(--triptale-primary)!important;color:var(--triptale-primary)!important}.triptale-theme-accent{border-left-color:var(--triptale-primary)!important;background:color-mix(in srgb,var(--triptale-accent) 38%,#fff)!important}.settings-tab.active{background:var(--triptale-primary)!important;border-color:var(--triptale-primary)!important}.settings-tab:not(.active),.back{background:var(--triptale-accent)!important;color:var(--triptale-primary)!important;border-color:var(--triptale-primary)!important}body:has(.triptale-server-header) main>a.settings[href="/settings.php"]{display:none!important}.triptale-server-header .triptale-account{font-weight:400;text-align:right}.triptale-server-header .triptale-user-name{font-weight:700}@media(min-width:601px){.triptale-server-header .triptale-account{margin-left:auto;white-space:nowrap}.triptale-logo-left .triptale-site-logo{order:1}.triptale-logo-left .triptale-brand{order:2}.triptale-logo-right .triptale-brand{order:1}.triptale-logo-right .triptale-site-logo{order:2}}@media(max-width:600px){.triptale-server-header{align-items:stretch!important}.triptale-server-header .triptale-brand-wrap{align-self:center!important;align-items:center!important;text-align:center!important}.triptale-server-header .triptale-brand{order:1}.triptale-server-header .triptale-site-logo{order:2}.triptale-server-header>.triptale-account{width:100%;text-align:center!important}}</style><script>document.addEventListener("DOMContentLoaded",function(){document.querySelectorAll("a.button,button").forEach(function(button){var color=(window.getComputedStyle(button).backgroundColor||"").replace(/\\s/g,"");if(color==="rgb(227,235,238)"){button.classList.add("triptale-light-button");}if(color==="rgb(18,110,130)"){button.classList.add("triptale-primary-button");}});document.querySelectorAll("main *").forEach(function(box){var color=(window.getComputedStyle(box).borderLeftColor||"").replace(/\\s/g,"");if(color==="rgb(117,174,185)"){box.classList.add("triptale-theme-accent");}});});</script>';
    $header .= '<style>a.button.back,.back{background:var(--triptale-accent)!important;color:var(--triptale-primary)!important;border:1px solid var(--triptale-primary)!important}.tabs a.triptale-light-button{background:var(--triptale-accent)!important;color:var(--triptale-primary)!important;border:1px solid var(--triptale-primary)!important}.tabs a.triptale-primary-button,.resource-menu summary{background:var(--triptale-primary)!important;color:#fff!important;border:1px solid var(--triptale-primary)!important}.resource-links a:hover{background:var(--triptale-accent)!important;color:var(--triptale-primary)!important}</style><script>document.addEventListener("DOMContentLoaded",function(){document.querySelectorAll("a.button,button,.tabs a").forEach(function(button){var color=(window.getComputedStyle(button).backgroundColor||"").replace(/\\s/g,"");if(color==="rgb(237,242,243)"){button.classList.add("triptale-light-button");}if(color==="rgb(18,110,130)"){button.classList.add("triptale-primary-button");}});});</script>';
    $header .= '<style>a.button:not(.back):not(.delete):not(.settings-tab),button.save,button[type="submit"]:not(.delete),.picker,.file-picker,.triptale-file-picker,#profile-image-link,.resource-menu summary,.notes-menu summary{background:var(--triptale-primary)!important;color:#fff!important;border-color:var(--triptale-primary)!important}button[type="submit"]{font:inherit!important;font-size:1rem!important}a.button.back,.back{background:var(--triptale-accent)!important;color:var(--triptale-primary)!important;border:1px solid var(--triptale-primary)!important}.picker,.file-picker,.triptale-file-picker{border:1px solid var(--triptale-primary)!important}.notes-links a:hover{background:var(--triptale-accent)!important;color:var(--triptale-primary)!important}:is(.day-chevron,.item-chevron,.accordion-chevron,.toggle-chevron,[class*="chevron"]){color:var(--triptale-primary!important}details summary::marker{color:var(--triptale-primary)!important}.triptale-trip-view main>.day{border-left:4px solid var(--triptale-primary)!important;border-right:1px solid #d6e0e4!important;box-shadow:none!important}.triptale-trip-view main>.day.open{border-left-color:var(--triptale-accent)!important}.triptale-trip-view main>.day:not(.open){border-top:2px solid var(--triptale-accent)!important;border-bottom:2px solid var(--triptale-accent)!important}.triptale-trip-view .day.open .item.open{padding:0!important;overflow:hidden!important;border-top-color:var(--triptale-accent)!important;border-right-color:var(--triptale-accent)!important;border-bottom-color:var(--triptale-accent)!important;background:#fff!important}.triptale-trip-view .day.open .item.open .item-toggle{margin:0!important;border:0!important;background:var(--triptale-accent)!important}.triptale-trip-view .day.open .item.open .item-panel{border-top:0!important;background:#fff!important}.triptale-trip-view .item-note{background:var(--triptale-accent)!important;border-left-color:var(--triptale-primary)!important}.triptale-trip-view .item-categories{border-top-color:var(--triptale-accent)!important;border-bottom-color:var(--triptale-accent)!important}</style><script>document.addEventListener("DOMContentLoaded",function(){if(location.pathname==="/trip.php"){document.body.classList.add("triptale-trip-view");}});</script>';
    $header .= '<style>:is(.day-chevron,.item-chevron,.accordion-chevron,.toggle-chevron,[class*="chevron"]){color:var(--triptale-primary)!important}.triptale-trip-view main>.day{border-left:4px solid var(--triptale-primary)!important;border-right:1px solid #d6e0e4!important;box-shadow:none!important}.triptale-trip-view main>.day.open{border-left-color:var(--triptale-accent)!important}.triptale-trip-view main>.day:not(.open){border-top:2px solid var(--triptale-accent)!important;border-bottom:2px solid var(--triptale-accent)!important}.triptale-trip-view .day.open .item.open{padding:0!important;overflow:hidden!important;border-top-color:var(--triptale-accent)!important;border-right-color:var(--triptale-accent)!important;border-bottom-color:var(--triptale-accent)!important;background:#fff!important}.triptale-trip-view .day.open .item.open .item-toggle{margin:0!important;border:0!important;background:var(--triptale-accent)!important}.triptale-trip-view .day.open .item.open .item-panel{border-top:0!important;background:#fff!important}.triptale-trip-view .item-note{background:var(--triptale-accent)!important;border-left-color:var(--triptale-primary)!important}.triptale-trip-view .item-categories{border-top-color:var(--triptale-accent)!important;border-bottom-color:var(--triptale-accent)!important}</style>';
    // Logo-Position: Desktop nebeneinander, mobil in derselben Reihenfolge übereinander.
    $header .= '<style>.triptale-server-header .triptale-brand-wrap{display:flex!important;flex-direction:row!important;align-items:center!important}.triptale-logo-left .triptale-site-logo{order:1!important}.triptale-logo-left .triptale-brand{order:2!important}.triptale-logo-right .triptale-brand{order:1!important}.triptale-logo-right .triptale-site-logo{order:2!important}@media(max-width:600px){.triptale-server-header{flex-direction:column!important;align-items:center!important}.triptale-server-header .triptale-brand-wrap{width:100%!important;flex-direction:column!important;align-items:center!important;text-align:center!important}.triptale-logo-left .triptale-site-logo{order:1!important}.triptale-logo-left .triptale-brand{order:2!important}.triptale-logo-right .triptale-brand{order:1!important}.triptale-logo-right .triptale-site-logo{order:2!important}.triptale-server-header>.triptale-account{width:100%!important;text-align:center!important}}</style>';
    $header .= $catalogLayoutScript;
    if ($user['role'] === 'main_admin') {
        $header .= '<script>document.addEventListener("DOMContentLoaded",function(){if(location.pathname!=="/website-footer-settings.php")return;var tabs=document.querySelector(".settings-tabs");if(!tabs||tabs.querySelector("a[href=\\\"/update.php\\\"]"))return;var link=document.createElement("a");link.className="button settings-tab";link.href="/update.php";link.textContent=' . tjs('updates.nav') . ';tabs.appendChild(link);});</script>';
        $header .= '<script>document.addEventListener("DOMContentLoaded",function(){if(location.pathname!=="/settings.php")return;var tabs=document.querySelector(".settings-tabs");if(!tabs)return;if(!tabs.querySelector("a[href=\\\"/main-admin-transfer.php\\\"]")){var transfer=document.createElement("a");transfer.className="button settings-tab";transfer.href="/main-admin-transfer.php";transfer.textContent=' . tjs('main_admin_transfer.nav') . ';tabs.appendChild(transfer);}if(!tabs.querySelector("a[href=\\\"/main-admin-password.php\\\"]")){var password=document.createElement("a");password.className="button settings-tab";password.href="/main-admin-password.php";password.textContent=' . tjs('main_admin_password.nav') . ';tabs.appendChild(password);}});</script>';
    }
    $settingsPage = basename((string)($_SERVER['SCRIPT_NAME'] ?? ''));
    $settingsPages = ['settings.php', 'website-footer-settings.php', 'update.php', 'update-manager.php', 'main-admin-transfer.php', 'main-admin-password.php', 'uninstall.php'];
    if ($user['role'] === 'main_admin' && in_array($settingsPage, $settingsPages, true)) {
        $tabs = [
            'settings.php' => t('settings.mail'),
            'website-footer-settings.php' => t('settings.website_footer'),
            'update.php' => t('updates.nav'),
            'main-admin-transfer.php' => t('main_admin_transfer.nav'),
            'main-admin-password.php' => t('main_admin_password.nav'),
            'uninstall.php' => t('uninstall.nav'),
        ];
        $settingsNav = '<nav class="settings-tabs triptale-settings-nav">';
        foreach ($tabs as $file => $label) {
            $active = ($settingsPage === $file || ($settingsPage === 'update-manager.php' && $file === 'update.php')) ? ' active' : '';
            $settingsNav .= '<a class="button settings-tab' . $active . '" href="/' . $file . '">' . htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '</a>';
        }
        $settingsNav .= '</nav>';
        if (preg_match('#<nav class="[^"]*settings-tabs[^"]*">.*?</nav>#is', $html)) {
            $html = preg_replace('#<nav class="[^"]*settings-tabs[^"]*">.*?</nav>#is', $settingsNav, $html, 1) ?? $html;
        } else {
            $html = preg_replace('#</h1>#i', '</h1>' . $settingsNav, $html, 1) ?? $html;
        }
        $backHref = $settingsPage === 'settings.php' ? '/dashboard.php' : '/settings.php';
        $backLabel = $settingsPage === 'settings.php' ? t('settings.back') : t('settings.back_to_settings');
        $backLink = '<a class="button back" href="' . $backHref . '">' . htmlspecialchars($backLabel, ENT_QUOTES, 'UTF-8') . '</a>';
        $html = preg_replace('#<a class="button back" href="[^"]*">.*?</a>#is', $backLink, $html, 1) ?? $html;
        $header .= '<style>.triptale-settings-nav{display:flex!important;flex-wrap:wrap!important;gap:8px!important;margin:0 0 18px!important}.triptale-settings-nav .settings-tab{background:var(--triptale-accent)!important;color:var(--triptale-primary)!important;border:1px solid var(--triptale-primary)!important}.triptale-settings-nav .settings-tab.active{background:var(--triptale-primary)!important;color:#fff!important;border-color:var(--triptale-primary)!important}.delete-backup{background:#9d2d2d!important;color:#fff!important;border-color:#9d2d2d!important}</style>';
    }
    $header .= '<style>.notes-filter summary,.comments-filter summary{background:var(--triptale-primary)!important;color:#fff!important;border-color:var(--triptale-primary)!important}.notes-filter nav a:hover,.comments-filter nav a:hover{background:var(--triptale-accent)!important;color:var(--triptale-primary)!important}.version{border-color:var(--triptale-primary)!important;background:var(--triptale-accent)!important;color:var(--triptale-primary)!important}input[type="file"]::file-selector-button{margin-right:10px;padding:9px 12px;border:1px solid var(--triptale-primary)!important;border-radius:7px;background:var(--triptale-primary)!important;color:#fff!important;font:inherit;font-weight:700;cursor:pointer}input[type="file"]::-webkit-file-upload-button{margin-right:10px;padding:9px 12px;border:1px solid var(--triptale-primary)!important;border-radius:7px;background:var(--triptale-primary)!important;color:#fff!important;font:inherit;font-weight:700;cursor:pointer}</style>';
    $header .= '<style>.triptale-logo-left .triptale-logo-link{order:1!important}.triptale-logo-right .triptale-logo-link{order:2!important}@media(max-width:600px){.triptale-logo-left .triptale-logo-link{order:1!important}.triptale-logo-right .triptale-logo-link{order:2!important}}</style>';
    $header .= '<style>.role-badge{background:var(--triptale-accent)!important;color:var(--triptale-primary)!important;border-color:var(--triptale-primary)!important}</style>';
    $html = preg_replace('#<header\b[^>]*>.*?</header>#is', '', $html, 1) ?? $html;
    $html = preg_replace('#(<body\b[^>]*>)#i', '$1' . $header, $html, 1) ?? $html;
    if (str_contains($html, 'name="category_ids[]"')) {
        $assets = '<link rel="stylesheet" href="/assets/category-checkboxes.css"><script src="/assets/category-checkboxes.js"></script>';
        $html = str_replace('</body>', $assets . '</body>', $html);
    }
    try {
        $footerSettings = db()->query('SELECT setting_key, setting_value FROM ' . table('settings') . " WHERE setting_key IN ('privacy_text','legal_text','contact_enabled','copyright')")->fetchAll(PDO::FETCH_KEY_PAIR);
        $links = '';
        if (!empty($footerSettings['privacy_text'])) { $links .= '<a href="/legal.php?type=privacy">' . htmlspecialchars(t('footer.privacy') !== 'footer.privacy' ? t('footer.privacy') : 'Datenschutz', ENT_QUOTES, 'UTF-8') . '</a>'; }
        if (!empty($footerSettings['legal_text'])) { $links .= '<a href="/legal.php?type=legal">' . htmlspecialchars(t('footer.legal') !== 'footer.legal' ? t('footer.legal') : 'Impressum', ENT_QUOTES, 'UTF-8') . '</a>'; }
        if (($footerSettings['contact_enabled'] ?? '') === '1') { $links .= '<a href="/contact.php">' . htmlspecialchars(t('footer.contact'), ENT_QUOTES, 'UTF-8') . '</a>'; }
        $copyright = htmlspecialchars((string)($footerSettings['copyright'] ?? ''), ENT_QUOTES, 'UTF-8');
        $footer = '<style>.triptale-footer{background:' . $primaryColor . ';color:#fff;padding:22px 7%;margin-top:40px;text-align:center}.triptale-footer a{color:#fff;margin:0 8px}.triptale-footer p{margin:8px 0}</style><footer class="triptale-footer"><p>' . $links . '</p><p>' . $copyright . ($copyright !== '' ? ' · ' : '') . htmlspecialchars(t('footer.created_by'), ENT_QUOTES, 'UTF-8') . ' <a href="https://www.willhoff.de" target="_blank" rel="noopener">www.willhoff.de</a></p></footer>';
        $html = str_replace('</body>', $footer . '</body>', $html);
    } catch (Throwable $exception) {}
    return $html;
}

if (!ob_get_level()) {
    ob_start('triptale_render_global_header');
}
