` `` -}}
+ {{- $tocMarkup = replace $tocMarkup `` `
` -}}
+ {{- end -}}
+
+ {{- if $hasDossierSummary -}}
+
+ Dossier
+
+ {{- $dossierSummary | safeHTML -}}
+
+
+ {{- end -}}
+ {{- if $hasTOC -}}
+
+ Sommaire
+
+
Sommaire
+ {{- $tocMarkup | safeHTML -}}
+
+
+ {{- end -}}
+
+{{- end -}}
diff --git a/themes/2026/layouts/_partials/breadcrumbs.html b/themes/2026/layouts/_partials/breadcrumbs.html
new file mode 100644
index 00000000..993d3d63
--- /dev/null
+++ b/themes/2026/layouts/_partials/breadcrumbs.html
@@ -0,0 +1,26 @@
+{{- $page := . -}}
+{{- with .Page }}{{ $page = . }}{{ end -}}
+{{- $trail := slice -}}
+{{- if $page -}}
+ {{- range $page.Ancestors.Reverse -}}
+ {{- if ne .RelPermalink "/" -}}
+ {{- $trail = $trail | append . -}}
+ {{- end -}}
+ {{- end -}}
+ {{- if eq $page.Kind "term" -}}
+ {{- with site.GetPage "taxonomy" $page.Data.Plural -}}
+ {{- if not (in $trail .) -}}
+ {{- $trail = $trail | append . -}}
+ {{- end -}}
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
+{{- if gt (len $trail) 0 -}}
+
+
+ {{- range $trail -}}
+ {{ with .LinkTitle }}{{ . }}{{ else }}{{ .Title }}{{ end }}
+ {{- end -}}
+
+
+{{- end -}}
diff --git a/themes/2026/layouts/_partials/card.html b/themes/2026/layouts/_partials/card.html
new file mode 100644
index 00000000..45f53555
--- /dev/null
+++ b/themes/2026/layouts/_partials/card.html
@@ -0,0 +1,182 @@
+{{- $page := . -}}
+{{- $showSection := true -}}
+{{- $linkSection := true -}}
+{{- $showMeta := true -}}
+{{- $showDossierBeforeTitle := false -}}
+{{- $showInterestingLinksMeta := false -}}
+{{- $thumbnailSize := "large" -}}
+{{- $externalLinksReport := dict -}}
+
+{{- if reflect.IsMap . -}}
+ {{- if isset . "Page" -}}
+ {{- $page = index . "Page" -}}
+ {{- end -}}
+ {{- if isset . "ShowSection" -}}
+ {{- $showSection = index . "ShowSection" -}}
+ {{- end -}}
+ {{- if isset . "LinkSection" -}}
+ {{- $linkSection = index . "LinkSection" -}}
+ {{- end -}}
+ {{- if isset . "ShowMeta" -}}
+ {{- $showMeta = index . "ShowMeta" -}}
+ {{- end -}}
+ {{- if isset . "ShowDossierBeforeTitle" -}}
+ {{- $showDossierBeforeTitle = index . "ShowDossierBeforeTitle" -}}
+ {{- end -}}
+ {{- if isset . "ShowInterestingLinksMeta" -}}
+ {{- $showInterestingLinksMeta = index . "ShowInterestingLinksMeta" -}}
+ {{- end -}}
+ {{- if isset . "ThumbnailSize" -}}
+ {{- $thumbnailSize = index . "ThumbnailSize" -}}
+ {{- end -}}
+ {{- if isset . "ExternalLinksReport" -}}
+ {{- $externalLinksReport = index . "ExternalLinksReport" -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $thumbnailTransform := "700x394" -}}
+{{- if eq $thumbnailSize "small" -}}
+ {{- $thumbnailTransform = "340x191" -}}
+{{- else if eq $thumbnailSize "spotlight" -}}
+ {{- $thumbnailTransform = "900x506" -}}
+{{- end -}}
+
+{{- $coverPath := $page.Params.cover -}}
+{{- $image := false -}}
+{{- if $coverPath -}}
+ {{- if strings.HasSuffix $coverPath ".yaml" -}}
+ {{- $coverAbsPath := printf "%s%s" $page.File.Dir $coverPath -}}
+ {{- $coverRaw := readFile $coverAbsPath -}}
+ {{- $coverData := $coverRaw | transform.Unmarshal -}}
+ {{- with $coverData.file -}}
+ {{- $image = $page.Resources.GetMatch . -}}
+ {{- end -}}
+ {{- else -}}
+ {{- $image = $page.Resources.GetMatch $coverPath -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $dossierTitle := "" -}}
+{{- $dossierFirstPage := false -}}
+{{- with $page.Params.dossier -}}
+ {{- with index . 0 -}}
+ {{- $dossierTitle = . -}}
+ {{- if $showDossierBeforeTitle -}}
+ {{- $dossierFirstPage = partial "dossier-first-page.html" $page -}}
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $originLink := "" -}}
+{{- $originHost := "" -}}
+{{- $statusTone := "unknown" -}}
+{{- $statusLabel := "État inconnu" -}}
+{{- $statusTitle := "" -}}
+{{- $statusChecked := "" -}}
+{{- if and $showMeta $showInterestingLinksMeta -}}
+ {{- with $page.Params.links -}}
+ {{- range . -}}
+ {{- if and (eq $originLink "") (not .archive) -}}
+ {{- with .url -}}
+ {{- $originLink = . -}}
+ {{- end -}}
+ {{- end -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- with partial "external-link-status.html" (dict "URL" $originLink "Report" $externalLinksReport) -}}
+ {{- with index . "Host" -}}
+ {{- $originHost = . -}}
+ {{- end -}}
+ {{- with index . "Tone" -}}
+ {{- $statusTone = . -}}
+ {{- end -}}
+ {{- with index . "Label" -}}
+ {{- $statusLabel = . -}}
+ {{- end -}}
+ {{- with index . "Title" -}}
+ {{- $statusTitle = . -}}
+ {{- end -}}
+ {{- with index . "CheckedAt" -}}
+ {{- $statusChecked = . -}}
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
+
+
+ {{- if $showDossierBeforeTitle -}}
+
+ {{- else -}}
+
+
+ {{- with $image -}}
+ {{- $resized := .Fill $thumbnailTransform -}}
+
+ {{- end -}}
+
+ {{ $page.Title }}
+
+ {{- end -}}
+ {{- with $page.Summary -}}
+ {{ . | plainify | truncate 180 }}
+ {{- end -}}
+ {{- if $showMeta -}}
+ {{- if $showInterestingLinksMeta -}}
+
+ {{- else -}}
+
+ {{- with $page.Date -}}
+ {{ . | time.Format "02/01/2006" }}
+ {{- end -}}
+ {{- if $showSection -}}
+ {{- with $page.Parent -}}
+ ·
+ {{- if $linkSection -}}
+ {{ with .LinkTitle }}{{ . }}{{ else }}{{ .Title }}{{ end }}
+ {{- else -}}
+ {{ with .LinkTitle }}{{ . }}{{ else }}{{ .Title }}{{ end }}
+ {{- end -}}
+ {{- end -}}
+ {{- end -}}
+ {{- if and (not $showDossierBeforeTitle) $dossierTitle -}}
+ ·
+ {{ $dossierTitle }}
+ {{- end -}}
+ {{- if and (not $page.IsSection) (ge $page.ReadingTime 5) -}}
+ · {{ $page.ReadingTime }} min
+ {{- end -}}
+
+ {{- end -}}
+ {{- end -}}
+
diff --git a/themes/2026/layouts/_partials/dossier-first-page.html b/themes/2026/layouts/_partials/dossier-first-page.html
new file mode 100644
index 00000000..d0cb5a9c
--- /dev/null
+++ b/themes/2026/layouts/_partials/dossier-first-page.html
@@ -0,0 +1,31 @@
+{{- $page := . -}}
+{{- $firstPage := false -}}
+
+{{- with $page.Params.dossier -}}
+ {{- $dossierID := index . 0 -}}
+ {{- if $dossierID -}}
+ {{- $group := where site.RegularPages "Params.dossier" "intersect" (slice $dossierID) -}}
+ {{- if gt (len $group) 0 -}}
+ {{- $weighted := slice -}}
+ {{- range $group -}}
+ {{- if isset .Params "weight" -}}
+ {{- $weighted = $weighted | append . -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- $candidates := $group -}}
+ {{- if gt (len $weighted) 0 -}}
+ {{- $sortedByWeight := sort $weighted "Weight" "asc" -}}
+ {{- $minWeight := (index $sortedByWeight 0).Weight -}}
+ {{- $candidates = where $sortedByWeight "Weight" $minWeight -}}
+ {{- end -}}
+
+ {{- $sortedByDate := sort $candidates "Date" "asc" -}}
+ {{- $firstDate := (index $sortedByDate 0).Date -}}
+ {{- $sameDate := where $sortedByDate "Date" $firstDate -}}
+ {{- $firstPage = index (sort $sameDate "RelPermalink" "asc") 0 -}}
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
+
+{{- return $firstPage -}}
diff --git a/themes/2026/layouts/_partials/dossier-summary.html b/themes/2026/layouts/_partials/dossier-summary.html
new file mode 100644
index 00000000..720bf4be
--- /dev/null
+++ b/themes/2026/layouts/_partials/dossier-summary.html
@@ -0,0 +1,33 @@
+{{- $current := . -}}
+{{- if reflect.IsMap . -}}
+ {{- with index . "Page" -}}
+ {{- $current = . -}}
+ {{- end -}}
+{{- end -}}
+
+{{- with $current.Params.dossier -}}
+ {{- $dossierID := index . 0 -}}
+ {{- if $dossierID -}}
+ {{- $allPages := site.RegularPages -}}
+ {{- $filtered := where $allPages "Params.dossier" "intersect" (slice $dossierID) -}}
+ {{- $sorted := sort $filtered "RelPermalink" "asc" -}}
+ {{- $sorted = sort $sorted "Date" "asc" -}}
+ {{- $sorted = sort $sorted "Weight" "asc" -}}
+ {{- if gt (len $sorted) 1 -}}
+
+ {{ $dossierID }}
+
+ {{- range $sorted -}}
+
+ {{- if eq .Permalink $current.Permalink -}}
+ {{ .Title }}
+ {{- else -}}
+ {{ .Title }}
+ {{- end -}}
+
+ {{- end -}}
+
+
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
diff --git a/themes/2026/layouts/_partials/external-link-status.html b/themes/2026/layouts/_partials/external-link-status.html
new file mode 100644
index 00000000..75da4594
--- /dev/null
+++ b/themes/2026/layouts/_partials/external-link-status.html
@@ -0,0 +1,128 @@
+{{- $url := "" -}}
+{{- $report := dict -}}
+{{- if reflect.IsMap . -}}
+ {{- with index . "URL" -}}
+ {{- $url = . -}}
+ {{- end -}}
+ {{- with index . "Report" -}}
+ {{- $report = . -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $entries := default (dict) (index $report "entries") -}}
+{{- $deadLinks := default (slice) (index $report "links") -}}
+
+{{- $host := "" -}}
+{{- with $url -}}
+ {{- $host = . | replaceRE "^https?://([^/]+).*$" "$1" | replaceRE "^www\\." "" -}}
+{{- end -}}
+
+{{- $lookupURLs := slice -}}
+{{- with $url -}}
+ {{- $lookupURLs = $lookupURLs | append . -}}
+ {{- if strings.HasSuffix . "/" -}}
+ {{- $withoutSlash := strings.TrimSuffix "/" . -}}
+ {{- if ne $withoutSlash . -}}
+ {{- $lookupURLs = $lookupURLs | append $withoutSlash -}}
+ {{- end -}}
+ {{- else -}}
+ {{- $lookupURLs = $lookupURLs | append (printf "%s/" .) -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $entry := dict -}}
+{{- range $lookupURLs -}}
+ {{- if and (eq (len $entry) 0) (isset $entries .) -}}
+ {{- $entry = index $entries . -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $deadInfo := dict -}}
+{{- range $lookupURLs -}}
+ {{- if eq (len $deadInfo) 0 -}}
+ {{- $matches := where $deadLinks "url" . -}}
+ {{- if gt (len $matches) 0 -}}
+ {{- $deadInfo = index $matches 0 -}}
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $statusCode := 0 -}}
+{{- $statusRaw := "" -}}
+{{- $statusChecked := "" -}}
+{{- $statusErrorType := "" -}}
+{{- $statusTone := "unknown" -}}
+{{- $statusLabel := "État inconnu" -}}
+{{- $statusTitle := "" -}}
+
+{{- if gt (len $entry) 0 -}}
+ {{- with index $entry "status" -}}
+ {{- $statusString := printf "%v" . -}}
+ {{- if gt (len (findRE "^[0-9]+$" $statusString)) 0 -}}
+ {{- $statusCode = int $statusString -}}
+ {{- else -}}
+ {{- $statusRaw = $statusString -}}
+ {{- end -}}
+ {{- end -}}
+ {{- with index $entry "checkedAt" -}}
+ {{- $statusChecked = . -}}
+ {{- end -}}
+ {{- with index $entry "errorType" -}}
+ {{- $statusErrorType = . -}}
+ {{- end -}}
+{{- end -}}
+
+{{- if and (eq $statusCode 0) (eq $statusRaw "") (gt (len $deadInfo) 0) -}}
+ {{- with index $deadInfo "status" -}}
+ {{- $statusString := printf "%v" . -}}
+ {{- if gt (len (findRE "^[0-9]+$" $statusString)) 0 -}}
+ {{- $statusCode = int $statusString -}}
+ {{- else -}}
+ {{- $statusRaw = $statusString -}}
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
+
+{{- if and (eq $statusErrorType "") (gt (len $deadInfo) 0) -}}
+ {{- with index $deadInfo "errorType" -}}
+ {{- $statusErrorType = . -}}
+ {{- end -}}
+{{- end -}}
+
+{{- if gt $statusCode 0 -}}
+ {{- if lt $statusCode 400 -}}
+ {{- $statusTone = "ok" -}}
+ {{- $statusLabel = printf "OK %d" $statusCode -}}
+ {{- else if lt $statusCode 500 -}}
+ {{- $statusTone = "warn" -}}
+ {{- $statusLabel = printf "Erreur %d" $statusCode -}}
+ {{- $statusTitle = printf "Réponse HTTP %d lors de la dernière vérification" $statusCode -}}
+ {{- else -}}
+ {{- $statusTone = "dead" -}}
+ {{- $statusLabel = printf "Erreur %d" $statusCode -}}
+ {{- $statusTitle = printf "Réponse HTTP %d lors de la dernière vérification" $statusCode -}}
+ {{- end -}}
+{{- else if ne $statusRaw "" -}}
+ {{- $statusTone = "dead" -}}
+ {{- $statusLabel = "Erreur" -}}
+ {{- $statusTitle = printf "Erreur %s lors de la dernière vérification" (upper $statusRaw) -}}
+{{- else if ne $statusErrorType "" -}}
+ {{- $statusTone = "dead" -}}
+ {{- $statusLabel = "Erreur" -}}
+ {{- $statusTitle = printf "Erreur %s lors de la dernière vérification" (upper $statusErrorType) -}}
+{{- end -}}
+
+{{- if and (ne $statusTitle "") (ne $statusChecked "") -}}
+ {{- $statusTitle = printf "%s (vérifié le %s)" $statusTitle ((time $statusChecked) | time.Format "02/01/2006") -}}
+{{- end -}}
+
+{{- return dict
+ "Host" $host
+ "Code" $statusCode
+ "Raw" $statusRaw
+ "CheckedAt" $statusChecked
+ "ErrorType" $statusErrorType
+ "Tone" $statusTone
+ "Label" $statusLabel
+ "Title" $statusTitle
+-}}
diff --git a/themes/2026/layouts/_partials/footer.html b/themes/2026/layouts/_partials/footer.html
new file mode 100644
index 00000000..5be7565e
--- /dev/null
+++ b/themes/2026/layouts/_partials/footer.html
@@ -0,0 +1,37 @@
+
diff --git a/themes/2026/layouts/_partials/head.html b/themes/2026/layouts/_partials/head.html
new file mode 100644
index 00000000..d62618cc
--- /dev/null
+++ b/themes/2026/layouts/_partials/head.html
@@ -0,0 +1,14 @@
+
+
+{{ if .IsHome }}{{ site.Title }}{{ else }}{{ printf "%s | %s" .Title site.Title }}{{ end }}
+{{ with .Description }}
+
+{{ else }}
+{{ with site.Params.description }}
+
+{{ end }}
+{{ end }}
+
+
+
+{{ partialCached "head/css.html" . }}
diff --git a/themes/2026/layouts/_partials/head/css.html b/themes/2026/layouts/_partials/head/css.html
new file mode 100644
index 00000000..1cb9ed46
--- /dev/null
+++ b/themes/2026/layouts/_partials/head/css.html
@@ -0,0 +1,9 @@
+{{- $mainCSS := resources.Get "css/index.css" | postCSS (dict "inlineImports" true) -}}
+{{- $bundle := slice $mainCSS | resources.Concat "css/bundle.css" -}}
+{{- if eq hugo.Environment "development" -}}
+
+{{- else -}}
+{{- with $bundle | minify | fingerprint -}}
+
+{{- end -}}
+{{- end -}}
diff --git a/themes/2026/layouts/_partials/header-brand.html b/themes/2026/layouts/_partials/header-brand.html
new file mode 100644
index 00000000..a7e48b59
--- /dev/null
+++ b/themes/2026/layouts/_partials/header-brand.html
@@ -0,0 +1,3 @@
+
+ {{ partialCached "site-title.html" (dict "Site" .) .Title (.Params.logo | default "logo-large.png") }}
+
diff --git a/themes/2026/layouts/_partials/hero-page.html b/themes/2026/layouts/_partials/hero-page.html
new file mode 100644
index 00000000..4ba8cb0b
--- /dev/null
+++ b/themes/2026/layouts/_partials/hero-page.html
@@ -0,0 +1,14 @@
+
diff --git a/themes/2026/layouts/_partials/hero-section.html b/themes/2026/layouts/_partials/hero-section.html
new file mode 100644
index 00000000..bb01875a
--- /dev/null
+++ b/themes/2026/layouts/_partials/hero-section.html
@@ -0,0 +1,5 @@
+
+ {{ partialCached "header-brand.html" .Site .Site.Title (.Site.Params.logo | default "logo-large.png") }}
+ {{ partial "breadcrumbs.html" . }}
+ {{ .Title }}
+
diff --git a/themes/2026/layouts/_partials/hero.html b/themes/2026/layouts/_partials/hero.html
new file mode 100644
index 00000000..00a80cfa
--- /dev/null
+++ b/themes/2026/layouts/_partials/hero.html
@@ -0,0 +1,3 @@
+
+ {{ partialCached "header-brand.html" .Site .Site.Title (.Site.Params.logo | default "logo-large.png") }}
+
diff --git a/themes/2026/layouts/_partials/is-dossier-lead.html b/themes/2026/layouts/_partials/is-dossier-lead.html
new file mode 100644
index 00000000..8d9bf622
--- /dev/null
+++ b/themes/2026/layouts/_partials/is-dossier-lead.html
@@ -0,0 +1,30 @@
+{{- $page := . -}}
+{{- $isLead := true -}}
+{{- with $page.Params.dossier -}}
+ {{- $dossierID := index . 0 -}}
+ {{- if $dossierID -}}
+ {{- $group := where site.RegularPages "Params.dossier" "intersect" (slice $dossierID) -}}
+ {{- if gt (len $group) 1 -}}
+ {{- $weighted := slice -}}
+ {{- range $group -}}
+ {{- if isset .Params "weight" -}}
+ {{- $weighted = $weighted | append . -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- $candidates := $group -}}
+ {{- if gt (len $weighted) 0 -}}
+ {{- $sortedByWeight := sort $weighted "Weight" "asc" -}}
+ {{- $minWeight := (index $sortedByWeight 0).Weight -}}
+ {{- $candidates = where $sortedByWeight "Weight" $minWeight -}}
+ {{- end -}}
+
+ {{- $sortedByDate := sort $candidates "Date" "asc" -}}
+ {{- $firstDate := (index $sortedByDate 0).Date -}}
+ {{- $sameDate := where $sortedByDate "Date" $firstDate -}}
+ {{- $firstPage := index (sort $sameDate "RelPermalink" "asc") 0 -}}
+ {{- $isLead = eq $firstPage.File.Path $page.File.Path -}}
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
+{{- if $isLead -}}true{{- end -}}
diff --git a/themes/2026/layouts/_partials/keywords.html b/themes/2026/layouts/_partials/keywords.html
new file mode 100644
index 00000000..3b5b26f8
--- /dev/null
+++ b/themes/2026/layouts/_partials/keywords.html
@@ -0,0 +1,25 @@
+{{- $items := . -}}
+{{- if gt (len $items) 0 -}}
+
+ {{- $type := printf "%T" $items -}}
+ {{- $isTextList := hasPrefix $type "[]string" -}}
+ {{- if $isTextList -}}
+ {{- range sort $items -}}
+ {{ . }}
+ {{- end -}}
+ {{- else -}}
+ {{- range sort $items "Title" -}}
+ {{- $itemType := printf "%T" . -}}
+ {{- $isPage := or (strings.HasPrefix $itemType "*hugolib.") (strings.HasPrefix $itemType "page.") -}}
+ {{- if $isPage -}}
+
+ {{ with .LinkTitle }}{{ . }}{{ else }}{{ .Title }}{{ end }}
+ {{ with .Pages }}{{ len . }} {{ else }}0 {{ end }}
+
+ {{- else -}}
+ {{ . }}
+ {{- end -}}
+ {{- end -}}
+ {{- end -}}
+
+{{- end -}}
diff --git a/themes/2026/layouts/_partials/liens-morts/report.html b/themes/2026/layouts/_partials/liens-morts/report.html
new file mode 100644
index 00000000..c4d5be48
--- /dev/null
+++ b/themes/2026/layouts/_partials/liens-morts/report.html
@@ -0,0 +1,76 @@
+{{- $defaultReportPath := "tools/cache/external_links.yaml" -}}
+{{- $reportPath := default $defaultReportPath .ReportPath -}}
+{{- $report := default (dict) .Report -}}
+{{- if or (eq (len $report) 0) (not (isset $report "links")) -}}
+ {{- if fileExists $reportPath -}}
+ {{- $report = transform.Unmarshal (readFile $reportPath) -}}
+ {{- else -}}
+ {{- warnf "Rapport des liens morts introuvable (%s)" $reportPath -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $allPages := where site.Pages ".File" "!=" nil -}}
+{{- $links := default (slice) $report.links -}}
+{{- $generatedLabel := "" -}}
+{{- with $report.generatedAt -}}
+ {{- $generatedLabel = (time .).Format "02/01/2006" -}}
+{{- end -}}
+
+
+ Dernière mise à jour
+ {{ $generatedLabel }}
+ Liens morts détectés
+ {{ len $links }}
+
+
+
+
+
+ URL
+ Emplacements
+ Statut
+
+
+
+ {{- range $links -}}
+
+ {{ .url }}
+
+ {{- $locations := default (slice) .locations -}}
+ {{- if gt (len $locations) 0 -}}
+ {{- range $locations -}}
+ {{- $file := .file -}}
+ {{- $line := .line -}}
+ {{- $pagePath := .page -}}
+ {{- $matchedPage := false -}}
+ {{- if $pagePath -}}
+ {{- $candidate := site.GetPage $pagePath -}}
+ {{- if $candidate -}}
+ {{- $matchedPage = $candidate -}}
+ {{- end -}}
+ {{- end -}}
+ {{- if and (not $matchedPage) $file -}}
+ {{- $normalized := replaceRE "^content/" "" $file -}}
+ {{- $candidates := where $allPages "File.Path" $normalized -}}
+ {{- if gt (len $candidates) 0 -}}
+ {{- $matchedPage = index $candidates 0 -}}
+ {{- end -}}
+ {{- end -}}
+ {{- if $matchedPage -}}
+ {{ $matchedPage.Title }}
+ {{- else if $file -}}
+ {{ $file }}{{ if $line }}:{{ $line }}{{ end }}
+ {{- else -}}
+ Emplacement inconnu
+ {{- end -}}
+
+ {{- end -}}
+ {{- else -}}
+ Emplacements inconnus
+ {{- end -}}
+
+ {{ .status }}
+
+ {{- end -}}
+
+
diff --git a/themes/2026/layouts/_partials/list-layout.html b/themes/2026/layouts/_partials/list-layout.html
new file mode 100644
index 00000000..df7a8968
--- /dev/null
+++ b/themes/2026/layouts/_partials/list-layout.html
@@ -0,0 +1,136 @@
+{{- $pages := .Pages -}}
+{{- $context := .Context -}}
+{{- $spotlightTitle := default "À la une" .SpotlightTitle -}}
+{{- $showInterestingLinksMeta := false -}}
+{{- $excludeInterestingLinks := false -}}
+{{- $groupBySubSections := false -}}
+{{- $subSections := slice -}}
+{{- $externalLinksReport := dict -}}
+{{- if fileExists "tools/cache/external_links.yaml" -}}
+ {{- $externalLinksReport = transform.Unmarshal (readFile "tools/cache/external_links.yaml") -}}
+{{- end -}}
+{{- with $context -}}
+ {{- if eq (strings.TrimSuffix "/" .RelPermalink) "/interets" -}}
+ {{- $excludeInterestingLinks = true -}}
+ {{- end -}}
+ {{- if and (eq .Kind "section") (gt (len .Sections) 0) -}}
+ {{- $groupBySubSections = true -}}
+ {{- range .Sections -}}
+ {{- $subSections = $subSections | append . -}}
+ {{- end -}}
+ {{- end -}}
+ {{- if eq .RelPermalink "/interets/liens-interessants/" -}}
+ {{- $showInterestingLinksMeta = true -}}
+ {{- end -}}
+{{- end -}}
+
+{{- if $excludeInterestingLinks -}}
+ {{- $filteredPages := slice -}}
+ {{- range $pages -}}
+ {{- if not (strings.HasPrefix .RelPermalink "/interets/liens-interessants/") -}}
+ {{- $filteredPages = $filteredPages | append . -}}
+ {{- end -}}
+ {{- end -}}
+ {{- $pages = $filteredPages -}}
+{{- end -}}
+{{- $spotlightPages := first 8 $pages -}}
+{{- $spotlightPermalinks := slice -}}
+{{- range $spotlightPages -}}
+ {{- $spotlightPermalinks = $spotlightPermalinks | append .RelPermalink -}}
+{{- end -}}
+{{- $remainingPages := $pages -}}
+{{- if gt (len $spotlightPermalinks) 0 -}}
+ {{- $remainingPages = where $pages "RelPermalink" "not in" $spotlightPermalinks -}}
+{{- end -}}
+{{- if gt (len $spotlightPages) 0 -}}
+
+
+ {{ $spotlightTitle }}
+
+ {{ partial "spotlight-block.html" (dict
+ "Cards" $spotlightPages
+ "FeedPages" $spotlightPages
+ "ShowFeedTitle" false
+ "FeedRich" true
+ "ShowSection" true
+ "AsideFirst" false
+ ) }}
+
+{{- end -}}
+
+{{- if gt (len $remainingPages) 0 -}}
+{{- if and $groupBySubSections (gt (len $subSections) 0) -}}
+{{- $groupedPermalinks := slice -}}
+{{- $groupedSections := slice -}}
+{{- range $subSections -}}
+ {{- $subSection := . -}}
+ {{- $subSectionPages := slice -}}
+ {{- range $remainingPages -}}
+ {{- if strings.HasPrefix .RelPermalink $subSection.RelPermalink -}}
+ {{- $subSectionPages = $subSectionPages | append . -}}
+ {{- $groupedPermalinks = $groupedPermalinks | append .RelPermalink -}}
+ {{- end -}}
+ {{- end -}}
+ {{- if gt (len $subSectionPages) 0 -}}
+ {{- $latestDateKey := "00000000000000" -}}
+ {{- with index $subSectionPages 0 -}}
+ {{- $latestDateKey = .Date.Format "20060102150405" -}}
+ {{- end -}}
+ {{- $groupedSections = $groupedSections | append (dict
+ "Section" $subSection
+ "Pages" $subSectionPages
+ "LatestDateKey" $latestDateKey
+ ) -}}
+ {{- end -}}
+{{- end -}}
+{{- $groupedSections = sort $groupedSections "LatestDateKey" "desc" -}}
+{{- range $groupedSections -}}
+ {{- $subSection := index . "Section" -}}
+ {{- $subSectionPages := index . "Pages" -}}
+
+
+ {{ with $subSection.LinkTitle }}{{ . }}{{ else }}{{ $subSection.Title }}{{ end }}
+
+ {{ partial "articles-list.html" (dict
+ "Pages" $subSectionPages
+ "Context" $context
+ "ShowDossierBeforeTitle" true
+ "ShowInterestingLinksMeta" $showInterestingLinksMeta
+ "ExternalLinksReport" $externalLinksReport
+ ) }}
+
+{{- end -}}
+
+{{- $ungroupedPages := $remainingPages -}}
+{{- if gt (len $groupedPermalinks) 0 -}}
+ {{- $ungroupedPages = where $remainingPages "RelPermalink" "not in" $groupedPermalinks -}}
+{{- end -}}
+{{- if gt (len $ungroupedPages) 0 -}}
+
+
+ {{ partial "articles-list.html" (dict
+ "Pages" $ungroupedPages
+ "Context" $context
+ "ShowDossierBeforeTitle" true
+ "ShowInterestingLinksMeta" $showInterestingLinksMeta
+ "ExternalLinksReport" $externalLinksReport
+ ) }}
+
+{{- end -}}
+{{- else -}}
+
+
+ {{ partial "articles-list.html" (dict
+ "Pages" $remainingPages
+ "Context" $context
+ "ShowDossierBeforeTitle" true
+ "ShowInterestingLinksMeta" $showInterestingLinksMeta
+ "ExternalLinksReport" $externalLinksReport
+ ) }}
+
+{{- end -}}
+{{- end -}}
diff --git a/themes/2026/layouts/_partials/media/render-image.html b/themes/2026/layouts/_partials/media/render-image.html
new file mode 100644
index 00000000..9ad07247
--- /dev/null
+++ b/themes/2026/layouts/_partials/media/render-image.html
@@ -0,0 +1,51 @@
+{{- $imgPath := .Destination -}}
+{{- $imgName := path.Base $imgPath | replaceRE "\\.[^.]+$" "" -}}
+{{- $dataPath := printf "data/images/%s.yaml" $imgName -}}
+{{- $dataFile := .Page.Resources.Get $dataPath -}}
+{{- $data := dict -}}
+{{- if $dataFile -}}
+ {{- $data = $dataFile.Content | transform.Unmarshal -}}
+{{- end -}}
+{{- $alt := .PlainText | default $data.title | default "" -}}
+{{- $title := .Title | default $data.title | default .Page.Title -}}
+{{- $description := $data.description | default "" -}}
+{{- $image := .Page.Resources.GetMatch $imgPath -}}
+{{- if not $image -}}
+ {{- return -}}
+{{- end -}}
+{{- $display := $image -}}
+{{- if and (ne $display.MediaType.SubType "svg") (gt $display.Height 810) -}}
+ {{- $display = $image.Resize "x810" -}}
+{{- end -}}
+{{- $metaTitle := index $data "title" -}}
+{{- $hasMeta := or $metaTitle (or $description (or $data.attribution $data.prompt)) -}}
+
+
+
+
+ {{- if $hasMeta -}}
+
+
+ {{- with $metaTitle -}}
+
{{ . | markdownify }}
+ {{- end -}}
+ {{- with $description -}}
+
{{ . | markdownify }}
+ {{- end -}}
+
+ {{- if or $data.attribution $data.prompt -}}
+
+ {{- end -}}
+
+ {{- end -}}
+
diff --git a/themes/2026/layouts/_partials/oeuvres/l-anankeisme.html b/themes/2026/layouts/_partials/oeuvres/l-anankeisme.html
new file mode 100644
index 00000000..1e4af0bc
--- /dev/null
+++ b/themes/2026/layouts/_partials/oeuvres/l-anankeisme.html
@@ -0,0 +1,18 @@
+
+
+
+ {{- $assetPath := "images/oeuvres/l-anankeisme.png" -}}
+ {{- $source := resources.Get $assetPath -}}
+ {{- if $source -}}
+ {{- $img := $source.Resize "320x" -}}
+
+ {{- end -}}
+
+ L'Anankéisme
+ L'Anankéisme propose un cadre axiomatique en dix propositions pour penser un déterminisme absolu, une vérité indépendante de toute cognition et une définition rigoureuse du vivant.
+
+ Acheter le livre
+ Découvrir le site dédié à l'Anankéisme
+
+
+
diff --git a/themes/2026/layouts/_partials/oeuvres/l-humain-cette-espece-primitive.html b/themes/2026/layouts/_partials/oeuvres/l-humain-cette-espece-primitive.html
new file mode 100644
index 00000000..ca0bac8f
--- /dev/null
+++ b/themes/2026/layouts/_partials/oeuvres/l-humain-cette-espece-primitive.html
@@ -0,0 +1,18 @@
+
+
+
+ {{- $assetPath := "images/oeuvres/l-humain-cette-espece-primitive.jpeg" -}}
+ {{- $source := resources.Get $assetPath -}}
+ {{- if $source -}}
+ {{- $img := $source.Resize "320x" -}}
+
+ {{- end -}}
+
+ L'Humain, cette espèce primitive
+ L'Humain, cette espèce primitive est un essai dans lequel vous explorez plusieurs facettes de ce que nous appelons notre évolution, en adoptant la perspective de l'exploration spatiale.
+
+ Acheter la version numérique
+ Lire le livre en ligne
+
+
+
diff --git a/themes/2026/layouts/_partials/page-links.html b/themes/2026/layouts/_partials/page-links.html
new file mode 100644
index 00000000..898693b4
--- /dev/null
+++ b/themes/2026/layouts/_partials/page-links.html
@@ -0,0 +1,96 @@
+{{- $page := . -}}
+{{- $commentsURL := "" -}}
+{{- $commentsLabel := "Commentaires" -}}
+{{- $linkClass := "" -}}
+{{- $linksParam := $page.Params.links -}}
+
+{{- if reflect.IsMap . -}}
+ {{- if isset . "Page" -}}
+ {{- $page = index . "Page" -}}
+ {{- end -}}
+ {{- if isset . "CommentsURL" -}}
+ {{- with (index . "CommentsURL") -}}
+ {{- $commentsURL = . -}}
+ {{- end -}}
+ {{- end -}}
+ {{- if isset . "CommentsLabel" -}}
+ {{- with (index . "CommentsLabel") -}}
+ {{- $commentsLabel = . -}}
+ {{- end -}}
+ {{- end -}}
+ {{- if isset . "LinkClass" -}}
+ {{- with (index . "LinkClass") -}}
+ {{- $linkClass = . -}}
+ {{- end -}}
+ {{- end -}}
+ {{- if isset . "Links" -}}
+ {{- $linksParam = index . "Links" -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $links := slice -}}
+{{- if $linksParam -}}
+ {{- $type := printf "%T" $linksParam -}}
+ {{- if hasPrefix $type "[]" -}}
+ {{- $links = $linksParam -}}
+ {{- else -}}
+ {{- $links = slice $linksParam -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $hasWikipediaLink := false -}}
+{{- range $links -}}
+ {{- if and (not $hasWikipediaLink) (and .url (in .url "wikipedia.org")) -}}
+ {{- $hasWikipediaLink = true -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $addWikiLink := false -}}
+{{- if and (eq $page.Kind "term") (not $hasWikipediaLink) -}}
+ {{- $addWikiLink = true -}}
+{{- end -}}
+
+{{- if or (ne $commentsURL "") (gt (len $links) 0) $addWikiLink -}}
+
+
+ {{- with $commentsURL -}}
+
+ {{- partial "render/link.html" (dict
+ "Destination" .
+ "Title" "Voir les commentaires"
+ "Text" $commentsLabel
+ "Class" $linkClass
+ "Page" $page
+ ) -}}
+
+ {{- end -}}
+ {{- range $links -}}
+ {{- $text := default .name .text -}}
+ {{- $title := default $text .title -}}
+
+ {{- partial "render/link.html" (dict
+ "Destination" .url
+ "Title" $title
+ "Text" $text
+ "Class" $linkClass
+ "Page" $page
+ ) -}}
+
+ {{- end -}}
+ {{- if $addWikiLink -}}
+ {{- $lang := default "fr" $page.Site.Language.Lang -}}
+ {{- $query := urlquery $page.Title -}}
+ {{- $searchUrl := printf "https://%s.wikipedia.org/w/index.php?search=%s" $lang $query -}}
+
+ {{- partial "render/link.html" (dict
+ "Destination" $searchUrl
+ "Title" (printf "Rechercher %s sur Wikipédia" $page.Title)
+ "Text" (printf "Rechercher %s sur Wikipédia" $page.Title)
+ "Class" $linkClass
+ "Page" $page
+ ) -}}
+
+ {{- end -}}
+
+
+{{- end -}}
diff --git a/themes/2026/layouts/_partials/page-meta.html b/themes/2026/layouts/_partials/page-meta.html
new file mode 100644
index 00000000..db9111b4
--- /dev/null
+++ b/themes/2026/layouts/_partials/page-meta.html
@@ -0,0 +1,8 @@
+
+ {{ with .Date }}
+ {{ . | time.Format "02/01/2006" }}
+ {{ end }}
+ {{ if ge .ReadingTime 5 }}
+ {{ .ReadingTime }} min de lecture
+ {{ end }}
+
diff --git a/themes/2026/layouts/_partials/render/link.html b/themes/2026/layouts/_partials/render/link.html
new file mode 100644
index 00000000..83adb563
--- /dev/null
+++ b/themes/2026/layouts/_partials/render/link.html
@@ -0,0 +1,115 @@
+{{- $isExternal := strings.HasPrefix .Destination "http" -}}
+{{- $parsed := urls.Parse .Destination -}}
+{{- $host := $parsed.Host -}}
+{{- $path := $parsed.Path -}}
+{{- $query := $parsed.RawQuery -}}
+{{- $page := .Page -}}
+{{- $site := $page.Site -}}
+{{- $aff := index $site.Data.affiliates.sites $host -}}
+{{- $isAffiliated := false -}}
+{{- $newURL := .Destination -}}
+{{- $customClass := "" -}}
+
+{{- if reflect.IsMap . -}}
+ {{- if isset . "Class" -}}
+ {{- with (index . "Class") -}}
+ {{- $customClass = . -}}
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
+
+{{- if and $isExternal $aff -}}
+ {{- $isAffiliated = true -}}
+ {{- if $query -}}
+ {{- $newURL = printf "%s://%s%s?%s&%s=%s" $parsed.Scheme $host $path $query $aff.param $aff.value -}}
+ {{- else -}}
+ {{- $newURL = printf "%s://%s%s?%s=%s" $parsed.Scheme $host $path $aff.param $aff.value -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $internalPage := "" -}}
+{{- $internalPageFound := false -}}
+{{- if not $isExternal -}}
+ {{- if strings.HasPrefix .Destination "/" -}}
+ {{- with $site.GetPage .Destination -}}
+ {{- $internalPage = . -}}
+ {{- $internalPageFound = true -}}
+ {{- end -}}
+ {{- else if and $path (ne $path "") -}}
+ {{- with $page.GetPage $path -}}
+ {{- $internalPage = . -}}
+ {{- $internalPageFound = true -}}
+ {{- end -}}
+ {{- end -}}
+ {{- if and (not $internalPageFound) $path (ne $path "") -}}
+ {{- with $site.GetPage $path -}}
+ {{- $internalPage = . -}}
+ {{- $internalPageFound = true -}}
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $report := dict -}}
+{{- if fileExists "tools/cache/external_links.yaml" -}}
+ {{- $report = transform.Unmarshal (readFile "tools/cache/external_links.yaml") -}}
+{{- end -}}
+{{- $deadList := default (slice) (index $report "links") -}}
+{{- $entriesMap := default (dict) (index $report "entries") -}}
+{{- $cacheEntry := index $entriesMap .Destination -}}
+{{- $deadInfo := dict -}}
+{{- $isDeadLink := false -}}
+{{- with (first 1 (where $deadList "url" .Destination)) -}}
+ {{- $deadInfo = index . 0 -}}
+ {{- $isDeadLink = true -}}
+{{- end -}}
+
+{{- $titleParts := slice -}}
+{{- if $isAffiliated -}}
+ {{- $titleParts = $titleParts | append "Lien affilié" -}}
+{{- else if $isExternal -}}
+ {{- $titleParts = $titleParts | append "Lien externe" -}}
+{{- end -}}
+{{- if and (not $isExternal) $internalPageFound -}}
+ {{- $internalTitle := $internalPage.LinkTitle | default $internalPage.Title -}}
+ {{- with $internalPage.Date -}}
+ {{- $internalTitle = printf "%s (%s)" $internalTitle (. | time.Format "02/01/2006") -}}
+ {{- end -}}
+ {{- $titleParts = $titleParts | append $internalTitle -}}
+{{- else -}}
+ {{- with .Title -}}
+ {{- $titleParts = $titleParts | append . -}}
+ {{- end -}}
+{{- end -}}
+{{- if $isDeadLink -}}
+ {{- $deadDetails := slice -}}
+ {{- with (index $cacheEntry "checkedAt") -}}
+ {{- $deadDetails = $deadDetails | append (printf "inaccessible depuis le %s" (time.Format "02/01/2006" (time .))) -}}
+ {{- end -}}
+ {{- with (index $cacheEntry "errorType") -}}
+ {{- $deadDetails = $deadDetails | append (printf "raison %s" .) -}}
+ {{- end -}}
+ {{- with (index $deadInfo "status") -}}
+ {{- $deadDetails = $deadDetails | append (printf "statut %v" .) -}}
+ {{- end -}}
+ {{- if gt (len $deadDetails) 0 -}}
+ {{- $titleParts = $titleParts | append (printf "(%s)" (delimit $deadDetails " ; ")) -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $titleValue := delimit $titleParts " - " -}}
+{{- $linkClasses := slice -}}
+{{- if $isExternal -}}
+ {{- $linkClasses = $linkClasses | append "link-external" -}}
+{{- end -}}
+{{- if $isAffiliated -}}
+ {{- $linkClasses = $linkClasses | append "link-affiliated" -}}
+{{- end -}}
+{{- with $customClass -}}
+ {{- range (split . " ") -}}
+ {{- if ne . "" -}}
+ {{- $linkClasses = $linkClasses | append . -}}
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
+{{- $classValue := delimit $linkClasses " " -}}
+{{- strings.TrimSpace .Text | safeHTML -}} {{- "" -}}
diff --git a/themes/2026/layouts/_partials/render/weather.html b/themes/2026/layouts/_partials/render/weather.html
new file mode 100644
index 00000000..b6179352
--- /dev/null
+++ b/themes/2026/layouts/_partials/render/weather.html
@@ -0,0 +1,81 @@
+{{- $w := .Params.weather -}}
+{{- if or (not $w) (eq (len $w) 0) -}}
+ {{- return -}}
+{{- end -}}
+
+{{- $date := .Date -}}
+{{- $hour := (time $date).Hour -}}
+{{- $isNight := false -}}
+{{- if or (lt $hour 6) (ge $hour 18) -}}
+ {{- $isNight = true -}}
+{{- end -}}
+
+{{- $precip := $w.precipitations -}}
+{{- $wind := $w.wind_speed -}}
+{{- $humidity := $w.humidity -}}
+{{- $illum := $w.illuminance -}}
+
+{{- $icon := "clear-day.svg" -}}
+{{- if $isNight -}}
+ {{- $icon = "clear-night.svg" -}}
+{{- end -}}
+
+{{- if $precip -}}
+ {{- $icon = "rain.svg" -}}
+{{- else if and $wind (ge $wind 45) -}}
+ {{- $icon = "wind.svg" -}}
+{{- else if and $humidity (ge $humidity 90) (or (not $illum) (lt $illum 80)) -}}
+ {{- $icon = "fog.svg" -}}
+{{- else if and $humidity (ge $humidity 75) -}}
+ {{- if $isNight -}}
+ {{- $icon = "partly-cloudy-night.svg" -}}
+ {{- else -}}
+ {{- $icon = "cloudy.svg" -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $label := "Météo" -}}
+{{- if eq $icon "clear-day.svg" -}}{{- $label = "Grand soleil" -}}{{- end -}}
+{{- if eq $icon "clear-night.svg" -}}{{- $label = "Ciel dégagé" -}}{{- end -}}
+{{- if eq $icon "partly-cloudy-day.svg" -}}{{- $label = "Partiellement nuageux" -}}{{- end -}}
+{{- if eq $icon "partly-cloudy-night.svg" -}}{{- $label = "Partiellement nuageux" -}}{{- end -}}
+{{- if eq $icon "cloudy.svg" -}}{{- $label = "Nuageux" -}}{{- end -}}
+{{- if eq $icon "drizzle.svg" -}}{{- $label = "Bruine" -}}{{- end -}}
+{{- if eq $icon "rain.svg" -}}{{- $label = "Pluvieux" -}}{{- end -}}
+{{- if eq $icon "snow.svg" -}}{{- $label = "Neige" -}}{{- end -}}
+{{- if eq $icon "thunderstorms-day.svg" -}}{{- $label = "Orage" -}}{{- end -}}
+{{- if eq $icon "fog.svg" -}}{{- $label = "Brouillard" -}}{{- end -}}
+{{- if eq $icon "wind.svg" -}}{{- $label = "Vent fort" -}}{{- end -}}
+
+{{- $sources := slice -}}
+{{- with $w.source -}}
+ {{- if reflect.IsSlice . -}}
+ {{- $sources = . -}}
+ {{- else -}}
+ {{- $sources = slice . -}}
+ {{- end -}}
+{{- end -}}
+
+
+ Météo observée
+
+
+ {{ printf "%s à %s" (time.Format "02/01/2006" $date) (time.Format ":time_short" $date) }}
+
+
+ {{- with $w.temperature -}}
Température {{ printf "%.1f" (mul . 1.0) }} °C {{- end -}}
+ {{- with $w.humidity -}}
Humidité {{ printf "%.0f" (mul . 1.0) }} % {{- end -}}
+ {{- with $w.pressure -}}
Pression {{ printf "%.0f" (mul . 1.0) }} hPa {{- end -}}
+ {{- with $w.illuminance -}}
Luminosité {{ printf "%.0f" (mul . 1.0) }} lx {{- end -}}
+ {{- with $w.wind_speed -}}
Vent {{ printf "%.1f" (mul . 1.0) }} km/h {{- end -}}
+ {{- with $w.wind_direction -}}
Direction {{ printf "%.0f" (mul . 1.0) }}° {{- end -}}
+
+ {{- if gt (len $sources) 0 -}}
+
+ Sources:
+ {{- range $i, $source := $sources -}}
+ {{- if gt $i 0 -}}, {{- end -}}{{ $source }}
+ {{- end -}}
+
+ {{- end -}}
+
diff --git a/themes/2026/layouts/_partials/site-stats.html b/themes/2026/layouts/_partials/site-stats.html
new file mode 100644
index 00000000..d2932d4c
--- /dev/null
+++ b/themes/2026/layouts/_partials/site-stats.html
@@ -0,0 +1,17 @@
+{{- $allSections := where .Site.Pages "Kind" "section" -}}
+{{- $allSections = where $allSections "RelPermalink" "!=" "/" -}}
+{{- $leafSections := slice -}}
+{{- range $allSections -}}
+{{- if eq (len .Sections) 0 -}}
+{{- $leafSections = $leafSections | append . -}}
+{{- end -}}
+{{- end -}}
+{{- $lastMod := .Site.Lastmod | time.Format "02/01/2006" -}}
+
+ Statistiques
+
+ Articles publiés {{ len .Site.RegularPages }}
+ Thématiques {{ len $leafSections }}
+ Dernière mise à jour {{ $lastMod }}
+
+
diff --git a/themes/2026/layouts/_partials/site-title.html b/themes/2026/layouts/_partials/site-title.html
new file mode 100644
index 00000000..3f9e421c
--- /dev/null
+++ b/themes/2026/layouts/_partials/site-title.html
@@ -0,0 +1,13 @@
+{{- $site := .Site -}}
+{{- if not $site -}}
+ {{- $site = . -}}
+{{- end -}}
+{{- $logoPath := $site.Params.logo | default "logo-large.png" -}}
+{{- $logo := resources.GetMatch $logoPath -}}
+
+ {{- with $logo -}}
+ {{- $resized := .Resize "64x" -}}
+
+ {{- end -}}
+ {{ $site.Title }}
+
diff --git a/themes/2026/layouts/_partials/spotlight-block.html b/themes/2026/layouts/_partials/spotlight-block.html
new file mode 100644
index 00000000..3227e6ec
--- /dev/null
+++ b/themes/2026/layouts/_partials/spotlight-block.html
@@ -0,0 +1,38 @@
+{{- $cards := slice -}}
+{{- with .Cards -}}
+ {{- $cards = . -}}
+{{- end -}}
+
+{{- $feedPages := slice -}}
+{{- with .FeedPages -}}
+ {{- $feedPages = . -}}
+{{- end -}}
+
+{{- $asideFirst := false -}}
+{{- with .AsideFirst -}}
+ {{- $asideFirst = . -}}
+{{- end -}}
+
+{{- $showSection := false -}}
+{{- with .ShowSection -}}
+ {{- $showSection = . -}}
+{{- end -}}
+
+{{- $spotlightClass := "spotlight" -}}
+{{- if $asideFirst -}}
+ {{- $spotlightClass = printf "%s spotlight-aside-first" $spotlightClass -}}
+{{- end -}}
+
+
+ {{- if and $asideFirst (gt (len $feedPages) 0) -}}
+ {{ partial "spotlight-feed.html" . }}
+ {{- end -}}
+
+ {{- range $cards -}}
+ {{ partial "card.html" (dict "Page" . "ShowSection" $showSection "LinkSection" false "ShowMeta" false "ThumbnailSize" "spotlight") }}
+ {{- end -}}
+
+ {{- if and (not $asideFirst) (gt (len $feedPages) 0) -}}
+ {{ partial "spotlight-feed.html" . }}
+ {{- end -}}
+
diff --git a/themes/2026/layouts/_partials/spotlight-feed.html b/themes/2026/layouts/_partials/spotlight-feed.html
new file mode 100644
index 00000000..8f711365
--- /dev/null
+++ b/themes/2026/layouts/_partials/spotlight-feed.html
@@ -0,0 +1,85 @@
+{{- $feedTitle := "Fil" -}}
+{{- with .FeedTitle -}}
+ {{- $feedTitle = . -}}
+{{- end -}}
+
+{{- $showFeedTitle := true -}}
+{{- if isset . "ShowFeedTitle" -}}
+ {{- $showFeedTitle = index . "ShowFeedTitle" -}}
+{{- end -}}
+
+{{- $feedPages := slice -}}
+{{- with .FeedPages -}}
+ {{- $feedPages = . -}}
+{{- end -}}
+
+{{- $feedRich := false -}}
+{{- with .FeedRich -}}
+ {{- $feedRich = . -}}
+{{- end -}}
+
+{{- $showSection := false -}}
+{{- with .ShowSection -}}
+ {{- $showSection = . -}}
+{{- end -}}
+
+
diff --git a/themes/2026/layouts/_partials/terms.html b/themes/2026/layouts/_partials/terms.html
new file mode 100644
index 00000000..2ca6f1b8
--- /dev/null
+++ b/themes/2026/layouts/_partials/terms.html
@@ -0,0 +1,14 @@
+{{- $page := .page -}}
+{{- $taxonomy := .taxonomy -}}
+
+{{- with $page.GetTerms $taxonomy -}}
+ {{- $label := (index . 0).Parent.LinkTitle -}}
+
+{{- end -}}
diff --git a/themes/2026/layouts/_partials/timeline-list.html b/themes/2026/layouts/_partials/timeline-list.html
new file mode 100644
index 00000000..a6beb8bd
--- /dev/null
+++ b/themes/2026/layouts/_partials/timeline-list.html
@@ -0,0 +1,78 @@
+{{- $pages := .Pages -}}
+{{- if gt (len $pages) 0 -}}
+
+
+
+ {{- range $pages -}}
+ {{- $page := . -}}
+ {{- $coverPath := $page.Params.cover -}}
+ {{- $image := false -}}
+ {{- if $coverPath -}}
+ {{- if strings.HasSuffix $coverPath ".yaml" -}}
+ {{- $coverAbsPath := printf "%s%s" $page.File.Dir $coverPath -}}
+ {{- $coverRaw := readFile $coverAbsPath -}}
+ {{- $coverData := $coverRaw | transform.Unmarshal -}}
+ {{- with $coverData.file -}}
+ {{- $image = $page.Resources.GetMatch . -}}
+ {{- end -}}
+ {{- else -}}
+ {{- $image = $page.Resources.GetMatch $coverPath -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- $dossierTitle := "" -}}
+ {{- $dossierFirstPage := false -}}
+ {{- with $page.Params.dossier -}}
+ {{- with index . 0 -}}
+ {{- $dossierTitle = . -}}
+ {{- $dossierFirstPage = partial "dossier-first-page.html" $page -}}
+ {{- end -}}
+ {{- end -}}
+
+
+
+ {{- with $image -}}
+
+
+ {{- $resized := .Fill "600x340" -}}
+
+
+
+ {{- end -}}
+
+
+ {{- with $page.Summary -}}
+
{{ . | plainify | truncate 240 }}
+ {{- end -}}
+
+
+
+
+ {{- end -}}
+
+
+{{- end -}}
diff --git a/themes/2026/layouts/_shortcodes/extimage.html b/themes/2026/layouts/_shortcodes/extimage.html
new file mode 100644
index 00000000..587af7ce
--- /dev/null
+++ b/themes/2026/layouts/_shortcodes/extimage.html
@@ -0,0 +1,34 @@
+{{- $imageURL := .Get 0 -}}
+{{- $title := .Get 2 | default "" -}}
+{{- $description := .Get 3 | default "" -}}
+{{- $attribution := .Get 4 | default "" -}}
+{{- $remoteURL := printf "%s?raw=true" $imageURL -}}
+{{- $remoteImage := resources.GetRemote $remoteURL -}}
+{{- $hash := md5 $remoteURL -}}
+{{- $extension := path.Ext $remoteURL -}}
+{{- $cleanFilename := printf "%s%s" $hash $extension | replace "?raw=true" "" -}}
+{{- $localImage := $remoteImage | resources.Copy (printf "remote-images/%s" $cleanFilename) -}}
+{{- $resizedImage := $localImage.Resize "1024x" -}}
+{{- $hasMeta := or $title (or $description $attribution) -}}
+
+
+
+
+ {{- if $hasMeta -}}
+
+
+ {{- with $title -}}
+
{{ . | markdownify }}
+ {{- end -}}
+ {{- with $description -}}
+
{{ . | markdownify }}
+ {{- end -}}
+
+ {{- with $attribution -}}
+
+ {{- end -}}
+
+ {{- end -}}
+
diff --git a/themes/2026/layouts/_shortcodes/sound.html b/themes/2026/layouts/_shortcodes/sound.html
new file mode 100644
index 00000000..3dc85dd2
--- /dev/null
+++ b/themes/2026/layouts/_shortcodes/sound.html
@@ -0,0 +1,21 @@
+{{- $soundData := .Get 0 -}}
+{{- $dataFile := .Page.Resources.Get (printf "data/sounds/%s.yaml" $soundData) -}}
+{{- if $dataFile -}}
+ {{- $data := $dataFile.Content | transform.Unmarshal -}}
+ {{- $audio := .Page.Resources.Get $data.file -}}
+ {{- if $audio -}}
+
+
+
+ Votre navigateur ne prend pas en charge la lecture audio.
+
+ {{- if or $data.title (or $data.description $data.attribution) -}}
+
+ {{- with $data.title -}}{{ . }}
{{- end -}}
+ {{- with $data.description -}}{{ . | markdownify }}
{{- end -}}
+ {{- with $data.attribution -}}Attribution : {{ . | markdownify }}
{{- end -}}
+
+ {{- end -}}
+
+ {{- end -}}
+{{- end -}}
diff --git a/themes/2026/layouts/_shortcodes/video.html b/themes/2026/layouts/_shortcodes/video.html
new file mode 100644
index 00000000..b75e6c5e
--- /dev/null
+++ b/themes/2026/layouts/_shortcodes/video.html
@@ -0,0 +1,40 @@
+{{- $videoData := .Get 0 -}}
+{{- $dataFile := .Page.Resources.Get (printf "data/videos/%s.yaml" $videoData) -}}
+{{- if $dataFile -}}
+ {{- $data := $dataFile.Content | transform.Unmarshal -}}
+ {{- $video := .Page.Resources.Get $data.file -}}
+ {{- if $video -}}
+{{- $hasMeta := or $data.title (or $data.description (or $data.attribution $data.prompt)) -}}
+
+
+
+ Votre navigateur ne prend pas en charge la lecture des videos.
+
+ {{- if $hasMeta -}}
+
+
+ {{- with $data.title -}}
+
{{ . | markdownify }}
+ {{- end -}}
+ {{- with $data.description -}}
+
{{ . | markdownify }}
+ {{- end -}}
+
+ {{- if or $data.attribution $data.prompt -}}
+
+ {{- end -}}
+
+ {{- end -}}
+
+ {{- end -}}
+{{- end -}}
diff --git a/themes/2026/layouts/baseof.html b/themes/2026/layouts/baseof.html
new file mode 100644
index 00000000..41b7408f
--- /dev/null
+++ b/themes/2026/layouts/baseof.html
@@ -0,0 +1,10 @@
+
+
+
+ {{ partial "head.html" . }}
+
+
+ {{ block "main" . }}{{ end }}
+ {{ partial "footer.html" . }}
+
+
diff --git a/themes/2026/layouts/contact/single.html b/themes/2026/layouts/contact/single.html
new file mode 100644
index 00000000..01276ff4
--- /dev/null
+++ b/themes/2026/layouts/contact/single.html
@@ -0,0 +1,23 @@
+{{ define "main" }}
+{{ partial "article-header.html" . }}
+
+
+ {{ .Content }}
+
+ {{- with .Params.oeuvres -}}
+
+
+ Mes livres
+ Si vous aimez ce blog, vous apprécierez mes livres. En les achetant, vous m'aidez à continuer de le faire vivre.
+
+
+ {{ partial "asides/oeuvres.html" $ }}
+
+
+ {{- end -}}
+
+ {{ partial "article-footer.html" . }}
+
+ {{ partial "asides/toc.html" . }}
+
+{{ end }}
diff --git a/themes/2026/layouts/home.html b/themes/2026/layouts/home.html
new file mode 100644
index 00000000..de2243c3
--- /dev/null
+++ b/themes/2026/layouts/home.html
@@ -0,0 +1,415 @@
+{{- define "main" -}}
+{{- $site := .Site -}}
+{{- $allArticles := $site.RegularPages.ByDate.Reverse -}}
+{{- $recettesPrefix := "/interets/recettes/" -}}
+{{- $interestsArticles := slice -}}
+{{- $recettesArticles := slice -}}
+{{- $critiquesArticles := slice -}}
+{{- $veilleArticles := slice -}}
+{{- range $allArticles -}}
+ {{- if eq (partial "is-dossier-lead.html" .) "true" -}}
+ {{- if strings.Contains .RelPermalink "/interets/liens-interessants/" -}}
+ {{- $veilleArticles = $veilleArticles | append . -}}
+ {{- else if strings.Contains .RelPermalink $recettesPrefix -}}
+ {{- $recettesArticles = $recettesArticles | append . -}}
+ {{- else if and (strings.Contains .RelPermalink "/interets/") (not (strings.Contains .RelPermalink $recettesPrefix)) -}}
+ {{- $interestsArticles = $interestsArticles | append . -}}
+ {{- else if strings.Contains .RelPermalink "/critiques/" -}}
+ {{- $critiquesArticles = $critiquesArticles | append . -}}
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $interestsSections := slice -}}
+{{- with $site.GetPage "/interets" -}}
+ {{- range .Sections -}}
+ {{- if and (not (strings.Contains .RelPermalink "/interets/liens-interessants/")) (not (strings.Contains .RelPermalink $recettesPrefix)) -}}
+ {{- $interestsSections = $interestsSections | append . -}}
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $veilleRoot := $site.GetPage "/interets/liens-interessants" -}}
+{{- $recettesRoot := $site.GetPage "/interets/recettes" -}}
+{{- $collectionsRoot := $site.GetPage "/collections" -}}
+{{- $critiquesRoot := $site.GetPage "/critiques" -}}
+{{- $externalLinksReport := dict -}}
+{{- if fileExists "tools/cache/external_links.yaml" -}}
+ {{- $externalLinksReport = transform.Unmarshal (readFile "tools/cache/external_links.yaml") -}}
+{{- end -}}
+
+{{- partial "hero.html" . -}}
+
+{{- $interestsUsed := slice -}}
+{{- $interestsSpotlight := first 8 $interestsArticles -}}
+{{- range $interestsSpotlight -}}
+ {{- $interestsUsed = $interestsUsed | append .File.Path -}}
+{{- end -}}
+
+{{- $interestsDeep := slice -}}
+{{- range $interestsArticles -}}
+ {{- if and (lt (len $interestsDeep) 15) (not (in $interestsUsed .File.Path)) -}}
+ {{- $interestsDeep = $interestsDeep | append . -}}
+ {{- $interestsUsed = $interestsUsed | append .File.Path -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $interestsSectionEntries := slice -}}
+{{- range $interestsSections -}}
+ {{- $section := . -}}
+ {{- $sectionPages := slice -}}
+ {{- $publishedCount := 0 -}}
+ {{- range $section.RegularPagesRecursive.ByDate.Reverse -}}
+ {{- if eq (partial "is-dossier-lead.html" .) "true" -}}
+ {{- $publishedCount = add $publishedCount 1 -}}
+ {{- if and (lt (len $sectionPages) 5) (not (in $interestsUsed .File.Path)) -}}
+ {{- $sectionPages = $sectionPages | append . -}}
+ {{- end -}}
+ {{- end -}}
+ {{- end -}}
+ {{- if gt (len $sectionPages) 0 -}}
+ {{- $latestDateKey := "00000000000000" -}}
+ {{- with index $sectionPages 0 -}}
+ {{- $latestDateKey = .Date.Format "20060102150405" -}}
+ {{- end -}}
+ {{- $interestsSectionEntries = $interestsSectionEntries | append (dict
+ "Section" $section
+ "Pages" $sectionPages
+ "PublishedCount" $publishedCount
+ "LatestDateKey" $latestDateKey
+ ) -}}
+ {{- end -}}
+{{- end -}}
+{{- $interestsSectionEntries = sort $interestsSectionEntries "LatestDateKey" "desc" -}}
+{{- $recettesSpotlight := first 8 $recettesArticles -}}
+{{- $collectionsEntries := slice -}}
+{{- with $collectionsRoot -}}
+ {{- range .Sections -}}
+ {{- $section := . -}}
+ {{- $items := $section.RegularPagesRecursive.ByDate.Reverse -}}
+ {{- $latestItems := $items -}}
+ {{- $latestDateKey := "00000000000000" -}}
+ {{- if gt (len $items) 0 -}}
+ {{- with index $items 0 -}}
+ {{- $latestDateKey = .Date.Format "20060102150405" -}}
+ {{- end -}}
+ {{- end -}}
+ {{- $collectionsEntries = $collectionsEntries | append (dict
+ "Section" $section
+ "Items" (len $items)
+ "LatestItems" $latestItems
+ "LatestDateKey" $latestDateKey
+ ) -}}
+ {{- end -}}
+{{- end -}}
+{{- $collectionsEntries = sort $collectionsEntries "LatestDateKey" "desc" -}}
+
+{{- $critiquesDisplayed := slice -}}
+
+{{- $critiquesCategoryDefs := slice -}}
+{{- $critiquesCategoryDefs = $critiquesCategoryDefs | append (dict "Path" "/critiques/films") -}}
+{{- $critiquesCategoryDefs = $critiquesCategoryDefs | append (dict "Path" "/critiques/series") -}}
+{{- $critiquesCategoryDefs = $critiquesCategoryDefs | append (dict "Path" "/critiques/jeux-video") -}}
+{{- $critiquesCategoryDefs = $critiquesCategoryDefs | append (dict "Path" "/critiques/livres") -}}
+
+
+ {{- if gt (len $interestsSpotlight) 0 -}}
+
+
+ {{ partial "spotlight-block.html" (dict
+ "Cards" $interestsSpotlight
+ "FeedPages" $interestsSpotlight
+ "FeedTitle" "Fil de publication"
+ "ShowFeedTitle" false
+ "FeedRich" true
+ "ShowSection" true
+ "AsideFirst" false
+ ) }}
+
+ {{- end -}}
+
+ {{- if gt (len $interestsDeep) 0 -}}
+
+
+ {{ partial "articles-list.html" (dict "Pages" $interestsDeep "Context" . "ShowDossierBeforeTitle" true) }}
+
+ {{- end -}}
+
+
+
+ Mes livres
+ Si vous aimez ce blog, vous apprécierez mes livres. En les achetant, vous m'aidez à continuer de le faire vivre.
+
+
+ {{ partial "oeuvres/l-anankeisme.html" . }}
+ {{ partial "oeuvres/l-humain-cette-espece-primitive.html" . }}
+
+
+
+ {{- if gt (len $interestsSectionEntries) 0 -}}
+
+
+
+ {{- range $interestsSectionEntries -}}
+ {{- $section := index . "Section" -}}
+ {{- $sectionPages := index . "Pages" -}}
+ {{- $publishedCount := index . "PublishedCount" -}}
+ {{- if gt (len $sectionPages) 0 -}}
+
+
+
+ {{- range $sectionPages -}}
+ {{- $page := . -}}
+ {{- $dossierTitle := "" -}}
+ {{- $dossierFirstPage := false -}}
+ {{- with $page.Params.dossier -}}
+ {{- with index . 0 -}}
+ {{- $dossierTitle = . -}}
+ {{- $dossierFirstPage = partial "dossier-first-page.html" $page -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- with $dossierFirstPage -}}
+ {{- with $dossierTitle -}}
+ {{ $dossierTitle }}
+ {{- end -}}
+ {{- end -}}
+ {{ $page.Title }}
+ {{- with $page.Date -}}{{ . | time.Format "02/01/2006" }} {{- end -}}
+
+ {{- end -}}
+
+
+ {{- end -}}
+ {{- end -}}
+
+
+ {{- end -}}
+
+ {{- if gt (len $critiquesArticles) 0 -}}
+
+ {{- end -}}
+
+ {{- range $critiqueIndex, $critiqueDef := $critiquesCategoryDefs -}}
+ {{- $critiquePath := index $critiqueDef "Path" -}}
+ {{- $critiquePrefix := printf "%s/" (strings.TrimSuffix "/" $critiquePath) -}}
+ {{- $critiqueSection := $site.GetPage $critiquePath -}}
+ {{- $critiquePool := slice -}}
+ {{- range $critiquesArticles -}}
+ {{- if and (strings.Contains .RelPermalink $critiquePrefix) (not (in $critiquesDisplayed .File.Path)) -}}
+ {{- $critiquePool = $critiquePool | append . -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- $critiqueSpotlight := first 8 $critiquePool -}}
+ {{- range $critiqueSpotlight -}}
+ {{- $critiquesDisplayed = $critiquesDisplayed | append .File.Path -}}
+ {{- end -}}
+
+ {{- if gt (len $critiqueSpotlight) 0 -}}
+
+
+ {{ partial "spotlight-block.html" (dict
+ "Cards" $critiqueSpotlight
+ "FeedPages" $critiqueSpotlight
+ "FeedTitle" "Dernières critiques"
+ "ShowFeedTitle" false
+ "FeedRich" true
+ "ShowSection" false
+ "AsideFirst" (eq (mod $critiqueIndex 2) 1)
+ ) }}
+
+ {{- end -}}
+ {{- end -}}
+
+ {{- if gt (len $veilleArticles) 0 -}}
+
+ {{- end -}}
+
+ {{- if gt (len $recettesSpotlight) 0 -}}
+
+
+ {{ partial "spotlight-block.html" (dict
+ "Cards" $recettesSpotlight
+ "FeedPages" $recettesSpotlight
+ "FeedTitle" "Dernières recettes"
+ "ShowFeedTitle" false
+ "FeedRich" true
+ "ShowSection" false
+ "AsideFirst" false
+ ) }}
+
+ {{- end -}}
+
+ {{- if gt (len $collectionsEntries) 0 -}}
+
+
+
+ {{- range $collectionsEntries -}}
+ {{- $section := index . "Section" -}}
+ {{- $latestItems := index . "LatestItems" -}}
+
+
+ {{- if gt (len $latestItems) 0 -}}
+
+ {{- end -}}
+
+ {{ index . "Items" }} objets
+ {{- range $section.Sections.ByTitle -}}
+ {{ with .LinkTitle }}{{ . }}{{ else }}{{ .Title }}{{ end }}
+ {{- end -}}
+
+
+ {{- end -}}
+
+
+ {{- end -}}
+
+{{- end -}}
diff --git a/themes/2026/layouts/index.rss.xml b/themes/2026/layouts/index.rss.xml
new file mode 100644
index 00000000..fa1c6c1b
--- /dev/null
+++ b/themes/2026/layouts/index.rss.xml
@@ -0,0 +1,58 @@
+{{- $authorEmail := "" -}}
+{{- $authorName := "" -}}
+{{- $favicon := "favicon.png" | absURL -}}
+{{- with site.Params.author -}}
+ {{- if reflect.IsMap . -}}
+ {{- with .email }}{{- $authorEmail = . -}}{{- end -}}
+ {{- with .name }}{{- $authorName = . -}}{{- end -}}
+ {{- else -}}
+ {{- $authorName = . -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $pctx := . -}}
+{{- if .IsHome -}}{{- $pctx = .Site -}}{{- end -}}
+
+{{- $pages := slice -}}
+{{- if or .IsHome .IsSection -}}
+ {{- $pages = $pctx.RegularPages -}}
+{{- else -}}
+ {{- $pages = $pctx.Pages -}}
+{{- end -}}
+
+{{- $pages = $pages.ByLastmod.Reverse -}}
+{{- $limit := .Site.Config.Services.RSS.Limit -}}
+{{- if ge $limit 1 -}}
+ {{- $pages = first $limit $pages -}}
+{{- end -}}
+{{- printf "" | safeHTML -}}
+
+
+ {{ .Site.Title }}
+ {{ .Permalink }}
+ {{ .Site.Title }}
+
+ {{ $favicon }}
+ {{ .Site.Title }}
+ {{ .Permalink }}
+
+ {{ site.Language.LanguageCode }} {{ with $authorEmail }}
+ {{.}}{{ with $authorName }} ({{ . }}){{ end }} {{ end }}{{ with $authorEmail }}
+ {{ . }}{{ with $authorName }} ({{ . }}){{ end }} {{ end }}{{ with .Site.Copyright }}
+ {{ . }} {{ end }}{{ if not .Date.IsZero }}
+ {{ (index $pages.ByLastmod.Reverse 0).Lastmod.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }} {{ end }}
+ {{- with .OutputFormats.Get "RSS" }}
+ {{ printf " " .Permalink .MediaType | safeHTML }}
+ {{- end }}
+ {{- range $pages }}
+ -
+
{{ .Title }}
+ {{ .Permalink }}
+ {{ .PublishDate.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}
+ {{- with $authorEmail }}{{ . }}{{ with $authorName }} ({{ . }}){{ end }} {{ end }}
+ {{ .Permalink }}
+ {{ .Summary | transform.XMLEscape | safeHTML }}
+
+ {{- end }}
+
+
diff --git a/themes/2026/layouts/liens-morts/single.html b/themes/2026/layouts/liens-morts/single.html
new file mode 100644
index 00000000..1687c95c
--- /dev/null
+++ b/themes/2026/layouts/liens-morts/single.html
@@ -0,0 +1,11 @@
+{{ define "main" }}
+{{ partial "article-header.html" . }}
+
+
+ {{ .Content }}
+ {{ partial "liens-morts/report.html" (dict "Page" .) }}
+ {{ partial "article-footer.html" . }}
+
+ {{ partial "asides/toc.html" . }}
+
+{{ end }}
diff --git a/themes/2026/layouts/page.html b/themes/2026/layouts/page.html
new file mode 100644
index 00000000..113cb180
--- /dev/null
+++ b/themes/2026/layouts/page.html
@@ -0,0 +1,10 @@
+{{ define "main" }}
+{{ partial "article-header.html" . }}
+
+
+ {{ .Content }}
+ {{ partial "article-footer.html" . }}
+
+ {{ partial "asides/toc.html" . }}
+
+{{ end }}
diff --git a/themes/2026/layouts/section.html b/themes/2026/layouts/section.html
new file mode 100644
index 00000000..c989c135
--- /dev/null
+++ b/themes/2026/layouts/section.html
@@ -0,0 +1,13 @@
+{{ define "main" }}
+{{ partial "hero.html" . }}
+
+ {{- $pages := .RegularPagesRecursive.ByDate.Reverse -}}
+ {{ with .Content }}
+
+ {{ . }}
+
+ {{ end }}
+
+ {{ partial "list-layout.html" (dict "Pages" $pages "Context" . "Site" .Site "SpotlightTitle" .Title) }}
+
+{{ end }}
diff --git a/themes/2026/layouts/taxonomies/taxonomies.html b/themes/2026/layouts/taxonomies/taxonomies.html
new file mode 100644
index 00000000..7a3168eb
--- /dev/null
+++ b/themes/2026/layouts/taxonomies/taxonomies.html
@@ -0,0 +1,25 @@
+{{ define "main" }}
+{{ partial "article-header.html" . }}
+
+
+ {{ .Content }}
+
+
+
+
+ {{- range $taxonomy, $terms := .Site.Taxonomies -}}
+ {{- with $.Site.GetPage $taxonomy -}}
+
+ {{ .Title }}
+ {{ len $terms }}
+
+ {{- end -}}
+ {{- end -}}
+
+
+
+ {{ partial "article-footer.html" . }}
+
+ {{ partial "asides/toc.html" . }}
+
+{{ end }}
diff --git a/themes/2026/layouts/taxonomy.html b/themes/2026/layouts/taxonomy.html
new file mode 100644
index 00000000..58dbb010
--- /dev/null
+++ b/themes/2026/layouts/taxonomy.html
@@ -0,0 +1,63 @@
+{{ define "main" }}
+{{ partial "hero-section.html" . }}
+
+ {{ with .Content }}
+
+ {{ . }}
+
+ {{ end }}
+
+ {{- $pages := .Pages -}}
+ {{- if gt (len $pages) 0 -}}
+ {{- $sorted := $pages.ByTitle -}}
+ {{- $scratch := newScratch -}}
+ {{- $scratch.Set "group" "" -}}
+
+ {{- range $sorted -}}
+ {{- $title := strings.TrimSpace (default .Title .LinkTitle) -}}
+ {{- if $title -}}
+ {{- $firstChar := slicestr $title 0 1 -}}
+ {{- $upper := strings.ToUpper $firstChar -}}
+ {{- $normalized := $upper -}}
+ {{- $normalized = replaceRE "[ÀÁÂÃÄÅĀĂĄÆ]" "A" $normalized -}}
+ {{- $normalized = replaceRE "[ÇĆĈĊČ]" "C" $normalized -}}
+ {{- $normalized = replaceRE "[ÈÉÊËĒĔĖĘĚ]" "E" $normalized -}}
+ {{- $normalized = replaceRE "[ÌÍÎÏĨĪĬĮİ]" "I" $normalized -}}
+ {{- $normalized = replaceRE "[ÑŃŅŇ]" "N" $normalized -}}
+ {{- $normalized = replaceRE "[ÒÓÔÕÖŌŎŐØŒ]" "O" $normalized -}}
+ {{- $normalized = replaceRE "[ÙÚÛÜŨŪŬŮŰŲ]" "U" $normalized -}}
+ {{- $normalized = replaceRE "[ÝŸŶ]" "Y" $normalized -}}
+
+ {{- $letterKey := "#" -}}
+ {{- if gt (len (findRE "^[A-Z]$" $normalized)) 0 -}}
+ {{- $letterKey = $normalized -}}
+ {{- end -}}
+
+ {{- $current := $scratch.Get "group" -}}
+ {{- if ne $letterKey $current -}}
+ {{- if ne $current "" -}}
+
+
+ {{- end -}}
+
+
+
+ {{- $scratch.Set "group" $letterKey -}}
+ {{- end -}}
+
+
+ {{ $title }}
+ {{ with .Pages }}{{ len . }} {{ else }}0 {{ end }}
+
+ {{- end -}}
+ {{- end -}}
+
+ {{- if ne ($scratch.Get "group") "" -}}
+
+
+ {{- end -}}
+ {{- else -}}
+ Aucun mot-clé disponible pour cette taxonomie.
+ {{- end -}}
+
+{{ end }}
diff --git a/themes/2026/layouts/term.html b/themes/2026/layouts/term.html
new file mode 100644
index 00000000..ff5be306
--- /dev/null
+++ b/themes/2026/layouts/term.html
@@ -0,0 +1,13 @@
+{{ define "main" }}
+{{ partial "hero.html" . }}
+
+ {{- $pages := .Pages.ByDate.Reverse -}}
+ {{ with .Content }}
+
+ {{ . }}
+
+ {{ end }}
+
+ {{ partial "list-layout.html" (dict "Pages" $pages "Context" . "Site" .Site "SpotlightTitle" .Title) }}
+
+{{ end }}