+
{{ slug }}
{{ labels.breadcrumbs.label }}
diff --git a/app/assets/css/seo-base.css b/app/assets/css/seo-base.css
index 3ca4513..b80a7e6 100644
--- a/app/assets/css/seo-base.css
+++ b/app/assets/css/seo-base.css
@@ -1,7 +1,7 @@
/* SEO layer base styles. Only .seo-* classes, never a bare element or
another layer's classes; values come from seo-tokens.css, and the app's
- own CSS (loaded after the layers') wins. The breadcrumb, pagination and
- HTML sitemap rules land with their components. */
+ own CSS (loaded after the layers') wins. Long names and titles wrap and
+ are never truncated: the full text stays in the HTML. */
/* Visually hidden, still read by screen readers (the new-tab hint inside
external links, labels of icon-only controls). */
@@ -26,3 +26,33 @@
outline: 2px solid var(--seo-color-accent);
outline-offset: 2px;
}
+
+/* L1 breadcrumbs: a wrapping row, separators generated here (never read by
+ screen readers), the current page muted and bold. */
+.seo-breadcrumbs {
+ font-size: var(--seo-font-size-small);
+}
+.seo-breadcrumbs__list {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ list-style: none;
+ margin: 0 0 var(--seo-space-4);
+ padding: 0;
+}
+.seo-breadcrumbs__item {
+ overflow-wrap: anywhere;
+}
+.seo-breadcrumbs__item + .seo-breadcrumbs__item::before {
+ content: var(--seo-breadcrumbs-separator) / '';
+ color: var(--seo-color-muted);
+ padding-inline: var(--seo-space-2);
+}
+.seo-breadcrumbs__link {
+ display: inline-block;
+ padding-block: var(--seo-space-1);
+}
+.seo-breadcrumbs__current {
+ color: var(--seo-color-muted);
+ font-weight: 600;
+}
diff --git a/app/components/Seo/Breadcrumbs.vue b/app/components/Seo/Breadcrumbs.vue
new file mode 100644
index 0000000..ebae47c
--- /dev/null
+++ b/app/components/Seo/Breadcrumbs.vue
@@ -0,0 +1,80 @@
+
+
+