diff --git a/docs/redesign/06-verification.md b/docs/redesign/06-verification.md index 16d653565..32a02cd3f 100644 --- a/docs/redesign/06-verification.md +++ b/docs/redesign/06-verification.md @@ -47,3 +47,9 @@ Every capability from the audit map is present and reachable: search (answer/doc - `prefers-reduced-motion` and forced-colors verified by code/token review, not an automated emulation pass. - `npm audit --audit-level=high` still reports one high-severity `esbuild` advisory. No audit fix was applied because that would broaden the dependency change beyond the ESLint compatibility repair. - ClinicalDashboard decomposition deferred (`04-deferred.md`, decision log D5). + +## 7. Post-cleanup dependency follow-up (esbuild) + +- Scope: address the remaining `npm audit --audit-level=high` finding without changing framework/runtime behavior. +- Change: added root `package.json` override for `esbuild@0.28.1` (latest stable) and regenerated `package-lock.json`. +- Result: full dependency resolution remains aligned with the existing stack (`next@16.2.7`, `tsx@4.22.4`, etc.); reran lint/build/test and high-severity audit to confirm no new regressions from the patch. diff --git a/package-lock.json b/package-lock.json index df7d4d23e..2da95213a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -344,9 +344,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", - "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", "cpu": [ "ppc64" ], @@ -361,9 +361,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", - "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", "cpu": [ "arm" ], @@ -378,9 +378,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", - "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", "cpu": [ "arm64" ], @@ -395,9 +395,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", - "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", "cpu": [ "x64" ], @@ -412,9 +412,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", - "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", "cpu": [ "arm64" ], @@ -429,9 +429,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", - "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", "cpu": [ "x64" ], @@ -446,9 +446,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", - "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", "cpu": [ "arm64" ], @@ -463,9 +463,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", - "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", "cpu": [ "x64" ], @@ -480,9 +480,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", - "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", "cpu": [ "arm" ], @@ -497,9 +497,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", - "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", "cpu": [ "arm64" ], @@ -514,9 +514,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", - "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", "cpu": [ "ia32" ], @@ -531,9 +531,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", - "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", "cpu": [ "loong64" ], @@ -548,9 +548,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", - "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", "cpu": [ "mips64el" ], @@ -565,9 +565,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", - "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", "cpu": [ "ppc64" ], @@ -582,9 +582,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", - "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", "cpu": [ "riscv64" ], @@ -599,9 +599,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", - "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", "cpu": [ "s390x" ], @@ -616,9 +616,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", - "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", "cpu": [ "x64" ], @@ -633,9 +633,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", - "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", "cpu": [ "arm64" ], @@ -650,9 +650,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", - "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", "cpu": [ "x64" ], @@ -667,9 +667,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", - "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", "cpu": [ "arm64" ], @@ -684,9 +684,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", - "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", "cpu": [ "x64" ], @@ -701,9 +701,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", - "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", "cpu": [ "arm64" ], @@ -718,9 +718,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", - "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", "cpu": [ "x64" ], @@ -735,9 +735,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", - "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", "cpu": [ "arm64" ], @@ -752,9 +752,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", - "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", "cpu": [ "ia32" ], @@ -769,9 +769,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", - "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", "cpu": [ "x64" ], @@ -4834,9 +4834,9 @@ } }, "node_modules/esbuild": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", - "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4847,32 +4847,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.0", - "@esbuild/android-arm": "0.28.0", - "@esbuild/android-arm64": "0.28.0", - "@esbuild/android-x64": "0.28.0", - "@esbuild/darwin-arm64": "0.28.0", - "@esbuild/darwin-x64": "0.28.0", - "@esbuild/freebsd-arm64": "0.28.0", - "@esbuild/freebsd-x64": "0.28.0", - "@esbuild/linux-arm": "0.28.0", - "@esbuild/linux-arm64": "0.28.0", - "@esbuild/linux-ia32": "0.28.0", - "@esbuild/linux-loong64": "0.28.0", - "@esbuild/linux-mips64el": "0.28.0", - "@esbuild/linux-ppc64": "0.28.0", - "@esbuild/linux-riscv64": "0.28.0", - "@esbuild/linux-s390x": "0.28.0", - "@esbuild/linux-x64": "0.28.0", - "@esbuild/netbsd-arm64": "0.28.0", - "@esbuild/netbsd-x64": "0.28.0", - "@esbuild/openbsd-arm64": "0.28.0", - "@esbuild/openbsd-x64": "0.28.0", - "@esbuild/openharmony-arm64": "0.28.0", - "@esbuild/sunos-x64": "0.28.0", - "@esbuild/win32-arm64": "0.28.0", - "@esbuild/win32-ia32": "0.28.0", - "@esbuild/win32-x64": "0.28.0" + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" } }, "node_modules/escalade": { diff --git a/package.json b/package.json index 9914a4c96..c23baf5af 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ }, "overrides": { "postcss": "^8.5.15", + "esbuild": "0.28.1", "tmp": "^0.2.7", "uuid": "^11.1.1" }, diff --git a/src/app/globals.css b/src/app/globals.css index b3aa90ecf..efce97bd0 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -10,15 +10,15 @@ * Radius usage rules: * rounded-md chips, inner elements, metadata pills * rounded-lg controls, inputs, buttons - * rounded-xl cards, panels, drawers - * rounded-2xl bottom sheets, hero surfaces + * rounded-lg cards, panels, drawers + * rounded-xl bottom sheets, dialogs, large shells */ @theme { --radius-sm: 0.375rem; --radius-md: 0.5rem; - --radius-lg: 0.875rem; - --radius-xl: 1.25rem; - --radius-2xl: 1.75rem; + --radius-lg: 0.625rem; + --radius-xl: 0.75rem; + --radius-2xl: 1rem; --text-2xs: 0.6875rem; --text-2xs--line-height: 1rem; @@ -88,25 +88,25 @@ --primary-800: #0c544f; --primary-900: #0b403d; - --background: #eaf3f5; - --app-shell: #04141b; - --app-shell-muted: #0b2a35; - --app-shell-accent: #0e8078; + --background: #f3f6f7; + --app-shell: #102028; + --app-shell-muted: #18303a; + --app-shell-accent: #3d8d86; --surface: var(--neutral-0); --surface-raised: #fbfdfe; - --surface-subtle: var(--neutral-100); - --surface-inset: #f4f9fa; - --surface-glass: rgb(255 255 255 / 76%); - --surface-highlight: rgb(255 255 255 / 68%); - --surface-lux: rgb(255 255 255 / 88%); - --surface-wash: #e4f0f2; + --surface-subtle: #eef4f5; + --surface-inset: #f7fafb; + --surface-glass: rgb(255 255 255 / 82%); + --surface-highlight: rgb(255 255 255 / 62%); + --surface-lux: rgb(255 255 255 / 94%); + --surface-wash: #edf4f5; --text: var(--neutral-900); --text-heading: var(--neutral-950); --text-muted: var(--neutral-600); --text-soft: var(--neutral-500); --border: var(--neutral-200); --border-strong: var(--neutral-300); - --border-lux: rgb(149 178 190 / 54%); + --border-lux: rgb(149 178 190 / 42%); --primary: var(--primary-500); --primary-strong: var(--primary-700); --primary-soft: #d6f2ec; @@ -145,15 +145,15 @@ --ease-out-soft: cubic-bezier(0.22, 1, 0.36, 1); --ease-spring: cubic-bezier(0.34, 1.3, 0.64, 1); - --glow-primary: 0 0 0 1px rgb(26 169 155 / 12%), 0 10px 28px rgb(12 130 120 / 10%); - --glow-soft: 0 0 0 1px rgb(26 169 155 / 9%), 0 8px 22px rgb(15 31 38 / 6%); + --glow-primary: 0 0 0 1px rgb(61 141 134 / 10%), 0 10px 24px rgb(61 141 134 / 8%); + --glow-soft: 0 0 0 1px rgb(61 141 134 / 7%), 0 8px 18px rgb(15 31 38 / 5%); /* Elevation: layered, small blur, low alpha */ - --shadow-soft: 0 1px 2px rgb(15 31 38 / 6%), 0 8px 20px rgb(15 31 38 / 7%); - --shadow-tight: 0 1px 2px rgb(15 31 38 / 6%), 0 4px 10px rgb(15 31 38 / 5%); - --shadow-hover: 0 2px 4px rgb(15 31 38 / 8%), 0 12px 28px rgb(15 31 38 / 9%); - --shadow-elevated: 0 1px 2px rgb(15 31 38 / 8%), 0 8px 16px rgb(15 31 38 / 8%), 0 24px 48px rgb(15 31 38 / 10%); - --shadow-lux: inset 0 1px 0 rgb(255 255 255 / 65%), 0 12px 32px rgb(15 31 38 / 8%); + --shadow-soft: 0 1px 2px rgb(15 31 38 / 5%), 0 7px 18px rgb(15 31 38 / 5%); + --shadow-tight: 0 1px 2px rgb(15 31 38 / 5%), 0 3px 8px rgb(15 31 38 / 4%); + --shadow-hover: 0 2px 4px rgb(15 31 38 / 7%), 0 10px 24px rgb(15 31 38 / 7%); + --shadow-elevated: 0 1px 2px rgb(15 31 38 / 7%), 0 8px 16px rgb(15 31 38 / 7%), 0 22px 44px rgb(15 31 38 / 8%); + --shadow-lux: inset 0 1px 0 rgb(255 255 255 / 65%), 0 10px 28px rgb(15 31 38 / 6%); --shadow-inset: inset 0 1px 0 rgb(255 255 255 / 60%); --ring-focus: 0 0 0 3px color-mix(in srgb, var(--focus) 28%, transparent); --space-1: 0.25rem; @@ -202,18 +202,18 @@ --primary-800: #a3ebe3; --primary-900: #c8f4ef; - --background: #03080d; - --app-shell: #020d14; - --app-shell-muted: #08232d; - --app-shell-accent: #2bc9bb; - --surface: var(--neutral-0); - --surface-raised: var(--neutral-100); - --surface-subtle: var(--neutral-50); - --surface-inset: #050e17; - --surface-glass: rgb(14 29 43 / 72%); + --background: #0d1318; + --app-shell: #111d24; + --app-shell-muted: #172a34; + --app-shell-accent: #46a39a; + --surface: #101923; + --surface-raised: #15202b; + --surface-subtle: #0f1821; + --surface-inset: #0b1218; + --surface-glass: rgb(20 31 42 / 78%); --surface-highlight: rgb(255 255 255 / 5%); - --surface-lux: rgb(15 31 47 / 84%); - --surface-wash: #07131d; + --surface-lux: rgb(20 31 42 / 92%); + --surface-wash: #111c25; --text: var(--neutral-900); --text-heading: var(--neutral-950); --text-muted: var(--neutral-600); @@ -251,13 +251,13 @@ --disabled: #64748b; --focus: #7de3d8; - --glow-primary: 0 0 0 1px rgb(51 212 194 / 18%), 0 16px 44px rgb(45 212 191 / 12%); - --glow-soft: 0 0 0 1px rgb(51 212 194 / 12%), 0 12px 30px rgb(0 0 0 / 22%); + --glow-primary: 0 0 0 1px rgb(70 163 154 / 16%), 0 14px 34px rgb(70 163 154 / 10%); + --glow-soft: 0 0 0 1px rgb(70 163 154 / 10%), 0 10px 24px rgb(0 0 0 / 18%); - --shadow-soft: 0 2px 6px rgb(0 0 0 / 32%), 0 12px 28px rgb(0 0 0 / 34%); - --shadow-tight: 0 1px 2px rgb(0 0 0 / 30%), 0 4px 12px rgb(0 0 0 / 28%); - --shadow-hover: 0 4px 10px rgb(0 0 0 / 38%), 0 16px 36px rgb(0 0 0 / 40%); - --shadow-elevated: 0 2px 6px rgb(0 0 0 / 36%), 0 10px 24px rgb(0 0 0 / 40%), 0 28px 56px rgb(0 0 0 / 46%); + --shadow-soft: 0 1px 4px rgb(0 0 0 / 24%), 0 10px 24px rgb(0 0 0 / 26%); + --shadow-tight: 0 1px 2px rgb(0 0 0 / 24%), 0 4px 10px rgb(0 0 0 / 22%); + --shadow-hover: 0 3px 8px rgb(0 0 0 / 30%), 0 14px 30px rgb(0 0 0 / 32%); + --shadow-elevated: 0 2px 6px rgb(0 0 0 / 30%), 0 10px 22px rgb(0 0 0 / 34%), 0 26px 52px rgb(0 0 0 / 38%); --shadow-lux: inset 0 1px 0 rgb(255 255 255 / 6%), 0 16px 40px rgb(0 0 0 / 44%); --shadow-inset: inset 0 1px 0 rgb(255 255 255 / 6%); --ring-focus: 0 0 0 3px color-mix(in srgb, var(--focus) 30%, transparent); @@ -272,15 +272,15 @@ html { min-width: 320px; background: - radial-gradient(circle at 50% -12%, color-mix(in srgb, var(--primary) 12%, transparent), transparent 34rem), + radial-gradient(circle at 50% -12%, color-mix(in srgb, var(--primary) 5%, transparent), transparent 34rem), linear-gradient(180deg, var(--background), color-mix(in srgb, var(--background) 90%, var(--surface-inset))); overflow-x: clip; } body { background: - radial-gradient(circle at 8% 0%, color-mix(in srgb, var(--primary) 9%, transparent), transparent 28rem), - radial-gradient(circle at 98% 12%, color-mix(in srgb, var(--info) 7%, transparent), transparent 26rem), + radial-gradient(circle at 8% 0%, color-mix(in srgb, var(--primary) 4%, transparent), transparent 28rem), + radial-gradient(circle at 98% 12%, color-mix(in srgb, var(--info) 3%, transparent), transparent 26rem), var(--background); color: var(--text); font-family: var(--font-geist-sans), Arial, Helvetica, sans-serif; diff --git a/src/components/ClinicalDashboard.tsx b/src/components/ClinicalDashboard.tsx index 8671975f8..e8e05930e 100644 --- a/src/components/ClinicalDashboard.tsx +++ b/src/components/ClinicalDashboard.tsx @@ -176,6 +176,7 @@ const mobileSectionFabMediaQuery = "(max-width: 768px), ((max-width: 1023px) and const themeStorageKey = "clinical-kb-theme"; const themeChangeEvent = "clinical-kb-theme-change"; const authEmailChangeEvent = "clinical-kb-auth-email-change"; +const recentQueryStorageKey = "clinical-kb-recent-queries"; const documentPageSize = 150; const activeIndexingPollFallbackMs = 5_000; const setupRecheckPollMs = 60_000; @@ -825,6 +826,7 @@ function MasterSearchHeader({ onQueryModeChange, onScopeFiltersChange, onToggleScope, + onScopeOpenChange, onOpenGuide, onToggleTheme, }: { @@ -847,6 +849,7 @@ function MasterSearchHeader({ onQueryModeChange: (mode: ClinicalQueryMode) => void; onScopeFiltersChange: (filters: SearchScopeFilters) => void; onToggleScope: (documentId: string) => void; + onScopeOpenChange?: (open: boolean) => void; onOpenGuide: () => void; onToggleTheme: () => void; }) { @@ -911,6 +914,10 @@ function MasterSearchHeader({ if (restoreFocus) scopeSummaryRef.current?.focus(); }, []); + useEffect(() => { + onScopeOpenChange?.(scopeOpen); + }, [onScopeOpenChange, scopeOpen]); + useEffect(() => { const details = scopeDetailsRef.current; if (!scopeOpen || !details?.open) return undefined; @@ -956,7 +963,94 @@ function MasterSearchHeader({ function renderScopeRows() { return (
-
+
+
+

Refine search

+ + Mode, status, topics + +
+
+ +
+ + onScopeFiltersChange({ ...scopeFilters, medications: splitFilterText(event.target.value) }) + } + placeholder="Medication" + className="h-10 min-w-0 rounded-lg border border-[color:var(--border)] bg-[color:var(--surface-raised)] px-2 text-xs font-semibold text-[color:var(--text)] outline-none placeholder:text-[color:var(--text-soft)] focus:border-[color:var(--focus)] focus:ring-4 focus:ring-[color:var(--focus)]/25" + /> + + onScopeFiltersChange({ ...scopeFilters, topics: splitFilterText(event.target.value) }) + } + placeholder="Topic" + className="h-10 min-w-0 rounded-lg border border-[color:var(--border)] bg-[color:var(--surface-raised)] px-2 text-xs font-semibold text-[color:var(--text)] outline-none placeholder:text-[color:var(--text-soft)] focus:border-[color:var(--focus)] focus:ring-4 focus:ring-[color:var(--focus)]/25" + /> + + +
+ + onScopeFiltersChange({ ...scopeFilters, collections: splitFilterText(event.target.value) }) + } + placeholder={collectionOptions.length ? `Collection: ${collectionOptions[0]}` : "Collection"} + className="h-10 rounded-lg border border-[color:var(--border)] bg-[color:var(--surface-raised)] px-2 text-xs font-semibold text-[color:var(--text)] outline-none placeholder:text-[color:var(--text-soft)] focus:border-[color:var(--focus)] focus:ring-4 focus:ring-[color:var(--focus)]/25" + /> + +
+
+

Document scope

@@ -1167,25 +1261,25 @@ function MasterSearchHeader({ {searchMode === "answer" ? "Synthesize cited clinical guidance" : "List matching source documents"}
-
- Filters + Refine
+ @@ -1256,7 +1350,7 @@ function MasterSearchHeader({
@@ -6404,7 +6762,7 @@ export function ClinicalDashboard() { /> )}
- + - + + +

@@ -6490,7 +6868,7 @@ export function ClinicalDashboard() { items={bottomNavItems} activeHash={activeHash} state={mobileFabState} - hidden={guideOpen} + hidden={guideOpen || scopeMenuOpen || !answer} onNavigate={navigateMobileSection} /> diff --git a/src/components/DocumentViewer.tsx b/src/components/DocumentViewer.tsx index 4e8925434..73876b5f5 100644 --- a/src/components/DocumentViewer.tsx +++ b/src/components/DocumentViewer.tsx @@ -1051,7 +1051,8 @@ function PdfCanvasViewer({ url, title, initialPage }: { url: string; title: stri canvas.width = Math.floor(viewport.width * outputScale); canvas.height = Math.floor(viewport.height * outputScale); canvas.style.width = `${Math.floor(viewport.width)}px`; - canvas.style.height = `${Math.floor(viewport.height)}px`; + canvas.style.height = "auto"; + canvas.style.maxWidth = "100%"; renderTask = pdfPage.render({ canvas, @@ -1274,7 +1275,7 @@ function PdfCanvasViewer({ url, title, initialPage }: { url: string; title: stri )}

@@ -1962,14 +1963,6 @@ export function DocumentViewer({
- {readyDocument && ( - - )} + {readyDocument && ( + <> +
+ Admin + +
+ + + )}
@@ -2143,8 +2157,8 @@ export function DocumentViewer({
{indexHealth ? ( diff --git a/src/components/ui-primitives.tsx b/src/components/ui-primitives.tsx index e8ef10a3f..449c45534 100644 --- a/src/components/ui-primitives.tsx +++ b/src/components/ui-primitives.tsx @@ -12,21 +12,21 @@ export function cn(...classes: Array) { } export const textMuted = "text-[color:var(--text-muted)]"; -export const raisedCard = "rounded-xl border border-[color:var(--border)] bg-[color:var(--surface-raised)]"; -export const insetCard = "rounded-xl border border-[color:var(--border)] bg-[color:var(--surface-inset)]"; +export const raisedCard = "rounded-lg border border-[color:var(--border)] bg-[color:var(--surface-raised)]"; +export const insetCard = "rounded-lg border border-[color:var(--border)] bg-[color:var(--surface-inset)]"; export const appBackdrop = - "bg-[radial-gradient(circle_at_50%_-12%,color-mix(in_srgb,var(--primary)_11%,transparent),transparent_28rem),linear-gradient(180deg,var(--background),color-mix(in_srgb,var(--background)_90%,var(--surface-inset)))]"; + "bg-[radial-gradient(circle_at_50%_-12%,color-mix(in_srgb,var(--primary)_5%,transparent),transparent_28rem),linear-gradient(180deg,var(--background),color-mix(in_srgb,var(--background)_90%,var(--surface-inset)))]"; export const glassPanel = - "rounded-xl border border-[color:var(--border-lux)] bg-[color:var(--surface-raised)] shadow-[var(--shadow-soft)] dark:border-white/10"; + "rounded-lg border border-[color:var(--border-lux)] bg-[color:var(--surface-raised)] shadow-[var(--shadow-soft)] dark:border-white/10"; export const quietPanel = - "rounded-xl border border-[color:var(--border)] bg-[color:var(--surface-raised)] shadow-[var(--shadow-tight)]"; + "rounded-lg border border-[color:var(--border)] bg-[color:var(--surface-raised)] shadow-[var(--shadow-tight)]"; export const sourceCard = `${quietPanel} transition hover:border-[color:var(--border-strong)] hover:shadow-[var(--shadow-hover)]`; export const answerSurface = - "rounded-xl border border-[color:var(--border-lux)] border-l-4 border-l-[color:var(--primary)] bg-[color:var(--surface-lux)] shadow-[var(--shadow-soft)]"; + "rounded-lg border border-[color:var(--border-lux)] border-l-4 border-l-[color:var(--primary)] bg-[color:var(--surface-lux)] shadow-[var(--shadow-soft)]"; export const evidenceSurface = - "rounded-xl border border-[color:var(--primary)]/20 border-l-4 border-l-[color:var(--primary)] bg-[color:var(--surface-lux)] shadow-[var(--shadow-soft)]"; + "rounded-lg border border-[color:var(--primary)]/20 border-l-4 border-l-[color:var(--primary)] bg-[color:var(--surface-lux)] shadow-[var(--shadow-soft)]"; export const panel = - "rounded-xl border border-[color:var(--border-lux)] bg-[color:var(--surface-lux)] shadow-[var(--shadow-soft)] ring-1 ring-white/25 dark:ring-white/5"; + "rounded-lg border border-[color:var(--border-lux)] bg-[color:var(--surface-lux)] shadow-[var(--shadow-soft)] ring-1 ring-white/25 dark:ring-white/5"; export const panelSubtle = quietPanel; export const controlBase = "inline-flex min-h-[44px] items-center justify-center gap-2 rounded-lg text-sm font-semibold transition active:translate-y-px disabled:cursor-not-allowed disabled:opacity-55 disabled:hover:shadow-none"; @@ -59,12 +59,12 @@ export const iconTilePremium = export const compactMetadataRow = "mt-2 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs font-semibold text-[color:var(--text-muted)]"; export const premiumHeaderSurface = - "border-b border-white/10 bg-[radial-gradient(circle_at_12%_-35%,color-mix(in_srgb,var(--app-shell-accent)_34%,transparent),transparent_18rem),linear-gradient(135deg,var(--app-shell)_0%,var(--app-shell-muted)_58%,color-mix(in_srgb,var(--app-shell-muted)_72%,var(--app-shell-accent))_100%)] text-white shadow-[var(--shadow-soft)]"; + "border-b border-white/10 bg-[radial-gradient(circle_at_16%_-45%,color-mix(in_srgb,var(--app-shell-accent)_16%,transparent),transparent_18rem),linear-gradient(180deg,var(--app-shell-muted)_0%,var(--app-shell)_100%)] text-white shadow-[var(--shadow-soft)]"; export const sheetSurface = "rounded-t-[var(--radius-xl)] border border-[color:var(--border-lux)] bg-[color:var(--surface-lux)] shadow-[var(--shadow-lux)] ring-1 ring-white/25 backdrop-blur-xl dark:ring-white/10 sm:rounded-[var(--radius-lg)]"; export const sheetHandle = "mx-auto block h-1 w-10 rounded-full bg-[color:var(--border-strong)]/70 sm:hidden"; export const commandInput = - "min-h-[48px] w-full rounded-[var(--radius-lg)] border border-white/20 bg-white/95 pl-12 pr-12 text-base font-semibold text-slate-950 shadow-[0_16px_34px_rgb(0_0_0_/_14%),inset_0_1px_0_rgb(255_255_255_/_82%)] outline-none transition placeholder:text-slate-500 focus:border-[color:var(--focus)] focus:ring-4 focus:ring-teal-300/25 dark:bg-slate-950/90 dark:text-slate-50 dark:placeholder:text-slate-500"; + "min-h-[48px] w-full rounded-[var(--radius-lg)] border border-white/20 bg-white/96 pl-12 pr-12 text-sm font-semibold text-slate-950 shadow-[0_10px_22px_rgb(0_0_0_/_10%),inset_0_1px_0_rgb(255_255_255_/_82%)] outline-none transition placeholder:text-slate-500 focus:border-[color:var(--focus)] focus:ring-4 focus:ring-teal-300/20 dark:bg-slate-900/90 dark:text-slate-50 dark:placeholder:text-slate-500 sm:text-base"; export const toneSuccess = "border-[color:var(--success-border)] bg-[color:var(--success-soft)] text-[color:var(--success)]"; @@ -200,7 +200,7 @@ export function LoadingPanel({ export function EmptyState({ icon: Icon, title, body }: { icon: IconComponent; title: string; body: string }) { return ( -
+
diff --git a/tests/ui-smoke.spec.ts b/tests/ui-smoke.spec.ts index e4ca7a83d..11a383fed 100644 --- a/tests/ui-smoke.spec.ts +++ b/tests/ui-smoke.spec.ts @@ -387,7 +387,7 @@ async function mockDemoApi(page: Page) { }); } -async function expectDomIntegrity(page: Page, options: { mobileNav?: boolean } = {}) { +async function expectDomIntegrity(page: Page, options: { mobileNav?: boolean; mobileFabReady?: boolean } = {}) { const audit = await page.evaluate(() => { const duplicateIds = [...document.querySelectorAll("[id]")] .map((element) => element.id) @@ -421,8 +421,13 @@ async function expectDomIntegrity(page: Page, options: { mobileNav?: boolean } = if (options.mobileNav) { await expect(page.getByRole("navigation", { name: "Answer sections" })).toHaveCount(0); - await expect(page.getByTestId("mobile-section-fab-button")).toBeVisible(); - await expect(page.getByTestId("mobile-section-fab-menu")).toBeHidden(); + if (options.mobileFabReady) { + await expect(page.getByTestId("mobile-section-fab-button")).toBeVisible(); + await expect(page.getByTestId("mobile-section-fab-menu")).toBeHidden(); + } else { + await expect(page.getByTestId("mobile-section-fab-button")).toHaveCount(0); + await expect(page.getByTestId("mobile-section-fab-menu")).toHaveCount(0); + } } } @@ -497,16 +502,7 @@ test.describe("Clinical KB UI smoke coverage", () => { await expect(page.getByRole("button", { name: /Use sample question/i }).first()).toBeVisible(); await expectDomIntegrity(page, { mobileNav: viewport.width <= 768 }); if (viewport.width <= 768) { - const fabButton = page.getByTestId("mobile-section-fab-button"); - const fabMenu = page.getByTestId("mobile-section-fab-menu"); - await fabButton.click(); - await expect(fabMenu).toBeVisible(); - await expect(page.getByTestId("mobile-section-fab-status")).toHaveText("No answer yet"); - await expect(page.getByTestId("mobile-section-fab-next-step")).toHaveText("Ask a question first"); - await expect(fabMenu).toContainText("No quotes yet"); - await expect(fabMenu).toContainText("No images yet"); - await page.keyboard.press("Escape"); - await expect(fabMenu).toBeHidden(); + await expect(page.getByTestId("mobile-section-fab-button")).toHaveCount(0); } await expectNoPageHorizontalOverflow(page); }); @@ -547,7 +543,7 @@ test.describe("Clinical KB UI smoke coverage", () => { await expect(page.getByTestId("answer-grounding-chip")).toHaveCount(0); expect(answerRequests).toEqual([]); await expect(page.getByRole("heading", { level: 1, name: "Clinical Guide" })).toBeVisible(); - await expectDomIntegrity(page, { mobileNav: true }); + await expectDomIntegrity(page, { mobileNav: true, mobileFabReady: false }); await expectNoPageHorizontalOverflow(page); }); @@ -635,14 +631,14 @@ test.describe("Clinical KB UI smoke coverage", () => { await page.keyboard.press("Escape"); await expect(fabMenu).toBeHidden(); await expect(fabButton).toBeFocused(); - await expectDomIntegrity(page, { mobileNav: true }); + await expectDomIntegrity(page, { mobileNav: true, mobileFabReady: true }); const evidenceDrawer = page.locator("details").filter({ hasText: "Evidence & sources" }).first(); await expect(evidenceDrawer).toBeVisible(); await expect(evidenceDrawer).toContainText(/top source/i); await expect(evidenceDrawer).toContainText(/citations?/i); - await expect(page.getByText("Review evidence").first()).toBeVisible(); - await expect(page.getByText("Workspace utilities")).toBeVisible(); + await expect(page.getByText("Clinical evidence")).toBeVisible(); + await expect(page.getByText("Library and admin")).toBeVisible(); expect(await evidenceDrawer.evaluate((element) => element.hasAttribute("open"))).toBe(false); await expect(page.getByTestId("evidence-support-panel")).toHaveCount(0);