diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..786dd3c
Binary files /dev/null and b/.DS_Store differ
diff --git a/ascii/ascii-logo.md b/ascii/ascii-logo.md
new file mode 100644
index 0000000..7598ce1
--- /dev/null
+++ b/ascii/ascii-logo.md
@@ -0,0 +1,28 @@
+
+
+ &&&& &&&&&
+ +xX&&XX+++x
+ &&$x+xX++x+:;
+ &;;:$&;:;X&&
+ ::::::::::;
+ &&$$$$$$$$$$$;::::x::+:;
+ &&XXX;::::::::::::::::::xxx
+ &&$x+x;::::::::::::::::::X&
+ &&X+++x;::::::::::::::::::X&
+ &&Xxxxx;::::::::::::::::::X&
+ &&&&&&+;::++;::;++;::;++:x&&
+ &$::&&X:;&&&&;:X&&::X&
+ &&xX&&$:;&&&&Xx&&&:;X&
+ &&&&&&&&& &&&& &&&&
+
+
+██╗ ██╗███████╗ ██████╗ ██████╗ ███████╗ ██████╗ ██╗ ██╗██╗██╗ ██████╗ ██╗ ██╗███╗ ███╗
+██║ ██║██╔════╝██╔════╝ ██╔═══██╗██╔════╝ ██╔══██╗██║ ██║██║██║ ██╔══██╗ ██║ ██║████╗ ████║
+███████║█████╗ ██║ ███╗ ██║ ██║███████╗ ██████╔╝██║ ██║██║██║ ██║ ██║ ██║ ██║██╔████╔██║
+██╔══██║██╔══╝ ██║ ██║ ██║ ██║╚════██║ ██╔══██╗██║ ██║██║██║ ██║ ██║ ╚██╗ ██╔╝██║╚██╔╝██║
+██║ ██║██║ ╚██████╔╝███████╗╚██████╔╝███████║ ██████╔╝╚██████╔╝██║███████╗██████╔╝ ╚████╔╝ ██║ ╚═╝ ██║
+╚═╝ ╚═╝╚═╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝╚══════╝╚═════╝ ╚═══╝ ╚═╝ ╚═╝
+
+DEBIAN 13 VM auf w4d-gpu unterm Schreibtisch
+
+
diff --git a/cms.py b/cms.py
new file mode 100755
index 0000000..9fda398
--- /dev/null
+++ b/cms.py
@@ -0,0 +1,569 @@
+#!/usr/bin/env python3
+"""Mini-CMS: MD-Dateien in md/ per Browseroberflaeche bearbeiten
+und als statische Seite (HTML + CSS) nach output/ exportieren.
+Nur Python-Standardbibliothek, kein Internet noetig.
+
+Aufruf:
+ python3 cms.py -> Server + UI starten (http://localhost:8500)
+ python3 cms.py export -> nur exportieren, kein Server
+ python3 cms.py port 9000 -> Server auf anderem Port
+"""
+
+import json
+import os
+import re
+import shutil
+import sys
+import threading
+import webbrowser
+from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
+from urllib.parse import unquote, urlparse
+
+ROOT = os.path.dirname(os.path.abspath(__file__))
+MD_DIR = os.path.join(ROOT, "md")
+TPL_DIR = os.path.join(ROOT, "templates")
+CSS_DIR = os.path.join(ROOT, "css")
+OUT_DIR = os.path.join(ROOT, "output")
+PORT = 8500
+
+for d in (MD_DIR, TPL_DIR, CSS_DIR, OUT_DIR):
+ os.makedirs(d, exist_ok=True)
+
+SLUG_RE = re.compile(r"^[a-z0-9][a-z0-9_-]*$", re.IGNORECASE)
+START_PAGE = "startseite"
+HEADER_PAGE = "header" # Baustein: wird ueber den Inhalt jeder Seite gesetzt
+FOOTER_PAGE = "footer" # Baustein: wird unter den Inhalt jeder Seite gesetzt
+
+
+# ---------------------------------------------------------------- markdown
+
+def md_to_html(text, headings=None):
+ """Minimaler Markdown->HTML-Konverter:
+ Ueberschriften, **fett**, *kursiv*, `code`, [Links](url),
+ Listen, Code-Bloecke, > Zitate, --- Trennlinien, Absaetze.
+ Ueberschriften bekommen id-Anker; in headings (Liste) werden
+ optional (anker, text) aller Ueberschriften gesammelt.
+ """
+ lines = text.replace("\r\n", "\n").split("\n")
+ out = []
+ i = 0
+ in_code = False
+ in_list = False
+ list_tag = None
+ used_ids = {}
+
+ def inline(s):
+ s = re.sub(r"`([^`]+)`", r"\1", s)
+ s = re.sub(r"\*\*([^*]+)\*\*", r"\1", s)
+ s = re.sub(r"\*([^*]+)\*", r"\1", s)
+ s = re.sub(r"\[([^\]]+)\]\(([^)]+)\)", r'\1', s)
+ return s
+
+ def close_list():
+ nonlocal in_list, list_tag
+ if in_list:
+ out.append("%s>" % list_tag)
+ in_list = False
+ list_tag = None
+
+ while i < len(lines):
+ line = lines[i]
+
+ if line.strip().startswith("```"):
+ close_list()
+ if not in_code:
+ out.append("
")
+ in_code = True
+ else:
+ out.append("
")
+ in_code = False
+ i += 1
+ continue
+
+ if in_code:
+ out.append(_escape(line))
+ i += 1
+ continue
+
+ stripped = line.strip()
+
+ if not stripped:
+ close_list()
+ i += 1
+ continue
+
+ # Rohe HTML-Zeilen (z.B. ,