import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import test from "node:test"; const css = readFileSync(new URL("../src/app/globals.css", import.meta.url), "utf8"); function ruleFor(selector: string): string { const start = css.indexOf(selector); assert.notEqual(start, -1, `missing ${selector}`); const open = css.indexOf("{", start); const close = css.indexOf("}", open); return css.slice(open, close + 1); } test("three-column markdown tables still card-stack on a phone", () => { assert.match( css, /@media \(max-width: 767px\) \{[\s\S]*\.markdown-table table:has\(thead th:nth-child\(3\):last-child\) tbody tr/, ); assert.match( css, /\.markdown-table table:has\(thead th:nth-child\(3\):last-child\) tbody td:nth-child\(3\)/, ); }); test("four-or-more-column chat tables become horizontally scrollable on a phone", () => { const mobile = css.slice(css.indexOf("@media (max-width: 767px)")); assert.match( mobile, /\.conversation \.markdown-table table:not\(:has\(thead th:nth-child\(3\):last-child\)\) \{[\s\S]*width:\s*auto;[\s\S]*min-width:\s*max-content;/, ); assert.match( mobile, /\.conversation \.markdown-table:has\(table:not\(:has\(thead th:nth-child\(3\):last-child\)\)\) \{[\s\S]*overscroll-behavior-x:\s*contain;/, ); }); test("wide-table scroll hint uses canvas tokens so dark theme stays in family", () => { const mobile = css.slice(css.indexOf("@media (max-width: 767px)")); const hint = mobile.slice( mobile.indexOf(".conversation .markdown-table:has(table:not(:has(thead th:nth-child(3):last-child)))"), ); const block = hint.slice(0, hint.indexOf(".conversation .markdown-table table:not")); assert.match(block, /var\(--color-canvas\)/); assert.doesNotMatch(block, /#[0-9a-fA-F]{3,8}/); }); test("the conversation pane itself still forbids page-level sideways scrolling", () => { assert.match(css, /\.conversation \{[^}]*overflow-x:\s*hidden;/); }); test("global text inputs are 16px so iOS does not zoom on focus", () => { const inputRule = ruleFor( "input:not([type=\"radio\"]):not([type=\"checkbox\"]):not([class^=\"ant-\"])", ); assert.match(inputRule, /font-size:\s*var\(--type-body-md\)/); assert.doesNotMatch(inputRule, /--type-body-sm/); }); test("otp and composer keep their existing safe sizes", () => { assert.match(ruleFor(".otp-input"), /font-size:\s*20px/); assert.match(ruleFor(".composer textarea {"), /font-size:\s*var\(--type-body-md\)/); }); test("personal-report tables are not retargeted by the chat wide-table rule", () => { const mobile = css.slice(css.indexOf("@media (max-width: 767px)")); const wide = mobile.match( /\.conversation \.markdown-table table:not\(:has\(thead th:nth-child\(3\):last-child\)\) \{[^}]+\}/, ); assert.ok(wide); assert.doesNotMatch(wide[0], /personal-report/); });