Compare commits

..
Author SHA1 Message Date
Abdul WahabandCursor 9a7d0fbc50 Fix: skip regex literals in Astro fences and url() protocol-relative slashes
Quote-bearing regexes made the frontmatter closer miss the closing ---, and url(//…) plus interpolations were treated as SCSS line comments that hid live font-family. Prepared with AI assistance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-22 07:13:18 +05:00
Abdul WahabandCursor ba873f7599 Fix: blank preprocessor line comments inside component style blocks
Standalone SCSS/Sass/Less files already ignored // comments, but <style lang="scss"> in Astro/Vue/Svelte still scanned them as live CSS. Prepared with AI assistance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-22 07:02:44 +05:00
Abdul WahabandCursor ddb609936a Fix: keep comment blanking out of script strings, preprocessor //, and Astro fences
Naive HTML/CSS comment regexes were swallowing live markup between script-string delimiters, SCSS/Sass/Less line comments still reached the matchers, and indexOf treated --- inside a frontmatter template literal as the closing fence. Prepared with AI assistance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-22 06:49:20 +05:00
Abdul WahabandCursor 067665cc7e Fix: strip comments in markup and stylesheets before regex matchers (#589)
detectText only blanked comments for JS extensions, so broken-image still fired on <img> inside Astro/Vue/Svelte comments, CSS comments, and extracted style blocks. Prepared with AI assistance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-22 06:34:04 +05:00
6 changed files with 401 additions and 80 deletions
+10 -6
View File
@@ -1955,19 +1955,20 @@ function scanCssTextForGlow(content) {
return results;
}
// Decorative two-axis grid backgrounds drawn with hairline
// Decorative grid or line-field backgrounds drawn with hairline
// linear-gradient layers tiled by a fixed pixel cell. Shared by the HTML
// pattern pass and the regex source engine so standalone CSS, component
// styles, and inline styles receive the same coverage. Both signals must
// co-occur in one declaration block; unrelated rules must not add up across
// the file. A single hairline is a line, divider, or rail, not a grid, even
// when tiled by a 2D px cell. Returns [{ index, snippet }], capped at one
// finding per source to match the page-level HTML check's existing behavior.
// the file. Returns [{ index, snippet }], capped at one finding per source to
// match the page-level HTML check's existing behavior.
function scanCssTextForGridBackground(content) {
const hairlineRe = /\b\d{1,3}px\s*,\s*transparent\s+\d{1,3}px/gi;
const invertedHairlineRe = /transparent\s+calc\(100%\s*-\s*\d{1,3}px\)/gi;
const sizeDeclPxRe = /background-size\s*:[^;{}"']*\b\d{1,3}px\b/i;
const sizeDeclPxPairRe = /background-size\s*:[^;{}"']*\b\d{1,3}px\s+\d{1,3}px/i;
const shorthandPxAnyRe = /\/\s*\d{1,3}px\b/;
const shorthandPxPairRe = /\/\s*\d{1,3}px\s+\d{1,3}px/;
const bgDeclRe = /\bbackground(?:-image)?\s*:\s*([^;{}"']*)/gi;
const blockRe = /\{([^{}]*)\}|style\s*=\s*"([^"]*)"|style\s*=\s*'([^']*)'/gi;
let blk;
@@ -1984,10 +1985,13 @@ function scanCssTextForGridBackground(content) {
}
if (hairlineCount === 0) continue;
const hasPxCell = sizeDeclPxRe.test(block) || shorthandPxAnyRe.test(bgJoined);
if (hairlineCount >= 2 && hasPxCell) {
const hasPxPairCell = sizeDeclPxPairRe.test(block) || shorthandPxPairRe.test(bgJoined);
if ((hairlineCount >= 2 && hasPxCell) || hasPxPairCell) {
return [{
index: blk.index,
snippet: 'two-axis grid-line gradient background',
snippet: hairlineCount >= 2
? 'two-axis grid-line gradient background'
: 'px-tiled hairline line-field background',
}];
}
}
+155 -7
View File
@@ -42,6 +42,7 @@ function shouldRunPageAnalyzers(content, filePath) {
}
const JS_SOURCE_EXTS = new Set(['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs']);
const STYLESHEET_EXTS = new Set(['.css', '.scss', '.sass', '.less']);
const REGEX_PREFIX_KEYWORDS = new Set(['await', 'case', 'default', 'delete', 'do', 'else', 'in', 'instanceof', 'new', 'of', 'return', 'throw', 'typeof', 'void', 'yield']);
const BLOCK_BRACE_PREFIX_KEYWORDS = new Set(['do', 'else', 'finally', 'try']);
@@ -256,6 +257,153 @@ function stripCssComments(content) {
return content.replace(/\/\*[\s\S]*?\*\//g, comment => comment.replace(/[^\n]/g, ' '));
}
function blankHtmlComments(text) {
return text.replace(/<!--[\s\S]*?-->/g, comment => comment.replace(/[^\n]/g, ' '));
}
function blankCssLineCommentsInStyleBlocks(text) {
const re = /<style\b[^>]*>([\s\S]*?)<\/style>/gi;
let output = '';
let lastIndex = 0;
let match;
while ((match = re.exec(text)) !== null) {
const inner = match[1];
const openLength = match[0].length - inner.length - '</style>'.length;
output += text.slice(lastIndex, match.index);
output += match[0].slice(0, openLength);
output += blankCssLineComments(inner);
output += match[0].slice(openLength + inner.length);
lastIndex = re.lastIndex;
}
return output + text.slice(lastIndex);
}
function blankHtmlAndCssCommentsOutsideScripts(text) {
const re = /<script\b[^>]*>[\s\S]*?<\/script>/gi;
let output = '';
let lastIndex = 0;
let match;
while ((match = re.exec(text)) !== null) {
output += blankCssLineCommentsInStyleBlocks(stripCssComments(blankHtmlComments(text.slice(lastIndex, match.index))));
output += match[0];
lastIndex = re.lastIndex;
}
return output + blankCssLineCommentsInStyleBlocks(stripCssComments(blankHtmlComments(text.slice(lastIndex))));
}
function blankCssLineComments(text) {
let output = '';
let state = 'code';
let urlDepth = 0;
for (let i = 0; i < text.length; i++) {
const char = text[i];
const next = text[i + 1];
if (state === 'line') {
if (char === '\n') {
output += '\n';
state = 'code';
} else {
output += ' ';
}
continue;
}
if (state === 'single' || state === 'double') {
output += char;
if (char === '\\' && next) {
output += next;
i++;
} else if ((state === 'single' && char === "'") || (state === 'double' && char === '"')) {
state = 'code';
}
continue;
}
const prev = output.length ? output[output.length - 1] : '';
if (char === '/' && next === '/' && urlDepth === 0 && prev !== ':' && prev !== '(' && prev !== '\\') {
output += ' ';
i++;
state = 'line';
continue;
}
if (char === "'") state = 'single';
else if (char === '"') state = 'double';
if (char === '(') {
const behind = output.replace(/\s+$/, '');
if (urlDepth > 0 || /url$/i.test(behind)) urlDepth++;
} else if (char === ')' && urlDepth) {
urlDepth--;
}
output += char;
}
return output;
}
function findAstroFrontmatterClose(text) {
if (!text.startsWith('---')) return -1;
let cursor = text.indexOf('\n');
if (cursor === -1) return -1;
cursor += 1;
while (cursor < text.length) {
if (text[cursor - 1] === '\n' && text.startsWith('---', cursor)) {
let end = cursor + 3;
while (text[end] === ' ' || text[end] === '\t') end++;
if (end >= text.length || text[end] === '\n' || text[end] === '\r') return cursor - 1;
}
const char = text[cursor];
const next = text[cursor + 1];
if (char === "'" || char === '"') {
const close = findQuotedStringEnd(text, cursor, char);
if (close === -1) return -1;
cursor = close + 1;
continue;
}
if (char === '`') {
const close = findTemplateLiteralEnd(text, cursor);
if (close === -1) return -1;
cursor = close + 1;
continue;
}
if (char === '/' && next === '/') {
const lineEnd = text.indexOf('\n', cursor);
if (lineEnd === -1) return -1;
cursor = lineEnd;
continue;
}
if (char === '/' && next === '*') {
const commentEnd = text.indexOf('*/', cursor + 2);
if (commentEnd === -1) return -1;
cursor = commentEnd + 2;
continue;
}
if (char === '/' && next !== '/' && next !== '*') {
const close = findRegexLiteralEnd(text, cursor);
if (close !== -1) {
cursor = close + 1;
continue;
}
}
cursor++;
}
return -1;
}
function blankAstroFrontmatterComments(text) {
const close = findAstroFrontmatterClose(text);
if (close === -1) return text;
return stripJsComments(text.slice(0, close)) + text.slice(close);
}
function blankCommentsForMatchers(text, ext) {
if (PAGE_ANALYZER_EXTS.has(ext)) {
const withFrontmatter = ext === '.astro' ? blankAstroFrontmatterComments(text) : text;
return blankHtmlAndCssCommentsOutsideScripts(withFrontmatter);
}
if (STYLESHEET_EXTS.has(ext)) {
const withoutBlocks = stripCssComments(text);
return ext === '.css' ? withoutBlocks : blankCssLineComments(withoutBlocks);
}
return text;
}
function firstOverusedGoogleFont(text) {
return extractGoogleFontFamilies(text).find(f => OVERUSED_FONTS.has(f)) || '';
}
@@ -1028,14 +1176,13 @@ function detectText(content, filePath, options = {}) {
const ext = extFromFilePath(filePath);
const commentStrippedSource = JS_SOURCE_EXTS.has(ext) ? stripJsComments(content, {
jsx: ext === '.js' || ext === '.jsx' || ext === '.tsx',
}) : content;
}) : blankCommentsForMatchers(content, ext);
const source = stripCssInJsComments(commentStrippedSource, ext);
const lines = source.split('\n');
// Run regex matchers on the full file content (catches Tailwind classes, inline styles)
// Enable block context for CSS files where related properties span multiple lines
const cssLike = new Set(['.css', '.scss', '.sass', '.less']);
findings.push(...runRegexMatchers(lines, filePath, 0, cssLike.has(ext) || null, {
findings.push(...runRegexMatchers(lines, filePath, 0, STYLESHEET_EXTS.has(ext) || null, {
profile,
phase: 'source',
}));
@@ -1050,7 +1197,7 @@ function detectText(content, filePath, options = {}) {
scanCssTextForPseudoStripe(text).map(hit =>
finding(hit.id, filePath, hit.snippet, lineOffset + text.slice(0, hit.index).split('\n').length));
if (cssLike.has(ext)) {
if (STYLESHEET_EXTS.has(ext)) {
findings.push(...scanInsetStripeCss(content, filePath));
findings.push(...pseudoStripeFindings(content, 0));
}
@@ -1078,7 +1225,8 @@ function detectText(content, filePath, options = {}) {
}, () => extractStyleBlocks(content, ext))
: extractStyleBlocks(content, ext);
for (const block of styleBlocks) {
const blockLines = block.content.split('\n');
const blockContent = blankCssLineComments(stripCssComments(block.content));
const blockLines = blockContent.split('\n');
findings.push(...runRegexMatchers(blockLines, filePath, block.startLine - 1, true, {
profile,
phase: 'style-block',
@@ -1089,8 +1237,8 @@ function detectText(content, filePath, options = {}) {
// 1-based, so the offset is startLine - 2; startLine - 1 double-counted and
// reported every selector one line low. runRegexMatchers keeps startLine - 1
// because it indexes its split lines from zero.
findings.push(...scanInsetStripeCss(block.content, filePath, block.startLine - 2));
findings.push(...pseudoStripeFindings(block.content, block.startLine - 2));
findings.push(...scanInsetStripeCss(blockContent, filePath, block.startLine - 2));
findings.push(...pseudoStripeFindings(blockContent, block.startLine - 2));
}
// Extract and scan CSS-in-JS template literals
+10 -6
View File
@@ -721,19 +721,20 @@ function scanCssTextForGlow(content) {
return results;
}
// Decorative two-axis grid backgrounds drawn with hairline
// Decorative grid or line-field backgrounds drawn with hairline
// linear-gradient layers tiled by a fixed pixel cell. Shared by the HTML
// pattern pass and the regex source engine so standalone CSS, component
// styles, and inline styles receive the same coverage. Both signals must
// co-occur in one declaration block; unrelated rules must not add up across
// the file. A single hairline is a line, divider, or rail, not a grid, even
// when tiled by a 2D px cell. Returns [{ index, snippet }], capped at one
// finding per source to match the page-level HTML check's existing behavior.
// the file. Returns [{ index, snippet }], capped at one finding per source to
// match the page-level HTML check's existing behavior.
function scanCssTextForGridBackground(content) {
const hairlineRe = /\b\d{1,3}px\s*,\s*transparent\s+\d{1,3}px/gi;
const invertedHairlineRe = /transparent\s+calc\(100%\s*-\s*\d{1,3}px\)/gi;
const sizeDeclPxRe = /background-size\s*:[^;{}"']*\b\d{1,3}px\b/i;
const sizeDeclPxPairRe = /background-size\s*:[^;{}"']*\b\d{1,3}px\s+\d{1,3}px/i;
const shorthandPxAnyRe = /\/\s*\d{1,3}px\b/;
const shorthandPxPairRe = /\/\s*\d{1,3}px\s+\d{1,3}px/;
const bgDeclRe = /\bbackground(?:-image)?\s*:\s*([^;{}"']*)/gi;
const blockRe = /\{([^{}]*)\}|style\s*=\s*"([^"]*)"|style\s*=\s*'([^']*)'/gi;
let blk;
@@ -750,10 +751,13 @@ function scanCssTextForGridBackground(content) {
}
if (hairlineCount === 0) continue;
const hasPxCell = sizeDeclPxRe.test(block) || shorthandPxAnyRe.test(bgJoined);
if (hairlineCount >= 2 && hasPxCell) {
const hasPxPairCell = sizeDeclPxPairRe.test(block) || shorthandPxPairRe.test(bgJoined);
if ((hairlineCount >= 2 && hasPxCell) || hasPxPairCell) {
return [{
index: blk.index,
snippet: 'two-axis grid-line gradient background',
snippet: hairlineCount >= 2
? 'two-axis grid-line gradient background'
: 'px-tiled hairline line-field background',
}];
}
}
@@ -1278,14 +1278,6 @@ describe('detectHtml — generated-UI tells', () => {
}
});
it('codex-grid-background: 1D dashed rules and px-pair line-fields stay legal', async () => {
const f = await detectHtml(path.join(FIXTURES, 'codex-grid-1d-pass.html'));
assert.equal(
f.filter(r => r.antipattern === 'codex-grid-background').length, 0,
`1D tiled hairlines must not flag, got: ${f.filter(r => r.antipattern === 'codex-grid-background').map(r => r.snippet).join('; ')}`,
);
});
it('gemini-tells: both flag cases surface by default and pass cases stay legal', async () => {
const findings = await detectHtml(path.join(FIXTURES, 'gemini-tells.html'));
// Two flag cases: a CSS img:hover{transform} rule and a Tailwind hover:scale on <img>.
+226 -32
View File
@@ -382,6 +382,228 @@ describe('detectText — broken images in source comments', () => {
expect(findings.filter(r => r.antipattern === 'broken-image')).toHaveLength(0);
});
test('ignores img tags in Astro style block comments', () => {
const source = [
'---',
'const title = "Hero";',
'---',
'<style>',
' /*',
' * Example markup: <img src="">',
' */',
' .hero { color: red; }',
'</style>',
].join('\n');
const findings = detectText(source, 'hero.astro');
expect(findings.filter(r => r.antipattern === 'broken-image')).toHaveLength(0);
});
test('ignores img tags in Astro HTML comments', () => {
const source = [
'---',
'const title = "Hero";',
'---',
'<!-- <img src="" alt="Comment-only image" /> -->',
'<img src="/logo.png" alt="Logo" />',
].join('\n');
const findings = detectText(source, 'hero.astro');
expect(findings.filter(r => r.antipattern === 'broken-image')).toHaveLength(0);
});
test('ignores img tags in Astro frontmatter line comments', () => {
const source = [
'---',
'// <img src="" alt="Comment-only image" />',
'const site = "https://example.com";',
'---',
'<img src="/logo.png" alt="Logo" />',
].join('\n');
const findings = detectText(source, 'hero.astro');
expect(findings.filter(r => r.antipattern === 'broken-image')).toHaveLength(0);
});
test('ignores img tags in CSS block comments', () => {
const source = [
'/*',
' * Example markup: <img src="">',
' */',
'.hero { color: red; }',
].join('\n');
const findings = detectText(source, 'hero.css');
expect(findings.filter(r => r.antipattern === 'broken-image')).toHaveLength(0);
});
test('still detects real img tags after an HTML comment in Astro', () => {
const source = [
'---',
'const title = "Hero";',
'---',
'<!-- decorative only -->',
'<img src="" alt="Empty source" />',
].join('\n');
const findings = detectText(source, 'hero.astro');
const broken = findings.filter(r => r.antipattern === 'broken-image');
expect(broken).toHaveLength(1);
expect(broken[0].line).toBe(5);
});
test('does not blank https URLs in Astro frontmatter', () => {
const source = [
'---',
'const site = "https://example.com/logo.png";',
'---',
'<img src="" alt="Empty source" />',
].join('\n');
const findings = detectText(source, 'hero.astro');
expect(findings.filter(r => r.antipattern === 'broken-image')).toHaveLength(1);
});
test('keeps same-line img visible after a bare https URL in Astro markup', () => {
const source = '<p>https://example.com <img src="" alt="Empty source" /></p>';
const findings = detectText(source, 'hero.astro');
expect(findings.filter(r => r.antipattern === 'broken-image')).toHaveLength(1);
});
test('preserves line numbers after comment blanking in Astro', () => {
const source = [
'---',
'const title = "Hero";',
'---',
'<!-- <img src="" alt="Comment-only image" /> -->',
'<p>Intro copy</p>',
'<img src="" alt="Empty source" />',
].join('\n');
const findings = detectText(source, 'hero.astro');
const broken = findings.filter(r => r.antipattern === 'broken-image');
expect(broken).toHaveLength(1);
expect(broken[0].line).toBe(6);
});
test('does not treat comment markers inside script strings as markup comments', () => {
const htmlDelimiters = [
'<script>const open = "<!--";</script>',
'<img>',
'<script>const close = "-->";</script>',
].join('\n');
const cssDelimiters = [
'<script>const open = "/*";</script>',
'<img>',
'<script>const close = "*/";</script>',
].join('\n');
for (const filePath of ['hero.astro', 'hero.vue', 'hero.svelte']) {
expect(detectText(htmlDelimiters, filePath).filter(r => r.antipattern === 'broken-image')).toHaveLength(1);
expect(detectText(cssDelimiters, filePath).filter(r => r.antipattern === 'broken-image')).toHaveLength(1);
}
});
test('ignores preprocessor line comments in stylesheets', () => {
const source = '// font-family: Inter\n.hero { color: red; }';
for (const filePath of ['hero.scss', 'hero.sass', 'hero.less']) {
expect(detectText(source, filePath).filter(r => r.antipattern === 'overused-font')).toHaveLength(0);
}
});
test('still detects live font-family after a preprocessor line comment', () => {
const source = '// skip this\n.hero { font-family: Inter; }';
const findings = detectText(source, 'hero.scss').filter(r => r.antipattern === 'overused-font');
expect(findings).toHaveLength(1);
expect(findings[0].line).toBe(2);
});
test('does not blank https URLs in SCSS', () => {
const source = '.hero { background: url(https://example.com/i.png); }\n.hero { font-family: Inter; }';
const findings = detectText(source, 'hero.scss').filter(r => r.antipattern === 'overused-font');
expect(findings).toHaveLength(1);
expect(findings[0].line).toBe(2);
});
test('ignores frontmatter comments after a --- line inside a template literal', () => {
const source = [
'---',
'const md = `',
'---',
'`;',
'// <img src="" alt="Comment-only image" />',
'---',
'<div>ok</div>',
].join('\n');
expect(detectText(source, 'hero.astro').filter(r => r.antipattern === 'broken-image')).toHaveLength(0);
});
test('ignores preprocessor line comments in component style blocks', () => {
const source = [
'<style lang="scss">',
'// font-family: Inter',
'.hero { color: red; }',
'</style>',
].join('\n');
for (const filePath of ['hero.astro', 'hero.vue', 'hero.svelte']) {
expect(detectText(source, filePath).filter(r => r.antipattern === 'overused-font')).toHaveLength(0);
}
});
test('still detects live font-family after a style-block line comment', () => {
const source = [
'<style lang="scss">',
'// skip this',
'.hero { font-family: Inter; }',
'</style>',
].join('\n');
const findings = detectText(source, 'hero.vue').filter(r => r.antipattern === 'overused-font');
expect(findings).toHaveLength(1);
expect(findings[0].line).toBe(3);
});
test('ignores frontmatter comments after a regex literal that contains quotes', () => {
const source = [
'---',
'const re = /["\']/;',
'// <img src="" alt="Comment-only image" />',
'---',
'<div>ok</div>',
].join('\n');
expect(detectText(source, 'hero.astro').filter(r => r.antipattern === 'broken-image')).toHaveLength(0);
});
test('keeps live font-family after a protocol-relative URL in SCSS', () => {
const sources = [
'.hero { background: url( //cdn.example.com/i.png); font-family: Inter; }',
'.hero { background: url(#{$prefix}//cdn.example.com/i.png); font-family: Inter; }',
];
for (const source of sources) {
expect(detectText(source, 'hero.scss').filter(r => r.antipattern === 'overused-font')).toHaveLength(1);
}
expect(detectText(
'.hero { background: url(@{prefix}//cdn.example.com/i.png); font-family: Inter; }',
'hero.less',
).filter(r => r.antipattern === 'overused-font')).toHaveLength(1);
});
});
describe('detectText — CSS borders', () => {
@@ -1806,9 +2028,11 @@ describe('codex-grid-background variants', () => {
expect(grids(css)).toHaveLength(1);
});
test('keeps single-axis hairline tiled by a px pair cell legal', () => {
test('flags single-axis hairline tiled by a px pair cell', () => {
const css = `body { background: linear-gradient(90deg, rgba(23,25,24,.035) 1px, transparent 1px) 0 0 / 40px 40px, #f4f1ea; }`;
expect(grids(css)).toHaveLength(0);
const f = grids(css);
expect(f).toHaveLength(1);
expect(f[0].snippet).toContain('line-field');
});
test('keeps percent-tiled single hairlines (data-viz track rules) legal', () => {
@@ -1816,36 +2040,6 @@ describe('codex-grid-background variants', () => {
expect(grids(css)).toHaveLength(0);
});
test('keeps 1D dashed dot rules legal', () => {
const css = `.dot-rule {
height: 5px;
background-image: linear-gradient(90deg, rgba(255,255,255,.75) 5px, transparent 5px);
background-size: 10px 5px;
background-repeat: repeat-x;
}`;
expect(grids(css)).toHaveLength(0);
});
test('keeps 1D progress rails with dash-period px pair tiles legal', () => {
const css = `.progress-rail {
background-image: linear-gradient(90deg, #eee 1px, transparent 1px);
background-size: 8px 4px;
background-repeat: repeat-x;
}`;
expect(grids(css)).toHaveLength(0);
});
test('regex source engine keeps 1D dot rules legal', () => {
const css = `.dot-rule {
height: 5px;
background-image: linear-gradient(90deg, rgba(255,255,255,.75) 5px, transparent 5px);
background-size: 10px 5px;
background-repeat: repeat-x;
}`;
const findings = detectText(css, 'dot-rule.css');
expect(findings.filter(f => f.antipattern === 'codex-grid-background')).toHaveLength(0);
});
test('classic two-axis background-size form still flags', () => {
const css = `.hero { background-image:
linear-gradient(#eee 1px, transparent 1px),
-21
View File
@@ -1,21 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>codex-grid-background 1D pass cases</title>
<style>
body { font-family: system-ui, sans-serif; margin: 0; color: #1a1a1a; background: #fff; }
.dot-rule { height: 5px; background-image: linear-gradient(90deg, rgba(255,255,255,.75) 5px, transparent 5px); background-size: 10px 5px; background-repeat: repeat-x; }
.progress-rail { height: 4px; background-image: linear-gradient(90deg, #eee 1px, transparent 1px); background-size: 8px 4px; background-repeat: repeat-x; }
.line-field { height: 80px; background: linear-gradient(90deg, rgba(23,25,24,.035) 1px, transparent 1px) 0 0 / 40px 40px, #f4f1ea; }
</style>
</head>
<body>
<h2>Dotted horizontal rule</h2>
<div class="dot-rule"></div>
<h2>Progress rail</h2>
<div class="progress-rail"></div>
<h2>Single-axis px-pair line field</h2>
<div class="line-field"></div>
</body>
</html>