diff --git a/pygitweb/config.py b/pygitweb/config.py
index 3a53189..a9604ae 100644
--- a/pygitweb/config.py
+++ b/pygitweb/config.py
@@ -15,7 +15,7 @@ from typing import Any
 PROJECTROOT = os.environ.get("GITWEB_PROJECTROOT", "/pub/scm")
 PROJECT_MAXDEPTH = int(os.environ.get("GITWEB_PROJECT_MAXDEPTH", "2"))
 PROJECTS_LIST = os.environ.get("GITWEB_LIST", PROJECTROOT)
-SITE_NAME = os.environ.get("GITWEB_SITENAME", "") or "Git"
+SITE_NAME = os.environ.get("GITWEB_SITENAME", "") or "DistGit"
 EXPORT_OK = os.environ.get("GITWEB_EXPORT_OK", "")
 # When True, list all directories under project root without repo/export_ok checks (default on for now).
 LIST_ALL = os.environ.get("GITWEB_LIST_ALL", "1").lower() in ("1", "true", "yes")
diff --git a/pygitweb/main.py b/pygitweb/main.py
index b301254..3f37278 100644
--- a/pygitweb/main.py
+++ b/pygitweb/main.py
@@ -95,7 +95,7 @@ env = Environment(
     lstrip_blocks=True,
 )
 PREAMBLE = env.get_template("preamble.html")
-POSTAMBLE = "</body></html>"
+POSTAMBLE = """</div></div></div><script src="https://cdn.jsdelivr.net/npm/@tabler/core@1.0.0-beta17/dist/js/tabler.min.js"></script></body></html>"""
 
 # Todo handle with nginx route
 _static_dir = Path(__file__).parent / "static"
@@ -188,7 +188,7 @@ def git_project_list(
             pr.get('descr') or pr.get('path', "")]
              for pr in list_[:50]]
     )
-    pre = PREAMBLE.render(title=f'{esc_html(config.SITE_NAME)} - Projects', theme="dark")
+    pre = PREAMBLE.render(title=f'{esc_html(config.SITE_NAME)} - Projects', theme="dark", site_name=config.SITE_NAME)
     return HTMLResponse(f"{pre}<h1>Project List</h1>{table}{POSTAMBLE}")
 
 
@@ -287,7 +287,7 @@ def dispatch(
     if action == "history":
         return git_history(proj, hash_param, file_name)
     # Stub others with minimal response
-    pre = PREAMBLE.render(title=f"{esc_html(action)} - {esc_html(proj)}", theme="dark")
+    pre = PREAMBLE.render(title=f"{esc_html(action)} - {esc_html(proj)}", theme="dark", site_name=config.SITE_NAME)
     return HTMLResponse(
         f"{pre}<p>Action: {esc_html(action)}</p><p>Project: {esc_html(proj)}</p>{POSTAMBLE}"
     )
@@ -315,7 +315,7 @@ def git_summary(project: str) -> HTMLResponse:
             [esc_html("tree"), f"<a href='/{project}?a=tree&h={head or ''}'>browse</a>"],
         ]
     )
-    pre = PREAMBLE.render(title=f"{esc_html(config.SITE_NAME)} - {project}", theme="dark")
+    pre = PREAMBLE.render(title=f"{esc_html(config.SITE_NAME)} - {project}", theme="dark", site_name=config.SITE_NAME)
     return HTMLResponse(f"{pre}<h1>{esc_html(project)}</h1>{table}{POSTAMBLE}")
 
 
@@ -350,7 +350,7 @@ def git_blob(project: str, h: str | None, f: str | None, *, raw: bool = False) -
     # HTML view: raw content, escaped for safe display
     text = to_utf8(data) or ""
     body = sanitize(text) or ""
-    pre = PREAMBLE.render(title=f"{esc_html(f)} - {esc_html(project)}", theme="dark")
+    pre = PREAMBLE.render(title=f"{esc_html(f)} - {esc_html(project)}", theme="dark", site_name=config.SITE_NAME)
     return HTMLResponse(
         f"{pre}<pre class='blob-content'>{body}</pre>{POSTAMBLE}")
 
@@ -392,7 +392,7 @@ def git_tree(project: str, h: str | None, f: str | None) -> HTMLResponse:
             [f'<a href="{link}">{esc_html(name)}</a>', "blob"]
         )
     title_path = f" / {f}" if f else ""
-    pre = PREAMBLE.render(title=f"{esc_html(project)}{esc_html(title_path)} - Tree", theme="dark")
+    pre = PREAMBLE.render(title=f"{esc_html(project)}{esc_html(title_path)} - Tree", theme="dark", site_name=config.SITE_NAME)
     table = env.get_template("table.html").render(
         cols=["Name", "Type"],
         rows=rows
@@ -413,7 +413,7 @@ def git_forks(project: str, request: Request) -> HTMLResponse:
     for pr in list_:
         path = pr.get("path", "")
         rows.append(f"<tr><td><a href='/{path}'>{esc_html(path)}</a></td></tr>")
-    pre = PREAMBLE.render(title=f"{esc_html(project)} - Forks", theme="dark")
+    pre = PREAMBLE.render(title=f"{esc_html(project)} - Forks", theme="dark", site_name=config.SITE_NAME)
     return HTMLResponse(
         f"{pre}<h1>Forks of {esc_html(project)}</h1><table>{"".join(rows)}</table>{POSTAMBLE}"
     )
@@ -492,7 +492,7 @@ def git_log(project: str, h: str | None) -> HTMLResponse:
     ref_display = h[:7] if h else "HEAD"
     title = f"Log - {esc_html(project)} @ {esc_html(ref_display)}"
 
-    pre = PREAMBLE.render(title=title, theme="dark")
+    pre = PREAMBLE.render(title=title, theme="dark", site_name=config.SITE_NAME)
     table = env.get_template("table.html").render(
         cols=["Commit", "Subject", "Author", "Date", "Age"],
         rows=rows
@@ -515,7 +515,7 @@ def git_shortlog(project: str, h: str | None) -> HTMLResponse:
     ref_display = h[:7] if h else "HEAD"
     title = f"Shortlog - {esc_html(project)} @ {esc_html(ref_display)}"
     
-    pre = PREAMBLE.render(title=title, theme="dark")
+    pre = PREAMBLE.render(title=title, theme="dark", site_name=config.SITE_NAME)
     table = env.get_template("table.html").render(
         cols=["Commit", "Subject", "Author", "Age"],
         rows=rows
@@ -542,7 +542,7 @@ def git_history(project: str, h: str | None, f: str | None) -> HTMLResponse:
 
     ref_display = h[:7] if h else "HEAD"    
     title=f"History - {esc_html(f)} - {esc_html(project)} @ {esc_html(ref_display)}"
-    pre = PREAMBLE.render(title=title, theme="dark")
+    pre = PREAMBLE.render(title=title, theme="dark", site_name=config.SITE_NAME)
     table = env.get_template("table.html").render(
         cols=["Commit", "Subject", "Author", "Date", "Age"],
         rows=rows
diff --git a/pygitweb/static/main.css b/pygitweb/static/main.css
index 2536d7a..279fc21 100644
--- a/pygitweb/static/main.css
+++ b/pygitweb/static/main.css
@@ -19,6 +19,20 @@ body {
 	color: var(--pgw-text);
 	border: 1px solid var(--pgw-border);
 }
+body:has(.page) {
+	padding: 0;
+}
+
+/* Fluid vertical layout: fixed sidebar + main content offset */
+.page .navbar-vertical.position-fixed {
+	top: 0;
+	bottom: 0;
+	left: 0;
+	z-index: 1030;
+}
+.page .navbar-vertical.position-fixed ~ .page-wrapper {
+	margin-left: var(--tblr-navbar-vertical-width, 15rem);
+}
 
 a {
 	color: var(--pgw-link);
@@ -93,6 +107,23 @@ tbody tr:hover {
 	background-color: var(--pgw-title-hover-bg);
 }
 
+/* Vertical navbar: size inline nav icons */
+.navbar-vertical .nav-link-icon {
+	display: inline-flex;
+	align-items: center;
+	justify-content: center;
+	width: 1.5rem;
+	height: 1.5rem;
+}
+.navbar-vertical .nav-link-icon svg {
+	width: 1.25rem;
+	height: 1.25rem;
+}
+.navbar-user .avatar svg {
+	width: 1.25rem;
+	height: 1.25rem;
+}
+
 /* Diff/status helpers (use var(--pgw-add-*) etc. in markup if needed) */
 .diff-add { color: var(--pgw-add-fg); background-color: var(--pgw-add-bg); }
 .diff-rem { color: var(--pgw-rem-fg); background-color: var(--pgw-rem-bg); }
diff --git a/pygitweb/templates/preamble.html b/pygitweb/templates/preamble.html
index 49dfe43..74e9894 100644
--- a/pygitweb/templates/preamble.html
+++ b/pygitweb/templates/preamble.html
@@ -1,9 +1,73 @@
-<!DOCTYPE html><html class="theme-{{theme}}"><head><title>{{title}}</title>
+<!DOCTYPE html><html class="theme-{{theme}}"><head><title>{{title | default('DistGit')}}</title>
+<link rel="icon" href="static/logo.svg" type="image/svg+xml">
 <script id="Highlight-script" async src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
 <script id="MathJax-script" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-chtml.min.js"></script>
 <script id="GraphViz-script" async src="https://cdnjs.cloudflare.com/ajax/libs/viz.js/1.8.2/viz.js"></script>
 <link rel="preconnect" href="https://fonts.googleapis.com">
 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
 <link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&family=Fira+Mono:wght@400;500;700&family=Fira+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
+<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/core@1.0.0-beta17/dist/css/tabler.min.css">
 <link rel="stylesheet" href="static/main.css"/>
-</head><body>
\ No newline at end of file
+</head><body>
+<div class="page">
+  <aside class="navbar navbar-vertical navbar-expand-sm position-fixed" data-bs-theme="{{ theme }}">
+    <div class="container-fluid d-flex flex-column vh-100 overflow-y-auto">
+      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#sidebar-menu" aria-controls="sidebar-menu" aria-expanded="false" aria-label="Toggle navigation">
+        <span class="navbar-toggler-icon"></span>
+      </button>
+      <h1 class="navbar-brand navbar-brand-autodark py-3">
+        <a href="/" class="d-flex align-items-center text-reset">
+          <img src="static/logo.svg" width="32" height="32" alt="Logo" class="navbar-brand-image me-2" style="object-fit: contain;">
+          <span class="nav-link-title">{{ site_name | default('DistGit') }}</span>
+        </a>
+      </h1>
+      <div class="collapse navbar-collapse flex-grow-1" id="sidebar-menu">
+        <ul class="navbar-nav pt-lg-3">
+          <li class="nav-item">
+            <a class="nav-link" href="/">
+              <span class="nav-link-icon"><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-folder" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 4h4l3 3h7a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-11a2 2 0 0 1 2 -2z" /></svg></span>
+              <span class="nav-link-title">Projects</span>
+            </a>
+          </li>
+          <li class="nav-item">
+            <a class="nav-link" href="#">
+              <span class="nav-link-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-activity"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M3 12h4l3 8l4 -16l3 8h4" /></svg></span>
+              <span class="nav-link-title">Activity</span>
+            </a>
+          </li>
+          <li class="nav-item">
+            <a class="nav-link" href="#">
+              <span class="nav-link-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-messages"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M21 14l-3 -3h-7a1 1 0 0 1 -1 -1v-6a1 1 0 0 1 1 -1h9a1 1 0 0 1 1 1v10" /><path d="M14 15v2a1 1 0 0 1 -1 1h-7l-3 3v-10a1 1 0 0 1 1 -1h2" /></svg></span>
+              <span class="nav-link-title">Discussions</span>
+            </a>
+          </li>
+          <li class="nav-item">
+            <a class="nav-link" href="#">
+              <span class="nav-link-icon"><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-checklist" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 11l3 3l8 -8" /><path d="M20 12v6a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h9" /></svg></span>
+              <span class="nav-link-title">Tasks</span>
+            </a>
+          </li>
+          <li class="nav-item">
+            <a class="nav-link" href="#">
+              <span class="nav-link-icon"><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-settings" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065z" /><path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" /></svg></span>
+              <span class="nav-link-title">Settings</span>
+            </a>
+          </li>
+        </ul>
+      </div>
+      <div class="navbar-user mt-auto py-3 px-3 border-top" id="navbar-user" data-logged-in="false">
+        <div class="d-flex align-items-center text-reset text-decoration-none">
+          <span class="avatar avatar-sm bg-secondary me-2 d-flex align-items-center justify-content-center">
+            <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-user" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0" /><path d="M6 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2" /></svg>
+          </span>
+          <div class="d-none d-xl-block">
+            <div class="navbar-user-name text-body">Guest</div>
+            <div class="navbar-user-meta text-muted small">Not signed in</div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </aside>
+  <div class="page-wrapper">
+    <div class="page-body">
+      <div class="container-xl">
