From a3f031ee09d7929479d727c18f48f2f8399c9770 Mon Sep 17 00:00:00 2001 From: Viktor Petersson Date: Mon, 13 Jul 2026 10:12:08 +0000 Subject: [PATCH 1/2] Add degraded mode for older/weaker browsers Static Tailwind sibling to the birthday pilot. On the ~2018 floor (Chrome 65 / Safari 11.1) compiled Tailwind's @layer wrapping is dropped by engines below Chrome 99 / Safari 15.4 (unstyling the page), and ?./?? is a parse-time error that kills the JS bundle. This makes the full app run on the floor and drops animation (weak hardware). Build: esbuild (iife, es2017) replacing Bun.build + replaceChildren shim; Tailwind -> @csstools/postcss-cascade-layers (flatten @layer) -> Lightning CSS (lower/prefix/minify). 100vh fallback ahead of 100svh. One browserslist floor. Runtime gate: inline script flags html.legacy on old/weak engines; CSS kill-switch drops animation/transition (content stays legible; entrances only animate the reveal). Also gitignores .claude/. Verified both modes via headless screenshots (1920x1080 / 800x480): content renders in both, page fully styled. typecheck, lint, tests, es-check es2017 all pass. Co-Authored-By: Claude Opus 4.8 (1M context) --- .gitignore | 3 + assets/static/js/main.ts | 4 ++ assets/static/js/polyfills.ts | 19 +++++++ assets/static/styles/tailwind.css | 14 +++++ build.js | 58 ++++++++++++++----- bun.lock | 93 ++++++++++++++++++++++++++++++- index.html | 19 +++++++ package.json | 6 ++ 8 files changed, 198 insertions(+), 18 deletions(-) create mode 100644 assets/static/js/polyfills.ts diff --git a/.gitignore b/.gitignore index 6fd4065..d86948f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ assets/static/fonts/*.woff2 # Output of 'npm pack' *.tgz + +# Claude Code local worktrees/artifacts +.claude/ diff --git a/assets/static/js/main.ts b/assets/static/js/main.ts index eaff106..794823e 100644 --- a/assets/static/js/main.ts +++ b/assets/static/js/main.ts @@ -2,6 +2,10 @@ // classic script with no exports, so it loads from a plain diff --git a/package.json b/package.json index 251de62..b88f1cb 100644 --- a/package.json +++ b/package.json @@ -13,14 +13,20 @@ "dev": "bun run build.js && bunx serve dist" }, "license": "AGPL-3.0-only", + "browserslist": ["chrome >= 65", "safari >= 11.1", "edge >= 79", "firefox >= 60"], "dependencies": { "@fontsource-variable/bricolage-grotesque": "^5.2.5", "@fontsource-variable/hanken-grotesk": "^5.2.8" }, "devDependencies": { "@biomejs/biome": "^2.5.1", + "@csstools/postcss-cascade-layers": "^6.0.0", "@tailwindcss/cli": "^4.1.0", "@types/bun": "^1.2.0", + "browserslist": "^4.28.6", + "esbuild": "^0.28.1", + "lightningcss": "^1.32.0", + "postcss": "^8.5.18", "tailwindcss": "^4.1.0", "typescript": "^5.7.0" } From c72696876a7a905f27a43154404a71c8a15b24b0 Mon Sep 17 00:00:00 2001 From: Viktor Petersson Date: Mon, 13 Jul 2026 12:29:01 +0000 Subject: [PATCH 2/2] Address Copilot review: raise CSS floor, fix gate + polyfill, harden build - browserslist floor -> chrome >= 79 / firefox >= 75 (keep safari 11.1, edge 79): the apps use clamp()/min()/max() pervasively, which need Chrome 79 (not 65). - Degraded-mode gate: drop the CSS color-mix() probe (2023 -- it flagged capable 2020-2022 browsers as legacy); detect old engines by the absent 2020-era Element.replaceChildren only; use classList.add('legacy') (idempotent). - replaceChildren shim: build the new children in a DocumentFragment first so a bad node throws before the element is cleared (effectively atomic like native); reworded header (defensive shim; no hard-coded browser floor). - build script: wrap the Lightning CSS step in try/catch with a per-file message; correct the comment that implied browserslist drives the JS floor (JS is a fixed esbuild es2017 floor kept in sync); refresh stale Bun.build references to esbuild. Verified: typecheck/lint/tests + es-check es2017 pass; rebuilt with the new floor. Co-Authored-By: Claude Opus 4.8 (1M context) --- assets/static/js/main.ts | 2 +- assets/static/js/polyfills.ts | 22 ++++++++++++--------- build.js | 36 ++++++++++++++++++++++------------- index.html | 11 +++++------ package.json | 7 ++++++- 5 files changed, 48 insertions(+), 30 deletions(-) diff --git a/assets/static/js/main.ts b/assets/static/js/main.ts index 794823e..4765504 100644 --- a/assets/static/js/main.ts +++ b/assets/static/js/main.ts @@ -1,4 +1,4 @@ -// Browser entry. Bun bundles this (inlining ./timer) into a self-contained +// Browser entry. esbuild bundles this (inlining ./timer) into a self-contained // classic script with no exports, so it loads from a plain diff --git a/package.json b/package.json index b88f1cb..ab29517 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,12 @@ "dev": "bun run build.js && bunx serve dist" }, "license": "AGPL-3.0-only", - "browserslist": ["chrome >= 65", "safari >= 11.1", "edge >= 79", "firefox >= 60"], + "browserslist": [ + "chrome >= 79", + "firefox >= 75", + "safari >= 11.1", + "edge >= 79" + ], "dependencies": { "@fontsource-variable/bricolage-grotesque": "^5.2.5", "@fontsource-variable/hanken-grotesk": "^5.2.8"