[object Object]

← back to Thesetdecorator

TSD a11y: fix WCAG 1.3.1 heading-order skips (DTD verdict A) — sr-only h2 before card-grids on 5 pages

9f62c217a59eb3cf70d05c756c3c51d883b85fac · 2026-06-03 09:07:48 -0700 · Steve

Files touched

Diff

commit 9f62c217a59eb3cf70d05c756c3c51d883b85fac
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Jun 3 09:07:48 2026 -0700

    TSD a11y: fix WCAG 1.3.1 heading-order skips (DTD verdict A) — sr-only h2 before card-grids on 5 pages
---
 public/fancy-search.html     |  1 +
 public/games.html            |  1 +
 public/resources.html        |  1 +
 public/submit.html           |  1 +
 public/unions.html           |  1 +
 scripts/heading-order-fix.py | 52 ++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 57 insertions(+)

diff --git a/public/fancy-search.html b/public/fancy-search.html
index 9b7ad00..936678e 100644
--- a/public/fancy-search.html
+++ b/public/fancy-search.html
@@ -127,6 +127,7 @@
 
         <section>
           <div class="fs-meta" id="meta">Loading…</div>
+          <h2 class="sr-only">Search results</h2>
           <div class="fs-results" id="results"></div>
         </section>
       </div>
diff --git a/public/games.html b/public/games.html
index 9c0d5e5..94d3da9 100644
--- a/public/games.html
+++ b/public/games.html
@@ -27,6 +27,7 @@
     <h1>Play with the props.</h1>
     <p class="tagline">Party games for film-set-decoration nerds. Solo or invite friends. <a href="/games/wwhl-brand-sheet.html">View the brand sheet ↗</a></p>
 
+    <h2 class="sr-only">Games</h2>
     <div class="game-grid">
       <a class="game-card" href="/games/know-your-set-dec.html" data-tilt="0">
         <div class="emoji">🎬</div>
diff --git a/public/resources.html b/public/resources.html
index 6ce9b8e..6cde744 100644
--- a/public/resources.html
+++ b/public/resources.html
@@ -92,6 +92,7 @@
       </div>
 
       <p class="muted" id="meta" style="font-size:0.85rem;margin:0 0 0.6rem">Loading…</p>
+      <h2 class="sr-only">Resources</h2>
       <div class="res-grid" id="grid" data-density-target></div>
     </section>
   </main>
diff --git a/public/submit.html b/public/submit.html
index f597a76..3ce26c6 100644
--- a/public/submit.html
+++ b/public/submit.html
@@ -72,6 +72,7 @@
   <h1>Sell your photography to film + TV</h1>
   <p class="lede">Share a Google Drive folder. We crawl it nightly, auto-filter people out, write set-decorator-targeted titles, list your photos for license. <strong>You keep 70%</strong>. No exclusivity. Pull any photo any time.</p>
 
+  <h2 class="sr-only">How it works</h2>
   <div class="steps">
     <div class="step"><span class="num">1</span><h3>Share a folder</h3><p>Right-click a folder in Drive → <strong>Share</strong> → enter <code id="submissions-email">submissions@thesetdecorator.com</code> → set permission to <strong>Viewer</strong>.</p></div>
     <div class="step"><span class="num">2</span><h3>Tell us where</h3><p>Paste the folder URL in the form below + sign the photographer warranty (1 page, plain English).</p></div>
diff --git a/public/unions.html b/public/unions.html
index 286a27b..a4b2bf0 100644
--- a/public/unions.html
+++ b/public/unions.html
@@ -59,6 +59,7 @@
         <button class="city-tab" data-filter="CA">Canada</button>
       </div>
 
+      <h2 class="sr-only">Unions directory</h2>
       <div id="union-list"></div>
     </section>
   </main>
diff --git a/scripts/heading-order-fix.py b/scripts/heading-order-fix.py
new file mode 100644
index 0000000..b6d43ba
--- /dev/null
+++ b/scripts/heading-order-fix.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python3
+"""Idempotent WCAG 1.3.1 heading-order fix for TSD (DTD verdict A).
+
+8 pages skipped h1->h3. Fix: insert a visually-hidden <h2 class="sr-only">
+section heading immediately before each card-grid / step container, so the
+existing repeating <h3>s become correctly-nested h1->h2->h3 descendants in the
+document outline. Zero visible change (.sr-only already exists in main.css);
+no JS-template edits. Complex/admin pages (stories, union-talk, logo-variants)
+deliberately left alone per the DTD verdict.
+
+Idempotent: skips a page that already has the sr-only h2 on the line above the
+anchor. Reversible: single <h2> line inserted per page.
+    python3 scripts/heading-order-fix.py
+"""
+import os, glob
+
+PUB = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "public")
+
+# filename -> (anchor substring that identifies the grid/container line, sr-only heading text)
+TARGETS = {
+    "games.html":        ('<div class="game-grid">',                 "Games"),
+    "fancy-search.html": ('<div class="fs-results" id="results">',   "Search results"),
+    "resources.html":    ('<div class="res-grid" id="grid"',         "Resources"),
+    "unions.html":       ('<div id="union-list">',                   "Unions directory"),
+    "submit.html":       ('<div class="steps">',                     "How it works"),
+}
+
+changed, skipped, missing = [], [], []
+for name, (anchor, heading) in TARGETS.items():
+    path = os.path.join(PUB, name)
+    if not os.path.exists(path):
+        missing.append(name); continue
+    lines = open(path, encoding="utf-8").read().splitlines(keepends=True)
+    marker = f'<h2 class="sr-only">{heading}</h2>'
+    if any(marker in ln for ln in lines):
+        skipped.append(name); continue
+    out, done = [], False
+    for ln in lines:
+        if not done and anchor in ln:
+            indent = ln[:len(ln) - len(ln.lstrip())]
+            out.append(f'{indent}{marker}\n')
+            done = True
+        out.append(ln)
+    if not done:
+        missing.append(f"{name} (anchor not found)"); continue
+    open(path, "w", encoding="utf-8").write("".join(out))
+    changed.append(name)
+
+print(f"changed ({len(changed)}): {', '.join(changed) or '-'}")
+print(f"skipped/already ({len(skipped)}): {', '.join(skipped) or '-'}")
+if missing:
+    print(f"MISSING/anchor-fail: {', '.join(missing)}")

← 1b62c7a backlog: mark loop #2 items done (favicon, canonical)  ·  back to Thesetdecorator  ·  backlog: mark loop #3 done (heading-order) + record audited- 1ec82e5 →