diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html
index 40f2da5..a22063b 100644
--- a/layouts/_default/baseof.html
+++ b/layouts/_default/baseof.html
@@ -1,12 +1,7 @@
-
-
- {{ block "title" . }}{{ .Title }} — {{ .Site.Title }}{{ end }}
- {{ $css := resources.Get "css/asw-built.css" | minify | fingerprint }}
-
- {{ block "head" . }}{{ end }}
+ {{- partial "head.html" . -}}
{{ block "main" . }}{{ end }}
diff --git a/layouts/_default/single.html b/layouts/_default/single.html
index 60f14a3..8cff90b 100644
--- a/layouts/_default/single.html
+++ b/layouts/_default/single.html
@@ -1,36 +1,3 @@
-{{ define "head" }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{{ end }}
-
{{ define "main" }}
{{ partial "nav.html" . }}
diff --git a/layouts/partials/head.html b/layouts/partials/head.html
new file mode 100644
index 0000000..ee55932
--- /dev/null
+++ b/layouts/partials/head.html
@@ -0,0 +1,26 @@
+
+
+
+
+ {{- if .IsHome -}}
+ {{ .Site.Title }}
+ {{- else -}}
+ {{ .Title }} · {{ .Site.Title }}
+ {{- end -}}
+
+{{- with .Description }}{{- end }}
+{{- if not .Description }}{{- with .Site.Params.description }}{{- end }}{{- end }}
+
+{{- /* ── Meta partials ─────────────────────────────────────────── */}}
+{{- partial "meta/seo.html" . -}}
+{{- partial "meta/og.html" . -}}
+{{- partial "meta/ai-disclosure.html" . -}}
+{{- partial "meta/json-ld.html" . -}}
+
+{{- /* ── CSS — fingerprinted via Hugo Pipes ─────────────────────── */}}
+{{ $css := resources.Get "css/asw-built.css" | minify | fingerprint }}
+
+
+{{- range .AlternativeOutputFormats -}}
+
+{{- end }}
diff --git a/layouts/partials/meta/ai-disclosure.html b/layouts/partials/meta/ai-disclosure.html
new file mode 100644
index 0000000..5b1fb7e
--- /dev/null
+++ b/layouts/partials/meta/ai-disclosure.html
@@ -0,0 +1,25 @@
+{{- /*
+ partials/meta/ai-disclosure.html — AI-generated content disclosure
+
+ Emits the proposed W3C/WHATWG AI content disclosure meta tag and the
+ corresponding HTTP-equiv header that satisfies EU AI Act Article 50
+ obligations for AI-generated/AI-assisted web content.
+
+ The disclosure level is controlled per-page via front matter:
+ ai_content: "generated" — fully AI-generated content
+ ai_content: "assisted" — human-written with AI assistance (default)
+ ai_content: "reviewed" — AI-generated, human-reviewed and edited
+ ai_content: "none" — no AI involvement (suppresses the tag)
+
+ Site-wide default in hugo.toml:
+ [params]
+ ai_content = "assisted" # default for all pages
+
+ Reference:
+ https://github.com/nickvdyck/ai-content-disclosure
+ EU AI Act Article 50 (transparency obligations, Chapter IV)
+*/ -}}
+{{- $level := or .Params.ai_content .Site.Params.ai_content "assisted" -}}
+{{- if ne $level "none" -}}
+
+{{- end }}
diff --git a/layouts/partials/meta/json-ld.html b/layouts/partials/meta/json-ld.html
new file mode 100644
index 0000000..cb20176
--- /dev/null
+++ b/layouts/partials/meta/json-ld.html
@@ -0,0 +1,101 @@
+{{- /*
+ partials/meta/json-ld.html — JSON-LD structured data (Schema.org)
+
+ Emits one " ($data | jsonify) | safeHTML -}}
+
+{{- else -}}
+
+{{- /* ── Article / TechArticle / WebPage ─────────────────────────── */}}
+{{- $schemaType := "WebPage" -}}
+{{- if and .IsPage (not .IsSection) -}}
+ {{- if eq .Params.type "docs" -}}
+ {{- $schemaType = "TechArticle" -}}
+ {{- else if .Date -}}
+ {{- $schemaType = "Article" -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $publisher := dict "@type" "Organization" "name" $author -}}
+{{- with $logo -}}
+ {{- $publisher = merge $publisher (dict "logo" (dict "@type" "ImageObject" "url" (. | absURL))) -}}
+{{- end -}}
+
+{{- $data := dict
+ "@context" "https://schema.org"
+ "@type" $schemaType
+ "headline" .Title
+ "description" $desc
+ "url" .Permalink
+ "author" $publisher
+ "publisher" $publisher
+-}}
+
+{{- with $image -}}
+ {{- $data = merge $data (dict "image" (. | absURL)) -}}
+{{- end -}}
+
+{{- if and .Date (not .IsSection) -}}
+ {{- $data = merge $data (dict
+ "datePublished" (.Date.Format "2006-01-02T15:04:05Z07:00")
+ "dateModified" (.Lastmod.Format "2006-01-02T15:04:05Z07:00")
+ ) -}}
+{{- end -}}
+
+{{- /* BreadcrumbList: .Ancestors is nearest→root; iterate by index to reverse */}}
+{{- with .Ancestors -}}
+ {{- $ancs := . -}}
+ {{- $len := len $ancs -}}
+ {{- $items := slice -}}
+ {{- range $i := seq $len -}}
+ {{- $a := index $ancs (sub $len $i) -}}
+ {{- $item := dict "@type" "ListItem" "position" $i "name" $a.Title "item" $a.Permalink -}}
+ {{- $items = $items | append $item -}}
+ {{- end -}}
+ {{- $last := dict "@type" "ListItem" "position" (add $len 1) "name" $.Title "item" $.Permalink -}}
+ {{- $items = $items | append $last -}}
+ {{- $crumb := dict "@type" "BreadcrumbList" "itemListElement" $items -}}
+ {{- $data = merge $data (dict "breadcrumb" $crumb) -}}
+{{- end -}}
+
+{{- printf "" ($data | jsonify) | safeHTML -}}
+{{- end }}
diff --git a/layouts/partials/meta/og.html b/layouts/partials/meta/og.html
new file mode 100644
index 0000000..61828a6
--- /dev/null
+++ b/layouts/partials/meta/og.html
@@ -0,0 +1,41 @@
+{{- /*
+ partials/meta/og.html — Open Graph + Twitter Card meta tags
+
+ og:title Page title (site title for home page)
+ og:description .Description → .Site.Params.description → ""
+ og:url .Permalink
+ og:type "website" (home) | "article" (everything else)
+ og:site_name .Site.Title
+ og:image .Params.image → .Site.Params.og_image → absent
+ twitter:card "summary_large_image" when image present, else "summary"
+ twitter:site .Site.Params.twitter (optional @handle)
+
+ Configure in hugo.toml:
+ [params]
+ og_image = "/images/og-default.png" # fallback OG image
+ twitter = "@yourhandle" # omit if not on Twitter/X
+*/ -}}
+{{- $title := cond .IsHome .Site.Title (printf "%s · %s" .Title .Site.Title) -}}
+{{- $desc := or .Description .Site.Params.description "" -}}
+{{- $image := or .Params.image .Site.Params.og_image "" -}}
+{{- $type := cond .IsHome "website" "article" -}}
+
+
+
+
+
+
+{{- with $image }}
+
+{{- end }}
+
+{{- /* Twitter / X Card */}}
+
+
+
+{{- with $image }}
+
+{{- end }}
+{{- with .Site.Params.twitter }}
+
+{{- end }}
diff --git a/layouts/partials/meta/seo.html b/layouts/partials/meta/seo.html
new file mode 100644
index 0000000..6e896c7
--- /dev/null
+++ b/layouts/partials/meta/seo.html
@@ -0,0 +1,16 @@
+{{- /*
+ partials/meta/seo.html — canonical URL + robots directives
+
+ Outputs:
+ Always emitted; uses .Permalink (absolute).
+ "noindex, nofollow" on draft/future pages,
+ "index, follow" otherwise.
+
+ No params required. Works from any page context.
+*/ -}}
+
+{{- if or .Draft (gt .Date now) }}
+
+{{- else }}
+
+{{- end }}
diff --git a/layouts/partials/tag-nav.html b/layouts/partials/tag-nav.html
new file mode 100644
index 0000000..bc11797
--- /dev/null
+++ b/layouts/partials/tag-nav.html
@@ -0,0 +1,21 @@
+{{- /*
+ tag-nav.html — renders all site tags as a navigable tag cloud.
+
+ Usage in a layout:
+ {{ partial "tag-nav.html" . }}
+
+ Outputs: