tuffgal 0.2.0-alpha.3 → 0.2.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/CHANGELOG.md +41 -20
  2. package/README.md +6 -6
  3. package/dist/cli.d.ts +5 -5
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +12 -5
  6. package/dist/cli.js.map +1 -1
  7. package/dist/commands/init.d.ts +1 -1
  8. package/dist/commands/init.js +6 -6
  9. package/dist/commands/supervise.d.ts +3 -3
  10. package/dist/commands/supervise.js +8 -4
  11. package/dist/commands/supervise.js.map +1 -1
  12. package/dist/config.d.ts +29 -13
  13. package/dist/config.d.ts.map +1 -1
  14. package/dist/config.js +5 -2
  15. package/dist/config.js.map +1 -1
  16. package/dist/coverage/screens.d.ts +10 -5
  17. package/dist/coverage/screens.d.ts.map +1 -1
  18. package/dist/coverage/screens.js +18 -8
  19. package/dist/coverage/screens.js.map +1 -1
  20. package/dist/reporter/assets/report.css +11 -11
  21. package/dist/reporter/assets/report.js +23 -23
  22. package/dist/reporter/template.js +48 -46
  23. package/dist/reporter/template.js.map +1 -1
  24. package/dist/runner/approve.d.ts +5 -5
  25. package/dist/runner/approve.js +5 -5
  26. package/dist/runner/approveFrom.d.ts +8 -8
  27. package/dist/runner/approveFrom.js +32 -31
  28. package/dist/runner/approveFrom.js.map +1 -1
  29. package/dist/runner/breakpointPasses.d.ts +16 -9
  30. package/dist/runner/breakpointPasses.d.ts.map +1 -1
  31. package/dist/runner/breakpointPasses.js +17 -9
  32. package/dist/runner/breakpointPasses.js.map +1 -1
  33. package/dist/runner/bridges/devServers.d.ts +10 -1
  34. package/dist/runner/bridges/devServers.d.ts.map +1 -1
  35. package/dist/runner/bridges/devServers.js +16 -8
  36. package/dist/runner/bridges/devServers.js.map +1 -1
  37. package/dist/runner/coverage.d.ts +3 -3
  38. package/dist/runner/coverage.js +5 -5
  39. package/dist/runner/coverage.js.map +1 -1
  40. package/dist/runner/exitCode.d.ts +7 -7
  41. package/dist/runner/exitCode.js +7 -7
  42. package/dist/runner/interpolate.js +1 -1
  43. package/dist/runner/interpolate.js.map +1 -1
  44. package/dist/runner/manifest.d.ts +16 -16
  45. package/dist/runner/manifest.js +12 -12
  46. package/dist/runner/mode.d.ts +2 -2
  47. package/dist/runner/mode.js +4 -4
  48. package/dist/runner/orphanScan.d.ts +3 -3
  49. package/dist/runner/orphanScan.js +5 -5
  50. package/dist/runner/orphanScan.js.map +1 -1
  51. package/dist/runner/resolveLocator.d.ts +5 -5
  52. package/dist/runner/resolveLocator.js +6 -6
  53. package/dist/runner/resolveLocator.js.map +1 -1
  54. package/dist/runner/run.d.ts +55 -18
  55. package/dist/runner/run.d.ts.map +1 -1
  56. package/dist/runner/run.js +118 -67
  57. package/dist/runner/run.js.map +1 -1
  58. package/dist/runner/runAction.d.ts +4 -4
  59. package/dist/runner/runAction.d.ts.map +1 -1
  60. package/dist/runner/runAction.js +103 -39
  61. package/dist/runner/runAction.js.map +1 -1
  62. package/dist/runner/runStory.d.ts +29 -18
  63. package/dist/runner/runStory.d.ts.map +1 -1
  64. package/dist/runner/runStory.js +38 -42
  65. package/dist/runner/runStory.js.map +1 -1
  66. package/dist/runner/scheduler.d.ts +11 -0
  67. package/dist/runner/scheduler.d.ts.map +1 -1
  68. package/dist/runner/scheduler.js +1 -1
  69. package/dist/runner/scheduler.js.map +1 -1
  70. package/dist/runner/steps/intercept.d.ts +6 -4
  71. package/dist/runner/steps/intercept.d.ts.map +1 -1
  72. package/dist/runner/steps/intercept.js.map +1 -1
  73. package/dist/runner/steps/navigate.d.ts +5 -2
  74. package/dist/runner/steps/navigate.d.ts.map +1 -1
  75. package/dist/runner/steps/navigate.js +17 -3
  76. package/dist/runner/steps/navigate.js.map +1 -1
  77. package/dist/runner/steps/read.d.ts +1 -1
  78. package/dist/runner/steps/read.js +1 -1
  79. package/dist/runner/steps/scroll.d.ts +1 -1
  80. package/dist/runner/steps/scroll.d.ts.map +1 -1
  81. package/dist/runner/steps/scroll.js +3 -2
  82. package/dist/runner/steps/scroll.js.map +1 -1
  83. package/dist/schema/action.d.ts +2 -2
  84. package/dist/schema/action.d.ts.map +1 -1
  85. package/dist/schema/action.js +58 -13
  86. package/dist/schema/action.js.map +1 -1
  87. package/dist/schema/load.js +1 -1
  88. package/dist/schema/load.js.map +1 -1
  89. package/dist/schema/result.d.ts +22 -22
  90. package/dist/schema/result.d.ts.map +1 -1
  91. package/dist/schema/result.js +1 -1
  92. package/dist/schema/story.d.ts +1 -1
  93. package/dist/schema/story.js +5 -5
  94. package/dist/screenshots/baselineStore.d.ts +44 -21
  95. package/dist/screenshots/baselineStore.d.ts.map +1 -1
  96. package/dist/screenshots/baselineStore.js +59 -28
  97. package/dist/screenshots/baselineStore.js.map +1 -1
  98. package/dist/screenshots/capture.d.ts +35 -4
  99. package/dist/screenshots/capture.d.ts.map +1 -1
  100. package/dist/screenshots/capture.js +61 -9
  101. package/dist/screenshots/capture.js.map +1 -1
  102. package/dist/screenshots/diff.d.ts +57 -8
  103. package/dist/screenshots/diff.d.ts.map +1 -1
  104. package/dist/screenshots/diff.js +78 -28
  105. package/dist/screenshots/diff.js.map +1 -1
  106. package/dist/util.d.ts +23 -2
  107. package/dist/util.d.ts.map +1 -1
  108. package/dist/util.js +42 -2
  109. package/dist/util.js.map +1 -1
  110. package/package.json +7 -5
package/dist/config.js CHANGED
@@ -30,6 +30,7 @@ export const BREAKPOINTS = {
30
30
  };
31
31
  const DEFAULTS = {
32
32
  captureMode: 'viewport',
33
+ maxFullPagePixels: 30_000_000,
33
34
  defaultTimeoutMs: 10_000,
34
35
  navigationTimeoutMs: 15_000,
35
36
  frozenTime: '2026-01-15T12:00:00.000Z',
@@ -75,7 +76,7 @@ export async function loadConfig(cwd) {
75
76
  * dereferences it. The config module is dynamically imported, so TypeScript
76
77
  * cannot guarantee it actually matches `TuffgalConfig`; without this a missing
77
78
  * `paths` or a non-string `baseUrl` throws an opaque TypeError inside
78
- * `resolveConfig`. Validation covers the fields `resolveConfig` reads — the
79
+ * `resolveConfig`. Validation covers the fields `resolveConfig` reads. The
79
80
  * `database`/`devServers` bridges hold functions and are left to fail at their
80
81
  * own call sites. `source` is the config file path, surfaced in every message.
81
82
  */
@@ -109,6 +110,7 @@ export function assertValidConfig(input, source) {
109
110
  'defaultTimeoutMs',
110
111
  'navigationTimeoutMs',
111
112
  'workers',
113
+ 'maxFullPagePixels',
112
114
  ]) {
113
115
  const value = config[key];
114
116
  if (value !== undefined && (typeof value !== 'number' || value <= 0)) {
@@ -173,6 +175,7 @@ function resolveConfig(input, rootDir) {
173
175
  storageStatePins: input.storageStatePins ?? [],
174
176
  breakpoints,
175
177
  captureMode: input.captureMode ?? DEFAULTS.captureMode,
178
+ maxFullPagePixels: input.maxFullPagePixels ?? DEFAULTS.maxFullPagePixels,
176
179
  defaultTimeoutMs: input.defaultTimeoutMs ?? DEFAULTS.defaultTimeoutMs,
177
180
  navigationTimeoutMs: input.navigationTimeoutMs ?? DEFAULTS.navigationTimeoutMs,
178
181
  frozenTime: input.frozenTime ?? DEFAULTS.frozenTime,
@@ -223,7 +226,7 @@ export function resolveSelectorList(selectors) {
223
226
  }
224
227
  /**
225
228
  * Resolves `config.breakpoints` to an always-non-empty list: the explicit
226
- * selectors when set (order preserved, duplicate names dropped — first wins),
229
+ * selectors when set (order preserved, duplicate names dropped, first wins),
227
230
  * else a single `desktop` breakpoint (1280x800). `assertValidConfig` has
228
231
  * already rejected unknown/empty `breakpoints`, so a non-empty input dedupes to
229
232
  * at least one entry; the cast restores the non-empty tuple type that lets
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,18 @@
1
1
  import type { CoverageMetric } from '../schema/result.ts';
2
2
  /**
3
3
  * Walks every `visit-*.json` action under `<actions>/screens/` and reports how
4
- * many have a baseline screenshot at `<baselineRoot>/<action-name>/0.png`. The
5
- * action name is taken from the filename (minus the `.json` suffix), which by
6
- * convention matches the action's declared `action` field.
4
+ * many have at least one baseline screenshot under
5
+ * `<baselineRoot>/<action-name>/`. The runner keys baselines by breakpoint
6
+ * (`<breakpoint>.png`, e.g. `desktop.png`) and a project baselined before that
7
+ * feature keeps a single legacy `0.png`; either counts, so a screen is covered
8
+ * when its action directory holds any `.png` file (non-PNG siblings such as the
9
+ * `<breakpoint>.a11y.yaml` snapshots are ignored). The action name is taken from
10
+ * the filename (minus the `.json` suffix), which by convention matches the
11
+ * action's declared `action` field.
7
12
  *
8
13
  * `baselineRoot` is the set the run compares against: committed `paths.baselines`
9
- * in CI mode, the per-machine `paths.localCache` in local mode (the caller — see
10
- * `coverageComparisonRoot` — picks it by mode so a local run never reads
14
+ * in CI mode, the per-machine `paths.localCache` in local mode (the caller, see
15
+ * `coverageComparisonRoot`, picks it by mode so a local run never reads
11
16
  * `paths.baselines`). The metric's meaning is the same either way: how many
12
17
  * screens have a baseline to diff against.
13
18
  */
@@ -1 +1 @@
1
- {"version":3,"file":"screens.d.ts","sourceRoot":"","sources":["../../src/coverage/screens.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAI1D;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CACzC,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,cAAc,CAAC,CA6BzB"}
1
+ {"version":3,"file":"screens.d.ts","sourceRoot":"","sources":["../../src/coverage/screens.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAI1D;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,qBAAqB,CACzC,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,cAAc,CAAC,CAoCzB"}
@@ -1,15 +1,20 @@
1
- import { access, readdir } from 'node:fs/promises';
1
+ import { readdir } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  const SCREENS_SUBDIR = 'screens';
4
4
  /**
5
5
  * Walks every `visit-*.json` action under `<actions>/screens/` and reports how
6
- * many have a baseline screenshot at `<baselineRoot>/<action-name>/0.png`. The
7
- * action name is taken from the filename (minus the `.json` suffix), which by
8
- * convention matches the action's declared `action` field.
6
+ * many have at least one baseline screenshot under
7
+ * `<baselineRoot>/<action-name>/`. The runner keys baselines by breakpoint
8
+ * (`<breakpoint>.png`, e.g. `desktop.png`) and a project baselined before that
9
+ * feature keeps a single legacy `0.png`; either counts, so a screen is covered
10
+ * when its action directory holds any `.png` file (non-PNG siblings such as the
11
+ * `<breakpoint>.a11y.yaml` snapshots are ignored). The action name is taken from
12
+ * the filename (minus the `.json` suffix), which by convention matches the
13
+ * action's declared `action` field.
9
14
  *
10
15
  * `baselineRoot` is the set the run compares against: committed `paths.baselines`
11
- * in CI mode, the per-machine `paths.localCache` in local mode (the caller — see
12
- * `coverageComparisonRoot` — picks it by mode so a local run never reads
16
+ * in CI mode, the per-machine `paths.localCache` in local mode (the caller, see
17
+ * `coverageComparisonRoot`, picks it by mode so a local run never reads
13
18
  * `paths.baselines`). The metric's meaning is the same either way: how many
14
19
  * screens have a baseline to diff against.
15
20
  */
@@ -28,11 +33,16 @@ export async function computeScreenCoverage(actionsDir, baselineRoot) {
28
33
  .sort();
29
34
  const missing = [];
30
35
  for (const name of screenNames) {
31
- const baseline = join(baselineRoot, name, '0.png');
36
+ const actionDir = join(baselineRoot, name);
37
+ let hasBaseline = false;
32
38
  try {
33
- await access(baseline);
39
+ const baselineFiles = await readdir(actionDir);
40
+ hasBaseline = baselineFiles.some((file) => file.toLowerCase().endsWith('.png'));
34
41
  }
35
42
  catch {
43
+ hasBaseline = false;
44
+ }
45
+ if (!hasBaseline) {
36
46
  missing.push(name);
37
47
  }
38
48
  }
@@ -1 +1 @@
1
- {"version":3,"file":"screens.js","sourceRoot":"","sources":["../../src/coverage/screens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,MAAM,cAAc,GAAG,SAAS,CAAC;AAEjC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,UAAkB,EAClB,YAAoB;IAEpB,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IACrD,IAAI,OAAO,GAAa,EAAE,CAAC;IAC3B,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACzD,CAAC;IACD,MAAM,WAAW,GAAG,OAAO;SACxB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;SACxC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;SAC3C,IAAI,EAAE,CAAC;IACV,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QACnD,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC;IACjC,MAAM,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC;IACvC,OAAO;QACL,KAAK;QACL,OAAO;QACP,KAAK,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,KAAK;QACxC,OAAO;KACR,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"screens.js","sourceRoot":"","sources":["../../src/coverage/screens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,MAAM,cAAc,GAAG,SAAS,CAAC;AAEjC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,UAAkB,EAClB,YAAoB;IAEpB,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IACrD,IAAI,OAAO,GAAa,EAAE,CAAC;IAC3B,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACzD,CAAC;IACD,MAAM,WAAW,GAAG,OAAO;SACxB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;SACxC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;SAC3C,IAAI,EAAE,CAAC;IACV,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QAC3C,IAAI,WAAW,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC;YAC/C,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CACxC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CACpC,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,WAAW,GAAG,KAAK,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC;IACjC,MAAM,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC;IACvC,OAAO;QACL,KAAK;QACL,OAAO;QACP,KAAK,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,KAAK;QACxC,OAAO;KACR,CAAC;AACJ,CAAC"}
@@ -347,7 +347,7 @@ h2 {
347
347
  color: var(--new-fg);
348
348
  }
349
349
 
350
- /* "all" stays NEUTRAL — never a status color, never blue. Pressed is a filled
350
+ /* "all" stays NEUTRAL; never a status color, never blue. Pressed is a filled
351
351
  neutral pill (it is pressed-by-default at load, so this is the resting view). */
352
352
  .summary-item[data-status='all'] .summary-filter {
353
353
  color: var(--text);
@@ -364,7 +364,7 @@ h2 {
364
364
  outline-offset: 2px;
365
365
  }
366
366
 
367
- /* Breakpoint filter — the SECOND, independent single-select filter dimension,
367
+ /* Breakpoint filter; the SECOND, independent single-select filter dimension,
368
368
  rendered below the status totals inside the summary region (only for
369
369
  multi-breakpoint runs). A role="group" row of neutral pills; report.js ANDs it
370
370
  with the status filter. The row sits on the page --bg with a top gap that also
@@ -376,15 +376,15 @@ h2 {
376
376
  margin-top: 0.75rem;
377
377
  }
378
378
 
379
- /* Neutral pills — no status hue, so the two filter rows read as siblings by
379
+ /* Neutral pills; no status hue, so the two filter rows read as siblings by
380
380
  geometry, not color. Same pill geometry/radius as the status filter.
381
381
  Default is an OUTLINE pill: transparent bg, --text-muted border (≥3:1 vs --bg
382
382
  in both themes → 1.4.11), --text label (≥4.5:1 → 1.4.3). Hover brightens the
383
383
  border + adds a faint neutral tint. Pressed is a FILLED pill: --text fill,
384
- --bg label, bold weight — the ONLY filled + bold pill, so the pressed state is
384
+ --bg label, bold weight; the ONLY filled + bold pill, so the pressed state is
385
385
  never conveyed by color alone (1.4.1); the inverse fill clears 4.5:1 in both
386
386
  themes. Focus ring is --accent 2px / offset 2px, painted on the page --bg
387
- outside the pill — identical to the status filter. Target size ≥24×24 via
387
+ outside the pill; identical to the status filter. Target size ≥24×24 via
388
388
  min-height/min-width (2.5.8). Stays a <button>: it filters in place. */
389
389
  .breakpoint-filter {
390
390
  display: inline-flex;
@@ -497,7 +497,7 @@ h2 {
497
497
  font-size: 0.8125rem;
498
498
  }
499
499
 
500
- /* Link-styled verbs ("Expand" / "Collapse") — still <button>s, they act in
500
+ /* Link-styled verbs ("Expand" / "Collapse"); still <button>s, they act in
501
501
  place. The underline is the affordance; verbs exceed 24px wide intrinsically,
502
502
  so min-height alone carries 2.5.8. */
503
503
  .story-bulk-toggle-button {
@@ -527,7 +527,7 @@ h2 {
527
527
  }
528
528
 
529
529
  /* Disabled verb: removing the underline is the color-independent cue (no
530
- opacity — it can compound below the contrast floor). Disabled controls are
530
+ opacity; it can compound below the contrast floor). Disabled controls are
531
531
  1.4.3/1.4.11 exempt, but the state stays perceptible without color. */
532
532
  .story-bulk-toggle-button:disabled {
533
533
  color: var(--text-subtle);
@@ -931,7 +931,7 @@ summary.action-row:focus-visible {
931
931
  chip focus ring is never clipped by the stage overflow nor painted over
932
932
  screenshot pixels. The chips reuse `.chip--toggle` (border `--border-bright`,
933
933
  `--accent` focus ring) and the same `.shot-radio-label` base styles as the
934
- radio-tab viewer — permanently visible, no interactiveMode-specific chip
934
+ radio-tab viewer; permanently visible, no interactiveMode-specific chip
935
935
  styling. Visible chips are the mouse/touch path to every variant (including
936
936
  Diff, which the press gesture does not cover) and double as the viewer's
937
937
  only visible affordance; the press-and-hold blink-compare in report.js is
@@ -946,9 +946,9 @@ summary.action-row:focus-visible {
946
946
  border: 0;
947
947
  }
948
948
 
949
- /* Persistent caption naming the DISPLAYED variant — the committed one, or the
949
+ /* Persistent caption naming the DISPLAYED variant; the committed one, or the
950
950
  press-and-hold preview while it is held (report.js keeps it in sync). Text on
951
- `--text` (≥4.5:1), so the active variant is never conveyed by color alone —
951
+ `--text` (≥4.5:1), so the active variant is never conveyed by color alone ;
952
952
  it pairs the checked chip's accent border with this readable label.
953
953
  aria-hidden keeps it visual only: the checked radio is the single accessible
954
954
  source of committed state. */
@@ -964,7 +964,7 @@ summary.action-row:focus-visible {
964
964
 
965
965
  /* The stage clips the screenshot to the viewport height. Its border uses
966
966
  `--border-bright` (3:1 non-text contrast). overflow:hidden only ever clips
967
- the image — the controls live in the sibling fieldset above. */
967
+ the image; the controls live in the sibling fieldset above. */
968
968
  .shot-stage {
969
969
  margin-top: 0.5rem;
970
970
  margin-left: 2.2rem;
@@ -18,7 +18,7 @@
18
18
  //
19
19
  // Both writers use `textContent` (not `innerHTML`). If the new message
20
20
  // equals the current `textContent`, some screen readers will not re-announce
21
- // — this is a documented platform limitation, not worked around here. A
21
+ //; this is a documented platform limitation, not worked around here. A
22
22
  // future caller that needs forced re-announcement would add a separate
23
23
  // `forceWrite()`; out of scope for this helper.
24
24
  //
@@ -115,7 +115,7 @@
115
115
  });
116
116
  });
117
117
 
118
- // Selection lives in the DOM, so a collapse only HIDES it — a prior
118
+ // Selection lives in the DOM, so a collapse only HIDES it; a prior
119
119
  // Baseline/Diff pick would otherwise still be checked on the next expand.
120
120
  // Reset on COLLAPSE, not expand: the `toggle` event fires AFTER the state
121
121
  // change, so resetting on open flashes a visible baseline→actual jump.
@@ -138,7 +138,7 @@
138
138
 
139
139
  // Interactive screenshot viewer (rendered when the report is built with
140
140
  // interactiveMode). Each action shows ONE shared <img>. A native radio group
141
- // (always-visible chips) is the committed-state source of truth — keyboard,
141
+ // (always-visible chips) is the committed-state source of truth; keyboard,
142
142
  // touch, and AT operate it exactly like the radio-tab viewer, and the chips
143
143
  // are the only path to Diff. On top of that, the mouse gesture is a STATELESS
144
144
  // blink-compare layered on the same <img>:
@@ -150,14 +150,14 @@
150
150
  // There is deliberately NO hover behavior: hover swapped the image the moment
151
151
  // the pointer wandered in, so the resting state under the cursor was the OLD
152
152
  // screenshot. Rest = committed; press = intentional compare. Diff is off the
153
- // gesture too (secondary forensic view — its chip covers it).
153
+ // gesture too (secondary forensic view; its chip covers it).
154
154
  // The preview rewrites img.src plus the sight-only (aria-hidden) caption, so
155
155
  // the "Showing: {variant}" line always names the DISPLAYED image. It never
156
156
  // changes the checked radio, the img alt, any ARIA attribute, or any live
157
- // region — so pressing announces nothing by construction. The caption and the
157
+ // region; so pressing announces nothing by construction. The caption and the
158
158
  // checked radio are two different truths on purpose: the caption tracks what
159
159
  // is displayed (preview included), the checked radio tracks the committed
160
- // state AT operates on; during a press they diverge briefly — both remain
160
+ // state AT operates on; during a press they diverge briefly; both remain
161
161
  // accurate. Do NOT "fix" that by moving radio.checked during preview: checked
162
162
  // is the single accessible source of committed state, and press-flapping it
163
163
  // would announce to AT and leave revert() nothing stable to revert to.
@@ -193,12 +193,12 @@
193
193
  if (src !== null) sources[variant] = src;
194
194
  });
195
195
 
196
- // `committed` mirrors the checked radio — the ONLY state the keyboard /
196
+ // `committed` mirrors the checked radio; the ONLY state the keyboard /
197
197
  // touch / AT path mutates. Mouse preview reverts here on release, leave,
198
198
  // and dragstart.
199
199
  var committed = null;
200
200
 
201
- // Caption always names the DISPLAYED variant — committed or previewed.
201
+ // Caption always names the DISPLAYED variant; committed or previewed.
202
202
  // The equality check is a cheap idempotence guard: writes are skipped
203
203
  // when the label is already showing (e.g. revert after a no-op press).
204
204
  function setCaption(variant) {
@@ -251,7 +251,7 @@
251
251
  stage.addEventListener('mouseleave', revert);
252
252
  // A press that turns into a native image drag can swallow the mouseup
253
253
  // (the pointer never "leaves" the stage), which would leave the preview
254
- // stuck. Native drag itself stays enabled — save-image is a platform
254
+ // stuck. Native drag itself stays enabled; save-image is a platform
255
255
  // feature, not ours to suppress.
256
256
  stage.addEventListener('dragstart', revert);
257
257
  }
@@ -269,7 +269,7 @@
269
269
  // `pass`): a story is status-eligible iff its own rollup `data-status`
270
270
  // (emitted on the .story element) matches the active status, or the status
271
271
  // filter is "all". Within an eligible story, non-matching actions are then
272
- // PRUNED (hidden) so e.g. the `changed` view shows only the changed rows —
272
+ // PRUNED (hidden) so e.g. the `changed` view shows only the changed rows ;
273
273
  // and expand-all opens only those rows' screenshots. `skipped` actions are
274
274
  // exempt from pruning: `skipped` exists on actions but not in the story
275
275
  // rollup vocabulary, so pruning it could empty a story the pill counts (a
@@ -289,7 +289,7 @@
289
289
  //
290
290
  // The two axes are ANDed: a story shows iff it is status-eligible (story
291
291
  // rollup) AND breakpoint-eligible (has a matching container). apply() is a
292
- // single top-down pass — story → [data-breakpoint] container — that reads BOTH
292
+ // single top-down pass; story → [data-breakpoint] container; that reads BOTH
293
293
  // active tokens, so re-running it after either axis changes yields the current
294
294
  // intersection (no stale hides carried between axes). The breakpoint pills
295
295
  // render only for multi-breakpoint runs, so on a single-breakpoint run this
@@ -326,7 +326,7 @@
326
326
 
327
327
  // Cached for the zero-match disable + focus-rescue logic in apply(). The
328
328
  // scope word is now static markup ("screenshots" visible, " all screenshots"
329
- // sr-only), so the buttons are never relabelled per filter — the filter's own
329
+ // sr-only), so the buttons are never relabelled per filter; the filter's own
330
330
  // live-region announcement already covers the context change.
331
331
  var expandButton = document.querySelector('[data-bulk-toggle="expand"]');
332
332
  var collapseButton = document.querySelector(
@@ -359,18 +359,18 @@
359
359
  // reveal starts from a clean slate.
360
360
  // 3. STATUS pruning is action-level. Inside each breakpoint-eligible
361
361
  // container, an action is hidden when statusFilter is active and the
362
- // action's own data-status differs — EXCEPT `skipped` actions, which
362
+ // action's own data-status differs; EXCEPT `skipped` actions, which
363
363
  // are never pruned. `skipped` is not a story-rollup status, so pruning
364
364
  // it could empty a story the pill counts (a dependency-blocked story
365
365
  // is rollup `failed` with only `skipped` actions); skipped rows are
366
366
  // context for the failure, not mismatches.
367
- // 4. A container pruned to zero visible actions is hidden — a captioned
367
+ // 4. A container pruned to zero visible actions is hidden; a captioned
368
368
  // empty list is a dead end. The story shows iff at least one container
369
369
  // survives with a visible action.
370
370
  // Deliberate gate asymmetry under combined filters: the ROLLUP gates the
371
371
  // story, the exact match prunes actions. Under "changed at mobile", a story
372
372
  // whose rollup is `failed` stays hidden even if its mobile container holds
373
- // a `changed` action — that matches the pill's per-story rollup semantics.
373
+ // a `changed` action; that matches the pill's per-story rollup semantics.
374
374
  //
375
375
  // Recompute invariant: apply() re-runs this for EVERY story on every filter
376
376
  // change, unconditionally recomputing action.hidden in every breakpoint-
@@ -462,7 +462,7 @@
462
462
  trigger.focus();
463
463
  }
464
464
  // Disable both bulk-toggle buttons when the intersection matches zero
465
- // stories — there is nothing to expand/collapse. Runs on EVERY apply()
465
+ // stories; there is nothing to expand/collapse. Runs on EVERY apply()
466
466
  // call, so a filter change that re-reveals stories re-enables them.
467
467
  if (expandButton) expandButton.disabled = hasNone;
468
468
  if (collapseButton) collapseButton.disabled = hasNone;
@@ -524,7 +524,7 @@
524
524
  var token = button.getAttribute('data-filter');
525
525
  var isActive = button.getAttribute('aria-pressed') === 'true';
526
526
  // Re-clicking the active, non-"all" filter reverts that axis to "all".
527
- // Focus stays on the clicked button — it is in the summary row and never
527
+ // Focus stays on the clicked button; it is in the summary row and never
528
528
  // hidden by its own action.
529
529
  if (isActive && token !== 'all') {
530
530
  setPressed(statusButtons, statusAllButton);
@@ -561,9 +561,9 @@
561
561
  // Bulk-toggle (expand all / collapse all) for the screenshot <details> panels.
562
562
  // Acts on the moment: only visible rows (.story:not([hidden])) are affected,
563
563
  // so the filter scope wins. Each <details> retains its own open state per
564
- // native HTML semantics — newly-revealed stories after a later filter change
564
+ // native HTML semantics; newly-revealed stories after a later filter change
565
565
  // stay closed by default (their default state). A future maintainer might be
566
- // tempted to "fix" this by tracking a global expanded mode; don't — the lack
566
+ // tempted to "fix" this by tracking a global expanded mode; don't; the lack
567
567
  // of persistence is the agreed accessibility-lead decision (act-on-the-moment).
568
568
  //
569
569
  // We use `details.open = true/false` rather than `details.click()` so the
@@ -587,7 +587,7 @@
587
587
  function apply(mode) {
588
588
  var shouldOpen = mode === 'expand';
589
589
  // Collapse-all focus rescue: if focus sits inside a disclosure that is
590
- // about to collapse, move it to that disclosure's <summary> first — the
590
+ // about to collapse, move it to that disclosure's <summary> first; the
591
591
  // summary stays visible after collapse, so focus is never dropped into a
592
592
  // hidden subtree. Expand-all reveals content, so it needs no rescue.
593
593
  if (!shouldOpen) {
@@ -607,7 +607,7 @@
607
607
  // axis prunes non-matching actions ([hidden] on the .action) and the
608
608
  // breakpoint axis hides whole containers, so an action is "visible"
609
609
  // iff neither it nor its container is hidden. Excluding both keeps a
610
- // pruned row's panels closed — otherwise they would open here and
610
+ // pruned row's panels closed; otherwise they would open here and
611
611
  // later appear pre-expanded when a filter change reveals them,
612
612
  // breaking the default-closed contract.
613
613
  var panels = Array.prototype.slice.call(
@@ -683,14 +683,14 @@
683
683
  // Deep-link support for the CI comment. A URL like `…/index.html#story-3`
684
684
  // (built by tuffgal-action from the same `results.json` story ordinal that
685
685
  // template.ts renders as `id="story-<index>"`) lands the reader ON that story
686
- // with its screenshots already expanded — no scrolling or clicking through a
686
+ // with its screenshots already expanded; no scrolling or clicking through a
687
687
  // 34-row report to find the one that changed.
688
688
  //
689
689
  // On a matching hash we:
690
690
  // 1. Expand every VISIBLE screenshot disclosure in that story, reusing the
691
691
  // bulk-toggle's own visibility predicate so a filtered-out row is not
692
692
  // force-opened (default-closed contract). Setting `details.open` directly
693
- // — not `.click()` — mirrors the bulk-toggle and avoids a toggle cascade.
693
+ // ; not `.click()`; mirrors the bulk-toggle and avoids a toggle cascade.
694
694
  // 2. Move focus to the story `<li>` (tabindex="-1") so assistive tech
695
695
  // announces the story prose rather than dropping the reader mid-list.
696
696
  // `preventScroll` keeps focus from yanking the viewport before our own