Clone-fidelity fix waves 1-3 (+ wave 4 in flight): capture settling, media, iframes

Fixes from the cropin.com / ooni.com audit reviews:
- walker: preserve whitespace-only text in inline elements ("ofthe" bug);
  capture ::placeholder styles for inputs
- css: emit visibility (hidden-at-rest wordmark artifact); exempt list
  markers from inherited elision (lost bullets); ::placeholder rules
- seo: sanitize og:type to Next's enum (render crash -> dev badge leak);
  generated next.config disables devIndicators
- capture/stabilize: promote lazy-loader data attrs before snapshots
  (collapsed sections, viewport-inconsistent captures); settle autoplay
  carousels to home slide before every snapshot; force-reveal hidden
  videos for poster shots + log failures
- generate: ship downloaded video files as local <video src>; keep
  picture>source through IR prune with srcset rewrite (mobile-crop-on-
  desktop heroes); pin Tailwind named screens to computeBands boundaries
- capture/graft: capture cross-origin iframe subtrees (Klaviyo signup
  forms) with element-screenshot fallback; asset download retry +
  visual-assets-missing reporting

Checkpoint commit: wave 4 (reveal settling, 206 range-response fix,
hidden-geometry banding, bare-zero utility gating) is mid-implementation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Samraaj Bath
2026-07-03 17:45:42 -07:00
co-authored by Claude Fable 5
parent da537e68b8
commit 9aed2540aa
31 changed files with 2579 additions and 121 deletions
+64
View File
@@ -0,0 +1,64 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import { computeBands } from "../src/generate/css.js";
import { bandScreens, prefixFor, tailwindGlobalsCss } from "../src/generate/tailwind.js";
/** Interval covered by a ditto.css band media query (integer px, inclusive). */
function bandInterval(media: string | null): [number, number] {
if (!media) return [0, Infinity];
const min = /min-width:\s*(\d+)px/.exec(media);
const max = /max-width:\s*(\d+)px/.exec(media);
return [min ? +min[1]! : 0, max ? +max[1]! : Infinity];
}
/** Integer interval covered by a Tailwind variant prefix under the given screens.
* v4 semantics for named AND arbitrary variants: `X:` = width >= X; `max-X:` = width < X. */
function prefixInterval(prefix: string, screens: Map<string, number>): [number, number] {
let lo = 0, hi = Infinity;
for (const m of prefix.matchAll(/(max-)?(?:(sm|md|lg|xl|2xl)|(?:min-)?\[(\d+)px\]):/g)) {
const px = m[3] ? +m[3] : screens.get(m[2]!);
assert.ok(px !== undefined, `screen defined for ${m[0]}`);
if (m[1]) hi = Math.min(hi, px! - 1);
else lo = Math.max(lo, px!);
}
return [lo, hi];
}
function assertAgreement(viewports: number[], canonical: number): void {
const screens = new Map(bandScreens(viewports, canonical));
for (const b of computeBands(viewports, canonical)) {
if (!b.media) continue;
assert.deepEqual(
prefixInterval(prefixFor(b.media), screens),
bandInterval(b.media),
`band vp${b.vp} (${b.media}) matches its Tailwind prefix`,
);
}
}
describe("tailwind screens agree with computeBands boundaries", () => {
it("standard 375/768/1280/1920 ladder: md/lg/2xl pinned to the band midpoint boundaries", () => {
const screens = new Map(bandScreens([375, 768, 1280, 1920], 1280));
// Midpoints 571/1024/1600 → bands ≤571, 5721024, base, ≥1601.
assert.deepEqual([...screens], [["md", 572], ["lg", 1025], ["2xl", 1601]]);
// NOT Tailwind's stock 768/1024/1536 — stock 2xl (1536) would flip utility-classed
// nodes to the 1920 layout in 15361600 while ditto.css still holds the 1280 layout.
assert.notEqual(screens.get("2xl"), 1536);
assertAgreement([375, 768, 1280, 1920], 1280);
});
it("odd viewport set: bands fall back to exact arbitrary prefixes (no named screens needed)", () => {
assert.deepEqual(bandScreens([320, 900, 1440], 900), []);
assertAgreement([320, 900, 1440], 900);
});
it("emits the derived screens into the generated @theme", () => {
const css = tailwindGlobalsCss({
reset: "", fontCss: "", tokensCss: "", htmlBg: "#fff", bodyFont: "sans-serif",
clip: "", colorTokens: [], viewports: [375, 768, 1280, 1920], canonical: 1280,
});
assert.ok(css.includes("--breakpoint-md: 572px;"));
assert.ok(css.includes("--breakpoint-lg: 1025px;"));
assert.ok(css.includes("--breakpoint-2xl: 1601px;"));
});
});