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"); const sidebar = readFileSync(new URL("../src/lib/sidebar-state.ts", import.meta.url), "utf8"); /** Widths that may appear in @media (min-width / max-width). Keep in sync with the comment at the top of globals.css. */ const ALLOWED = new Set([480, 640, 641, 767, 768, 860, 1023, 1024]); function mediaWidthBreakpoints(source: string): number[] { const widths = new Set(); for (const block of source.matchAll(/@media[^{]+/g)) { for (const hit of block[0].matchAll(/\((?:min|max)-width:\s*(\d+)px\)/g)) { widths.add(Number(hit[1])); } } return [...widths].sort((a, b) => a - b); } test("CSS width breakpoints stay on the published allowlist", () => { assert.deepEqual(mediaWidthBreakpoints(css), [...ALLOWED].sort((a, b) => a - b)); }); test("tablet CSS cuts at 1023 so it matches sidebarViewportForWidth", () => { assert.doesNotMatch(css, /@media[^{]*max-width:\s*900px/); assert.match(css, /@media \(max-width: 1023px\)/); assert.match(sidebar, /if \(width < 768\) return "mobile"/); assert.match(sidebar, /if \(width < 1024\) return "tablet"/); }); test("report centre and reader share the global mobile cut", () => { assert.match(css, /@media \(max-width: 767px\) \{[\s\S]*\.report-center-shell/); assert.match(css, /@media \(max-width: 767px\) \{[\s\S]*\.personal-report-reader-body/); assert.doesNotMatch(css, /@media \(max-width: 720px\)/); assert.doesNotMatch(css, /@media \(max-width: 760px\)/); }); test("report TOC keeps a content-width exception at 860px", () => { assert.match(css, /Report TOC is the third column/); assert.match(css, /@media \(max-width: 860px\) \{[\s\S]*\.personal-report-md-layout/); }); test("ephemeris page stacks at the global mobile cut", () => { assert.match(css, /@media \(max-width: 767px\) \{[\s\S]*\.ephemeris-shell/); assert.match(css, /@media \(max-width: 767px\) \{[\s\S]*\.ephemeris-panchanga \{[\s\S]*grid-template-columns:\s*1fr/); });