test: vitest unit + playwright e2e suites; fix a11y, contrast, no-JS reveal

- vitest: dictionary parity, slug-map bijection, content-schema validation, JSON-LD (23)
- playwright: both locales, language-switch mapping (incl. no-JS), CV downloads,
  form happy-path + honeypot, axe a11y on 5 templates x 2 themes (23)
- fix: raise ink-faint + light accent to meet WCAG AA 4.5:1 (axe-verified)
- fix: gate reveal animations behind html.js so content is visible without JS
  (progressive enhancement - was hidden at opacity 0); scan reduced-motion path
- fix: validate contact form before the anti-bot time-trap (no false success)
- chore: ESLint node globals, typed diagram props, resvg fontFiles, prettier pass

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
cesnimda
2026-07-04 06:14:18 +02:00
parent 9fa16b650d
commit 033c9ec315
64 changed files with 1627 additions and 278 deletions
+10 -8
View File
@@ -3,8 +3,10 @@
Reduced-motion is a single global override — not per-component JS (ANIMATION_SPEC §1).
*/
/* ---- Reveal (A2): opacity + 12px rise, staggered by --reveal-index ---- */
[data-reveal] {
/* ---- Reveal (A2): opacity + 12px rise, staggered by --reveal-index ----
Gated behind html.js so content stays visible with no JavaScript
(progressive enhancement — content is never hidden by animation). */
html.js [data-reveal] {
opacity: 0;
transform: translateY(12px);
transition:
@@ -12,7 +14,7 @@
transform var(--dur-entrance) var(--ease-out);
transition-delay: calc(var(--reveal-index, 0) * 60ms);
}
[data-reveal].is-revealed {
html.js [data-reveal].is-revealed {
opacity: 1;
transform: none;
}
@@ -68,7 +70,7 @@
}
/* ---- Timeline spine grow (A8) ---- */
.timeline-spine {
html.js .timeline-spine {
transform: scaleY(0);
transform-origin: top;
transition: transform var(--dur-entrance) var(--ease-out);
@@ -118,14 +120,14 @@
transition-duration: 1ms !important;
scroll-behavior: auto !important;
}
[data-reveal] {
opacity: 1;
transform: none;
html.js [data-reveal] {
opacity: 1 !important;
transform: none !important;
}
.trace-line {
stroke-dashoffset: 0;
}
.timeline-spine {
transform: scaleY(1);
transform: scaleY(1) !important;
}
}