{name}
\n"); if (!string.IsNullOrEmpty(farbe)) sb.Append($"{farbe}
\n"); if (!string.IsNullOrWhiteSpace(group)) sb.Append($"Gruppe: {H(group)}
\n"); if (!string.IsNullOrWhiteSpace(saleText)) sb.Append($"{H(saleText)}
\n"); sb.Append("{H(intro)}
\n"); if (animals.Count == 0) { sb.Append("Zurzeit stehen keine Tiere zur Abgabe bereit.
\n"); } else { sb.Append("{farbe}
\n"); if (!string.IsNullOrWhiteSpace(group)) sb.Append($"Gruppe: {H(group)}
\n"); if (!string.IsNullOrWhiteSpace(saleText)) sb.Append($"{H(saleText)}
\n"); sb.Append("{InlineHtml(line)}
"); } CloseList(); return sb.ToString().Trim(); } private static string InlineHtml(string text) { // First HTML-encode, then selectively un-encode our safe inline patterns // to avoid encoding the tags we are about to add. // Order matters: bold before italic. text = H(text); // Bold **text** text = Regex.Replace(text, @"\*\*(.+?)\*\*", "$1"); // Italic *text* (single, not preceded/followed by *) text = Regex.Replace(text, @"(?$1"); // Inline code `text` text = Regex.Replace(text, @"`(.+?)`", "$1");
// Links [text](url) — note: url is already HTML-encoded by H()
text = Regex.Replace(text, @"\[(.+?)\]\((.+?)\)", "$1");
return text;
}
// ── CSS ──────────────────────────────────────────────────────────────
internal static string SiteCss() => """
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--color-bg: #fdf8f3;
--color-surface: #fff;
--color-text: #2c2c2c;
--color-muted: #6b6b6b;
--color-accent: #c0392b;
--color-border: #e0d8d0;
--font-body: system-ui, sans-serif;
--max-w: 860px;
}
body {
font-family: var(--font-body);
background: var(--color-bg);
color: var(--color-text);
line-height: 1.65;
}
a { color: var(--color-accent); text-decoration: none; }
a:hover { text-decoration: underline; }
img { max-width: 100%; height: auto; display: block; }
/* ── Header ── */
.site-header {
background: var(--color-surface);
border-bottom: 1px solid var(--color-border);
padding: .75rem 1rem;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: .5rem 1.5rem;
}
.site-logo {
font-weight: 700;
font-size: 1.1rem;
color: var(--color-text);
white-space: nowrap;
}
.site-nav { display: flex; flex-wrap: wrap; gap: .25rem .75rem; }
.site-nav-link {
font-size: .9rem;
color: var(--color-muted);
padding: .2rem .4rem;
border-radius: 4px;
}
.site-nav-link:hover, .site-nav-link[aria-current="page"] {
color: var(--color-accent);
background: #fef0ee;
text-decoration: none;
}
/* ── Main ── */
.site-main {
max-width: var(--max-w);
margin: 2rem auto;
padding: 0 1rem 3rem;
}
/* ── Footer ── */
.site-footer {
border-top: 1px solid var(--color-border);
padding: 1.5rem 1rem;
text-align: center;
font-size: .85rem;
color: var(--color-muted);
}
/* ── CMS blocks ── */
.cms-heading { margin: 1.5rem 0 .5rem; }
h1.cms-heading { font-size: 1.8rem; }
h2.cms-heading { font-size: 1.4rem; }
.cms-richtext { margin: 1rem 0; }
.cms-richtext p { margin-bottom: .75rem; }
.cms-richtext ul, .cms-richtext ol { margin: .5rem 0 .75rem 1.5rem; }
.cms-richtext li { margin-bottom: .3rem; }
.cms-image { margin: 1.5rem 0; }
.cms-image img { border-radius: 6px; }
.cms-gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: .75rem;
margin: 1.5rem 0;
}
.cms-gallery-item img { border-radius: 4px; aspect-ratio: 1; object-fit: cover; }
.cms-contact {
font-style: normal;
display: flex;
flex-direction: column;
gap: .4rem;
margin: 1rem 0;
}
.cms-contact-row { display: flex; gap: .5rem; align-items: flex-start; }
/* ── Abgabetiere ── */
.cms-abgabe { margin: 1rem 0; }
.cms-abgabe-intro { margin-bottom: 1.25rem; font-size: 1.05rem; }
.cms-abgabe-empty { color: var(--color-muted); font-style: italic; }
.cms-animal-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 1.25rem;
}
.cms-animal-card {
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: 8px;
overflow: hidden;
}
.cms-animal-photo { width: 100%; aspect-ratio: 4/3; object-fit: cover; }
.cms-animal-info { padding: .875rem; }
.cms-animal-name { font-size: 1.1rem; font-weight: 600; margin-bottom: .25rem; }
.cms-animal-farbe { font-size: .9rem; color: var(--color-muted); margin-bottom: .25rem; }
.cms-animal-group { font-size: .85rem; color: var(--color-muted); }
.cms-animal-text { font-size: .9rem; margin-top: .5rem; }
@media (max-width: 480px) {
h1.cms-heading { font-size: 1.4rem; }
.cms-animal-grid { grid-template-columns: 1fr; }
}
""";
// ── Helpers ─────────────────────────────────────────────────────────
private static IReadOnlyList