diff --git a/astro.config.mjs b/astro.config.mjs index 10d5430..d96c899 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -5,6 +5,7 @@ import sitemap from '@astrojs/sitemap'; import { defineConfig } from 'astro/config'; import rehypeAutolinkHeadings from 'rehype-autolink-headings'; import rehypeSlug from 'rehype-slug'; +import { visit } from 'unist-util-visit'; // Build a lookup of post slugs to their last modification dates so the sitemap // can advertise accurate values to crawlers. astro:content isn't @@ -99,6 +100,21 @@ export default defineConfig({ content: [], }, ], + // Make scrollable code blocks and tables reachable via keyboard (WCAG + // 2.1.1): without tabindex, a keyboard user cannot focus a horizontally + // overflowing
 or  to scroll it. tabindex=0 is sufficient
+      // on its own; role=region would require a meaningful per-block label,
+      // which we don't have at markdown level.
+      function rehypeFocusableScrollables() {
+        const SCROLLABLE = new Set(['pre', 'table']);
+        return (tree) => {
+          visit(tree, 'element', (node) => {
+            if (!SCROLLABLE.has(node.tagName)) return;
+            node.properties = node.properties ?? {};
+            node.properties.tabindex = '0';
+          });
+        };
+      },
     ],
   },
 });
diff --git a/package-lock.json b/package-lock.json
index 359c598..fc57806 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,7 +19,8 @@
         "prettier-plugin-astro": "^0.14.1",
         "rehype-autolink-headings": "^7.1.0",
         "rehype-slug": "^6.0.0",
-        "typescript": "^5.9.3"
+        "typescript": "^5.9.3",
+        "unist-util-visit": "^5.1.0"
       },
       "engines": {
         "node": ">=22.13.0"
@@ -6351,6 +6352,19 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/yaml-language-server/node_modules/yaml": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz",
+      "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "yaml": "bin.mjs"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
     "node_modules/yargs": {
       "version": "17.7.2",
       "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
@@ -7596,7 +7610,7 @@
       "dev": true,
       "requires": {
         "normalize-path": "^3.0.0",
-        "picomatch": "2.3.2"
+        "picomatch": "^2.0.4"
       },
       "dependencies": {
         "picomatch": {
@@ -7651,7 +7665,7 @@
         "clsx": "^2.1.1",
         "common-ancestor-path": "^2.0.0",
         "cookie": "^1.1.1",
-        "devalue": "5.8.1",
+        "devalue": "^5.6.3",
         "diff": "^8.0.3",
         "dset": "^3.1.4",
         "es-module-lexer": "^2.0.0",
@@ -10255,7 +10269,7 @@
         "vscode-languageserver-textdocument": "^1.0.1",
         "vscode-languageserver-types": "^3.16.0",
         "vscode-uri": "^3.0.2",
-        "yaml": "2.8.4"
+        "yaml": "2.7.1"
       },
       "dependencies": {
         "ajv": {
@@ -10288,6 +10302,12 @@
           "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.5.8.tgz",
           "integrity": "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==",
           "dev": true
+        },
+        "yaml": {
+          "version": "2.7.1",
+          "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz",
+          "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==",
+          "dev": true
         }
       }
     },
diff --git a/package.json b/package.json
index f33781d..b7d350e 100644
--- a/package.json
+++ b/package.json
@@ -46,9 +46,8 @@
     "prettier-plugin-astro": "^0.14.1",
     "rehype-autolink-headings": "^7.1.0",
     "rehype-slug": "^6.0.0",
-    "typescript": "^5.9.3"
-  },
-  "dependencies": {
+    "typescript": "^5.9.3",
+    "unist-util-visit": "^5.1.0",
     "sharp": "^0.34.5"
   }
 }
diff --git a/src/components/Footer.astro b/src/components/Footer.astro
index ee75965..45f2c8f 100644
--- a/src/components/Footer.astro
+++ b/src/components/Footer.astro
@@ -19,11 +19,14 @@ const footerNavItems = navItems.filter((item) => item.href !== '/');
       }
     
-  
+    {/* address wraps only the author's contact details, per HTML spec. */}
+    
+  
diff --git a/src/components/PostMediaFigure.astro b/src/components/PostMediaFigure.astro
index 4968cfb..9a3a936 100644
--- a/src/components/PostMediaFigure.astro
+++ b/src/components/PostMediaFigure.astro
@@ -17,15 +17,29 @@ const fallbackFormatFor = (format: string | undefined): 'png' | 'jpg' =>
 
{ item.type === 'video' ? ( - + // Decorative videos auto-play silently (like a GIF) and are hidden from + // assistive tech. Meaningful videos expose controls and an accessible + // name so users can play and identify them. + item.decorative ? ( + + ) : ( + + ) ) : ( item.src && ( - {noindex && } {!noindex && } -