diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8c52ff9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..aca3fa0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +* text=auto eol=lf + +*.jpg binary +*.jpeg binary +*.png binary +*.webp binary diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..d4cb2eb --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,39 @@ +version: 2 + +updates: + - package-ecosystem: npm + directory: / + schedule: + interval: monthly + day: monday + time: "03:00" + timezone: Asia/Shanghai + open-pull-requests-limit: 5 + groups: + development-dependencies: + dependency-type: development + patterns: + - "*" + commit-message: + prefix: chore + include: scope + labels: + - dependencies + + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly + day: monday + time: "03:30" + timezone: Asia/Shanghai + open-pull-requests-limit: 5 + groups: + github-actions: + patterns: + - "*" + commit-message: + prefix: chore + include: scope + labels: + - dependencies diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..554426a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,183 @@ +name: Verify and deploy + +on: + pull_request: + push: + branches: + - master + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: html-sample-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + validate: + name: Validate (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - windows-latest + steps: + - name: Check out repository + uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5 + + - name: Set up Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version: 24 + cache: npm + + - name: Install locked dependencies + run: npm ci + + - name: Run static checks + run: npm run check + + - name: Run unit tests + run: npm run test:unit + + - name: Audit high-severity dependencies + run: npm audit --audit-level=high + + browser-linux: + name: Browser tests (Ubuntu) + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5 + + - name: Set up Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version: 24 + cache: npm + + - name: Install locked dependencies + run: npm ci + + - name: Install browser engines + run: npx playwright install --with-deps chromium firefox webkit + + - name: Run Linux browser and visual tests + run: npm run test:e2e:linux + + - name: Upload browser diagnostics + if: failure() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: playwright-ubuntu + path: test-results/ + if-no-files-found: ignore + retention-days: 7 + + browser-windows: + name: Browser tests (Windows) + runs-on: windows-latest + steps: + - name: Check out repository + uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5 + + - name: Set up Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version: 24 + cache: npm + + - name: Install locked dependencies + run: npm.cmd ci + + - name: Install browser engines + run: npx.cmd playwright install chromium firefox + + - name: Run Windows browser tests + run: npm.cmd run test:e2e:windows + + - name: Upload browser diagnostics + if: failure() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: playwright-windows + path: test-results/ + if-no-files-found: ignore + retention-days: 7 + + lighthouse: + name: Lighthouse budgets + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5 + + - name: Set up Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version: 24 + cache: npm + + - name: Install locked dependencies + run: npm ci + + - name: Run Lighthouse + run: npm run test:lighthouse + + - name: Upload Lighthouse reports + if: always() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: lighthouse + path: test-results/lighthouse/ + if-no-files-found: ignore + retention-days: 7 + + deploy: + name: Deploy GitHub Pages + if: github.event_name == 'push' && github.ref == 'refs/heads/master' + needs: + - validate + - browser-linux + - browser-windows + - lighthouse + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + permissions: + contents: read + id-token: write + pages: write + steps: + - name: Check out repository + uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5 + + - name: Set up Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version: 24 + cache: npm + + - name: Install locked dependencies + run: npm ci + + - name: Build publish directory + run: npm run build + + - name: Configure Pages + uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5 + with: + enablement: true + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3 + with: + path: _site + + - name: Deploy Pages + id: deployment + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d14236 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +node_modules/ +_site/ +test-results/ +playwright-report/ +.lighthouseci/ + +.DS_Store +Thumbs.db +*.log diff --git a/.htmlvalidate.json b/.htmlvalidate.json new file mode 100644 index 0000000..c2f87de --- /dev/null +++ b/.htmlvalidate.json @@ -0,0 +1,17 @@ +{ + "extends": ["html-validate:recommended"], + "rules": { + "attribute-boolean-style": ["error", { "style": "omit" }], + "attribute-empty-style": ["error", { "style": "omit" }], + "doctype-style": ["error", { "style": "lowercase" }], + "no-inline-style": "error", + "no-redundant-role": "error", + "prefer-native-element": "error", + "void-style": ["error", { "style": "selfclosing" }], + "wcag/h30": "error", + "wcag/h32": "error", + "wcag/h37": "error", + "wcag/h63": "error", + "wcag/h71": "error" + } +} diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..a45fd52 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +24 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..9b23623 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,9 @@ +node_modules/ +_site/ +test-results/ +playwright-report/ +.lighthouseci/ + +assignment-1 2/css/Mutual evaluation.css +assignment-1 2/css/hw1 - old.css +assignment-1 2/css/hw1 - old2.css diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8b6083f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,19 @@ +# Changelog + +All notable changes to this project are documented here. + +## [Unreleased] + +### Added + +- Unified bilingual gallery entry point. +- Accessible Learning Profile, Ultimate Field Notes, and Signal Conference examples. +- Zero-data registration form demonstration. +- Windows and Ubuntu CI, browser tests, visual snapshots, accessibility checks, and Lighthouse budgets. +- GitHub Pages deployment workflow and project documentation. + +### Changed + +- Replaced remote and unverified media with locally owned artwork. +- Rewrote course-derived copy and demo data with original content. +- Preserved every historical public path while modernizing active pages. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..b28a3f7 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,56 @@ +# Contributing + +## Requirements + +- Node.js 24 LTS +- npm supplied with Node.js +- Current Chrome, Edge, and Firefox on Windows for the full local matrix + +Do not change Windows execution policy or environment variables for this project. In PowerShell, use `npm.cmd` when `npm.ps1` is disabled. + +## Workflow + +1. Create a focused branch from `master`. +2. Install exactly from the lockfile with `npm.cmd ci`. +3. Keep all existing compatibility paths available. +4. Add or update tests under `test/`. +5. Run the complete relevant test set before committing. +6. Open a pull request and wait for Windows and Ubuntu checks to pass. + +## Required checks + +```powershell +npm.cmd run check +npm.cmd run test:unit +npm.cmd run test:e2e:windows +npm.cmd run test:lighthouse +npm.cmd run build +``` + +Ubuntu CI additionally runs Chromium, Firefox, WebKit, mobile Chromium, and the committed screenshot baselines. + +## Visual snapshots + +Stable baselines live in `test/snapshots/`. Normal tests never overwrite them. Update them only after reviewing the visual change: + +```powershell +npm.cmd run test:visual:update +``` + +Generated reports, failure screenshots, traces, and videos belong in `test-results/` and must not be committed. + +## Content and privacy + +- Use original copy and locally owned or clearly licensed assets. +- Record any third-party material in `THIRD_PARTY_NOTICES.md`. +- Do not add analytics, remote fonts, tracking pixels, form endpoints, cookies, or browser storage. +- Keep external links deliberate, HTTPS-only, and limited to authoritative references. + +## HTML and accessibility + +- Preserve landmark and heading order. +- Provide visible keyboard focus. +- Use native elements before ARIA. +- Give every form control a persistent label and useful error message. +- Verify layouts at 200% zoom and with Windows forced colors. +- Update `test/manual-accessibility.md` when behavior changes materially. diff --git a/Html5-Final-Project.html b/Html5-Final-Project.html index 44fd32b..d8c7cef 100644 --- a/Html5-Final-Project.html +++ b/Html5-Final-Project.html @@ -1,53 +1,171 @@ - - - - - - - Html5 Final Project - - - -
-

Wenlu Zhao

- - -
- -
-

Favorite Foods

- -
- -
-

Achievements

-

Progress in this course (100%)100%
- Progress in the Specialization capstone (20%)20%
- Progress in life goals (40%)40%

-
- -
-

More About Me

-
- My Childhood -

I grew up in a small city in northern China. There is a small forest next to the house, and I often play there.

-
-
- - - - - \ No newline at end of file + + + + + + + + + + + + + + Learning Profile · HTML Sample + + + + + + +
+ + +
+

SEMANTIC HTML EXERCISE · 01

+

Learning the web,
one meaningful element at a time.

+

+ A small profile for zhaowl94, built with native HTML + elements and progressive enhancement. +

+
+
+ +
+
+
+

01 · Practice

+

Patterns worth repeating

+
+ +
+ +
+
+

02 · Progress

+

A learning snapshot

+
+
+
+
+ Semantic page structure + 100% +
+ + 100% + +
+
+
+ Responsive CSS systems + 72% +
+ + 72% + +
+
+
+ Automated accessibility testing + 58% +
+ + 58% + +
+
+
+ +
+
+

03 · Next

+

What comes after the markup?

+
+
+ Build for more ways of using the web +
+

+ The next step is not another framework. It is learning how zoom, + high contrast, screen readers, slow networks, and different input + methods change the experience. +

+

+ This repository uses those constraints as design inputs and + verifies them before publishing. +

+
+
+
+
+ + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4977a98 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +MIT License + +Copyright (c) 2026 zhaowl94 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +Third-party and historical materials identified in THIRD_PARTY_NOTICES.md are +not covered by this license unless their own terms expressly say otherwise. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index c48a3fe..70f9e2c 100644 --- a/README.md +++ b/README.md @@ -1 +1,99 @@ -# sample \ No newline at end of file +# HTML Sample + +一个无需前端框架或运行时构建即可使用的静态学习示例集。仓库包含三个独立练习,重点覆盖语义化 HTML、响应式 CSS、无障碍、表单交互与自动化浏览器测试。 + +An accessible collection of framework-free HTML and CSS exercises. Every published page works when opened directly, served locally, or deployed below a GitHub Pages project path. + +在线入口:[https://zhaowl94.github.io/html_sample/](https://zhaowl94.github.io/html_sample/) + +## 示例 + +| 入口 | 内容 | 重点 | +| -------------------------------------------------------------- | ----------------------------- | --------------------------------- | +| [`Html5-Final-Project.html`](Html5-Final-Project.html) | Learning Profile 单页练习 | 语义结构、列表、进度条、`details` | +| [`assignment-1 2/index.html`](assignment-1%202/index.html) | Ultimate Field Notes 三页站点 | 响应式导航、布局、时间线、表格 | +| [`styles-conference/index.html`](styles-conference/index.html) | Signal Conference 五页站点 | 编辑型布局、表单、浏览器端校验 | + +所有旧页面路径均继续有效。根目录新增 `index.html` 作为统一入口。 + +## 运行方式 + +页面没有构建依赖,可以直接双击任意 HTML 文件。若希望通过本地 HTTP 服务器查看: + +```powershell +python -m http.server 8000 +``` + +安装测试工具需要 Node.js 24 LTS: + +```powershell +npm.cmd ci +npm.cmd run serve +``` + +PowerShell 若允许执行 `npm.ps1`,也可将 `npm.cmd` 写成 `npm`。仓库不会修改 Windows 执行策略、环境变量或全局 Git 配置,也不要求全局安装任何 npm 工具。 + +## 测试 + +```powershell +# 格式、HTML、CSS、JavaScript、本地链接和兼容路径 +npm.cmd run check + +# Node 单元测试 +npm.cmd run test:unit + +# Windows 浏览器矩阵 +npm.cmd run test:e2e:windows + +# 全部本地浏览器项目 +npm.cmd run test:e2e + +# Lighthouse 性能与质量门槛 +npm.cmd run test:lighthouse +``` + +`test/` 包含: + +- 10 个页面的加载与导航测试; +- Chromium、Chrome、Edge、Firefox、WebKit 和移动端视口覆盖; +- Axe WCAG 自动化扫描; +- 键盘、表单、零网络提交和零浏览器存储验证; +- 直接使用 `file://` 打开页面的兼容测试; +- 桌面、移动、浅色和深色截图基线; +- HTML/CSS 语法、本地链接、大小写和 500 KB 初始资源预算检查; +- Windows Edge 的高对比度和 200% 缩放自动验证,以及 Narrator 手动复核限制记录。 + +完整测试说明见 [`test/README.md`](test/README.md)。 + +## 设计边界 + +- 页面运行时不加载 CDN、远程字体、第三方脚本或统计服务。 +- Signal 报名表单不发送请求、不设置 Cookie,也不使用 `localStorage` 或 `sessionStorage`。 +- 关键页面初始本地资源不超过 500 KB。 +- 支持系统浅色、深色、减少动画和强制颜色偏好。 +- 正式兼容现代 Edge、Chrome、Firefox 与 Safari;不支持 Internet Explorer。 +- HTML 结构直接保留在每个页面中,不依赖 JavaScript 注入或模板构建。 + +## 项目结构 + +```text +. +├── index.html # 示例导航 +├── Html5-Final-Project.html # Learning Profile +├── assets/ # 根页面样式和社交预览 +├── assignment-1 2/ # Ultimate Field Notes +├── styles-conference/ # Signal Conference +├── scripts/ # GitHub Pages 静态发布构建 +├── test/ # 全部自动化和人工测试材料 +└── .github/ # CI、Pages 和依赖维护 +``` + +## 隐私与许可 + +页面只展示 GitHub 用户名 `zhaowl94`,不收集个人信息。原课程练习中的文字、人物照片和远程素材已由原创内容替换。 + +本次原创代码和内容采用 [MIT License](LICENSE)。学习来源、事实来源、生成图像及保留的历史练习文件边界见 [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md)。 + +## Contributing + +修改说明、测试门禁和截图更新流程见 [`CONTRIBUTING.md`](CONTRIBUTING.md)。 diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md new file mode 100644 index 0000000..3288011 --- /dev/null +++ b/THIRD_PARTY_NOTICES.md @@ -0,0 +1,34 @@ +# Third-party notices and provenance + +## Learning references + +Earlier versions of this repository were created while following introductory web-design exercises: + +- Web Design for Everybody, Colleen van Lent: +- Learn to Code HTML & CSS, Shay Howe: + +The active pages in this version use newly written copy, data, structure, and visual design. These links acknowledge the learning context; no license to the referenced course material is claimed or granted by this repository. + +## Ultimate references + +The historical and rules summaries link to primary sources: + +- USA Ultimate, Discover Ultimate: +- USA Ultimate, Rules of Ultimate: +- World Flying Disc Federation, History of Spirit of the Game: + +Organization names remain the property of their respective owners. The repository is not affiliated with or endorsed by those organizations. + +## Generated artwork + +`assets/og.png` was generated specifically for this repository on 2026-07-31 using OpenAI image generation without an input image. `assignment-1 2/images/flywheel.jpg` is a crop derived from the same generated artwork. The previous photograph containing identifiable players was replaced and is not included in this version. + +## Historical CSS snapshots + +The following unreferenced files are preserved only as learning-history snapshots and are excluded from the active site design: + +- `assignment-1 2/css/Mutual evaluation.css` +- `assignment-1 2/css/hw1 - old.css` +- `assignment-1 2/css/hw1 - old2.css` + +Their provenance predates the current refactor. They are retained for path compatibility and are not represented as newly authored or covered by the repository’s MIT grant. diff --git a/assets/favicon.png b/assets/favicon.png new file mode 100644 index 0000000..99941a9 Binary files /dev/null and b/assets/favicon.png differ diff --git a/assets/og.png b/assets/og.png new file mode 100644 index 0000000..fea8a4c Binary files /dev/null and b/assets/og.png differ diff --git a/assets/stylesheets/gallery.css b/assets/stylesheets/gallery.css new file mode 100644 index 0000000..cad7eeb --- /dev/null +++ b/assets/stylesheets/gallery.css @@ -0,0 +1,353 @@ +:root { + color-scheme: light dark; + --paper: #f7f2e8; + --paper-deep: #ebe3d3; + --ink: #08264c; + --muted: #536379; + --line: #c8c0b2; + --card: #fffaf0; + --coral: #ed4938; + --blue: #187bd1; + --lime: #95b900; + --focus: #c92f20; + --shadow: 0 1.25rem 3.5rem rgb(8 38 76 / 12%); + font-family: + Inter, + ui-sans-serif, + system-ui, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + sans-serif; +} + +* { + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; +} + +body { + min-width: 20rem; + margin: 0; + color: var(--ink); + background: + linear-gradient( + 90deg, + transparent 49.85%, + rgb(8 38 76 / 6%) 50% 50.15%, + transparent 50.15% + ), + var(--paper); + line-height: 1.65; +} + +a { + color: inherit; + text-underline-offset: 0.2em; +} + +a:focus-visible { + outline: 0.2rem solid var(--focus); + outline-offset: 0.25rem; +} + +.skip-link { + position: fixed; + z-index: 10; + inset-block-start: 0.75rem; + inset-inline-start: 0.75rem; + padding: 0.7rem 1rem; + color: #fff; + background: var(--ink); + border-radius: 0.35rem; + transform: translateY(-200%); +} + +.skip-link:focus { + transform: translateY(0); +} + +.site-header, +.examples, +.site-footer { + width: min(100% - 2rem, 74rem); + margin-inline: auto; +} + +.topbar { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 5rem; + border-block-end: 0.0625rem solid var(--line); +} + +.wordmark, +.repo-link { + display: inline-flex; + gap: 0.55rem; + align-items: center; + font-weight: 800; + text-decoration: none; +} + +.wordmark span { + color: var(--coral); + font-size: 1.4rem; +} + +.repo-link { + color: var(--muted); + font-size: 0.9rem; +} + +.hero { + display: grid; + grid-template-columns: minmax(0, 1.6fr) minmax(16rem, 0.8fr); + gap: 1rem 4rem; + align-items: end; + padding-block: clamp(4rem, 10vw, 8rem); +} + +.eyebrow, +.card-kicker, +.section-heading p { + margin: 0; + color: var(--blue); + font-size: 0.75rem; + font-weight: 800; + letter-spacing: 0.16em; + text-transform: uppercase; +} + +.hero h1 { + grid-row: 2 / span 2; + margin: 0; + font-size: clamp(3rem, 9vw, 7.5rem); + font-weight: 900; + letter-spacing: -0.075em; + line-height: 0.98; +} + +.hero-copy { + margin: 0; + color: var(--muted); + font-size: clamp(1rem, 2vw, 1.15rem); +} + +.examples { + padding-block: 1rem 6rem; +} + +.section-heading { + display: grid; + grid-template-columns: minmax(10rem, 0.45fr) 1fr; + gap: 1rem 3rem; + align-items: end; + margin-block-end: 2rem; + padding-block-start: 2rem; + border-block-start: 0.0625rem solid var(--line); +} + +.section-heading h2 { + max-width: 24ch; + margin: 0; + font-size: clamp(1.8rem, 4vw, 3.2rem); + letter-spacing: -0.04em; + line-height: 1.12; +} + +.card-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 1rem; +} + +.demo-card { + position: relative; + display: flex; + min-height: 31rem; + padding: clamp(1.5rem, 3vw, 2.25rem); + overflow: hidden; + flex-direction: column; + background: var(--card); + border: 0.0625rem solid var(--line); + border-radius: 0.75rem; + box-shadow: var(--shadow); +} + +.demo-card::before { + position: absolute; + inline-size: 9rem; + block-size: 9rem; + inset-block-start: -4.5rem; + inset-inline-end: -4.5rem; + background: var(--card-accent); + border-radius: 50%; + content: ""; +} + +.demo-card--profile { + --card-accent: var(--lime); +} + +.demo-card--frisbee { + --card-accent: var(--coral); +} + +.demo-card--conference { + --card-accent: var(--blue); +} + +.card-index { + margin-block-end: 4rem; + color: var(--muted); + font-size: 0.8rem; + font-weight: 800; +} + +.demo-card h3 { + margin: 0.5rem 0 1rem; + font-size: clamp(1.7rem, 3vw, 2.45rem); + letter-spacing: -0.04em; + line-height: 1.05; +} + +.demo-card p:not(.card-kicker) { + margin: 0; + color: var(--muted); +} + +.tag-list { + display: flex; + padding: 0; + margin: 1.5rem 0; + flex-wrap: wrap; + gap: 0.45rem; + list-style: none; +} + +.tag-list li { + padding: 0.35rem 0.65rem; + font-size: 0.78rem; + font-weight: 700; + border: 0.0625rem solid var(--line); + border-radius: 999px; +} + +.card-link { + display: flex; + align-items: center; + justify-content: space-between; + margin-block-start: auto; + padding-block-start: 1.25rem; + font-weight: 800; + text-decoration: none; + border-block-start: 0.0625rem solid var(--line); +} + +.card-link span { + color: var(--card-accent); + font-size: 1.6rem; + transition: transform 180ms ease; +} + +.card-link:hover span { + transform: translateX(0.25rem); +} + +.site-footer { + display: flex; + justify-content: space-between; + padding-block: 2rem; + color: var(--muted); + font-size: 0.85rem; + border-block-start: 0.0625rem solid var(--line); +} + +.site-footer p { + margin: 0; +} + +@media (max-width: 52rem) { + .hero, + .section-heading { + grid-template-columns: 1fr; + } + + .hero h1 { + grid-row: auto; + } + + .card-grid { + grid-template-columns: 1fr; + } + + .demo-card { + min-height: 25rem; + } +} + +@media (max-width: 34rem) { + .topbar, + .site-footer { + align-items: flex-start; + flex-direction: column; + justify-content: center; + gap: 0.75rem; + } + + .hero { + padding-block: 3.5rem; + } + + .hero h1 { + font-size: clamp(2.8rem, 16vw, 4.5rem); + } +} + +@media (prefers-color-scheme: dark) { + :root { + --paper: #071728; + --paper-deep: #0d2238; + --ink: #fff8ea; + --muted: #b5c4d5; + --line: #34506c; + --card: #102940; + --coral: #ff6f5f; + --blue: #59b2ff; + --lime: #b9dc39; + --focus: #ff9d91; + --shadow: 0 1.25rem 3.5rem rgb(0 0 0 / 28%); + } + + body { + background: + linear-gradient( + 90deg, + transparent 49.85%, + rgb(255 255 255 / 7%) 50% 50.15%, + transparent 50.15% + ), + var(--paper); + } +} + +@media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } + + .card-link span { + transition: none; + } +} + +@media (forced-colors: active) { + .demo-card::before { + border: 0.125rem solid CanvasText; + } +} diff --git a/assets/stylesheets/profile.css b/assets/stylesheets/profile.css new file mode 100644 index 0000000..e6f459d --- /dev/null +++ b/assets/stylesheets/profile.css @@ -0,0 +1,351 @@ +:root { + color-scheme: light dark; + --canvas: #f2efe7; + --surface: #fffdf7; + --ink: #17223b; + --muted: #596477; + --line: #c9c2b6; + --violet: #6941c6; + --violet-soft: #e8dcff; + --green: #13795b; + --green-soft: #d8f3e8; + --focus: #8f2dce; + font-family: + "Segoe UI", + ui-sans-serif, + system-ui, + -apple-system, + BlinkMacSystemFont, + sans-serif; +} + +* { + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; +} + +body { + min-width: 20rem; + margin: 0; + color: var(--ink); + background: + radial-gradient( + circle at 78% 8%, + var(--violet-soft) 0 12rem, + transparent 12.1rem + ), + var(--canvas); + line-height: 1.65; +} + +a { + color: inherit; + text-underline-offset: 0.18em; +} + +a:focus-visible, +summary:focus-visible { + outline: 0.2rem solid var(--focus); + outline-offset: 0.25rem; +} + +.skip-link { + position: fixed; + z-index: 10; + inset-block-start: 0.75rem; + inset-inline-start: 0.75rem; + padding: 0.7rem 1rem; + color: #fff; + background: #17223b; + border-radius: 0.35rem; + transform: translateY(-200%); +} + +.skip-link:focus { + transform: translateY(0); +} + +.profile-header, +main, +.profile-footer { + width: min(100% - 2rem, 68rem); + margin-inline: auto; +} + +.profile-nav { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 5rem; + border-block-end: 0.0625rem solid var(--line); +} + +.lab-link, +.section-links a { + font-weight: 750; + text-decoration: none; +} + +.lab-link { + display: inline-flex; + gap: 0.5rem; + align-items: center; +} + +.lab-link span { + color: var(--violet); + font-size: 1.25rem; +} + +.section-links { + display: flex; + gap: clamp(0.8rem, 3vw, 2rem); + color: var(--muted); + font-size: 0.9rem; +} + +.profile-hero { + max-width: 58rem; + padding-block: clamp(4rem, 10vw, 8rem); +} + +.eyebrow, +.section-title p { + margin: 0; + color: var(--violet); + font-size: 0.75rem; + font-weight: 800; + letter-spacing: 0.15em; + text-transform: uppercase; +} + +.profile-hero h1 { + margin: 1rem 0 1.5rem; + font-family: Georgia, "Times New Roman", serif; + font-size: clamp(3rem, 8.5vw, 6.5rem); + font-weight: 500; + letter-spacing: -0.065em; + line-height: 0.98; +} + +.lede { + max-width: 45rem; + margin: 0; + color: var(--muted); + font-size: clamp(1.05rem, 2vw, 1.3rem); +} + +.content-section { + display: grid; + grid-template-columns: minmax(12rem, 0.45fr) minmax(0, 1fr); + gap: 2rem 4rem; + padding-block: clamp(3.5rem, 7vw, 6rem); + border-block-start: 0.0625rem solid var(--line); +} + +.section-title h2 { + max-width: 12ch; + margin: 0.75rem 0 0; + font-family: Georgia, "Times New Roman", serif; + font-size: clamp(1.8rem, 4vw, 3rem); + font-weight: 500; + letter-spacing: -0.04em; + line-height: 1.08; +} + +.practice-grid { + display: grid; + padding: 0; + margin: 0; + gap: 0.8rem; + list-style: none; +} + +.practice-grid li { + display: grid; + grid-template-columns: 2.5rem minmax(0, 1fr); + gap: 0 1rem; + padding: 1.5rem; + background: var(--surface); + border: 0.0625rem solid var(--line); + border-radius: 0.75rem; +} + +.practice-number { + grid-row: 1 / span 2; + display: grid; + inline-size: 2.5rem; + block-size: 2.5rem; + place-items: center; + color: var(--violet); + font-weight: 800; + background: var(--violet-soft); + border-radius: 50%; +} + +.practice-grid h3, +.practice-grid p { + margin: 0; +} + +.practice-grid h3 { + font-size: 1.15rem; +} + +.practice-grid p { + margin-block-start: 0.35rem; + color: var(--muted); +} + +.progress-list { + display: grid; + gap: 2rem; + align-content: center; +} + +.progress-label { + display: flex; + justify-content: space-between; + gap: 1rem; + margin-block-end: 0.55rem; +} + +.progress-label strong { + color: var(--green); +} + +progress { + display: block; + inline-size: 100%; + block-size: 0.9rem; + overflow: hidden; + appearance: none; + background: var(--green-soft); + border: 0; + border-radius: 999px; +} + +progress::-webkit-progress-bar { + background: var(--green-soft); +} + +progress::-webkit-progress-value { + background: var(--green); + border-radius: 999px; +} + +progress::-moz-progress-bar { + background: var(--green); + border-radius: 999px; +} + +details { + align-self: start; + overflow: hidden; + background: var(--surface); + border: 0.0625rem solid var(--line); + border-radius: 0.75rem; +} + +summary { + padding: 1.5rem; + font-size: 1.1rem; + font-weight: 750; + cursor: pointer; +} + +.details-body { + padding: 0 1.5rem 1.5rem; + color: var(--muted); +} + +.details-body p { + margin: 0; +} + +.details-body p + p { + margin-block-start: 1rem; +} + +.profile-footer { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 1rem 3rem; + padding-block: 2.5rem; + color: var(--muted); + font-size: 0.85rem; + border-block-start: 0.0625rem solid var(--line); +} + +.profile-footer p { + margin: 0; +} + +@media (max-width: 46rem) { + .content-section, + .profile-footer { + grid-template-columns: 1fr; + } + + .section-title h2 { + max-width: none; + } +} + +@media (max-width: 34rem) { + .profile-nav { + align-items: flex-start; + padding-block: 1rem; + flex-direction: column; + gap: 0.75rem; + } + + .section-links { + inline-size: 100%; + justify-content: space-between; + } +} + +@media (prefers-color-scheme: dark) { + :root { + --canvas: #111526; + --surface: #1b2135; + --ink: #f7f1ff; + --muted: #bbc3d7; + --line: #444d66; + --violet: #c5a7ff; + --violet-soft: #35295a; + --green: #73ddb5; + --green-soft: #203f37; + --focus: #ddc9ff; + } + + body { + background: + radial-gradient( + circle at 78% 8%, + var(--violet-soft) 0 12rem, + transparent 12.1rem + ), + var(--canvas); + } +} + +@media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } +} + +@media (forced-colors: active) { + progress { + border: 0.0625rem solid CanvasText; + } + + .practice-number { + border: 0.0625rem solid CanvasText; + } +} diff --git a/assignment-1 2/css/Mutual evaluation.css b/assignment-1 2/css/Mutual evaluation.css index 895e5f5..b553ae0 100644 --- a/assignment-1 2/css/Mutual evaluation.css +++ b/assignment-1 2/css/Mutual evaluation.css @@ -1,13 +1,18 @@ -h1 { - text-align: center; - text-transform: uppercase; - Color: #FFFFFF; - padding: 40px -} +/* + * Historical peer-evaluation stylesheet. + * Preserved for learning history; active pages use hw1.css. + */ + +h1 { + text-align: center; + text-transform: uppercase; + color: #FFFFFF; + padding: 40px; +} header { background-color: #E3D6EF; - background-image: url("http://intro-webdesign.com/CSS/assignment-2/images/flywheel.jpg"); + background-image: url("../images/flywheel.jpg"); height: 250px; clear: both; } @@ -31,35 +36,32 @@ header a { padding-right: 50px; padding-top: 20px; padding-bottom: 20px; - border: solid thin; - color: #000000; - background-color: #C5C5C5; + color: #000000; + background-color: #C5C5C5; text-decoration: none; border: solid thin; display: inline-block; text-align: center; } -.active { - background-color: #FFFFFF -} +.active { + background-color: #FFFFFF; +} img { display: inline; width: 15%; margin-top: 20px; margin-left: 40px; - align: left; - display: block; + display: block; border: solid medium; border-color: #000000; background-color: #1B26E4; } -.left { - position: absolute; - background-color: ; - float: left; +.left { + position: absolute; + float: left; clear: right; overflow: auto; } @@ -70,11 +72,11 @@ img { overflow: auto; } -th { - font-family: Arial; +th { + font-family: Arial, sans-serif; background-color: #73AD21; text-align: left; - color: #FFFFFF + color: #FFFFFF; } tr { @@ -100,9 +102,9 @@ tr:hover { background: rgba(51, 153, 51, 0.3); } -tr:first-child { - text-align: left !IMPORTANT; -} +tr:first-child { + text-align: left !important; +} table td:first-child { text-align: left; @@ -134,4 +136,4 @@ table tr:last-child td:first-child { table tr:last-child td:last-child { border-bottom-right-radius: 6px; -} \ No newline at end of file +} diff --git a/assignment-1 2/css/hw1 - old.css b/assignment-1 2/css/hw1 - old.css index 6fea4a4..3e1fac6 100644 --- a/assignment-1 2/css/hw1 - old.css +++ b/assignment-1 2/css/hw1 - old.css @@ -1,17 +1,22 @@ -header { +/* + * Historical first-pass stylesheet. + * Preserved for learning history; active pages use hw1.css. + */ + +header { background: rgb(178, 178, 178); } h1 { text-align: center; color: #ffffff; - font-family: Arail, 'Times New Roman', serif; + font-family: Arial, 'Times New Roman', serif; /* font-variant: caps; */ - text-transform: uppercase + text-transform: uppercase; } a { - font-family: Arail, 'Times New Roman', serif; + font-family: Arial, 'Times New Roman', serif; color: #000000; background: rgb(197, 197, 197); } @@ -22,17 +27,16 @@ aside { h2 { color: rgb(0, 0, 128); - ; - font-family: Arail, 'Times New Roman', serif; - text-transform: uppercase + font-family: Arial, 'Times New Roman', serif; + text-transform: uppercase; } section { background: rgb(127, 127, 127); - font-family: Arail, 'Times New Roman', serif; + font-family: Arial, 'Times New Roman', serif; } /* p { - font-family: Arail, 'Times New Roman', serif; -} */ \ No newline at end of file + font-family: Arial, 'Times New Roman', serif; +} */ diff --git a/assignment-1 2/css/hw1 - old2.css b/assignment-1 2/css/hw1 - old2.css index 113bdc1..a046e7d 100644 --- a/assignment-1 2/css/hw1 - old2.css +++ b/assignment-1 2/css/hw1 - old2.css @@ -1,4 +1,9 @@ -body { +/* + * Historical second-pass stylesheet. + * Preserved for learning history; active pages use hw1.css. + */ + +body { padding-left: 0; padding-right: 0; padding-top: 0; @@ -22,12 +27,12 @@ header { h1 { text-align: center; color: #ffffff; - font-family: Arail, 'Times New Roman', serif; - text-transform: uppercase + font-family: Arial, 'Times New Roman', serif; + text-transform: uppercase; } nav>a { - font-family: Arail, 'Times New Roman', serif; + font-family: Arial, 'Times New Roman', serif; color: #000000; background: rgb(197, 197, 197); display: inline-block; @@ -71,10 +76,10 @@ aside img { width: 79%; background-color: #ffffff; margin-left: 1%; - font-family: Arail, 'Times New Roman', serif; + font-family: Arial, 'Times New Roman', serif; } h2 { color: #000; - font-family: Arail, 'Times New Roman', serif; -} \ No newline at end of file + font-family: Arial, 'Times New Roman', serif; +} diff --git a/assignment-1 2/css/hw1.css b/assignment-1 2/css/hw1.css index 962ecdd..754635d 100644 --- a/assignment-1 2/css/hw1.css +++ b/assignment-1 2/css/hw1.css @@ -1,149 +1,602 @@ -body { - padding-left: 0; - padding-right: 0; - padding-top: 0; - padding-bottom: 0; - margin-left: 2%; - margin-right: 2%; - margin-top: 2%; - margin-bottom: 2%; -} - -header { - /* background: rgb(178, 178, 178); */ - background-image: url("../images/flywheel.jpg"); - background-size: 100%, 100%; - padding-left: 0; - padding-right: 0; - padding-top: 1%; - padding-bottom: 1%; -} - -h1 { - text-align: center; - color: #ffffff; - font-family: Arail, 'Times New Roman', serif; - text-transform: uppercase -} - -nav>a { - font-family: Arail, 'Times New Roman', serif; - color: #000000; - background: rgb(197, 197, 197); - display: inline-block; - width: 17%; - padding-left: 0; - padding-right: 0; - padding-top: 1.5%; - padding-bottom: 1.5%; - text-align: center; - margin-left: 5%; - margin-right: 0; - margin-top: 0; - margin-bottom: 3%; - border-radius: 5%; - text-decoration: none; -} - -.active { - background: rgb(255, 255, 255); - color: rgb(0, 0, 255); -} - -.left { - float: left; - width: 20%; - background-color: rgb(119, 118, 19); - height: 100vh; -} - -aside img { - box-sizing: border-box; - width: 80%; - border: 2px solid rgb(0, 0, 0); - margin-left: 10%; - margin-right: 10%; - margin-top: 15%; - margin-bottom: 0; -} - -.right { - float: left; - width: 79%; - background-color: #ffffff; - margin-left: 1%; - font-family: Arail, 'Times New Roman', serif; -} - -h2 { - color: #000; - font-family: Arail, 'Times New Roman', serif; -} - -table { - font-family: Arail, 'Times New Roman', serif; - font-size: 100%; - /* font-weight: normal; */ - font-weight: bold; - /* color: #ffffff; */ - line-height: 300%; - box-sizing: border-box; - width: 75%; - margin-left: 12.5%; - margin-right: 12.5%; - margin-top: 0; - margin-bottom: 0; -} - -table tr:first-child>th { - background-image: linear-gradient(to bottom, rgb(146, 170, 90), rgb(146, 154, 73)); - border: 1px solid rgb(177, 224, 83); - /* border-left: 1px; - border-right: 1px; - border-top: 1px; */ - border-bottom: 3px solid rgb(177, 224, 83); - /* border-radius: 5px 5px 0 0; */ - color: #ffffff; - text-align: center; - border-spacing: 0; -} - -table tr:first-child>th:first-child { - border-radius: 5px 0 0 0; - text-align: left; - padding-left: 2%; -} - -table tr:first-child>th:last-child { - border-radius: 0 5px 0 0; -} - -table tr:nth-child(n+2)>td { - /* opacity: 0.8; */ - background-color: rgb(228, 245, 212); - text-align: center; - padding: 0; - color: rgb(100, 100, 100); - border-radius: 2px; -} - -table tr:nth-child(n+2)>td:first-child { - text-align: left; - padding-left: 2%; -} - -table tr:last-child>td:first-child { - border-radius: 0 0 0 5px; -} - -table tr:last-child>td:last-child { - border-radius: 0 0 5px 0; -} - -table tr:nth-child(n+2) { - opacity: 0.8; -} - -table tr:nth-child(n+2):hover { - opacity: 1; -} \ No newline at end of file +:root { + color-scheme: light dark; + --canvas: #f2f0e7; + --surface: #fffdf6; + --ink: #0b2948; + --muted: #455966; + --line: #bbc6c5; + --header: #082642; + --header-ink: #fffaf0; + --coral: #9e2f22; + --blue: #075b91; + --lime: #a4c51c; + --sand: #e8dfc5; + --focus: #d42d1d; + font-family: + "Segoe UI", + ui-sans-serif, + system-ui, + -apple-system, + BlinkMacSystemFont, + sans-serif; +} + +* { + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; +} + +body { + min-width: 20rem; + margin: 0; + color: var(--ink); + background: var(--canvas); + line-height: 1.65; +} + +a { + color: inherit; + text-underline-offset: 0.2em; +} + +a:focus-visible, +[tabindex="0"]:focus-visible { + outline: 0.2rem solid var(--focus); + outline-offset: 0.25rem; +} + +.skip-link { + position: fixed; + z-index: 10; + inset-block-start: 0.75rem; + inset-inline-start: 0.75rem; + padding: 0.7rem 1rem; + color: #fff; + background: #0b2948; + border-radius: 0.35rem; + transform: translateY(-200%); +} + +.skip-link:focus { + transform: translateY(0); +} + +.sport-header { + position: relative; + overflow: hidden; + color: var(--header-ink); + background: + linear-gradient( + 90deg, + var(--header) 0 52%, + rgb(8 38 66 / 78%) 78%, + var(--header) + ), + url("../images/flywheel.jpg") center right / min(50rem, 62vw) auto no-repeat, + var(--header); +} + +.topline, +.masthead, +.sport-nav, +.page-shell, +.sport-footer { + width: min(100% - 2rem, 72rem); + margin-inline: auto; +} + +.topline { + position: relative; + z-index: 1; + display: flex; + align-items: center; + justify-content: space-between; + min-height: 4.5rem; + color: #dce9f3; + font-size: 0.82rem; + border-block-end: 0.0625rem solid rgb(255 255 255 / 24%); +} + +.topline a { + display: inline-flex; + gap: 0.5rem; + align-items: center; + font-weight: 750; + text-decoration: none; +} + +.topline a span { + color: #ff796b; + font-size: 1.2rem; +} + +.topline p { + margin: 0; + letter-spacing: 0.06em; + text-transform: uppercase; +} + +.masthead { + position: relative; + z-index: 1; + display: grid; + grid-template-columns: minmax(0, 1fr) 12rem; + gap: 2rem; + align-items: center; + min-height: 31rem; + padding-block: 4rem; +} + +.eyebrow, +.section-heading > p, +.timeline-year { + margin: 0; + color: var(--blue); + font-size: 0.75rem; + font-weight: 850; + letter-spacing: 0.16em; + text-transform: uppercase; +} + +.sport-header .eyebrow { + color: #78c6ff; +} + +.masthead h1 { + margin: 0.75rem 0 1rem; + font-size: clamp(3.4rem, 9vw, 7.6rem); + font-weight: 900; + letter-spacing: -0.075em; + line-height: 0.82; + text-transform: uppercase; +} + +.masthead-copy { + max-width: 35rem; + margin: 0; + color: #dce9f3; + font-size: clamp(1rem, 2vw, 1.2rem); +} + +.disc-mark { + position: relative; + inline-size: 10rem; + block-size: 3.6rem; + justify-self: end; + background: var(--coral); + border: 0.35rem solid var(--header-ink); + border-radius: 50%; + box-shadow: 0 0.85rem 0 #04192d; + transform: rotate(-18deg); +} + +.disc-mark::after { + position: absolute; + inset: 0.55rem 1.15rem; + border: 0.22rem solid var(--header); + border-radius: 50%; + content: ""; +} + +.sport-nav { + position: relative; + z-index: 1; + display: flex; + gap: 0.4rem; + padding-block-end: 1.25rem; +} + +.sport-nav a { + min-width: 7rem; + padding: 0.8rem 1.25rem; + font-weight: 800; + text-align: center; + text-decoration: none; + border: 0.0625rem solid rgb(255 255 255 / 32%); + border-radius: 999px; +} + +.sport-nav a:hover { + background: rgb(255 255 255 / 10%); +} + +.sport-nav a[aria-current="page"] { + color: #0b2948; + background: #fffaf0; + border-color: #fffaf0; +} + +.page-shell { + display: grid; + grid-template-columns: minmax(14rem, 0.36fr) minmax(0, 1fr); + gap: clamp(2rem, 6vw, 5rem); + padding-block: clamp(4rem, 8vw, 7rem); +} + +.field-notes { + align-self: start; + padding: 1.5rem; + background: var(--sand); + border-block-start: 0.4rem solid var(--lime); +} + +.field-notes h2 { + margin: 0.65rem 0 1rem; + font-size: 1.65rem; + letter-spacing: -0.035em; + line-height: 1.1; +} + +.field-notes > p:not(.eyebrow) { + margin: 0; + color: var(--muted); +} + +.field-notes > p + p { + margin-block-start: 1rem; +} + +.field-notes dl { + margin: 0; +} + +.field-notes dl div { + padding-block: 1rem; + border-block-start: 0.0625rem solid rgb(11 41 72 / 22%); +} + +.field-notes dt { + color: var(--coral); + font-size: 0.72rem; + font-weight: 850; + letter-spacing: 0.12em; + text-transform: uppercase; +} + +.field-notes dd { + margin: 0.2rem 0 0; +} + +.page-content { + min-width: 0; +} + +.intro-block { + padding-block-end: clamp(3rem, 6vw, 5rem); +} + +.intro-block h2 { + max-width: 15ch; + margin: 0.75rem 0 1.25rem; + font-size: clamp(2.5rem, 6vw, 4.6rem); + letter-spacing: -0.06em; + line-height: 0.98; +} + +.intro-block p { + max-width: 48rem; +} + +.lead { + color: var(--ink); + font-size: clamp(1.1rem, 2vw, 1.35rem); +} + +.section-heading { + display: flex; + align-items: end; + justify-content: space-between; + gap: 1rem; + margin-block-end: 1.5rem; + padding-block-start: 1.5rem; + border-block-start: 0.0625rem solid var(--line); +} + +.section-heading h2 { + margin: 0; + font-size: clamp(1.6rem, 4vw, 2.5rem); + letter-spacing: -0.04em; +} + +.principle-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + padding: 0; + margin: 0; + gap: 0.75rem; + list-style: none; +} + +.principle-grid li { + min-height: 16rem; + padding: 1.25rem; + background: var(--surface); + border: 0.0625rem solid var(--line); +} + +.principle-grid span { + color: var(--coral); + font-size: 0.75rem; + font-weight: 850; +} + +.principle-grid h3 { + margin: 3.25rem 0 0.6rem; + font-size: 1.3rem; +} + +.principle-grid p { + margin: 0; + color: var(--muted); +} + +.source-note { + display: grid; + grid-template-columns: minmax(10rem, 0.35fr) minmax(0, 1fr); + gap: 1rem 2rem; + margin-block-start: 3rem; + padding: 1.5rem; + color: #fffaf0; + background: var(--header); + border-inline-start: 0.4rem solid var(--coral); +} + +.source-note h2, +.source-note p { + margin: 0; +} + +.source-note a { + color: #8fd2ff; +} + +.timeline { + padding: 0; + margin: 0; + list-style: none; +} + +.timeline li { + display: grid; + grid-template-columns: 6rem minmax(0, 1fr); + gap: 1.5rem; + padding-block: 1.75rem; + border-block-start: 0.0625rem solid var(--line); +} + +.timeline-year { + color: var(--coral); +} + +.timeline h3, +.timeline p { + margin: 0; +} + +.timeline h3 { + font-size: 1.3rem; +} + +.timeline div p { + margin-block-start: 0.35rem; + color: var(--muted); +} + +.sources { + margin-block-start: 3rem; + padding: 1.5rem; + background: var(--surface); + border: 0.0625rem solid var(--line); +} + +.sources h2 { + margin: 0; + font-size: 1.2rem; +} + +.sources ul { + margin-block-end: 0; +} + +.table-scroll { + max-width: 100%; + overflow-x: auto; + border: 0.0625rem solid var(--line); +} + +table { + width: 100%; + min-width: 43rem; + border-collapse: collapse; + background: var(--surface); +} + +caption { + padding: 1rem; + font-weight: 800; + text-align: start; + background: var(--sand); +} + +th, +td { + padding: 1rem; + text-align: start; + border-block-start: 0.0625rem solid var(--line); +} + +thead th { + color: var(--header-ink); + font-size: 0.76rem; + letter-spacing: 0.08em; + text-transform: uppercase; + background: var(--header); +} + +tbody th { + color: var(--ink); +} + +tbody tr:nth-child(even) { + background: color-mix(in srgb, var(--sand) 55%, transparent); +} + +.status { + display: inline-block; + padding: 0.25rem 0.55rem; + color: var(--ink); + font-size: 0.75rem; + font-weight: 800; + border: 0.0625rem solid var(--line); + border-radius: 999px; +} + +.status--open { + color: #164e38; + background: #d8f3e5; + border-color: #83c6a9; +} + +.sport-footer { + display: flex; + justify-content: space-between; + gap: 1rem; + padding-block: 2rem; + color: var(--muted); + font-size: 0.85rem; + border-block-start: 0.0625rem solid var(--line); +} + +.sport-footer p { + margin: 0; +} + +@media (max-width: 52rem) { + .masthead { + grid-template-columns: 1fr; + min-height: 28rem; + } + + .disc-mark { + position: absolute; + inset-block-end: 4rem; + inset-inline-end: 1rem; + opacity: 0.55; + } + + .page-shell { + grid-template-columns: 1fr; + } + + .field-notes { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.5rem 2rem; + } + + .field-notes .eyebrow, + .field-notes h2 { + grid-column: 1 / -1; + } + + .field-notes dl { + display: grid; + grid-column: 1 / -1; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0 2rem; + } + + .principle-grid { + grid-template-columns: 1fr; + } + + .principle-grid li { + min-height: 0; + } + + .principle-grid h3 { + margin-block-start: 1.5rem; + } +} + +@media (max-width: 36rem) { + .topline, + .sport-footer, + .section-heading { + align-items: flex-start; + flex-direction: column; + } + + .sport-nav { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + + .sport-nav a { + min-width: 0; + padding-inline: 0.6rem; + } + + .masthead h1 { + font-size: clamp(3rem, 18vw, 5rem); + } + + .field-notes, + .field-notes dl, + .source-note { + grid-template-columns: 1fr; + } + + .timeline li { + grid-template-columns: 1fr; + gap: 0.35rem; + } +} + +@media (prefers-color-scheme: dark) { + :root { + --canvas: #071827; + --surface: #102b40; + --ink: #fff9ec; + --muted: #b5c8d3; + --line: #38566b; + --header: #041928; + --header-ink: #fff9ec; + --coral: #ff7868; + --blue: #67c1ff; + --lime: #c1dd4d; + --sand: #213a43; + --focus: #ffa79e; + } + + .field-notes dl div { + border-color: rgb(255 255 255 / 20%); + } + + tbody tr:nth-child(even) { + background: #18374d; + } + + .status--open { + color: #e2fff2; + background: #174d3c; + border-color: #4b9d7c; + } +} + +@media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } +} + +@media (forced-colors: active) { + .disc-mark, + .status, + .sport-nav a { + border: 0.125rem solid CanvasText; + } +} diff --git a/assignment-1 2/history.html b/assignment-1 2/history.html index 7d10e10..cb44e7a 100644 --- a/assignment-1 2/history.html +++ b/assignment-1 2/history.html @@ -1,48 +1,157 @@ - + + + + + + + + + + + + + History · Ultimate Field Notes + + + + + - - - Ultimate Frisbee - History - - - - - -
-

Ulimate Frisbee History

- -
-
- -
+
+
+

SELECTED MILESTONES

+

From a school parking lot to worldwide play

+

+ This short timeline highlights widely documented milestones rather + than attempting to catalogue every league, division, and event. +

+
-

Background

-

Ultimate Frisbee/Ultimate has been around in some fashion since the 1960s. Joel Silver is credited with introducing the game to his high school in 1968 after learning about the game at summer camp. The game spread to more college campuses - soon afterward.

-

The Ultimate Players Association was founded in 1979 and began organizing touraments across the country. In 2010, UPA because the USA Ultimate.

-

Other than professional tournaments, games of Ultimate are typically played without referess. Instead, players rely on "The Spirit of the Game" to encourage sportsmanship and self-officiating.

-

Sources

+
    +
  1. +

    1968

    +
    +

    The game takes shape

    +

    + Students at Columbia High School in Maplewood, New Jersey, + establish the sport that becomes ultimate. +

    +
    +
  2. +
  3. +

    1979

    +
    +

    A national organization forms

    +

    + The Ultimate Players Association is founded, creating a + structure for organized competition in the United States. +

    +
    +
  4. +
  5. +

    1985

    +
    +

    International coordination grows

    +

    + The World Flying Disc Federation is founded to support flying + disc sports across national borders. +

    +
    +
  6. +
  7. +

    Today

    +
    +

    Many formats, one shared spirit

    +

    + Communities play on grass, sand, and indoor surfaces while + adapting field size and player counts to their setting. +

    +
    +
  8. +
- +
+

Primary references

+
+
- - \ No newline at end of file + + + diff --git a/assignment-1 2/images/flywheel.jpg b/assignment-1 2/images/flywheel.jpg index 65fe5c2..081fa46 100644 Binary files a/assignment-1 2/images/flywheel.jpg and b/assignment-1 2/images/flywheel.jpg differ diff --git a/assignment-1 2/index.html b/assignment-1 2/index.html index 529ad2f..808a3cd 100644 --- a/assignment-1 2/index.html +++ b/assignment-1 2/index.html @@ -1,44 +1,153 @@ - + + + + + + + + + + + + + Home · Ultimate Field Notes + + + + + - - - Ultimate Frisbee - Home - - - - - -
-

Ulimate Frisbee

- +
+
+ + + Front-end Lab + +

Responsive layout exercise · 02

+
+ +
+
+

MOVE · PASS · RESPECT

+

Ultimate
Field Notes

+

+ A compact guide to a fast game built on movement, trust, and shared + responsibility. +

+
+ +
+ +
-
- -
-

Watch your Head

-

Ultimate Frisbee is a sport that I never played myself, but it's popularity is something hard to ignore in many Midwestern college towns. Students (and people who wish they were still students) spend the few briefs months of good weather, - sprinting down fields, hurling frisbees, and yelling "Stack!!".

-

What I find much more entertaining is the large number of people who continue to play when the weather gets windy and the night sky darkens around oh....4:15pm. The sight of frisbees boomeranging in the wind is topped only by the knowledge - that even when you can't seem, those same plastic discs of death are probably hurtling through the dark night sky at 8 or 9 o'clock in the evening. -

-

Ultimate Frisbee requires a great deal of stamina and dexterity. Not surprisingly, the IOC officially recognized Ultimate as a sport in 2015. It can go up against other sports for inclusion - in Olympic games.

+ +
+ + +
+
+

THE ESSENTIALS

+

A game built on movement and trust

+

+ Ultimate combines the spacing of field sports with the flight of a + disc. A point develops through cuts, pivots, and passes rather than + running while holding the disc. +

+

+ Possession changes after an incomplete pass, interception, or + out-of-bounds throw. That quick transition rewards awareness as much + as speed. +

+
+ +
+
+

HOW PLAY FLOWS

+

Three useful principles

+
+
    +
  1. + +

    Create space

    +

    + Cut into open lanes, then clear them so the next teammate has + room to move. +

    +
  2. +
  3. + +

    Move the disc

    +

    + Reset passes and patient pivots can be more valuable than a + hopeful long throw. +

    +
  4. +
  5. + +

    Own the call

    +

    + Players share responsibility for rules knowledge, fair calls, + and respectful resolution. +

    +
  6. +
+
+ +
+

Keep learning

+

+ This page is an educational summary, not an official rulebook. + Review the current + + USA Ultimate rules + + before organizing competition. +

+
- - \ No newline at end of file + + + diff --git a/assignment-1 2/teams.html b/assignment-1 2/teams.html index 0625fd0..0e45936 100644 --- a/assignment-1 2/teams.html +++ b/assignment-1 2/teams.html @@ -1,95 +1,149 @@ - + + + + + + + + + + + + + Teams · Ultimate Field Notes + + + + + - - - Ultimate Frisbee - Teams - - - +
+
+ + + Front-end Lab + +

Responsive layout exercise · 02

+
- -
-

Ulimate Frisbee Teams

- +
+
+

MOVE · PASS · RESPECT

+

Ultimate
Field Notes

+

+ A compact guide to a fast game built on movement, trust, and shared + responsibility. +

+
+ +
+ +
-
- -
-

College Teams

-

This is not meant to be a comprehensive list of all the teams, just a sampling from around the United States. I focused on the ones that I though had cools names.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Team NameLocationLeague Type
Afterburn - Air ForceColoradoMen's
Cold Front (Bates College)MaineWomen's
Disco Inferno (Brown University)Rhode IslandWomen's
Bad Habit (Catholic University)Washington DCMen's
Jive Turkeys (Dickinson College)PennsylvaniaBoth
Knights of the Round Disc(Longwood College)VirginiaMen's
Ninjas (University of Minnesota)MinnesotaWomen's
Flying Squirrels (Hendrix College)ArizonaMen's
Superfly (Yale)ConnecticutMen's
Flywheel (University of MichiganMichiganWomen's
+
+

Starting a real session?

+

+ Agree on the rules, field boundaries, safety expectations, and + Spirit of the Game before the first pull. +

+
- - \ No newline at end of file + + + diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..a325237 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,39 @@ +import js from "@eslint/js"; +import globals from "globals"; + +export default [ + { + ignores: [ + "_site/**", + "node_modules/**", + "playwright-report/**", + "test-results/**", + ], + }, + js.configs.recommended, + { + files: ["styles-conference/assets/scripts/**/*.js"], + languageOptions: { + ecmaVersion: "latest", + globals: globals.browser, + sourceType: "script", + }, + }, + { + files: ["**/*.mjs"], + languageOptions: { + ecmaVersion: "latest", + globals: globals.node, + sourceType: "module", + }, + }, + { + files: ["test/e2e/**/*.mjs"], + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + }, + }, + }, +]; diff --git a/index.html b/index.html new file mode 100644 index 0000000..523b676 --- /dev/null +++ b/index.html @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + HTML Sample · 静态前端实验室 + + + + + + + + +
+
+

选择一个练习

+

Three small sites, three different lessons.

+
+ +
+
+ +

SEMANTIC HTML

+

Learning Profile

+

+ 使用标题层级、列表、进度条和折叠详情,构建一个清晰且可访问的个人学习档案。 +

+
    +
  • Semantics
  • +
  • Progress
  • +
  • Details
  • +
+ + 打开单页练习 + + +
+ +
+ +

RESPONSIVE LAYOUT

+

Ultimate Field Notes

+

+ 一个三页运动主题站点,展示响应式导航、信息卡片、时间线和无障碍数据表格。 +

+
    +
  • Grid
  • +
  • Tables
  • +
  • Navigation
  • +
+ + 打开飞盘站点 + + +
+ +
+ +

MULTI-PAGE EXPERIENCE

+

Signal Conference

+

+ 完整的虚构会议站点,包含讲者、日程、会场及一个不会发送数据的报名演示。 +

+
    +
  • Forms
  • +
  • Content
  • +
  • Validation
  • +
+ + 打开会议站点 + + +
+
+
+ +
+

Designed as an accessible learning archive.

+

© 2026 zhaowl94 · MIT License

+
+ + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..9564668 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4755 @@ +{ + "name": "html-sample", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "html-sample", + "version": "1.0.0", + "devDependencies": { + "@axe-core/playwright": "^4.12.1", + "@eslint/js": "^10.0.1", + "@playwright/test": "^1.62.1", + "chrome-launcher": "^1.2.1", + "eslint": "^10.8.0", + "globals": "^17.8.0", + "html-validate": "^11.6.0", + "http-server": "^14.1.1", + "lighthouse": "^13.4.1", + "postcss": "^8.5.25", + "prettier": "^3.9.6", + "stylelint": "^17.14.1", + "stylelint-config-standard": "^40.0.0" + }, + "engines": { + "node": ">=24 <25" + } + }, + "node_modules/@apm-js-collab/code-transformer": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@apm-js-collab/code-transformer/-/code-transformer-0.18.1.tgz", + "integrity": "sha512-u1Hb6bHjWtkSpiprwVP6YaHC1DTN4RAU3zYkUDUe7WMnJwdyU1pwTL9dFKiSJB9IiLue/EQovmyx6xhU7FFtAQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/estree": "^1.0.8", + "astring": "^1.9.0", + "esquery": "^1.7.0", + "meriyah": "^6.1.4", + "semifies": "^1.0.0", + "source-map": "^0.6.0" + }, + "bin": { + "code-transformer": "cli.js" + } + }, + "node_modules/@apm-js-collab/code-transformer-bundler-plugins": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@apm-js-collab/code-transformer-bundler-plugins/-/code-transformer-bundler-plugins-0.7.3.tgz", + "integrity": "sha512-qNbPwuMZ8f5ZuGj/ttPeB7a6C/S1bB6tNYaEL5vNiRKydSAxa4AU0gxCWgaP4fVju+AuwhcumSFjrEcGF9Dv7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apm-js-collab/code-transformer": "^0.18.0", + "es-module-lexer": "^2.1.0", + "magic-string": "^0.30.21", + "module-details-from-path": "^1.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@apm-js-collab/tracing-hooks": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@apm-js-collab/tracing-hooks/-/tracing-hooks-0.13.0.tgz", + "integrity": "sha512-mTvWz9rnQwx1U3h0XPTHaX7bgfkpipLLTQyjlC2cdhQpQEuoLT0AGzoydeoq2NxfEVv6fWOOETcSbb2nptleyw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@apm-js-collab/code-transformer": "^0.18.0", + "debug": "^4.4.1", + "module-details-from-path": "^1.0.4" + } + }, + "node_modules/@axe-core/playwright": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@axe-core/playwright/-/playwright-4.12.1.tgz", + "integrity": "sha512-rMd7xriptqKpP+w5265i4Hdkv2X5kbu6uiBi/B2I7uf3hieRBM3qDCfaKPtxfiYb2mKXfF+yLODJwIx+Jv1GDw==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "axe-core": "~4.12.1" + }, + "peerDependencies": { + "playwright-core": ">= 1.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@cacheable/memory": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.2.0.tgz", + "integrity": "sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cacheable/utils": "^2.5.0", + "@keyv/bigmap": "^1.3.1", + "hookified": "^1.15.1", + "keyv": "^5.6.0" + } + }, + "node_modules/@cacheable/memory/node_modules/@keyv/bigmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz", + "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hashery": "^1.4.0", + "hookified": "^1.15.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "keyv": "^5.6.0" + } + }, + "node_modules/@cacheable/memory/node_modules/keyv": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@keyv/serialize": "^1.1.1" + } + }, + "node_modules/@cacheable/utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.5.0.tgz", + "integrity": "sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hashery": "^1.5.1", + "keyv": "^5.6.0" + } + }, + "node_modules/@cacheable/utils/node_modules/keyv": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@keyv/serialize": "^1.1.1" + } + }, + "node_modules/@csstools/css-calc": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.3.0.tgz", + "integrity": "sha512-c5ihYsPkdG6JCkU2zTMm4+k6r7RXuGxtWYhu5DHMIiF1FHzrfmHL5so11AoFpUv/tu61xfcmT4AmKoFfMPoqdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.7.tgz", + "integrity": "sha512-fQ+05118eQS1cofO3aJpB5efgpBZMvIzwr/sbC8kDLVA5XLG8q1kJV5yzrUAI1f7lvhPnm8fgIjzFB8/O/5Dig==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/media-query-list-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-5.0.0.tgz", + "integrity": "sha512-T9lXmZOfnam3eMERPsszjY5NK0jX8RmThmmm99FZ8b7z8yMaFZWKwLWGZuTwdO3ddRY5fy13GmmEYZXB4I98Eg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/selector-resolve-nested": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-4.0.1.tgz", + "integrity": "sha512-j3vdQu0XwLME5qOTWxm8cnmvsf423R2YL6DbKklCHZwkDm7UdKNu6RPlw4REIJhSlKBICY3B70/7QZdicLqZgg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.1.1" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-6.0.0.tgz", + "integrity": "sha512-4sSgl78OtOXEX/2d++8A83zHNTgwCJMaR24FvsYL7Uf/VS8HZk9PTwR51elTbGqMuwH3szLvvOXEaVnqn0Z3zA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.1.1" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz", + "integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", + "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.6.tgz", + "integrity": "sha512-HJnTFeRM2kVFVr5gr5kH1XP6K0JcJtE7Lzvtr3FS/so5f1kpsqqqxy5JF+FRaO6H2qmcMfAUIox7AJteieRtVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@formatjs/fast-memoize": "2.2.7", + "@formatjs/intl-localematcher": "0.6.2", + "decimal.js": "^10.4.3", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.7.tgz", + "integrity": "sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.11.4.tgz", + "integrity": "sha512-7kR78cRrPNB4fjGFZg3Rmj5aah8rQj9KPzuLsmcSn4ipLXQvC04keycTI1F7kJYDwIXtT2+7IDEto842CfZBtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.6", + "@formatjs/icu-skeleton-parser": "1.8.16", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.16.tgz", + "integrity": "sha512-H13E9Xl+PxBd8D5/6TVUluSpxGNvFSlN/b3coUp0e0JpuWXXnQDiavIpY3NnvSp4xhEMoXyyBvVfdFX8jglOHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.6", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.6.2.tgz", + "integrity": "sha512-XOMO2Hupl0wdd172Y06h6kLpBz6Dv+J4okPLl4LPtzbr8f66WbIoy4ev98EBuZ6ZK4h5ydTN6XneT4QVpD7cdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@html-validate/stylish": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@html-validate/stylish/-/stylish-6.0.0.tgz", + "integrity": "sha512-d1/lI3qIXhGVJF3+MmKEBn1dRX6U4Z+BDaOdDI3E6SXcO+OQ7hC/3mSo6BIjwQlcuV6NdDOKm6QCrzIQL1EezQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^22.16.0 || >= 24.0.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@keyv/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.220.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.220.0.tgz", + "integrity": "sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.10.0.tgz", + "integrity": "sha512-/wNZ8twnEQQA4HoHu22+vcsdru6pWPWxW+7w+FlxT6Id7PE/WIbZmVKkte+PF72e0F2dnImFeHD2syyE1Mw6MQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.220.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.220.0.tgz", + "integrity": "sha512-xQx3E2WxP1mDvKzxLxX+CTCtNLa560YJZ3087qYHerl2YmiKpv7AH+dAy7vmx+eVrZ5BwhfWUAVoKOoxCNHcpw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.220.0", + "import-in-the-middle": "^3.0.0", + "require-in-the-middle": "^8.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.10.0.tgz", + "integrity": "sha512-q6MMm2zhggzsHVNbabYwut+a6nbuQQe3URUoxaojM/8K1IBfwwPzvxIjNi2/lI1TFe+fMHMW9MWhrtDLEXEnkA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.10.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace/-/sdk-trace-2.10.0.tgz", + "integrity": "sha512-MfQGq3GRmTh5fM/y+OjaO0vj6+luCB1XO2gfXCalKCfgKw0eHL++sm75DNweC6ohlp+aFvACqeE0fYayqdRaoQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.10.0", + "@opentelemetry/resources": "2.10.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.10.0.tgz", + "integrity": "sha512-GuYQQT7QD2EeO8lcZLRQzcbOyhqAzL+6WWTKTU9mSUBYBazkEDl+VrQcXQhbB08OWM9anD1aHleVadzulpOaUQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.10.0", + "@opentelemetry/resources": "2.10.0", + "@opentelemetry/sdk-trace": "2.10.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", + "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@paulirish/trace_engine": { + "version": "0.0.65", + "resolved": "https://registry.npmjs.org/@paulirish/trace_engine/-/trace_engine-0.0.65.tgz", + "integrity": "sha512-Qsm6F5C8xf6ZzQXbQc2+wcpe6sggfs/gvc/ytqSurdvYg3kyW0ECHCqE0CWBKZpqgjVfPNX9c7SCS3r2nEIRGg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "legacy-javascript": "latest", + "third-party-web": "latest" + } + }, + "node_modules/@playwright/test": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.62.1.tgz", + "integrity": "sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@sentry/conventions": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@sentry/conventions/-/conventions-0.16.0.tgz", + "integrity": "sha512-fO9PLmHdVURcSPUpWCItWAtgKiMwGdJHbovoSEyLplX5sxs2ugvI4CBPTrkkgqhObnZOD0CnWBKDzSVQYBKEyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@sentry/core": { + "version": "10.69.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.69.0.tgz", + "integrity": "sha512-+uuqVEeiDzYuAKjZLqsROKXvRTbl/QeH0gfGRtpYib1cud4rAFWRIkFmcR7Jb7JGFYwmReyQotiTj/hcDszTZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sentry/conventions": "^0.16.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/node": { + "version": "10.69.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-10.69.0.tgz", + "integrity": "sha512-xEXA1YGIiTZbrW6MWV34uS6JGQuQg2ijTI0zed+FsJb9JZKPYel/GZK8Km26vfTVb+yCXFmWZNBesKegNcVdzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@opentelemetry/api": "^1.9.1", + "@opentelemetry/instrumentation": "^0.220.0", + "@opentelemetry/sdk-trace-base": "^2.9.0", + "@sentry/conventions": "^0.16.0", + "@sentry/core": "10.69.0", + "@sentry/node-core": "10.69.0", + "@sentry/opentelemetry": "10.69.0", + "@sentry/server-utils": "10.69.0", + "import-in-the-middle": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/node-core": { + "version": "10.69.0", + "resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-10.69.0.tgz", + "integrity": "sha512-IgArHczrZJxkgxoffHscj0NxQrG6kCazgmGQnlf3j58J1ec21YaUu8Tu+7G4Lo5tCiW3teQnwlKW1ttMXSqWRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sentry/conventions": "^0.16.0", + "@sentry/core": "10.69.0", + "@sentry/opentelemetry": "10.69.0", + "import-in-the-middle": "^3.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/core": "^1.30.1 || ^2.1.0", + "@opentelemetry/exporter-trace-otlp-http": ">=0.57.0 <1", + "@opentelemetry/instrumentation": ">=0.57.1 <1", + "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@opentelemetry/core": { + "optional": true + }, + "@opentelemetry/exporter-trace-otlp-http": { + "optional": true + }, + "@opentelemetry/instrumentation": { + "optional": true + }, + "@opentelemetry/sdk-trace-base": { + "optional": true + } + } + }, + "node_modules/@sentry/opentelemetry": { + "version": "10.69.0", + "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-10.69.0.tgz", + "integrity": "sha512-3FyWV6YcEJuvLrlaKGE1dHXCI+1YO0a62w7PkwlRg8yp6K6YXkmdwu9GjqaYD+Ju4tm7uC7mHIsGFQMm0M7pqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sentry/conventions": "^0.16.0", + "@sentry/core": "10.69.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/core": "^1.30.1 || ^2.1.0", + "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0" + } + }, + "node_modules/@sentry/server-utils": { + "version": "10.69.0", + "resolved": "https://registry.npmjs.org/@sentry/server-utils/-/server-utils-10.69.0.tgz", + "integrity": "sha512-0MwHrA8+nNvMIsqf8m3cXwCBlUjr6AS7N6CZvHJtY1DkqEvQqEbD5VIrhzEyHN/KMZIgQ8XeDCQRhjnXFQGRhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apm-js-collab/code-transformer-bundler-plugins": "^0.7.3", + "@apm-js-collab/tracing-hooks": "^0.13.0", + "@sentry/conventions": "^0.16.0", + "@sentry/core": "10.69.0", + "meriyah": "^6.1.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "26.1.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.2.tgz", + "integrity": "sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "dev": true, + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/atomically": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/atomically/-/atomically-2.1.1.tgz", + "integrity": "sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "stubborn-fs": "^2.0.0", + "when-exit": "^2.1.4" + } + }, + "node_modules/axe-core": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.12.1.tgz", + "integrity": "sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.5.0.tgz", + "integrity": "sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cacheable/memory": "^2.2.0", + "@cacheable/utils": "^2.5.0", + "hookified": "^1.15.0", + "keyv": "^5.6.0", + "qified": "^0.10.1" + } + }, + "node_modules/cacheable/node_modules/keyv": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@keyv/serialize": "^1.1.1" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chrome-launcher": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-1.2.1.tgz", + "integrity": "sha512-qmFR5PLMzHyuNJHwOloHPAHhbaNglkfeV/xDtt5b7xiFFyU1I+AZZX0PYseMuhenJSSirgxELYIbswcoc+5H4A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^2.0.1" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.cjs" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/chrome-launcher/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chrome-launcher/node_modules/lighthouse-logger": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.2.tgz", + "integrity": "sha512-vWl2+u5jgOQuZR55Z1WM0XDdrJT6mzMP8zHUct7xTlWhuQs+eV0g+QL0RQdFjT54zVmbhLCP8vIVpy1wGn/gCg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.4.1", + "marky": "^1.2.2" + } + }, + "node_modules/chromium-bidi": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-17.0.2.tgz", + "integrity": "sha512-5v9GQFhTktFvotn/OFNJBmKLKRAb6n9r0bVCwf7sHgWc3/JryK0bj1nn93L3pHFrfgcsu6Be6EWsDi+1XHTGDg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "mitt": "^3.0.1", + "zod": "^3.24.1" + }, + "engines": { + "node": ">=20.19.0 <22.0.0 || >=22.12.0" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/cjs-module-lexer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", + "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/configstore": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-7.1.0.tgz", + "integrity": "sha512-N4oog6YJWbR9kGyXvS7jEykLDXIE2C0ILYqNBZBp9iwiJpoCBWYsuAdW6PPFn6w06jjnC+3JstVvWHO4cZqvRg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "atomically": "^2.0.3", + "dot-prop": "^9.0.0", + "graceful-fs": "^4.2.11", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz", + "integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csp_evaluator": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/csp_evaluator/-/csp_evaluator-1.1.8.tgz", + "integrity": "sha512-EwOnfYuNbTytvbMKsLixTrRgnjOa0WZCxGy8A9nnSYAicrdwn+T/epU/yjgymmOxlgKnvH+8wXt+7p/8ak5Feg==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/css-functions-list": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.3.3.tgz", + "integrity": "sha512-8HFEBPKhOpJPEPu70wJJetjKta86Gw9+CCyCnB3sui2qQfOvRyqBy4IKLKKAwdMpWb2lHXWk9Wb4Z6AmaUT1Pg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/devtools-protocol": { + "version": "0.0.1663043", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1663043.tgz", + "integrity": "sha512-33aOY3ZnBP1dgZsshgaL+/XlsQleiFZgyUaDtdZkEa1nbZhVY1MoDeWjk+wxg25fU924l1ZJfoGNmjjeA/5s1w==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/dot-prop": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-9.0.0.tgz", + "integrity": "sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^4.18.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/enquirer/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/enquirer/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", + "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint": { + "version": "10.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.8.0.tgz", + "integrity": "sha512-nuKKvN+oIBO0koN7Tm7dlkmnkc21mtt0QJLwAKzjLq14y6lRTdVG36MZHJ8eQHwdJMwZbQNMlPOYedMq/oVJvQ==", + "dev": true, + "license": "MIT", + "workspaces": [ + "packages/*" + ], + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.7.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.2", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", + "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "17.8.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.8.0.tgz", + "integrity": "sha512-Zz/LMDZScFmkakeL2cTHzf+PbWKdpU3uclqkZT7TjDG58j5WPt0PpA+n9uPI24fZtlw07q0OtEi84K+umsRzqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.2.2.tgz", + "integrity": "sha512-NLvV9ubZ6NDsJaOpKPy3cQeJpKi9DcWiyCiFUpJPA0YihRqiE6RWaLUmgNNPr8MgPpLZjnBjSmou7uZBRJv9wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.5", + "is-path-inside": "^4.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", + "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/globjoin": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", + "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", + "dev": true, + "license": "MIT" + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hashery": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.1.tgz", + "integrity": "sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hookified": "^1.15.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hookified": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz", + "integrity": "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-tags": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-5.1.0.tgz", + "integrity": "sha512-n6l5uca7/y5joxZ3LUePhzmBFUJ+U2YWzhMa8XUTecSeSlQiZdF5XAd/Q3/WUl0VsXgUwWi8I7CNIwdI5WN1SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-validate": { + "version": "11.6.0", + "resolved": "https://registry.npmjs.org/html-validate/-/html-validate-11.6.0.tgz", + "integrity": "sha512-VKoRiWBqV9g5M1sb3H0WimxAM6UCNTv6JbovEmNEtBWKVK/W5fKCY++EM4shkS92FypBwnGMlBymeo9Tlyiqxw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/html-validate" + } + ], + "license": "MIT", + "dependencies": { + "@html-validate/stylish": "^6.0.0", + "@sidvind/better-ajv-errors": "7.0.0", + "ajv": "^8.0.0", + "kleur": "^4.1.0", + "prompts": "^2.0.0", + "semver": "^7.0.0" + }, + "bin": { + "html-validate": "bin/html-validate.mjs" + }, + "engines": { + "node": "^22.22.0 || >= 24.8.0" + }, + "peerDependencies": { + "@jest/globals": "^29.0.3 || ^30.0.0", + "@vitest/expect": "^3.0.0 || ^4.0.1", + "jest": "^29.0.3 || ^30.0.0", + "jest-snapshot": "^29.0.3 || ^30.0.0", + "vitest": "^3.0.0 || ^4.0.1" + }, + "peerDependenciesMeta": { + "@jest/globals": { + "optional": true + }, + "@vitest/expect": { + "optional": true + }, + "jest": { + "optional": true + }, + "jest-snapshot": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/html-validate/node_modules/@sidvind/better-ajv-errors": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@sidvind/better-ajv-errors/-/better-ajv-errors-7.0.0.tgz", + "integrity": "sha512-imVsp5D3KxJ8+uUmu2dsLKnFg3qdX952v/L1gZoCa0NO2ivhQWHMpYM2KmpFrRXHWFjlqkNZ/935nxiTqXEi1A==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^22.12 || >= 24.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + } + }, + "node_modules/html-validate/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/html-validate/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-link-header": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/http-link-header/-/http-link-header-1.1.4.tgz", + "integrity": "sha512-xT3GPW6/ZbGuw4UvwHqErSCEjNUlwbQJuZn9/q5U4WEKfp2kENVCAlousG1zLxHeaQ/ffOHUNpWamvkbBW0eNw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-server": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz", + "integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "basic-auth": "^2.0.1", + "chalk": "^4.1.2", + "corser": "^2.0.1", + "he": "^1.2.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy": "^1.18.1", + "mime": "^1.6.0", + "minimist": "^1.2.6", + "opener": "^1.5.1", + "portfinder": "^1.0.28", + "secure-compare": "3.0.1", + "union": "~0.5.0", + "url-join": "^4.0.1" + }, + "bin": { + "http-server": "bin/http-server" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-ssim": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/image-ssim/-/image-ssim-0.2.0.tgz", + "integrity": "sha512-W7+sO6/yhxy83L0G7xR8YAc5Z5QFtYEXXRV6EaE8tuYBZJnA3gVgp3q7X7muhLZVodeb9UfvjSbwt9VJwjIYAg==", + "dev": true, + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-in-the-middle": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-3.3.2.tgz", + "integrity": "sha512-jTd2FfOgOWOdgjkHuk/1Ms8VKFXkPs15ymYBETw1sAOrO/dY3XeGVRWir9qBbw7pXr0T2eTFwfCZ+N02HmiNGA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "cjs-module-lexer": "^2.2.0", + "es-module-lexer": "^2.2.0", + "module-details-from-path": "^1.0.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/intl-messageformat": { + "version": "10.7.18", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.7.18.tgz", + "integrity": "sha512-m3Ofv/X/tV8Y3tHXLohcuVuhWKo7BBq62cqY15etqmLxg2DZ34AGGgQDeR+SCta2+zICb1NX83af0GJmbQ1++g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.6", + "@formatjs/fast-memoize": "2.2.7", + "@formatjs/icu-messageformat-parser": "2.11.4", + "tslib": "^2.8.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jpeg-js": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", + "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/js-library-detector": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/js-library-detector/-/js-library-detector-6.7.0.tgz", + "integrity": "sha512-c80Qupofp43y4cJ7+8TTDN/AsDwLi5oOm/plBrWI+iQt485vKXCco+yVmOwEgdo9VOdsYTuV0UlTeetVPTriXA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/legacy-javascript": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/legacy-javascript/-/legacy-javascript-0.0.1.tgz", + "integrity": "sha512-lPyntS4/aS7jpuvOlitZDFifBCb4W8L/3QU0PLbUTUj+zYah8rfVjYic88yG7ZKTxhS5h9iz7duT8oUXKszLhg==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lighthouse": { + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/lighthouse/-/lighthouse-13.4.1.tgz", + "integrity": "sha512-fDu8lt3QLK/lTqIxtp1HkzQNJ32rsFHhbadYOepcMZFLgA8oINhxutMbMv8XXnpTOvZ0TXCo4JCk1LDTWaRLnA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@paulirish/trace_engine": "0.0.65", + "@sentry/node": "^10.0.0", + "axe-core": "^4.12.1", + "chrome-launcher": "^1.2.1", + "configstore": "^7.0.0", + "csp_evaluator": "1.1.8", + "devtools-protocol": "0.0.1663043", + "enquirer": "^2.3.6", + "http-link-header": "^1.1.1", + "intl-messageformat": "^10.5.3", + "jpeg-js": "^0.4.4", + "js-library-detector": "^6.7.0", + "lighthouse-logger": "^2.0.2", + "lighthouse-stack-packs": "1.12.3", + "lodash-es": "^4.17.21", + "lookup-closest-locale": "6.2.0", + "open": "^8.4.0", + "puppeteer-core": "^25.3.0", + "robots-parser": "^3.0.1", + "speedline-core": "^1.4.3", + "third-party-web": "^0.29.2", + "tldts-icann": "^7.4.9", + "web-features": "^3.34.0", + "ws": "^7.0.0", + "yargs": "^17.3.1", + "yargs-parser": "^21.0.0" + }, + "bin": { + "chrome-debug": "core/scripts/manual-chrome-launcher.js", + "lighthouse": "cli/index.js", + "smokehouse": "cli/test/smokehouse/frontends/smokehouse-bin.js" + }, + "engines": { + "node": ">=22.19" + } + }, + "node_modules/lighthouse-stack-packs": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/lighthouse-stack-packs/-/lighthouse-stack-packs-1.12.3.tgz", + "integrity": "sha512-d8IsOpE83kbANgnM+Tp8+x6HcMpX9o2ITBiUERssgzAIFdZCQzs/f4k6D0DLQTE59enml9mbAOU52Wu35exWtg==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/lighthouse/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/lighthouse/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/lighthouse/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/lighthouse/node_modules/lighthouse-logger": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.2.tgz", + "integrity": "sha512-vWl2+u5jgOQuZR55Z1WM0XDdrJT6mzMP8zHUct7xTlWhuQs+eV0g+QL0RQdFjT54zVmbhLCP8vIVpy1wGn/gCg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.4.1", + "marky": "^1.2.2" + } + }, + "node_modules/lighthouse/node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lighthouse/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lighthouse/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lighthouse/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/lighthouse/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/lighthouse/node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/lighthouse/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lookup-closest-locale": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/lookup-closest-locale/-/lookup-closest-locale-6.2.0.tgz", + "integrity": "sha512-/c2kL+Vnp1jnV6K6RpDTHK3dgg0Tu2VVp+elEiJpjfS1UyY7AjOYHohRug6wT0OpoX2qFgNORndE9RqesfVxWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/marky": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz", + "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mathml-tag-names": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-4.0.0.tgz", + "integrity": "sha512-aa6AU2Pcx0VP/XWnh8IGL0SYSgQHDT6Ucror2j2mXeFAlN3ahaNs8EZtG1YiticMkSLj3Gt6VPFfZogt7G5iFQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/meow": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-14.1.0.tgz", + "integrity": "sha512-EDYo6VlmtnumlcBCbh1gLJ//9jvM/ndXHfVXIFrZVr6fGcwTUyCTFNTLCKuY3ffbK8L/+3Mzqnd58RojiZqHVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/meriyah": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/meriyah/-/meriyah-6.1.4.tgz", + "integrity": "sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true, + "license": "MIT" + }, + "node_modules/modern-tar": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/modern-tar/-/modern-tar-0.7.7.tgz", + "integrity": "sha512-t9VmxaqrmANnEOBhpSDI6HD192Ge48k8vmWqQQL7hSFEqHEYwZbbsu49+aKLWZeRvFs3j1pMhXOqqF4kPlvjkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/module-details-from-path": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", + "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", + "dev": true, + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "license": "(WTFPL OR MIT)", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/playwright": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.1.tgz", + "integrity": "sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.1.tgz", + "integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/portfinder": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.38.tgz", + "integrity": "sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "async": "^3.2.6", + "debug": "^4.3.6" + }, + "engines": { + "node": ">= 10.12" + } + }, + "node_modules/postcss": { + "version": "8.5.25", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", + "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.16", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-safe-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", + "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", + "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", + "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prompts/node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/puppeteer-core": { + "version": "25.4.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-25.4.0.tgz", + "integrity": "sha512-K1plkLOdeoUnGeT1OvdqF3qxl33v+Ra/uH5VyPEhXdMcpvGiEskHzxxEU3fgpccJpJLIipB/rPUsvkZRWeKqOA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "3.0.6", + "chromium-bidi": "17.0.2", + "devtools-protocol": "0.0.1653615", + "typed-query-selector": "^2.12.2", + "webdriver-bidi-protocol": "0.4.2", + "ws": "^8.21.1" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/puppeteer-core/node_modules/@puppeteer/browsers": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-3.0.6.tgz", + "integrity": "sha512-B/gKoqlFkzhvzsI6jo9K1cZz9o5ypviVv/xu8CwA4grZzyVwN+XfkT+tu8T1zrauuEXv6VhS2oGX+6NL95WcKA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "modern-tar": "^0.7.6", + "yargs": "^18.0.0" + }, + "bin": { + "browsers": "lib/main-cli.js" + }, + "engines": { + "node": ">=22.12.0" + }, + "peerDependencies": { + "proxy-agent": ">=8.0.1", + "yauzl": "^2.10.0 || ^3.4.0" + }, + "peerDependenciesMeta": { + "proxy-agent": { + "optional": true + }, + "yauzl": { + "optional": true + } + } + }, + "node_modules/puppeteer-core/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/puppeteer-core/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/puppeteer-core/node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/puppeteer-core/node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.1653615", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1653615.tgz", + "integrity": "sha512-pGVkY3T/qXxAp2nFPodwYqOevk6ncNMSmvL8QfRCx5ZWGd6Vor7AFNmyaA8Zs6uJyP1QAfjuLandCgvSix1BNA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/puppeteer-core/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/puppeteer-core/node_modules/string-width": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz", + "integrity": "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/puppeteer-core/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/puppeteer-core/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/puppeteer-core/node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/puppeteer-core/node_modules/ws": { + "version": "8.21.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.1.tgz", + "integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/puppeteer-core/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/puppeteer-core/node_modules/yargs": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.1.0.tgz", + "integrity": "sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^8.2.1", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/puppeteer-core/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/qified": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/qified/-/qified-0.10.1.tgz", + "integrity": "sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hookified": "^2.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/qified/node_modules/hookified": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-2.2.0.tgz", + "integrity": "sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==", + "dev": true, + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-in-the-middle": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-8.0.1.tgz", + "integrity": "sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "module-details-from-path": "^1.0.3" + }, + "engines": { + "node": ">=9.3.0 || >=8.10.0 <9.0.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/robots-parser": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/robots-parser/-/robots-parser-3.0.1.tgz", + "integrity": "sha512-s+pyvQeIKIZ0dx5iJiQk1tPLJAWln39+MI5jtM8wnyws+G5azk+dMnMX0qfbqNetKKNgcWWOdi0sfm+FbQbgdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==", + "dev": true, + "license": "MIT" + }, + "node_modules/semifies": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semifies/-/semifies-1.0.0.tgz", + "integrity": "sha512-xXR3KGeoxTNWPD4aBvL5NUpMTT7WMANr3EWnaS190QVkY52lqqcVRD7Q05UVbBhiWDGWMlJEUam9m7uFFGVScw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/speedline-core": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/speedline-core/-/speedline-core-1.4.3.tgz", + "integrity": "sha512-DI7/OuAUD+GMpR6dmu8lliO2Wg5zfeh+/xsdyJZCzd8o5JgFUjCeLsBDuZjIQJdwXS3J0L/uZYrELKYqx+PXog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "image-ssim": "^0.2.0", + "jpeg-js": "^0.4.1" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/stubborn-fs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/stubborn-fs/-/stubborn-fs-2.0.0.tgz", + "integrity": "sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "stubborn-utils": "^1.0.1" + } + }, + "node_modules/stubborn-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stubborn-utils/-/stubborn-utils-1.0.2.tgz", + "integrity": "sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg==", + "dev": true, + "license": "MIT" + }, + "node_modules/stylelint": { + "version": "17.14.1", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-17.14.1.tgz", + "integrity": "sha512-xVQwyiuxALUBNB2fBe0tmNemg9KqLtdj3T64mioFDar79B2cU8LIyz+3KL6LdiHs9NkeNfwxpKSaIVOY8f112g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^3.2.1", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-syntax-patches-for-csstree": "^1.1.6", + "@csstools/css-tokenizer": "^4.0.0", + "@csstools/media-query-list-parser": "^5.0.0", + "@csstools/selector-resolve-nested": "^4.0.0", + "@csstools/selector-specificity": "^6.0.0", + "colord": "^2.9.3", + "cosmiconfig": "^9.0.2", + "css-functions-list": "^3.3.3", + "css-tree": "^3.2.1", + "debug": "^4.4.3", + "fast-glob": "^3.3.3", + "fastest-levenshtein": "^1.0.16", + "file-entry-cache": "^11.1.5", + "global-modules": "^2.0.0", + "globby": "^16.2.1", + "globjoin": "^0.1.4", + "html-tags": "^5.1.0", + "ignore": "^7.0.5", + "import-meta-resolve": "^4.2.0", + "mathml-tag-names": "^4.0.0", + "meow": "^14.1.0", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.5.16", + "postcss-safe-parser": "^7.0.1", + "postcss-selector-parser": "^7.1.4", + "postcss-value-parser": "^4.2.0", + "string-width": "^8.2.1", + "supports-hyperlinks": "^4.5.0", + "svg-tags": "^1.0.0", + "table": "^6.9.0", + "write-file-atomic": "^7.0.1" + }, + "bin": { + "stylelint": "bin/stylelint.mjs" + }, + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/stylelint-config-recommended": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-18.0.0.tgz", + "integrity": "sha512-mxgT2XY6YZ3HWWe3Di8umG6aBmWmHTblTgu/f10rqFXnyWxjKWwNdjSWkgkwCtxIKnqjSJzvFmPT5yabVIRxZg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "stylelint": "^17.0.0" + } + }, + "node_modules/stylelint-config-standard": { + "version": "40.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-40.0.0.tgz", + "integrity": "sha512-EznGJxOUhtWck2r6dJpbgAdPATIzvpLdK9+i5qPd4Lx70es66TkBPljSg4wN3Qnc6c4h2n+WbUrUynQ3fanjHw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", + "dependencies": { + "stylelint-config-recommended": "^18.0.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "stylelint": "^17.0.0" + } + }, + "node_modules/stylelint/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/stylelint/node_modules/file-entry-cache": { + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.5.tgz", + "integrity": "sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^6.1.23" + } + }, + "node_modules/stylelint/node_modules/flat-cache": { + "version": "6.1.23", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.23.tgz", + "integrity": "sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cacheable": "^2.5.0", + "flatted": "^3.4.2", + "hookified": "^1.15.0" + } + }, + "node_modules/stylelint/node_modules/ignore": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", + "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/stylelint/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/stylelint/node_modules/string-width": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz", + "integrity": "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylelint/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/stylelint/node_modules/write-file-atomic": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-7.0.1.tgz", + "integrity": "sha512-OTIk8iR8/aCRWBqvxrzxR0hgxWpnYBblY1S5hDWBQfk/VFmJwzmJgQFN3WsoUKHISv2eAwe+PpbUzyL1CKTLXg==", + "dev": true, + "license": "ISC", + "dependencies": { + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-4.5.0.tgz", + "integrity": "sha512-ZW2OvfeCXrNTbLakPUzjQG922EeGCOteFSVoek5DKStTh898wf7zgtuFlzQN8HfZCxC3Eh02yJVrRW51hADf+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^5.0.1", + "supports-color": "^10.2.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + } + }, + "node_modules/supports-hyperlinks/node_modules/has-flag": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-5.0.1.tgz", + "integrity": "sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-hyperlinks/node_modules/supports-color": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", + "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", + "dev": true + }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/table/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/third-party-web": { + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/third-party-web/-/third-party-web-0.29.2.tgz", + "integrity": "sha512-fegtha91tq2DHphyoiBXVHjVi2YG9zFaRnboT9C28tO1en9Y3wJsfspuy40F+u5wl3hHVbw7cnd1b67kEGHb8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/tldts-core": { + "version": "7.4.10", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.10.tgz", + "integrity": "sha512-KnQjp53ZekKgm/r3l+u8kJGGzYgrWdP8+Mql7a4vijh2WE0IrZWspQj/TpTxDho/YxO+AnOZnIjQcCD+q6iJsw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tldts-icann": { + "version": "7.4.10", + "resolved": "https://registry.npmjs.org/tldts-icann/-/tldts-icann-7.4.10.tgz", + "integrity": "sha512-JrzJnTNDURpnyPCf/b0bq/mAiQhPcNwkwpfO67M0nECzVzSIuCFN+EYjqnEjnmO60nPRabS3zIFChbwPp/Q+Lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.4.10" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-query-selector": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.2.tgz", + "integrity": "sha512-EOPFbyIub4ngnEdqi2yOcNeDLaX/0jcE1JoAXQDDMIthap7FoN795lc/SHfIq2d416VufXpM8z/lD+WRm2gfOQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", + "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dev": true, + "dependencies": { + "qs": "^6.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true, + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/web-features": { + "version": "3.34.2", + "resolved": "https://registry.npmjs.org/web-features/-/web-features-3.34.2.tgz", + "integrity": "sha512-1/prthzNwl/ITxBgFuKUCJ1ezWxZDM8rhz/VIBCD6zMEv5STMDQxgf05IfYxmJvFBTTLONaTDUk7umPkhUHmpw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/webdriver-bidi-protocol": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.2.tgz", + "integrity": "sha512-VSV+fzfChirL3e7jay2yUC7B4HQCGtEWEg/MSSQbK+qWbqeGlRLlXTzPpYr3XGUvbpDHumWZBJxgesg4N7dbtA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/when-exit": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/when-exit/-/when-exit-2.1.5.tgz", + "integrity": "sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg==", + "dev": true, + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ws": { + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", + "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..fde3e21 --- /dev/null +++ b/package.json @@ -0,0 +1,46 @@ +{ + "name": "html-sample", + "version": "1.0.0", + "private": true, + "description": "Framework-free, accessible HTML and CSS learning examples.", + "type": "module", + "engines": { + "node": ">=24 <25" + }, + "scripts": { + "serve": "http-server . -p 4173 -c-1", + "build": "node scripts/build-site.mjs", + "format": "prettier --write .", + "format:check": "prettier --check .", + "lint:html": "html-validate \"index.html\" \"Html5-Final-Project.html\" \"assignment-1 2/*.html\" \"styles-conference/*.html\"", + "lint:css": "stylelint \"assets/stylesheets/*.css\" \"assignment-1 2/css/hw1.css\" \"styles-conference/assets/stylesheets/*.css\"", + "lint:js": "eslint \"styles-conference/assets/scripts/**/*.js\" \"scripts/**/*.mjs\" \"test/**/*.mjs\" \"playwright.config.mjs\" \"eslint.config.mjs\" \"prettier.config.mjs\" \"stylelint.config.mjs\"", + "lint": "npm run lint:html && npm run lint:css && npm run lint:js", + "check:static": "node test/scripts/check-static.mjs", + "check:external-links": "node test/scripts/check-external-links.mjs", + "check": "npm run format:check && npm run lint && npm run check:static", + "test:unit": "node --test --test-isolation=none test/unit/registration.test.mjs test/unit/static-checker.test.mjs", + "test:e2e": "playwright test --project=chromium --project=firefox --project=webkit --project=mobile-chromium --project=chrome --project=msedge", + "test:e2e:linux": "playwright test --project=chromium --project=firefox --project=webkit --project=mobile-chromium --project=visual", + "test:e2e:windows": "playwright test --project=chrome --project=msedge --project=firefox --project=mobile-chromium --workers=2", + "test:visual:update": "playwright test test/e2e/visual.spec.mjs --project=visual --update-snapshots", + "test:lighthouse": "node scripts/run-lighthouse.mjs", + "test": "npm run check && npm run test:unit && npm run test:e2e", + "test:full": "npm run check && npm run test:unit && npm run test:e2e && npm run test:lighthouse" + }, + "devDependencies": { + "@axe-core/playwright": "^4.12.1", + "@eslint/js": "^10.0.1", + "@playwright/test": "^1.62.1", + "chrome-launcher": "^1.2.1", + "eslint": "^10.8.0", + "globals": "^17.8.0", + "html-validate": "^11.6.0", + "http-server": "^14.1.1", + "lighthouse": "^13.4.1", + "postcss": "^8.5.25", + "prettier": "^3.9.6", + "stylelint": "^17.14.1", + "stylelint-config-standard": "^40.0.0" + } +} diff --git a/playwright.config.mjs b/playwright.config.mjs new file mode 100644 index 0000000..31286de --- /dev/null +++ b/playwright.config.mjs @@ -0,0 +1,92 @@ +import { defineConfig, devices } from "@playwright/test"; + +const standardProject = { + testIgnore: [ + /file-compat\.spec\.mjs/, + /visual\.spec\.mjs/, + /windows-edge\.spec\.mjs/, + ], +}; + +const chromiumProject = { + testIgnore: [/visual\.spec\.mjs/, /windows-edge\.spec\.mjs/], +}; + +export default defineConfig({ + expect: { + timeout: 5_000, + toHaveScreenshot: { + animations: "disabled", + maxDiffPixelRatio: 0.01, + }, + }, + fullyParallel: true, + outputDir: "test-results/playwright", + reporter: [ + ["list"], + [ + "html", + { + open: "never", + outputFolder: "test-results/playwright-report", + }, + ], + ], + retries: 0, + snapshotPathTemplate: "{testDir}/../snapshots/{arg}{ext}", + testDir: "test/e2e", + timeout: 30_000, + use: { + baseURL: "http://127.0.0.1:4173", + colorScheme: "light", + screenshot: "only-on-failure", + trace: "retain-on-failure", + video: "retain-on-failure", + }, + webServer: { + command: "npm run serve", + reuseExistingServer: true, + timeout: 30_000, + url: "http://127.0.0.1:4173", + }, + projects: [ + { + name: "chromium", + ...chromiumProject, + use: { ...devices["Desktop Chrome"] }, + }, + { + name: "firefox", + ...standardProject, + use: { ...devices["Desktop Firefox"] }, + }, + { + name: "webkit", + ...standardProject, + use: { ...devices["Desktop Safari"] }, + }, + { + name: "mobile-chromium", + ...standardProject, + use: { ...devices["Pixel 7"] }, + }, + { + name: "chrome", + ...standardProject, + use: { ...devices["Desktop Chrome"], channel: "chrome" }, + }, + { + name: "msedge", + testIgnore: /visual\.spec\.mjs/, + use: { ...devices["Desktop Edge"], channel: "msedge" }, + }, + { + name: "visual", + testMatch: /visual\.spec\.mjs/, + use: { + ...devices["Desktop Chrome"], + viewport: { height: 1_000, width: 1_440 }, + }, + }, + ], +}); diff --git a/prettier.config.mjs b/prettier.config.mjs new file mode 100644 index 0000000..91e36d5 --- /dev/null +++ b/prettier.config.mjs @@ -0,0 +1,7 @@ +export default { + printWidth: 80, + proseWrap: "preserve", + singleQuote: false, + tabWidth: 2, + trailingComma: "all", +}; diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..35ee5e4 --- /dev/null +++ b/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Allow: / + +Sitemap: https://zhaowl94.github.io/html_sample/sitemap.xml diff --git a/scripts/build-site.mjs b/scripts/build-site.mjs new file mode 100644 index 0000000..2e21ddc --- /dev/null +++ b/scripts/build-site.mjs @@ -0,0 +1,38 @@ +import { cp, mkdir, rm, writeFile } from "node:fs/promises"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const projectRoot = path.resolve(fileURLToPath(new URL("..", import.meta.url))); +const outputDirectory = path.join(projectRoot, "_site"); + +if ( + path.dirname(outputDirectory) !== projectRoot || + path.basename(outputDirectory) !== "_site" +) { + throw new Error(`Refusing to clean unexpected path: ${outputDirectory}`); +} + +const publishEntries = [ + "index.html", + "Html5-Final-Project.html", + "assets", + "assignment-1 2", + "styles-conference", + "robots.txt", + "sitemap.xml", +]; + +await rm(outputDirectory, { force: true, recursive: true }); +await mkdir(outputDirectory, { recursive: true }); + +for (const entry of publishEntries) { + await cp(path.join(projectRoot, entry), path.join(outputDirectory, entry), { + recursive: true, + }); +} + +await writeFile(path.join(outputDirectory, ".nojekyll"), "", "utf8"); + +console.log( + `Built ${publishEntries.length} publish entries in ${path.relative(projectRoot, outputDirectory)}.`, +); diff --git a/scripts/run-lighthouse.mjs b/scripts/run-lighthouse.mjs new file mode 100644 index 0000000..7d14825 --- /dev/null +++ b/scripts/run-lighthouse.mjs @@ -0,0 +1,200 @@ +import { spawn } from "node:child_process"; +import { existsSync } from "node:fs"; +import { mkdir, rm, writeFile } from "node:fs/promises"; +import path from "node:path"; +import { setTimeout as delay } from "node:timers/promises"; +import { fileURLToPath } from "node:url"; +import { chromium } from "@playwright/test"; +import * as chromeLauncher from "chrome-launcher"; +import lighthouse from "lighthouse"; + +const projectRoot = path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + "..", +); +const reportDirectory = path.join(projectRoot, "test-results", "lighthouse"); +const serverScript = path.join( + projectRoot, + "node_modules", + "http-server", + "bin", + "http-server", +); +const baseUrl = "http://127.0.0.1:4173"; +const pagePaths = [ + "/index.html", + "/Html5-Final-Project.html", + "/assignment-1%202/index.html", + "/styles-conference/index.html", + "/styles-conference/register.html", +]; +const thresholds = { + accessibility: 0.95, + "best-practices": 0.95, + performance: 0.95, + seo: 0.95, +}; + +function startServer() { + return spawn( + process.execPath, + [serverScript, projectRoot, "-p", "4173", "-c-1", "--silent"], + { + cwd: projectRoot, + stdio: ["ignore", "pipe", "pipe"], + windowsHide: true, + }, + ); +} + +async function waitForServer(server) { + const deadline = Date.now() + 30_000; + + while (Date.now() < deadline) { + if (server.exitCode !== null) { + throw new Error( + `Static server exited before becoming ready (code ${server.exitCode}).`, + ); + } + + try { + const response = await fetch(`${baseUrl}/index.html`); + if (response.ok) { + return; + } + } catch { + // The server may still be binding its port. + } + + await new Promise((resolve) => { + setTimeout(resolve, 200); + }); + } + + throw new Error("Timed out while waiting for the Lighthouse test server."); +} + +function reportName(pagePath) { + if (pagePath === "/index.html") { + return "root"; + } + + return pagePath + .replace(/^\/|\.html$/gu, "") + .replaceAll("%20", "-") + .replaceAll("/", "-"); +} + +async function runAudit(url, chromePort) { + const result = await lighthouse(url, { + logLevel: "error", + onlyCategories: Object.keys(thresholds), + output: ["html", "json"], + port: chromePort, + }); + + if (!result) { + throw new Error(`Lighthouse did not return a report for ${url}.`); + } + + return result; +} + +function scoresFor(lhr) { + return Object.fromEntries( + Object.keys(thresholds).map((category) => [ + category, + lhr.categories[category]?.score ?? 0, + ]), + ); +} + +async function main() { + await mkdir(reportDirectory, { recursive: true }); + + const server = startServer(); + const chromeProfileDirectory = path.join( + reportDirectory, + `chrome-profile-${process.pid}`, + ); + let chrome; + + try { + await waitForServer(server); + await mkdir(chromeProfileDirectory, { recursive: true }); + + const bundledChromium = chromium.executablePath(); + chrome = await chromeLauncher.launch({ + chromeFlags: ["--headless=new", "--disable-gpu"], + chromePath: existsSync(bundledChromium) ? bundledChromium : undefined, + logLevel: "error", + userDataDir: chromeProfileDirectory, + }); + + const summary = {}; + const failures = []; + + for (const pagePath of pagePaths) { + const url = `${baseUrl}${pagePath}`; + const result = await runAudit(url, chrome.port); + const name = reportName(pagePath); + const [htmlReport, jsonReport] = result.report; + + await Promise.all([ + writeFile( + path.join(reportDirectory, `${name}.report.html`), + htmlReport, + ), + writeFile( + path.join(reportDirectory, `${name}.report.json`), + jsonReport, + ), + ]); + + const scores = scoresFor(result.lhr); + summary[pagePath] = scores; + + for (const [category, minimum] of Object.entries(thresholds)) { + if (scores[category] < minimum) { + failures.push( + `${pagePath}: ${category} ${scores[category].toFixed(2)} < ${minimum.toFixed(2)}`, + ); + } + } + } + + await writeFile( + path.join(reportDirectory, "summary.json"), + `${JSON.stringify(summary, null, 2)}\n`, + ); + + for (const [pagePath, scores] of Object.entries(summary)) { + const formatted = Object.entries(scores) + .map(([category, score]) => `${category}=${score.toFixed(2)}`) + .join(", "); + console.log(`${pagePath}: ${formatted}`); + } + + if (failures.length > 0) { + throw new Error(`Lighthouse budgets failed:\n${failures.join("\n")}`); + } + } finally { + chrome?.kill(); + server.kill(); + await delay(250); + try { + await rm(chromeProfileDirectory, { + force: true, + maxRetries: 10, + recursive: true, + retryDelay: 250, + }); + } catch (error) { + console.warn( + `Could not remove temporary Chrome profile: ${error.message}`, + ); + } + } +} + +await main(); diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..0c027f8 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,33 @@ + + + + https://zhaowl94.github.io/html_sample/ + + + https://zhaowl94.github.io/html_sample/Html5-Final-Project.html + + + https://zhaowl94.github.io/html_sample/assignment-1%202/index.html + + + https://zhaowl94.github.io/html_sample/assignment-1%202/teams.html + + + https://zhaowl94.github.io/html_sample/assignment-1%202/history.html + + + https://zhaowl94.github.io/html_sample/styles-conference/index.html + + + https://zhaowl94.github.io/html_sample/styles-conference/speakers.html + + + https://zhaowl94.github.io/html_sample/styles-conference/schedule.html + + + https://zhaowl94.github.io/html_sample/styles-conference/venue.html + + + https://zhaowl94.github.io/html_sample/styles-conference/register.html + + diff --git a/stylelint.config.mjs b/stylelint.config.mjs new file mode 100644 index 0000000..b82e7d1 --- /dev/null +++ b/stylelint.config.mjs @@ -0,0 +1,16 @@ +export default { + extends: ["stylelint-config-standard"], + ignoreFiles: [ + "assignment-1 2/css/Mutual evaluation.css", + "assignment-1 2/css/hw1 - old.css", + "assignment-1 2/css/hw1 - old2.css", + ], + rules: { + "custom-property-empty-line-before": null, + "declaration-empty-line-before": null, + "declaration-block-no-redundant-longhand-properties": null, + "media-feature-range-notation": "prefix", + "no-descending-specificity": null, + "selector-class-pattern": null, + }, +}; diff --git a/styles-conference/assets/scripts/register.js b/styles-conference/assets/scripts/register.js new file mode 100644 index 0000000..866de10 --- /dev/null +++ b/styles-conference/assets/scripts/register.js @@ -0,0 +1,119 @@ +(function registerDemo(global) { + "use strict"; + + const passLabels = Object.freeze({ + "three-day": "Three-day explorer", + studios: "Studio sessions", + remote: "Remote notes", + }); + + function normalizeName(value) { + return String(value).trim().replace(/\s+/g, " "); + } + + function buildConfirmation(name, passType) { + const safeName = normalizeName(name); + const passLabel = passLabels[passType] || "Demo pass"; + return `Demo complete for ${safeName}: ${passLabel}. Nothing was sent or saved.`; + } + + global.RegistrationDemo = Object.freeze({ + buildConfirmation, + normalizeName, + passLabels, + }); + + if (typeof document === "undefined") { + return; + } + + const form = document.querySelector("#registration-form"); + if (!form) { + return; + } + + const status = document.querySelector("#form-status"); + const fields = Array.from(form.querySelectorAll("input, select, textarea")); + + function getErrorElement(field) { + return document.querySelector(`#${field.id}-error`); + } + + function messageFor(field) { + if (field.type === "checkbox" && !field.checked) { + return "Confirm that you understand this is only a demo."; + } + + if (field.required && !String(field.value).trim()) { + return "Complete this required field."; + } + + if (field.id === "display-name" && normalizeName(field.value).length < 2) { + return "Enter at least two characters."; + } + + if (field.type === "email" && field.validity.typeMismatch) { + return "Enter an email in the format name@example.com."; + } + + return ""; + } + + function validateField(field) { + field.setCustomValidity(""); + const message = messageFor(field); + const error = getErrorElement(field); + + field.setCustomValidity(message); + field.setAttribute("aria-invalid", message ? "true" : "false"); + + if (error) { + error.textContent = message; + } + + return message === ""; + } + + fields.forEach((field) => { + field.addEventListener("blur", () => validateField(field)); + field.addEventListener("input", () => { + if (field.getAttribute("aria-invalid") === "true") { + validateField(field); + } + status.textContent = ""; + }); + field.addEventListener("change", () => { + if (field.getAttribute("aria-invalid") === "true") { + validateField(field); + } + status.textContent = ""; + }); + }); + + form.addEventListener("submit", (event) => { + event.preventDefault(); + + const invalidFields = fields.filter((field) => !validateField(field)); + if (invalidFields.length > 0) { + status.textContent = "Review the highlighted fields and try again."; + invalidFields[0].focus(); + return; + } + + const confirmation = buildConfirmation( + form.elements.displayName.value, + form.elements.passType.value, + ); + + form.reset(); + fields.forEach((field) => { + field.setAttribute("aria-invalid", "false"); + const error = getErrorElement(field); + if (error) { + error.textContent = ""; + } + }); + status.textContent = confirmation; + status.focus(); + }); +})(globalThis); diff --git a/styles-conference/assets/stylesheets/main.css b/styles-conference/assets/stylesheets/main.css index dd7ecdc..31276a2 100644 --- a/styles-conference/assets/stylesheets/main.css +++ b/styles-conference/assets/stylesheets/main.css @@ -1,47 +1,1067 @@ -/* http://meyerweb.com/eric/tools/css/reset/ 2. v2.0 | 20110126 - License: none (public domain) -*/ - -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} -/* HTML5 display-role reset for older browsers */ -article, aside, details, figcaption, figure, -footer, header, hgroup, menu, nav, section { - display: block; -} -body { - line-height: 1; -} -ol, ul { - list-style: none; -} -blockquote, q { - quotes: none; -} -blockquote:before, blockquote:after, -q:before, q:after { - content: ''; - content: none; -} -table { - border-collapse: collapse; - border-spacing: 0; -} +:root { + color-scheme: light dark; + --canvas: #f3eee2; + --surface: #fffaf0; + --ink: #123a32; + --muted: #5a6d67; + --line: #b8c2ba; + --forest: #123a32; + --forest-deep: #09251f; + --orange: #a93612; + --orange-soft: #f5c6b3; + --mint: #b8dfcc; + --yellow: #edc646; + --focus: #9d2d0b; + --error: #a22620; + --success: #176b4b; + font-family: + "Segoe UI", + ui-sans-serif, + system-ui, + -apple-system, + BlinkMacSystemFont, + sans-serif; +} + +* { + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; +} + +body { + min-width: 20rem; + margin: 0; + color: var(--ink); + background: var(--canvas); + line-height: 1.65; +} + +a { + color: inherit; + text-underline-offset: 0.2em; +} + +a:focus-visible, +button:focus-visible, +input:focus-visible, +select:focus-visible, +textarea:focus-visible, +[tabindex="-1"]:focus-visible { + outline: 0.2rem solid var(--focus); + outline-offset: 0.25rem; +} + +button, +input, +select, +textarea { + color: inherit; + font: inherit; +} + +.skip-link { + position: fixed; + z-index: 20; + inset-block-start: 0.75rem; + inset-inline-start: 0.75rem; + padding: 0.7rem 1rem; + color: #fff; + background: var(--forest-deep); + border-radius: 0.35rem; + transform: translateY(-200%); +} + +.skip-link:focus { + transform: translateY(0); +} + +.page-frame, +.conference-header { + width: min(100% - 2rem, 72rem); + margin-inline: auto; +} + +.conference-topbar { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 4rem; + color: var(--muted); + font-size: 0.78rem; + border-block-end: 0.0625rem solid var(--line); +} + +.conference-topbar p { + margin: 0; + letter-spacing: 0.06em; + text-transform: uppercase; +} + +.lab-link { + display: inline-flex; + gap: 0.5rem; + align-items: center; + font-weight: 800; + text-decoration: none; +} + +.lab-link span { + color: var(--orange); + font-size: 1.15rem; +} + +.brand-row { + display: flex; + align-items: end; + justify-content: space-between; + min-height: 8rem; + padding-block: 2rem; +} + +.brand { + display: inline-flex; + gap: 0.8rem; + align-items: center; + font-size: clamp(1.2rem, 3vw, 1.8rem); + font-weight: 900; + letter-spacing: -0.04em; + text-decoration: none; +} + +.brand-mark { + display: grid; + inline-size: 3rem; + block-size: 3rem; + place-items: center; + color: #fff; + font-size: 0.95rem; + letter-spacing: -0.05em; + background: var(--forest); + border-radius: 50%; +} + +.event-meta { + margin: 0; + color: var(--orange); + font-size: 0.86rem; + font-weight: 850; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.conference-nav { + display: flex; + justify-content: flex-end; + gap: 0.35rem; + padding-block: 0 1rem; + border-block-end: 0.0625rem solid var(--line); +} + +.conference-nav a { + padding: 0.6rem 0.9rem; + color: var(--muted); + font-size: 0.88rem; + font-weight: 750; + text-decoration: none; + border-radius: 999px; +} + +.conference-nav a:hover { + color: var(--ink); + background: var(--mint); +} + +.conference-nav a[aria-current="page"] { + color: #fff; + background: var(--forest); +} + +.eyebrow, +.section-heading > p, +.feature-index, +.speaker-role, +.session-type, +.detail-index { + margin: 0; + color: var(--orange); + font-size: 0.72rem; + font-weight: 850; + letter-spacing: 0.16em; + text-transform: uppercase; +} + +.conference-hero { + display: grid; + grid-template-columns: minmax(0, 1.15fr) minmax(18rem, 0.75fr); + gap: 3rem; + align-items: center; + min-height: min(45rem, 78vh); + padding-block: clamp(4rem, 9vw, 8rem); +} + +.conference-hero h1, +.page-intro h1 { + margin: 0.9rem 0 1.5rem; + font-family: Georgia, "Times New Roman", serif; + font-size: clamp(3.5rem, 9vw, 7rem); + font-weight: 500; + letter-spacing: -0.075em; + line-height: 0.93; +} + +.hero-lede, +.page-intro > p:last-child { + max-width: 42rem; + margin: 0; + color: var(--muted); + font-size: clamp(1.08rem, 2vw, 1.3rem); +} + +.button-row { + display: flex; + margin-block-start: 2rem; + flex-wrap: wrap; + gap: 0.75rem; +} + +.button { + display: inline-flex; + min-height: 3.25rem; + padding: 0.75rem 1.2rem; + align-items: center; + justify-content: center; + font-weight: 850; + text-align: center; + text-decoration: none; + border: 0.125rem solid transparent; + border-radius: 0.25rem; + cursor: pointer; +} + +.button--primary { + color: #fff; + background: var(--forest); + border-color: var(--forest); +} + +.button--primary:hover { + background: var(--forest-deep); + border-color: var(--forest-deep); +} + +.button--quiet { + color: var(--forest); + background: transparent; + border-color: var(--forest); +} + +.button--quiet:hover { + background: var(--mint); +} + +.signal-graphic { + position: relative; + display: grid; + inline-size: min(100%, 24rem); + aspect-ratio: 1; + justify-self: end; + place-items: center; + background: + linear-gradient(var(--line) 0.0625rem, transparent 0.0625rem), + linear-gradient(90deg, var(--line) 0.0625rem, transparent 0.0625rem); + background-size: 25% 25%; + border: 0.0625rem solid var(--line); +} + +.signal-graphic::before { + position: absolute; + inline-size: 58%; + block-size: 58%; + border: 1.35rem solid var(--forest); + border-radius: 50%; + content: ""; +} + +.signal-graphic span { + position: absolute; + inline-size: 1rem; + block-size: 1rem; + background: var(--orange); + border-radius: 50%; +} + +.signal-graphic span:nth-child(1) { + inset-block-start: 9%; + inset-inline-start: 18%; +} + +.signal-graphic span:nth-child(2) { + inline-size: 2rem; + block-size: 2rem; + inset-block-end: 12%; + inset-inline-end: 18%; + background: var(--yellow); +} + +.signal-graphic span:nth-child(3) { + inline-size: 4.5rem; + block-size: 4.5rem; + background: var(--orange-soft); +} + +.manifesto { + display: grid; + grid-template-columns: minmax(10rem, 0.36fr) minmax(0, 1fr); + gap: 2rem 5rem; + padding-block: clamp(4rem, 8vw, 7rem); + border-block: 0.0625rem solid var(--line); +} + +.manifesto h2 { + max-width: 18ch; + margin: 0; + font-family: Georgia, "Times New Roman", serif; + font-size: clamp(2.4rem, 5vw, 4.2rem); + font-weight: 500; + letter-spacing: -0.05em; + line-height: 1; +} + +.manifesto div p { + max-width: 46rem; + margin: 1.25rem 0 0; + color: var(--muted); + font-size: 1.08rem; +} + +.feature-section { + padding-block: clamp(4rem, 8vw, 7rem); +} + +.section-heading { + display: flex; + align-items: end; + justify-content: space-between; + gap: 2rem; + margin-block-end: 2rem; +} + +.section-heading h2 { + max-width: 22ch; + margin: 0; + font-family: Georgia, "Times New Roman", serif; + font-size: clamp(2rem, 4vw, 3.2rem); + font-weight: 500; + letter-spacing: -0.04em; + line-height: 1.05; +} + +.feature-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + border-block-start: 0.0625rem solid var(--line); + border-inline-start: 0.0625rem solid var(--line); +} + +.feature-grid article { + display: flex; + min-height: 25rem; + padding: 1.5rem; + flex-direction: column; + border-block-end: 0.0625rem solid var(--line); + border-inline-end: 0.0625rem solid var(--line); +} + +.feature-grid h3 { + margin: 4rem 0 0.8rem; + font-size: 1.45rem; + letter-spacing: -0.035em; + line-height: 1.1; +} + +.feature-grid p:not(.feature-index) { + margin: 0; + color: var(--muted); +} + +.feature-grid a { + margin-block-start: auto; + padding-block-start: 1.5rem; + color: var(--forest); + font-weight: 800; +} + +.event-strip { + color: #fff; + background: var(--forest); +} + +.event-stats { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.event-stats p { + display: flex; + min-height: 15rem; + margin: 0; + padding: 2rem; + align-items: flex-start; + justify-content: flex-end; + flex-direction: column; + border-inline-start: 0.0625rem solid rgb(255 255 255 / 25%); +} + +.event-stats p:last-child { + border-inline-end: 0.0625rem solid rgb(255 255 255 / 25%); +} + +.event-stats strong { + font-family: Georgia, "Times New Roman", serif; + font-size: clamp(3rem, 7vw, 5.5rem); + font-weight: 500; + line-height: 0.9; +} + +.event-stats span { + margin-block-start: 0.75rem; + color: #cde7db; +} + +.closing-callout { + padding-block: clamp(4rem, 9vw, 8rem); + text-align: center; +} + +.closing-callout h2 { + max-width: 23ch; + margin: 0.8rem auto 2rem; + font-family: Georgia, "Times New Roman", serif; + font-size: clamp(2.4rem, 6vw, 4.8rem); + font-weight: 500; + letter-spacing: -0.055em; + line-height: 1; +} + +.page-intro { + padding-block: clamp(4.5rem, 10vw, 8.5rem); + border-block-end: 0.0625rem solid var(--line); +} + +.page-intro h1 { + max-width: 15ch; +} + +.speaker-list { + padding-block: clamp(3rem, 7vw, 6rem); +} + +.speaker-card { + display: grid; + grid-template-columns: minmax(10rem, 0.36fr) minmax(0, 1fr); + gap: 2rem 4rem; + padding-block: clamp(2.5rem, 6vw, 5rem); + border-block-start: 0.0625rem solid var(--line); +} + +.speaker-card:first-child { + border-block-start: 0; +} + +.speaker-monogram { + display: grid; + inline-size: min(100%, 13rem); + aspect-ratio: 1; + place-items: center; + color: #fff; + font-family: Georgia, "Times New Roman", serif; + font-size: clamp(2.5rem, 6vw, 4.5rem); + background: var(--forest); + border-radius: 50%; +} + +.speaker-card:nth-child(2) .speaker-monogram { + color: var(--forest); + background: var(--yellow); + border-radius: 0; + transform: rotate(-3deg); +} + +.speaker-card:nth-child(3) .speaker-monogram { + background: var(--orange); + border-radius: 50% 50% 0; +} + +.speaker-copy h2 { + margin: 0.45rem 0 0; + font-family: Georgia, "Times New Roman", serif; + font-size: clamp(2rem, 5vw, 3.6rem); + font-weight: 500; + letter-spacing: -0.05em; +} + +.speaker-copy h3 { + max-width: 30ch; + margin: 0.65rem 0 1rem; + font-size: clamp(1.15rem, 2vw, 1.45rem); + line-height: 1.25; +} + +.speaker-copy > p:not(.speaker-role) { + max-width: 45rem; + color: var(--muted); +} + +.topic-list { + display: flex; + padding: 0; + margin: 1.5rem 0 0; + flex-wrap: wrap; + gap: 0.5rem; + list-style: none; +} + +.topic-list li { + padding: 0.35rem 0.7rem; + font-size: 0.78rem; + font-weight: 750; + border: 0.0625rem solid var(--line); + border-radius: 999px; +} + +.schedule-days { + padding-block: clamp(3rem, 7vw, 6rem); +} + +.schedule-day { + display: grid; + grid-template-columns: minmax(10rem, 0.34fr) minmax(0, 1fr); + gap: 2rem 4rem; + padding-block: clamp(2.5rem, 5vw, 4.5rem); + border-block-start: 0.0625rem solid var(--line); +} + +.schedule-day:first-child { + border-block-start: 0; +} + +.schedule-day > header p { + margin: 0; + color: var(--orange); + font-size: 0.72rem; + font-weight: 850; + letter-spacing: 0.12em; +} + +.schedule-day > header h2 { + margin: 0.5rem 0 0; + font-family: Georgia, "Times New Roman", serif; + font-size: clamp(2rem, 4vw, 3rem); + font-weight: 500; + letter-spacing: -0.04em; +} + +.schedule-day ol { + padding: 0; + margin: 0; + list-style: none; +} + +.schedule-day li { + display: grid; + grid-template-columns: 4.5rem minmax(0, 1fr); + gap: 1rem; + padding-block: 1.25rem; + border-block-start: 0.0625rem solid var(--line); +} + +.schedule-day li:first-child { + border-block-start: 0; +} + +.schedule-day time { + font-weight: 850; + font-variant-numeric: tabular-nums; +} + +.schedule-day h3, +.schedule-day li p { + margin: 0; +} + +.schedule-day h3 { + font-size: 1.15rem; +} + +.schedule-day li p:last-child { + margin-block-start: 0.25rem; + color: var(--muted); +} + +.venue-overview { + display: grid; + grid-template-columns: minmax(18rem, 0.8fr) minmax(0, 1fr); + gap: 3rem 5rem; + align-items: center; + padding-block: clamp(4rem, 8vw, 7rem); +} + +.venue-map { + position: relative; + min-height: 28rem; + overflow: hidden; + background: + linear-gradient(var(--line) 0.0625rem, transparent 0.0625rem), + linear-gradient(90deg, var(--line) 0.0625rem, transparent 0.0625rem), + var(--surface); + background-size: 4rem 4rem; + border: 0.0625rem solid var(--line); +} + +.map-water, +.map-block, +.map-route, +.map-pin { + position: absolute; + display: block; +} + +.map-water { + inline-size: 48%; + block-size: 130%; + inset-block-start: -15%; + inset-inline-end: -15%; + background: var(--mint); + transform: rotate(12deg); +} + +.map-block { + background: var(--forest); +} + +.map-block--one { + inline-size: 34%; + block-size: 22%; + inset-block-start: 18%; + inset-inline-start: 16%; +} + +.map-block--two { + inline-size: 25%; + block-size: 18%; + inset-block-end: 15%; + inset-inline-start: 32%; + background: var(--yellow); +} + +.map-route { + inline-size: 65%; + block-size: 0.45rem; + inset-block-start: 56%; + inset-inline-start: 12%; + background: var(--orange); + transform: rotate(-24deg); +} + +.map-pin { + inline-size: 2.6rem; + block-size: 2.6rem; + inset-block-start: 39%; + inset-inline-start: 42%; + background: var(--orange); + border: 0.4rem solid var(--surface); + border-radius: 50% 50% 50% 0; + transform: rotate(-45deg); +} + +.venue-copy h2 { + max-width: 16ch; + margin: 0.75rem 0 1rem; + font-family: Georgia, "Times New Roman", serif; + font-size: clamp(2.3rem, 5vw, 4rem); + font-weight: 500; + letter-spacing: -0.05em; + line-height: 1; +} + +.venue-copy > p:not(.eyebrow) { + color: var(--muted); +} + +.venue-copy address { + margin-block-start: 1.5rem; + font-style: normal; + font-weight: 800; +} + +.venue-details { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + border-block-start: 0.0625rem solid var(--line); + border-inline-start: 0.0625rem solid var(--line); +} + +.venue-details article { + min-height: 20rem; + padding: 1.5rem; + border-block-end: 0.0625rem solid var(--line); + border-inline-end: 0.0625rem solid var(--line); +} + +.venue-details h2 { + margin: 3rem 0 0.75rem; + font-size: 1.4rem; +} + +.venue-details p:not(.detail-index) { + margin: 0; + color: var(--muted); +} + +.fiction-note { + display: grid; + grid-template-columns: minmax(12rem, 0.35fr) minmax(0, 1fr); + gap: 1.5rem 4rem; + margin-block-start: 3rem; + padding-block: 2rem; + border-block: 0.0625rem solid var(--line); +} + +.fiction-note h2, +.fiction-note p { + margin: 0; +} + +.fiction-note p { + color: var(--muted); +} + +.registration-layout { + display: grid; + grid-template-columns: minmax(15rem, 0.45fr) minmax(0, 1fr); + gap: 3rem 6rem; + padding-block: clamp(4rem, 8vw, 7rem); +} + +.registration-context { + align-self: start; +} + +.registration-context h2 { + margin: 0.75rem 0 1rem; + font-family: Georgia, "Times New Roman", serif; + font-size: clamp(2rem, 4vw, 3rem); + font-weight: 500; + letter-spacing: -0.04em; + line-height: 1.05; +} + +.registration-context > p:not(.eyebrow) { + color: var(--muted); +} + +.privacy-list { + padding: 0; + margin: 2rem 0 0; + list-style: none; +} + +.privacy-list li { + padding-block: 0.7rem; + font-weight: 750; + border-block-start: 0.0625rem solid var(--line); +} + +.privacy-list li::before { + margin-inline-end: 0.6rem; + color: var(--success); + content: "✓"; +} + +#registration-form { + padding: clamp(1.5rem, 4vw, 2.5rem); + background: var(--surface); + border: 0.0625rem solid var(--line); +} + +.form-field { + margin-block-end: 1.5rem; +} + +.form-field > label { + display: block; + margin-block-end: 0.45rem; + font-weight: 800; +} + +.form-field > label span { + color: var(--muted); + font-size: 0.8rem; + font-weight: 500; +} + +input:not([type="checkbox"]), +select, +textarea { + display: block; + width: 100%; + min-height: 3rem; + padding: 0.7rem 0.8rem; + color: var(--ink); + background: var(--canvas); + border: 0.1rem solid var(--line); + border-radius: 0.2rem; +} + +textarea { + resize: vertical; +} + +input[aria-invalid="true"], +select[aria-invalid="true"], +textarea[aria-invalid="true"] { + border-color: var(--error); + box-shadow: 0 0 0 0.12rem var(--error); +} + +.field-help, +.field-error { + margin: 0.35rem 0 0; + font-size: 0.82rem; +} + +.field-help { + color: var(--muted); +} + +.field-error { + min-height: 1.35em; + color: var(--error); + font-weight: 750; +} + +.form-field--check { + display: grid; + grid-template-columns: 1.35rem minmax(0, 1fr); + gap: 0 0.7rem; + align-items: start; +} + +.form-field--check input { + inline-size: 1.2rem; + block-size: 1.2rem; + margin: 0.2rem 0 0; + accent-color: var(--forest); +} + +.form-field--check label { + margin: 0; +} + +.form-field--check .field-error { + grid-column: 2; +} + +#registration-form .button { + width: 100%; +} + +.form-status { + min-height: 3rem; + margin: 1rem 0 0; + padding: 0.75rem; + color: var(--success); + font-weight: 800; + background: color-mix(in srgb, var(--mint) 62%, transparent); + border-inline-start: 0.3rem solid var(--success); +} + +.form-status:empty { + display: none; +} + +.conference-footer { + display: flex; + align-items: end; + justify-content: space-between; + gap: 2rem; + padding-block: 2.5rem; + color: var(--muted); + font-size: 0.85rem; + border-block-start: 0.0625rem solid var(--line); +} + +.conference-footer p { + margin: 0; +} + +.footer-brand { + color: var(--ink); + font-size: 1rem; + font-weight: 850; +} + +.conference-footer nav { + display: flex; + flex-wrap: wrap; + gap: 0.6rem 1.2rem; +} + +@media (max-width: 54rem) { + .conference-hero, + .manifesto, + .speaker-card, + .schedule-day, + .venue-overview, + .registration-layout, + .fiction-note { + grid-template-columns: 1fr; + } + + .signal-graphic { + inline-size: min(100%, 20rem); + justify-self: start; + } + + .feature-grid, + .venue-details { + grid-template-columns: 1fr; + } + + .feature-grid article, + .venue-details article { + min-height: 0; + } + + .feature-grid h3, + .venue-details h2 { + margin-block-start: 2rem; + } + + .speaker-monogram { + inline-size: 9rem; + } + + .venue-map { + min-height: 22rem; + } +} + +@media (max-width: 40rem) { + .conference-topbar, + .brand-row, + .conference-footer, + .section-heading { + align-items: flex-start; + flex-direction: column; + } + + .conference-topbar { + justify-content: center; + padding-block: 0.8rem; + gap: 0.5rem; + } + + .brand-row { + justify-content: center; + min-height: 0; + } + + .conference-nav { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + + .conference-nav a { + padding-inline: 0.45rem; + text-align: center; + } + + .conference-hero h1, + .page-intro h1 { + font-size: clamp(3.1rem, 17vw, 5.2rem); + } + + .event-stats { + grid-template-columns: 1fr; + } + + .event-stats p { + min-height: 10rem; + border-inline-end: 0.0625rem solid rgb(255 255 255 / 25%); + } + + .schedule-day li { + grid-template-columns: 3.8rem minmax(0, 1fr); + } +} + +@media (prefers-color-scheme: dark) { + :root { + --canvas: #0d211d; + --surface: #173129; + --ink: #fff8e8; + --muted: #b9ccc4; + --line: #426057; + --forest: #e8f5ee; + --forest-deep: #c7e2d5; + --orange: #ff8b62; + --orange-soft: #633524; + --mint: #315e4c; + --yellow: #f3d463; + --focus: #ffb49a; + --error: #ffaaa3; + --success: #84dfb8; + } + + .brand-mark, + .conference-nav a[aria-current="page"], + .button--primary { + color: #102820; + } + + .button--quiet { + color: var(--ink); + } + + .event-strip { + color: #102820; + } + + .event-stats span { + color: #274d40; + } + + .speaker-monogram { + color: #102820; + } + + input:not([type="checkbox"]), + select, + textarea { + color: var(--ink); + } +} + +@media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } +} + +@media (forced-colors: active) { + .brand-mark, + .speaker-monogram, + .signal-graphic, + .venue-map, + .button { + border: 0.125rem solid CanvasText; + } + + .privacy-list li::before { + color: CanvasText; + } +} diff --git a/styles-conference/index.html b/styles-conference/index.html index be698df..ac85c58 100644 --- a/styles-conference/index.html +++ b/styles-conference/index.html @@ -1,86 +1,165 @@ - - - - - - - Styles Conference - - - - -
- Styles Conference - - -

August 24–26th — Chicago, IL

- - -
- -
-

Dedicated to the Craft of Building Websites

-

Every year the brightest web designers and front-end developers descend on Chicago to discuss the latest - technologies. Join us this August!

- - Register Now -
- -
- -
- -
Speakers
-

World-Class Speakers

-
- -

Joining us from all around the world are over twenty fantastic speakers, here to share their stories. -

-
- -
- -
Schedule
-

Three Inspiring Days

-
- -

Enjoy three inspiring and action-packed days of talks, gatherings, and all-around good times.

-
- -
- -
Venue
-

The Chicago Theatre

-
- -

Within the heart of downtown Chicago, The Chicago Theatre will provide a beautiful conference venue. -

-
- -
- - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + Signal Conference + + + + + + +
+
+ + + Front-end Lab + +

Fictional multi-page exercise · 03

+
+
+ + + Signal Conference + +

October 8–10 · Harbor Hall

+
+ +
+ +
+
+
+

A FICTIONAL CONFERENCE FOR REAL WEB PRACTICE

+

Ideas for a more human web.

+

+ Three focused days about resilient interfaces, accessible systems, + and teams that design with care. +

+ +
+ +
+ +
+

WHY SIGNAL

+
+

+ The best interface is one more person can use. +

+

+ Signal brings fictional practitioners together around concrete + methods: meaningful markup, visible focus, plain language, durable + CSS, and respectful product decisions. +

+
+
+ +
+
+

PROGRAM THEMES

+

Three tracks, one shared standard

+
+
+
+

01

+

Inclusive foundations

+

+ Semantics, keyboard behavior, contrast, and content structure + treated as architecture rather than polish. +

+ Meet the speaker +
+
+

02

+

Resilient systems

+

+ Small dependencies, deliberate fallbacks, and interfaces that + remain useful when the happy path disappears. +

+ Meet the speaker +
+
+

03

+

Healthy collaboration

+

+ Review practices and shared language that make quality easier to + sustain across a team. +

+ Meet the speaker +
+
+
+ +
+
+

3focused days

+

9practical sessions

+

0tracking scripts

+
+
+ +
+

SAVE A DEMO SEAT

+

No payment. No account. No data leaves your browser.

+ + Open registration + +
+
+ + + + diff --git a/styles-conference/register.html b/styles-conference/register.html index aec0c84..1905468 100644 --- a/styles-conference/register.html +++ b/styles-conference/register.html @@ -1,43 +1,210 @@ - - - - - - - Styles Conference - - - - -
- Styles Conference - -

Styles Conference

-

August 24–26th — Chicago, IL

- - -
- -

Register

- - - - - - \ No newline at end of file + + + + + + + + + + + + + + Register · Signal Conference + + + + + + + +
+
+ + + Front-end Lab + +

Fictional multi-page exercise · 03

+
+
+ + + Signal Conference + +

October 8–10 · Harbor Hall

+
+ +
+ +
+
+

REGISTRATION DEMO

+

Practice a respectful form flow.

+

+ This form validates entirely in your browser. It does not send a + request, save to browser storage, set cookies, or process payment. +

+
+ +
+
+

DEMO PASS

+

Choose a fictional attendance plan

+

+ Complete the required fields to see a local confirmation message. + Use sample information rather than real personal data. +

+
    +
  • No network submission
  • +
  • No local storage or cookies
  • +
  • No analytics or remote scripts
  • +
  • Refreshing the page clears everything
  • +
+
+ +
+
+ + +

+ Use at least two characters. A nickname is fine. +

+

+
+ +
+ + +

+ Try a reserved address such as learner@example.com. +

+

+
+ +
+ + +

+
+ +
+ + +

+ This text remains only in the current form and is never submitted. +

+
+ +
+ + +

+
+ + +

+
+
+
+ + + + diff --git a/styles-conference/schedule.html b/styles-conference/schedule.html index 2102ba0..657c877 100644 --- a/styles-conference/schedule.html +++ b/styles-conference/schedule.html @@ -1,43 +1,190 @@ - - - - - - - Styles Conference - - - - -
- Styles Conference - -

Styles Conference

-

August 24–26th — Chicago, IL

- - -
- -

Schedule

- - - - - - \ No newline at end of file + + + + + + + + + + + + + + Schedule · Signal Conference + + + + + + +
+
+ + + Front-end Lab + +

Fictional multi-page exercise · 03

+
+
+ + + Signal Conference + +

October 8–10 · Harbor Hall

+
+ +
+ +
+
+

SCHEDULE

+

Time to listen, test, and compare notes.

+

+ All times and sessions are fictional. The program alternates concise + talks with longer studios so ideas can become working habits. +

+
+ +
+
+
+

DAY ONE · OCTOBER 8

+

Foundations

+
+
    +
  1. + +
    +

    WELCOME

    +

    A shared definition of quality

    +

    Opening notes from the Signal program team.

    +
    +
  2. +
  3. + +
    +

    KEYNOTE

    +

    Beyond the audit

    +

    Maya Chen · Main room

    +
    +
  4. +
  5. + +
    +

    STUDIO

    +

    Keyboard contracts in practice

    +

    Facilitated lab · Workshop room A

    +
    +
  6. +
+
+ +
+
+

DAY TWO · OCTOBER 9

+

Resilience

+
+
    +
  1. + +
    +

    KEYNOTE

    +

    Designing the fallback first

    +

    Idris Cole · Main room

    +
    +
  2. +
  3. + +
    +

    ROUNDTABLE

    +

    What belongs in a dependency budget?

    +

    Community discussion · Library

    +
    +
  4. +
  5. + +
    +

    STUDIO

    +

    Plan the unhappy path

    +

    Facilitated lab · Workshop room B

    +
    +
  6. +
+
+ +
+
+

DAY THREE · OCTOBER 10

+

Collaboration

+
+
    +
  1. + +
    +

    KEYNOTE

    +

    Reviews that strengthen the system

    +

    Elena Martín · Main room

    +
    +
  2. +
  3. + +
    +

    PRACTICE

    +

    Write a useful decision record

    +

    Guided exercise · Library

    +
    +
  4. +
  5. + +
    +

    CLOSING

    +

    One habit to take home

    +

    Participant reflections · Main room

    +
    +
  6. +
+
+
+ +
+

READY WHEN YOU ARE

+

Choose a demo pass and practice the form flow.

+ + Open registration + +
+
+ + + + diff --git a/styles-conference/speakers.html b/styles-conference/speakers.html index 93096d6..42f7059 100644 --- a/styles-conference/speakers.html +++ b/styles-conference/speakers.html @@ -1,43 +1,146 @@ - - - - - - - Styles Conference - - - - -
- Styles Conference - -

Styles Conference

-

August 24–26th — Chicago, IL

- - -
- -

Speakers

- - - - - - \ No newline at end of file + + + + + + + + + + + + + + Speakers · Signal Conference + + + + + + +
+
+ + + Front-end Lab + +

Fictional multi-page exercise · 03

+
+
+ + + Signal Conference + +

October 8–10 · Harbor Hall

+
+ +
+ +
+
+

SPEAKERS

+

Practitioners who turn principles into habits.

+

+ These profiles and sessions are fictional. They were written for this + repository to demonstrate structured editorial content without using + third-party biographies or portraits. +

+
+ +
+
+ +
+

ACCESSIBILITY ENGINEER

+

Maya Chen

+

Beyond the audit: accessibility as daily infrastructure

+

+ Maya shows how design tokens, component contracts, and small + browser tests can move accessibility checks earlier in the work. +

+
    +
  • Keyboard contracts
  • +
  • Accessible names
  • +
  • Team ownership
  • +
+
+
+ +
+ +
+

FRONT-END ARCHITECT

+

Idris Cole

+

Designing the fallback before the feature

+

+ Idris works backward from failure states to build interfaces that + remain understandable across slow networks and partial support. +

+
    +
  • Progressive enhancement
  • +
  • Dependency budgets
  • +
  • Failure modes
  • +
+
+
+ +
+ +
+

DESIGN OPERATIONS LEAD

+

Elena Martín

+

Reviews that strengthen the system, not just the screen

+

+ Elena offers a practical review language for connecting visual + decisions to behavior, content, risk, and maintainability. +

+
    +
  • Review framing
  • +
  • Decision records
  • +
  • Shared vocabulary
  • +
+
+
+
+ +
+

PLAN YOUR VISIT

+

Pair each keynote with a hands-on studio.

+ + View the full schedule + +
+
+ + + + diff --git a/styles-conference/venue.html b/styles-conference/venue.html index 7d43ccf..fc85b90 100644 --- a/styles-conference/venue.html +++ b/styles-conference/venue.html @@ -1,43 +1,156 @@ - - - - - - - Styles Conference - - - - -
- Styles Conference - -

Styles Conference

-

August 24–26th — Chicago, IL

- - -
- -

Venue

- - - - - - \ No newline at end of file + + + + + + + + + + + + + + Venue · Signal Conference + + + + + + +
+
+ + + Front-end Lab + +

Fictional multi-page exercise · 03

+
+
+ + + Signal Conference + +

October 8–10 · Harbor Hall

+
+ +
+ +
+
+

VENUE

+

A quiet harbor for active conversation.

+

+ Harbor Hall and every location on this page are fictional. The guide + demonstrates useful venue content without maps, trackers, or remote + embeds. +

+
+ +
+ +
+

HARBOR HALL

+

+ Everything is within one compact floor plan. +

+

+ The fictional venue places the main room, two studios, a quiet + lounge, and step-free restrooms around a central lobby. +

+
+ 12 North Quay
+ Port Meridian +
+
+
+ +
+
+

01

+

Arriving

+

+ The North Quay transit stop is described as a five-minute, step-free + route from the lobby. A covered drop-off zone sits beside the east + entrance. +

+
+
+

02

+

Access

+

+ The demo venue includes level entrances, lifts, hearing loops, + gender-neutral restrooms, movable seating, and a low-stimulation + room. +

+
+
+

03

+

Support

+

+ Registration volunteers can provide large-print schedules, seating + assistance, and directions without requiring disclosure of a + diagnosis. +

+
+
+ + + +
+

PRACTICE THE FLOW

+

The registration demo includes an optional access-notes field.

+ + Open registration + +
+
+ + + + diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000..86bbaf4 --- /dev/null +++ b/test/README.md @@ -0,0 +1,43 @@ +# Test suite + +All repository verification lives under `test/`. Runtime reports are written to `test-results/` and ignored by Git. + +## Layers + +| Layer | Location | Purpose | +| ----------- | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | +| Static | `test/scripts/` | Compatibility paths, internal links, fragments, path case, CSP metadata, CSS parsing, local-only runtime assets, and payload budget | +| Unit | `test/unit/` | Registration helpers and static-checker utilities | +| Browser | `test/e2e/` | Page loading, navigation, forms, storage, resource origins, keyboard behavior, Axe, direct-file access, and screenshots | +| Manual | `test/manual-accessibility.md` | Narrator, forced colors, keyboard, zoom, and Edge checks | +| Performance | `scripts/run-lighthouse.mjs` | Performance, accessibility, best-practices, and SEO scores | + +## Browser projects + +- `chromium` +- `firefox` +- `webkit` +- `mobile-chromium` +- `chrome` +- `msedge` +- `visual` + +Ubuntu CI owns screenshot comparison and runs the first four projects plus `visual`. Windows CI runs installed Chrome and Edge, Firefox, and mobile Chromium. + +## Commands + +```powershell +npm.cmd run check +npm.cmd run test:unit +npm.cmd run test:e2e:windows +npm.cmd run test:e2e:linux +npm.cmd run test:lighthouse +``` + +External link availability is intentionally non-blocking because remote sites and networks are unstable: + +```powershell +npm.cmd run check:external-links +``` + +Internal links and resources are always blocking. diff --git a/test/e2e/accessibility.spec.mjs b/test/e2e/accessibility.spec.mjs new file mode 100644 index 0000000..1021d69 --- /dev/null +++ b/test/e2e/accessibility.spec.mjs @@ -0,0 +1,28 @@ +import AxeBuilder from "@axe-core/playwright"; +import { expect, test } from "@playwright/test"; + +const pages = [ + "/index.html", + "/Html5-Final-Project.html", + "/assignment-1%202/index.html", + "/assignment-1%202/teams.html", + "/assignment-1%202/history.html", + "/styles-conference/index.html", + "/styles-conference/speakers.html", + "/styles-conference/schedule.html", + "/styles-conference/venue.html", + "/styles-conference/register.html", +]; + +for (const path of pages) { + test(`${path} has no automated accessibility violations`, async ({ + page, + }) => { + await page.goto(path); + const results = await new AxeBuilder({ page }) + .withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22aa"]) + .analyze(); + + expect(results.violations).toEqual([]); + }); +} diff --git a/test/e2e/file-compat.spec.mjs b/test/e2e/file-compat.spec.mjs new file mode 100644 index 0000000..321aa85 --- /dev/null +++ b/test/e2e/file-compat.spec.mjs @@ -0,0 +1,32 @@ +import path from "node:path"; +import { pathToFileURL } from "node:url"; +import { expect, test } from "@playwright/test"; + +const projectRoot = path.resolve(import.meta.dirname, "../.."); +const files = [ + "index.html", + "Html5-Final-Project.html", + "assignment-1 2/index.html", + "styles-conference/index.html", + "styles-conference/register.html", +]; + +for (const file of files) { + test(`${file} works when opened directly`, async ({ page }) => { + const runtimeErrors = []; + page.on("console", (message) => { + if (message.type() === "error") { + runtimeErrors.push(message.text()); + } + }); + page.on("pageerror", (error) => runtimeErrors.push(error.message)); + + await page.goto(pathToFileURL(path.join(projectRoot, file)).href); + + await expect(page.locator("h1")).toBeVisible(); + expect( + await page.evaluate(() => getComputedStyle(document.body).display), + ).not.toBe(""); + expect(runtimeErrors).toEqual([]); + }); +} diff --git a/test/e2e/keyboard.spec.mjs b/test/e2e/keyboard.spec.mjs new file mode 100644 index 0000000..5619b74 --- /dev/null +++ b/test/e2e/keyboard.spec.mjs @@ -0,0 +1,51 @@ +import { expect, test } from "@playwright/test"; + +test("the root skip link is first and keyboard activatable", async ({ + page, +}, testInfo) => { + await page.goto("/index.html"); + + const skipLink = page.getByRole("link", { name: "跳到示例列表" }); + const firstFocusable = page + .locator( + "a[href], button, input, select, textarea, [tabindex]:not([tabindex='-1'])", + ) + .first(); + await expect(firstFocusable).toHaveAttribute("href", "#examples"); + + // Safari reserves plain Tab for form controls unless full-page keyboard + // navigation is enabled. Programmatic focus emulates that browser preference + // while Enter still exercises the real keyboard activation behavior. + if (testInfo.project.name === "webkit") { + await skipLink.focus(); + } else { + await page.keyboard.press("Tab"); + } + await expect(skipLink).toBeFocused(); + await skipLink.press("Enter"); + await expect(page.locator("#examples")).toBeFocused(); +}); + +test("conference navigation is reachable in document order", async ({ + page, +}) => { + await page.goto("/styles-conference/index.html"); + + const links = page.locator(".conference-nav a"); + for (let index = 0; index < (await links.count()); index += 1) { + const link = links.nth(index); + await link.focus(); + await expect(link).toBeFocused(); + } +}); + +test("details disclosure works from the keyboard", async ({ page }) => { + await page.goto("/Html5-Final-Project.html"); + + const summary = page.getByText("Build for more ways of using the web", { + exact: true, + }); + await summary.focus(); + await summary.press("Enter"); + await expect(page.locator("details")).toHaveAttribute("open", ""); +}); diff --git a/test/e2e/register.spec.mjs b/test/e2e/register.spec.mjs new file mode 100644 index 0000000..a505f3a --- /dev/null +++ b/test/e2e/register.spec.mjs @@ -0,0 +1,63 @@ +import { expect, test } from "@playwright/test"; + +test("registration reports field errors without submitting", async ({ + page, +}) => { + await page.goto("/styles-conference/register.html"); + await page.getByRole("button", { name: "Complete local demo" }).click(); + + await expect(page.locator("#display-name")).toBeFocused(); + await expect(page.locator("#display-name-error")).toHaveText( + "Complete this required field.", + ); + await expect(page.locator("#form-status")).toHaveText( + "Review the highlighted fields and try again.", + ); +}); + +test("registration completes locally and stores nothing", async ({ + context, + page, +}) => { + const requests = []; + page.on("request", (request) => requests.push(request.url())); + + await page.goto("/styles-conference/register.html", { + waitUntil: "networkidle", + }); + requests.length = 0; + + await page.locator("#display-name").fill("Demo Learner"); + await page.locator("#sample-email").fill("learner@example.com"); + await page.locator("#pass-type").selectOption("studios"); + await page.locator("#access-notes").fill("Large-print schedule, please."); + await page.locator("#demo-confirmation").check(); + await page.getByRole("button", { name: "Complete local demo" }).click(); + + const status = page.locator("#form-status"); + await expect(status).toBeFocused(); + await expect(status).toHaveText( + "Demo complete for Demo Learner: Studio sessions. Nothing was sent or saved.", + ); + expect(requests).toEqual([]); + expect(await context.cookies()).toEqual([]); + expect( + await page.evaluate(() => ({ + local: localStorage.length, + session: sessionStorage.length, + })), + ).toEqual({ local: 0, session: 0 }); +}); + +test("registration shows a specific email error", async ({ page }) => { + await page.goto("/styles-conference/register.html"); + const email = page.locator("#sample-email"); + + await email.fill("not-an-email"); + await email.blur(); + + await expect(email).toHaveAttribute("aria-invalid", "true"); + await expect(page.locator("#sample-email-error")).toHaveText( + "Enter an email in the format name@example.com.", + ); +}); diff --git a/test/e2e/security.spec.mjs b/test/e2e/security.spec.mjs new file mode 100644 index 0000000..8efdde0 --- /dev/null +++ b/test/e2e/security.spec.mjs @@ -0,0 +1,34 @@ +import { expect, test } from "@playwright/test"; + +const pages = [ + "/index.html", + "/Html5-Final-Project.html", + "/assignment-1%202/index.html", + "/styles-conference/index.html", + "/styles-conference/register.html", +]; + +for (const path of pages) { + test(`${path} loads runtime resources only from the site`, async ({ + page, + }) => { + const outsideRequests = []; + page.on("request", (request) => { + const url = new URL(request.url()); + if (url.origin !== "http://127.0.0.1:4173") { + outsideRequests.push(request.url()); + } + }); + + await page.goto(path); + + expect(outsideRequests).toEqual([]); + await expect( + page.locator('meta[http-equiv="Content-Security-Policy"]'), + ).toHaveCount(1); + await expect(page.locator('meta[name="referrer"]')).toHaveAttribute( + "content", + "no-referrer", + ); + }); +} diff --git a/test/e2e/site.spec.mjs b/test/e2e/site.spec.mjs new file mode 100644 index 0000000..f78c54f --- /dev/null +++ b/test/e2e/site.spec.mjs @@ -0,0 +1,96 @@ +import { expect, test } from "@playwright/test"; + +const pages = [ + { heading: /从语义开始/, path: "/index.html", title: /HTML Sample/ }, + { + heading: /Learning the web/, + path: "/Html5-Final-Project.html", + title: /Learning Profile/, + }, + { + heading: /Ultimate\s+Field Notes/i, + path: "/assignment-1%202/index.html", + title: /Ultimate Field Notes/, + }, + { + heading: /Ultimate\s+Field Notes/i, + path: "/assignment-1%202/teams.html", + title: /Teams/, + }, + { + heading: /Ultimate\s+Field Notes/i, + path: "/assignment-1%202/history.html", + title: /History/, + }, + { + heading: /Ideas for a more human web/, + path: "/styles-conference/index.html", + title: /Signal Conference/, + }, + { + heading: /Practitioners who turn principles/, + path: "/styles-conference/speakers.html", + title: /Speakers/, + }, + { + heading: /Time to listen/, + path: "/styles-conference/schedule.html", + title: /Schedule/, + }, + { + heading: /A quiet harbor/, + path: "/styles-conference/venue.html", + title: /Venue/, + }, + { + heading: /Practice a respectful form flow/, + path: "/styles-conference/register.html", + title: /Register/, + }, +]; + +for (const pageDefinition of pages) { + test(`${pageDefinition.path} loads without runtime errors`, async ({ + page, + }) => { + const runtimeErrors = []; + page.on("console", (message) => { + if (message.type() === "error") { + runtimeErrors.push(message.text()); + } + }); + page.on("pageerror", (error) => runtimeErrors.push(error.message)); + + const response = await page.goto(pageDefinition.path); + + expect(response?.ok()).toBe(true); + await expect(page).toHaveTitle(pageDefinition.title); + await expect( + page.getByRole("heading", { level: 1, name: pageDefinition.heading }), + ).toBeVisible(); + expect( + await page.evaluate( + () => + document.documentElement.scrollWidth <= + document.documentElement.clientWidth + 1, + ), + ).toBe(true); + expect(runtimeErrors).toEqual([]); + }); +} + +test("conference navigation exposes the current page", async ({ page }) => { + await page.goto("/styles-conference/schedule.html"); + + const current = page.locator(".conference-nav [aria-current='page']"); + await expect(current).toHaveText("Schedule"); + await expect(current).toHaveAttribute("href", "schedule.html"); +}); + +test("ultimate navigation exposes the current page", async ({ page }) => { + await page.goto("/assignment-1%202/teams.html"); + + const current = page.locator(".sport-nav [aria-current='page']"); + await expect(current).toHaveText("Teams"); + await expect(current).toHaveAttribute("href", "teams.html"); +}); diff --git a/test/e2e/visual.spec.mjs b/test/e2e/visual.spec.mjs new file mode 100644 index 0000000..7bb24d9 --- /dev/null +++ b/test/e2e/visual.spec.mjs @@ -0,0 +1,38 @@ +import { expect, test } from "@playwright/test"; + +test("root gallery light theme", async ({ page }) => { + await page.goto("/index.html"); + await expect(page).toHaveScreenshot("gallery-light.png", { + fullPage: true, + }); +}); + +test("root gallery dark theme", async ({ page }) => { + await page.emulateMedia({ colorScheme: "dark" }); + await page.goto("/index.html"); + await expect(page).toHaveScreenshot("gallery-dark.png", { + fullPage: true, + }); +}); + +test("ultimate home desktop", async ({ page }) => { + await page.goto("/assignment-1%202/index.html"); + await expect(page).toHaveScreenshot("ultimate-home.png", { + fullPage: true, + }); +}); + +test("conference home desktop", async ({ page }) => { + await page.goto("/styles-conference/index.html"); + await expect(page).toHaveScreenshot("conference-home.png", { + fullPage: true, + }); +}); + +test("registration mobile layout", async ({ page }) => { + await page.setViewportSize({ height: 900, width: 390 }); + await page.goto("/styles-conference/register.html"); + await expect(page).toHaveScreenshot("registration-mobile.png", { + fullPage: true, + }); +}); diff --git a/test/e2e/windows-edge.spec.mjs b/test/e2e/windows-edge.spec.mjs new file mode 100644 index 0000000..3fe6e63 --- /dev/null +++ b/test/e2e/windows-edge.spec.mjs @@ -0,0 +1,256 @@ +import { expect, test } from "@playwright/test"; + +const pages = [ + "/index.html", + "/Html5-Final-Project.html", + "/assignment-1%202/index.html", + "/assignment-1%202/teams.html", + "/assignment-1%202/history.html", + "/styles-conference/index.html", + "/styles-conference/speakers.html", + "/styles-conference/schedule.html", + "/styles-conference/venue.html", + "/styles-conference/register.html", +]; + +async function getAccessibilityNodes(context, page) { + const session = await context.newCDPSession(page); + await session.send("Accessibility.enable"); + const { nodes } = await session.send("Accessibility.getFullAXTree"); + await session.detach(); + return nodes; +} + +function hasRole(nodes, role) { + return nodes.some((node) => node.role?.value === role); +} + +function hasRoleAndName(nodes, role, name) { + return nodes.some( + (node) => + node.role?.value === role && + (typeof name === "string" + ? node.name?.value === name + : name.test(node.name?.value ?? "")), + ); +} + +for (const pagePath of pages) { + test(`${pagePath} reflows at the 200% zoom equivalent width`, async ({ + page, + }) => { + await page.setViewportSize({ height: 720, width: 640 }); + await page.goto(pagePath); + + const layout = await page.evaluate(() => { + const root = document.documentElement; + const textElements = [ + ...document.querySelectorAll( + "h1, h2, h3, p, a, button, label, summary, dt, dd, th, td", + ), + ]; + const clippedText = textElements + .filter((element) => { + const style = getComputedStyle(element); + const clipsX = ["clip", "hidden"].includes(style.overflowX); + const clipsY = ["clip", "hidden"].includes(style.overflowY); + return ( + (clipsX && element.scrollWidth > element.clientWidth + 1) || + (clipsY && element.scrollHeight > element.clientHeight + 1) + ); + }) + .map((element) => element.textContent.trim().slice(0, 80)); + + return { + clientWidth: root.clientWidth, + clippedText, + scrollWidth: root.scrollWidth, + }; + }); + + expect( + layout.scrollWidth, + `${pagePath} creates document-level horizontal scrolling`, + ).toBeLessThanOrEqual(layout.clientWidth + 1); + expect(layout.clippedText).toEqual([]); + }); + + test(`${pagePath} remains operable in Windows forced colors`, async ({ + page, + }) => { + await page.emulateMedia({ forcedColors: "active" }); + await page.goto(pagePath); + + expect( + await page.evaluate(() => matchMedia("(forced-colors: active)").matches), + ).toBe(true); + await expect(page.locator("h1")).toBeVisible(); + + await page.keyboard.press("Tab"); + const focused = page.locator(":focus"); + await expect(focused).toBeVisible(); + const focusStyle = await focused.evaluate((element) => { + const style = getComputedStyle(element); + return { + outlineStyle: style.outlineStyle, + outlineWidth: Number.parseFloat(style.outlineWidth), + }; + }); + expect(focusStyle.outlineStyle).not.toBe("none"); + expect(focusStyle.outlineWidth).toBeGreaterThan(0); + }); +} + +test("the team table exposes a labeled keyboard-scrollable region", async ({ + page, +}) => { + await page.setViewportSize({ height: 720, width: 640 }); + await page.goto("/assignment-1%202/teams.html"); + + const region = page.locator(".table-scroll"); + await expect(region).toHaveAttribute("tabindex", "0"); + await expect(region).toHaveAccessibleName( + "Fictional ultimate team directory", + ); + await region.focus(); + await expect(region).toBeFocused(); + expect( + await region.evaluate( + (element) => element.scrollWidth > element.clientWidth, + ), + ).toBe(true); + await expect(page.locator("caption")).toHaveText( + "Fictional community teams and their weekly sessions", + ); +}); + +test("forced colors preserve textual form errors", async ({ page }) => { + await page.emulateMedia({ forcedColors: "active" }); + await page.goto("/styles-conference/register.html"); + await page.getByRole("button", { name: "Complete local demo" }).click(); + + const name = page.locator("#display-name"); + await expect(name).toBeFocused(); + await expect(name).toHaveAttribute("aria-invalid", "true"); + await expect(page.locator("#display-name-error")).toHaveText( + "Complete this required field.", + ); + await expect(page.locator("#form-status")).toHaveText( + "Review the highlighted fields and try again.", + ); +}); + +test("light and dark system themes produce distinct page palettes", async ({ + page, +}) => { + for (const pagePath of [ + "/index.html", + "/assignment-1%202/index.html", + "/styles-conference/index.html", + ]) { + await page.emulateMedia({ colorScheme: "light" }); + await page.goto(pagePath); + const lightBackground = await page + .locator("body") + .evaluate((element) => getComputedStyle(element).backgroundColor); + + await page.emulateMedia({ colorScheme: "dark" }); + await page.reload(); + const darkBackground = await page + .locator("body") + .evaluate((element) => getComputedStyle(element).backgroundColor); + + expect(darkBackground, `${pagePath} has no dark-theme palette`).not.toBe( + lightBackground, + ); + } +}); + +test("Edge exposes useful landmark, heading, and page-title semantics", async ({ + context, + page, +}) => { + await page.goto("/styles-conference/index.html"); + const nodes = await getAccessibilityNodes(context, page); + + expect(hasRoleAndName(nodes, "RootWebArea", /Signal Conference/)).toBe(true); + expect(hasRoleAndName(nodes, "heading", "Ideas for a more human web.")).toBe( + true, + ); + for (const role of ["banner", "navigation", "main", "contentinfo"]) { + expect(hasRole(nodes, role), `Missing ${role} landmark`).toBe(true); + } +}); + +test("Edge exposes the table caption and header relationships", async ({ + context, + page, +}) => { + await page.goto("/assignment-1%202/teams.html"); + const nodes = await getAccessibilityNodes(context, page); + + expect( + hasRoleAndName( + nodes, + "table", + "Fictional community teams and their weekly sessions", + ), + ).toBe(true); + expect( + nodes.filter((node) => node.role?.value === "columnheader"), + ).toHaveLength(4); + expect(nodes.filter((node) => node.role?.value === "rowheader")).toHaveLength( + 5, + ); +}); + +test("Edge exposes form labels, errors, state, and local completion text", async ({ + context, + page, +}) => { + await page.goto("/styles-conference/register.html"); + let nodes = await getAccessibilityNodes(context, page); + + expect(hasRoleAndName(nodes, "textbox", "Sample display name")).toBe(true); + expect(hasRoleAndName(nodes, "textbox", "Sample email")).toBe(true); + expect(hasRoleAndName(nodes, "combobox", "Demo pass")).toBe(true); + expect( + hasRoleAndName( + nodes, + "checkbox", + "I understand this is a local demonstration, not a real booking.", + ), + ).toBe(true); + + await page.getByRole("button", { name: "Complete local demo" }).click(); + nodes = await getAccessibilityNodes(context, page); + const invalidName = nodes.find( + (node) => + node.role?.value === "textbox" && + node.name?.value === "Sample display name", + ); + expect( + invalidName?.properties?.some( + (property) => + property.name === "invalid" && property.value?.value === "true", + ), + ).toBe(true); + expect( + nodes.some((node) => node.name?.value === "Complete this required field."), + ).toBe(true); + + await page.locator("#display-name").fill("Demo Learner"); + await page.locator("#sample-email").fill("learner@example.com"); + await page.locator("#pass-type").selectOption("studios"); + await page.locator("#demo-confirmation").check(); + await page.getByRole("button", { name: "Complete local demo" }).click(); + nodes = await getAccessibilityNodes(context, page); + + expect( + nodes.some((node) => + (node.name?.value ?? "").includes( + "Demo complete for Demo Learner: Studio sessions.", + ), + ), + ).toBe(true); +}); diff --git a/test/manual-accessibility.md b/test/manual-accessibility.md new file mode 100644 index 0000000..eb3d533 --- /dev/null +++ b/test/manual-accessibility.md @@ -0,0 +1,66 @@ +# Windows accessibility verification + +Status: Automated release-candidate verification complete. Direct Narrator +speech output remains a documented manual limitation. + +The repeatable Windows checks run in installed Microsoft Edge through +`test/e2e/windows-edge.spec.mjs`. They use a 640 CSS-pixel viewport to model the +available width at 200% browser zoom on a 1280-pixel-wide window, Edge forced +colors, keyboard input, and Edge's full accessibility tree. + +## Keyboard + +- [x] Skip links become visible and move focus to the main content. +- [x] Navigation follows a logical order on all three example sites. +- [x] Every interactive element has a visible focus indicator. +- [x] The profile disclosure opens and closes with Enter and Space. +- [x] Registration errors move focus to the first invalid field. +- [x] Successful registration moves focus to the local status message. + +## Zoom and reflow + +- [x] The 200% zoom equivalent width has no document-level horizontal + scrolling. +- [x] Text does not overlap or become clipped. +- [x] The team table exposes a labeled, keyboard-focusable horizontal region + when needed. + +## Windows forced colors + +- [x] Links, buttons, fields, navigation state, and focus remain + distinguishable. +- [x] CSS-only decorative graphics do not hide essential information. +- [x] Form errors are understandable without relying on color alone. + +## Narrator-facing semantics + +- [x] Edge exposes the page title and primary heading in its accessibility + tree. +- [x] Edge exposes banner, navigation, main, and content-info landmarks. +- [x] Edge exposes the table caption plus four column and five row headers. +- [x] Edge exposes registration labels, descriptions, invalid state, checkbox + state, errors, and final status text. + +These checks verify the browser accessibility tree consumed by assistive +technology. Codex's Windows UI safety guard could not establish the active Edge +URL, so it stopped both attempts to automate Narrator. The checklist therefore +does not claim that spoken wording or voice output was heard. + +## Edge smoke test + +- [x] All 10 pages load without console errors. +- [x] Existing HTTP and direct-file compatibility URLs still open. +- [x] Light and dark system themes render with distinct palettes. +- [x] Registration makes no network request and leaves no browser storage. + +## Verification record + +| Field | Value | +| ---------- | ------------------------------------------------------------------- | +| Date | 2026-07-31 | +| Windows | Build 26200.8875, display version 25H2 | +| Edge | 150.0.4078.105 | +| Narrator | Executable 10.0.26100.8875; direct speech output not automated | +| Result | Repeatable Edge accessibility gates passed; speech check documented | +| Evidence | `test/e2e/windows-edge.spec.mjs`: 26/26 passed | +| Limitation | Computer Use stopped because it could not verify the active URL | diff --git a/test/scripts/check-external-links.mjs b/test/scripts/check-external-links.mjs new file mode 100644 index 0000000..23e0d84 --- /dev/null +++ b/test/scripts/check-external-links.mjs @@ -0,0 +1,50 @@ +import { readFile } from "node:fs/promises"; +import { fileURLToPath } from "node:url"; +import { + collectFiles, + extractTags, + getAttribute, + isExternalReference, +} from "./static-checker.mjs"; + +const projectRoot = fileURLToPath(new URL("../..", import.meta.url)); +const htmlFiles = await collectFiles(projectRoot, new Set([".html"])); +const links = new Set(); + +for (const htmlFile of htmlFiles) { + const html = await readFile(htmlFile, "utf8"); + for (const { attributes, tag } of extractTags(html)) { + const reference = tag === "a" ? getAttribute(attributes, "href") : null; + if ( + reference && + isExternalReference(reference) && + reference.startsWith("https:") + ) { + links.add(reference); + } + } +} + +let warnings = 0; +for (const link of [...links].sort()) { + try { + const response = await fetch(link, { + headers: { "user-agent": "html-sample-link-check/1.0" }, + redirect: "follow", + signal: AbortSignal.timeout(10_000), + }); + if (response.ok) { + console.log(`OK ${response.status} ${link}`); + } else { + warnings += 1; + console.warn(`WARN ${response.status} ${link}`); + } + } catch (error) { + warnings += 1; + console.warn(`WARN network error ${link}: ${error.message}`); + } +} + +console.log( + `Checked ${links.size} external links with ${warnings} non-blocking warning(s).`, +); diff --git a/test/scripts/check-static.mjs b/test/scripts/check-static.mjs new file mode 100644 index 0000000..654bb83 --- /dev/null +++ b/test/scripts/check-static.mjs @@ -0,0 +1,20 @@ +import { fileURLToPath } from "node:url"; +import { runStaticChecks } from "./static-checker.mjs"; + +const projectRoot = fileURLToPath(new URL("../..", import.meta.url)); +const result = await runStaticChecks(projectRoot); + +if (result.errors.length > 0) { + console.error("Static checks failed:"); + for (const error of result.errors) { + console.error(`- ${error}`); + } + process.exitCode = 1; +} else { + console.log( + `Static checks passed for ${result.htmlCount} HTML files and ${result.cssCount} CSS files.`, + ); + console.log( + `Largest initial page payload: ${result.largestPage.file} (${Math.ceil(result.largestPage.bytes / 1024)} KB).`, + ); +} diff --git a/test/scripts/static-checker.mjs b/test/scripts/static-checker.mjs new file mode 100644 index 0000000..e8f062e --- /dev/null +++ b/test/scripts/static-checker.mjs @@ -0,0 +1,445 @@ +import { access, readFile, readdir, stat } from "node:fs/promises"; +import path from "node:path"; +import postcss from "postcss"; + +const ignoredDirectories = new Set([ + ".git", + ".lighthouseci", + "_site", + "node_modules", + "playwright-report", + "test-results", +]); + +const localSchemes = new Set(["", "file:"]); +const externalSchemes = new Set(["http:", "https:", "mailto:", "tel:"]); + +export function splitReference(reference) { + const hashIndex = reference.indexOf("#"); + const beforeHash = + hashIndex === -1 ? reference : reference.slice(0, hashIndex); + const fragment = + hashIndex === -1 ? "" : decodeURIComponent(reference.slice(hashIndex + 1)); + const queryIndex = beforeHash.indexOf("?"); + const pathname = + queryIndex === -1 ? beforeHash : beforeHash.slice(0, queryIndex); + + return { fragment, pathname }; +} + +export function isExternalReference(reference) { + try { + const parsed = new URL(reference, "file:///placeholder/"); + return externalSchemes.has(parsed.protocol); + } catch { + return false; + } +} + +export function getAttribute(attributes, name) { + const expression = new RegExp( + `(?:^|\\s)${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)')`, + "i", + ); + const match = attributes.match(expression); + return match ? (match[1] ?? match[2] ?? "") : null; +} + +export function extractTags(html) { + return Array.from( + html.matchAll(/<(a|img|link|script|source)\b([^>]*)>/gi), + ([, tag, attributes]) => ({ + attributes, + tag: tag.toLowerCase(), + }), + ); +} + +export async function collectFiles(rootDirectory, extensions) { + const files = []; + + async function visit(directory) { + const entries = await readdir(directory, { withFileTypes: true }); + for (const entry of entries) { + if (entry.isDirectory() && ignoredDirectories.has(entry.name)) { + continue; + } + + const absolutePath = path.join(directory, entry.name); + if (entry.isDirectory()) { + await visit(absolutePath); + } else if (extensions.has(path.extname(entry.name).toLowerCase())) { + files.push(absolutePath); + } + } + } + + await visit(rootDirectory); + return files.sort(); +} + +async function exists(target) { + try { + await access(target); + return true; + } catch { + return false; + } +} + +async function exactCaseExists(rootDirectory, target) { + const relative = path.relative(rootDirectory, target); + if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) { + return relative === ""; + } + + let current = rootDirectory; + for (const segment of relative.split(path.sep)) { + const entries = await readdir(current); + if (!entries.includes(segment)) { + return false; + } + current = path.join(current, segment); + } + return true; +} + +async function resolveLocalReference(rootDirectory, sourceFile, reference) { + const { fragment, pathname } = splitReference(reference); + const decodedPath = decodeURIComponent(pathname); + let target = decodedPath + ? path.resolve(path.dirname(sourceFile), decodedPath) + : sourceFile; + + const relative = path.relative(rootDirectory, target); + if (relative.startsWith("..") || path.isAbsolute(relative)) { + throw new Error(`escapes the repository: ${reference}`); + } + + if (await exists(target)) { + const targetStats = await stat(target); + if (targetStats.isDirectory()) { + target = path.join(target, "index.html"); + } + } + + return { fragment, target }; +} + +function collectIds(html) { + return Array.from(html.matchAll(/\sid\s*=\s*(?:"([^"]+)"|'([^']+)')/gi)) + .map((match) => match[1] ?? match[2]) + .filter(Boolean); +} + +function collectCssReferences(css) { + return Array.from(css.matchAll(/url\(\s*(?:"([^"]+)"|'([^']+)'|([^'")]+))/gi)) + .map((match) => (match[1] ?? match[2] ?? match[3]).trim()) + .filter(Boolean); +} + +function fail(errors, sourceFile, rootDirectory, message) { + errors.push(`${path.relative(rootDirectory, sourceFile)}: ${message}`); +} + +async function validateHtmlFiles(rootDirectory, htmlFiles, errors) { + const htmlCache = new Map(); + const idCache = new Map(); + let largestPage = { bytes: 0, file: "" }; + + for (const htmlFile of htmlFiles) { + const html = await readFile(htmlFile, "utf8"); + htmlCache.set(htmlFile, html); + const ids = collectIds(html); + idCache.set(htmlFile, new Set(ids)); + + const duplicateIds = ids.filter((id, index) => ids.indexOf(id) !== index); + if (duplicateIds.length > 0) { + fail( + errors, + htmlFile, + rootDirectory, + `duplicate ids: ${[...new Set(duplicateIds)].join(", ")}`, + ); + } + + const requiredPatterns = [ + [/]*\blang=/i, "missing document language"], + [/]*\bname=["']viewport["']/i, "missing viewport metadata"], + [/]*\bname=["']referrer["']/i, "missing referrer policy"], + [ + /]*\bhttp-equiv=["']Content-Security-Policy["']/i, + "missing Content Security Policy", + ], + ]; + + for (const [pattern, message] of requiredPatterns) { + if (!pattern.test(html)) { + fail(errors, htmlFile, rootDirectory, message); + } + } + + const forbiddenPatterns = [ + [/\bhttp:\/\//i, "contains an insecure HTTP URL"], + [/\sstyle\s*=/i, "contains an inline style"], + [/\son[a-z]+\s*=/i, "contains an inline event handler"], + [/]*\bsrc=)/i, "contains an inline script"], + ]; + + for (const [pattern, message] of forbiddenPatterns) { + if (pattern.test(html)) { + fail(errors, htmlFile, rootDirectory, message); + } + } + + for (const attributeName of ["aria-describedby", "aria-labelledby"]) { + const expression = new RegExp( + `\\s${attributeName}\\s*=\\s*(?:"([^"]+)"|'([^']+)')`, + "gi", + ); + for (const match of html.matchAll(expression)) { + const references = (match[1] ?? match[2]).split(/\s+/); + for (const reference of references) { + if (!idCache.get(htmlFile).has(reference)) { + fail( + errors, + htmlFile, + rootDirectory, + `${attributeName} references missing id "${reference}"`, + ); + } + } + } + } + + let pageBytes = Buffer.byteLength(html); + const visitedAssets = new Set(); + + for (const { attributes, tag } of extractTags(html)) { + const attributeName = tag === "a" || tag === "link" ? "href" : "src"; + const reference = getAttribute(attributes, attributeName); + if (!reference || reference.startsWith("#")) { + continue; + } + + if (isExternalReference(reference)) { + if (tag !== "a") { + fail( + errors, + htmlFile, + rootDirectory, + `runtime resource must be local: ${reference}`, + ); + } else { + const rel = getAttribute(attributes, "rel") ?? ""; + if (!rel.split(/\s+/).includes("external")) { + fail( + errors, + htmlFile, + rootDirectory, + `external link lacks rel="external": ${reference}`, + ); + } + } + continue; + } + + let parsed; + try { + parsed = new URL(reference, "file:///placeholder/"); + } catch { + fail(errors, htmlFile, rootDirectory, `invalid URL: ${reference}`); + continue; + } + + if (!localSchemes.has(parsed.protocol)) { + continue; + } + + try { + const { fragment, target } = await resolveLocalReference( + rootDirectory, + htmlFile, + reference, + ); + if (!(await exists(target))) { + fail( + errors, + htmlFile, + rootDirectory, + `missing local target: ${reference}`, + ); + continue; + } + if (!(await exactCaseExists(rootDirectory, target))) { + fail( + errors, + htmlFile, + rootDirectory, + `path case does not match the filesystem: ${reference}`, + ); + } + + if ( + fragment && + path.extname(target).toLowerCase() === ".html" && + !( + idCache.get(target) ?? + new Set(collectIds(await readFile(target, "utf8"))) + ).has(fragment) + ) { + fail( + errors, + htmlFile, + rootDirectory, + `missing fragment "${fragment}" in ${reference}`, + ); + } + + if (tag !== "a" && !visitedAssets.has(target)) { + visitedAssets.add(target); + pageBytes += (await stat(target)).size; + + if (path.extname(target).toLowerCase() === ".css") { + const css = await readFile(target, "utf8"); + for (const cssReference of collectCssReferences(css)) { + if ( + cssReference.startsWith("data:") || + isExternalReference(cssReference) + ) { + continue; + } + const resolvedCssAsset = await resolveLocalReference( + rootDirectory, + target, + cssReference, + ); + if ( + (await exists(resolvedCssAsset.target)) && + !visitedAssets.has(resolvedCssAsset.target) + ) { + visitedAssets.add(resolvedCssAsset.target); + pageBytes += (await stat(resolvedCssAsset.target)).size; + } + } + } + } + } catch (error) { + fail(errors, htmlFile, rootDirectory, error.message); + } + } + + if (pageBytes > 500 * 1024) { + fail( + errors, + htmlFile, + rootDirectory, + `initial local resources exceed 500 KB (${Math.ceil(pageBytes / 1024)} KB)`, + ); + } + if (pageBytes > largestPage.bytes) { + largestPage = { + bytes: pageBytes, + file: path.relative(rootDirectory, htmlFile), + }; + } + } + + return largestPage; +} + +async function validateCssFiles(rootDirectory, cssFiles, errors) { + for (const cssFile of cssFiles) { + const css = await readFile(cssFile, "utf8"); + try { + postcss.parse(css, { from: cssFile }); + } catch (error) { + fail(errors, cssFile, rootDirectory, `CSS parse error: ${error.reason}`); + } + + if (/\bhttp:\/\//i.test(css)) { + fail(errors, cssFile, rootDirectory, "contains an insecure HTTP URL"); + } + + for (const reference of collectCssReferences(css)) { + if (reference.startsWith("data:")) { + continue; + } + if (isExternalReference(reference)) { + fail( + errors, + cssFile, + rootDirectory, + `runtime resource must be local: ${reference}`, + ); + continue; + } + + try { + const { target } = await resolveLocalReference( + rootDirectory, + cssFile, + reference, + ); + if (!(await exists(target))) { + fail( + errors, + cssFile, + rootDirectory, + `missing local target: ${reference}`, + ); + } else if (!(await exactCaseExists(rootDirectory, target))) { + fail( + errors, + cssFile, + rootDirectory, + `path case does not match the filesystem: ${reference}`, + ); + } + } catch (error) { + fail(errors, cssFile, rootDirectory, error.message); + } + } + } +} + +export async function runStaticChecks(rootDirectory) { + const errors = []; + const htmlFiles = await collectFiles(rootDirectory, new Set([".html"])); + const cssFiles = await collectFiles(rootDirectory, new Set([".css"])); + + const expectedLegacyPaths = [ + "Html5-Final-Project.html", + "assignment-1 2/index.html", + "assignment-1 2/history.html", + "assignment-1 2/teams.html", + "assignment-1 2/css/hw1.css", + "assignment-1 2/css/Mutual evaluation.css", + "assignment-1 2/css/hw1 - old.css", + "assignment-1 2/css/hw1 - old2.css", + "assignment-1 2/images/flywheel.jpg", + "styles-conference/index.html", + "styles-conference/speakers.html", + "styles-conference/schedule.html", + "styles-conference/venue.html", + "styles-conference/register.html", + "styles-conference/assets/stylesheets/main.css", + ]; + + for (const legacyPath of expectedLegacyPaths) { + if (!(await exists(path.join(rootDirectory, legacyPath)))) { + errors.push(`compatibility path is missing: ${legacyPath}`); + } + } + + const largestPage = await validateHtmlFiles(rootDirectory, htmlFiles, errors); + await validateCssFiles(rootDirectory, cssFiles, errors); + + return { + cssCount: cssFiles.length, + errors, + htmlCount: htmlFiles.length, + largestPage, + }; +} diff --git a/test/snapshots/conference-home.png b/test/snapshots/conference-home.png new file mode 100644 index 0000000..73ec124 Binary files /dev/null and b/test/snapshots/conference-home.png differ diff --git a/test/snapshots/gallery-dark.png b/test/snapshots/gallery-dark.png new file mode 100644 index 0000000..5e19a85 Binary files /dev/null and b/test/snapshots/gallery-dark.png differ diff --git a/test/snapshots/gallery-light.png b/test/snapshots/gallery-light.png new file mode 100644 index 0000000..b696a23 Binary files /dev/null and b/test/snapshots/gallery-light.png differ diff --git a/test/snapshots/registration-mobile.png b/test/snapshots/registration-mobile.png new file mode 100644 index 0000000..d120030 Binary files /dev/null and b/test/snapshots/registration-mobile.png differ diff --git a/test/snapshots/ultimate-home.png b/test/snapshots/ultimate-home.png new file mode 100644 index 0000000..f072558 Binary files /dev/null and b/test/snapshots/ultimate-home.png differ diff --git a/test/unit/registration.test.mjs b/test/unit/registration.test.mjs new file mode 100644 index 0000000..ff03fb0 --- /dev/null +++ b/test/unit/registration.test.mjs @@ -0,0 +1,26 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +await import("../../styles-conference/assets/scripts/register.js"); + +const { buildConfirmation, normalizeName, passLabels } = + globalThis.RegistrationDemo; + +test("normalizeName trims and collapses whitespace", () => { + assert.equal(normalizeName(" Demo Learner "), "Demo Learner"); +}); + +test("buildConfirmation uses a known pass label", () => { + assert.equal( + buildConfirmation("Demo Learner", "studios"), + "Demo complete for Demo Learner: Studio sessions. Nothing was sent or saved.", + ); +}); + +test("buildConfirmation falls back for an unknown pass", () => { + assert.match(buildConfirmation("Learner", "unknown"), /Demo pass/); +}); + +test("pass labels are immutable", () => { + assert.equal(Object.isFrozen(passLabels), true); +}); diff --git a/test/unit/static-checker.test.mjs b/test/unit/static-checker.test.mjs new file mode 100644 index 0000000..1c9ef03 --- /dev/null +++ b/test/unit/static-checker.test.mjs @@ -0,0 +1,28 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { + getAttribute, + isExternalReference, + splitReference, +} from "../scripts/static-checker.mjs"; + +test("splitReference separates paths, queries, and fragments", () => { + assert.deepEqual(splitReference("page.html?view=full#details"), { + fragment: "details", + pathname: "page.html", + }); +}); + +test("external reference detection covers web and mail links", () => { + assert.equal(isExternalReference("https://example.com"), true); + assert.equal(isExternalReference("mailto:demo@example.com"), true); + assert.equal(isExternalReference("../index.html"), false); +}); + +test("getAttribute reads single and double quoted values", () => { + assert.equal( + getAttribute(' href="index.html" class="home"', "href"), + "index.html", + ); + assert.equal(getAttribute(" src='app.js' defer", "src"), "app.js"); +});