diff --git a/.gitignore b/.gitignore index 7e741688..20916767 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,8 @@ src/static/* !src/static/bloblang-docs.json test-results.* test-results-*.* -.playwright-mcp/ \ No newline at end of file +.playwright-mcp/ + +# Test screenshots +*.png +!/src/img/*.png \ No newline at end of file diff --git a/WHATS-NEW-SYSTEM.md b/WHATS-NEW-SYSTEM.md new file mode 100644 index 00000000..24907710 --- /dev/null +++ b/WHATS-NEW-SYSTEM.md @@ -0,0 +1,194 @@ +# What's New System Documentation + +The What's New system allows components to define their latest features and have them displayed automatically on component landing pages and aggregated on the Data Platform umbrella page. + +## How It Works + +### For Component Writers + +Define What's New items in your **component's home/landing page** (e.g., `modules/ROOT/pages/index.adoc` or `antora.yml`): + +```asciidoc += Component Home Page + +// What's New Item 1 +:component-whats-new-1-title: Redpanda SQL +:component-whats-new-1-desc: Query your streaming data in real-time with SQL. Run analytical queries directly on topics without ETL. +:component-whats-new-1-link: sql:index.adoc +:component-whats-new-1-tag: Cloud BYOC + +// What's New Item 2 +:component-whats-new-2-title: Enhanced Monitoring +:component-whats-new-2-desc: New Grafana dashboards with real-time metrics +:component-whats-new-2-link: manage:monitoring.adoc +:component-whats-new-2-tag: All Tiers + +// Up to 10 items supported (component-whats-new-3-*, component-whats-new-4-*, etc.) +``` + +### Attribute Reference + +Each What's New item requires 4 attributes (where N = 1, 2, 3... up to 10): + +| Attribute | Required | Description | Example | +|-----------|----------|-------------|---------| +| `component-whats-new-N-title` | Yes | Feature title (short, punchy) | `Redpanda SQL` | +| `component-whats-new-N-desc` | Yes | Feature description (1-2 sentences) | `Query streaming data in real-time with SQL` | +| `component-whats-new-N-link` | Yes | Link to feature docs (Antora xref format) | `sql:index.adoc` | +| `component-whats-new-N-tag` | No | Badge text (platform/tier info) | `Cloud BYOC`, `Enterprise`, `All Tiers` | + +### Display Locations + +#### 1. Component Landing Pages (Automatic) + +The What's New section automatically appears on component landing pages that use the `component-home-v2` or `component-home-v3` layout. + +No template changes needed - just define the attributes and they'll show up! + +**Example components:** +- `cloud-data-platform/modules/ROOT/pages/index.adoc` +- `streaming/modules/home/pages/index.adoc` +- `connect/modules/ROOT/pages/index.adoc` + +#### 2. Data Platform Umbrella Page (Aggregated) + +The Data Platform home aggregates What's New from multiple components: + +In `data-platform/modules/ROOT/partials/data-platform.hbs`: +```handlebars +{{#with (aggregate-whats-new site "cloud-data-platform" "streaming" "connect")}} + {{> whats-new-section items=items}} +{{/with}} +``` + +This pulls items from each specified component and displays them together. + +## Technical Details + +### Helpers + +**`get-whats-new-items.js`** +- Reads `component-whats-new-*` attributes from current page +- Used automatically by component landing pages +- Returns: `{ items: [], componentName: string, hasItems: boolean }` + +**`aggregate-whats-new.js`** +- Collects What's New from multiple components +- Searches each component's home page for attributes +- Used by Data Platform umbrella page +- Returns: `{ items: [], hasItems: boolean }` + +Each item includes: +```javascript +{ + title: string, + desc: string, + link: string, // Antora resource reference + tag: string, // Optional badge text + componentName: string, + componentColor: string, // Hex color for styling + index: number +} +``` + +### Partial + +**`whats-new-section.hbs`** +- Reusable section template +- Supports both modes: + - Automatic (reads from current page) + - Aggregated (passed items array) + +### Styling + +Styles defined in `src/css/whats-new.css` (create this): +- `.whats-new-compact` - Main container +- `.whats-new-badge` - NEW badge +- `.whats-new-item` - Individual item card +- `.whats-new-tag` - Platform/tier badge + +## Examples + +### Cloud Component Home Page + +```asciidoc += Redpanda Cloud +:page-layout: component-home-v2 + +// What's New - displays automatically +:component-whats-new-1-title: Redpanda SQL +:component-whats-new-1-desc: Query streaming topics with real-time SQL analytics (BYOC only) +:component-whats-new-1-link: sql:index.adoc +:component-whats-new-1-tag: Cloud BYOC + +:component-whats-new-2-title: Serverless Autoscaling +:component-whats-new-2-desc: Automatic capacity adjustments based on workload +:component-whats-new-2-link: manage:autoscaling.adoc +:component-whats-new-2-tag: Serverless +``` + +### Streaming Component + +```asciidoc += Redpanda Streaming +:page-layout: component-home-v3 + +:component-whats-new-1-title: Kubernetes Operator 2.0 +:component-whats-new-1-desc: Enhanced scaling, monitoring, and Day 2 operations +:component-whats-new-1-link: deploy:kubernetes/operator.adoc + +:component-whats-new-2-title: ARM64 Support +:component-whats-new-2-desc: Run Redpanda natively on ARM64 processors +:component-whats-new-2-link: deploy:arm64.adoc +``` + +### Data Platform Umbrella + +The Data Platform page automatically shows items from all specified components: + +```handlebars +{{!-- In data-platform.hbs --}} +
+ {{#with (aggregate-whats-new site "cloud-data-platform" "streaming" "connect")}} + {{> whats-new-section items=items}} + {{/with}} +
+``` + +This will display SQL (from cloud), Kubernetes Operator (from streaming), and any Connect features together. + +## Best Practices + +1. **Keep titles short** - 2-4 words max +2. **Descriptions concise** - 1-2 sentences, focus on benefit +3. **Update regularly** - Remove old items when adding new ones +4. **Use clear tags** - Platform/tier information (Cloud BYOC, Enterprise, etc.) +5. **Link to docs** - Always provide a link to full documentation +6. **Limit items** - Show 1-3 most important features, not everything + +## Maintenance + +To remove an item, delete its attributes. The numbering doesn't need to be contiguous: + +```asciidoc +// This works fine - skipping 2 +:component-whats-new-1-title: Feature A +:component-whats-new-3-title: Feature C +``` + +But for clarity, keep them sequential when possible. + +## Troubleshooting + +**Q: My What's New section isn't showing** +- Check that attributes start with `component-whats-new-` (not `page-whats-new-`) +- Verify you have at least `-title`, `-desc`, and `-link` for item 1 +- Ensure the page uses a component home layout + +**Q: Attributes not found on Data Platform** +- Component home page must be at root (`index.adoc`) or in `home/` module +- Attributes must be defined in the page, not in navigation config + +**Q: Links broken** +- Use Antora resource syntax: `module:page.adoc` +- Links are relative to the component defining them diff --git a/context/header.json b/context/header.json index a3771ac8..a2fa90c2 100644 --- a/context/header.json +++ b/context/header.json @@ -6,13 +6,13 @@ }, "homeUrl": "/", "components": { - "redpanda-labs": { + "labs": { "latest": { "title": "Labs", - "url": "/redpanda-labs/", + "url": "/labs/", "asciidoc": { "attributes": { - "page-header-data": { + "component-metadata": { "order": 4 } } @@ -25,38 +25,39 @@ "url": "/api/" } }, - "redpanda-cloud": { + "cloud-data-platform": { "latest": { "title": "Cloud", - "url": "/redpanda-cloud/home/", + "url": "/cloud-data-platform/home/", "asciidoc": { "attributes": { - "page-header-data": { - "order": 1 } + "component-metadata": { + "order": 1 + } } } } }, - "redpanda-connect": { + "connect": { "latest": { "title": "Connect", - "url": "/redpanda-connect/home/", + "url": "/connect/home/", "asciidoc": { "attributes": { - "page-header-data": { + "component-metadata": { "order": 3 } } } } }, - "ROOT": { + "streaming": { "latest": { - "title": "Self-Managed", + "title": "Streaming", "url": "/current/home/", "asciidoc": { "attributes": { - "page-header-data": { + "component-metadata": { "order": 2 } } @@ -72,8 +73,8 @@ "latest": { "asciidoc": { "attributes": { - "page-header-data": { - "color": "#d73d23" + "component-metadata": { + "color": "#4338ca" } } } @@ -82,4 +83,3 @@ }, "uiRootPath": "/_" } - diff --git a/debug-snapshot.md b/debug-snapshot.md new file mode 100644 index 00000000..9997aacc --- /dev/null +++ b/debug-snapshot.md @@ -0,0 +1,292 @@ +- generic [active] [ref=e1]: + - banner: + - navigation [ref=e2]: + - navigation "breadcrumbs" [ref=e4]: + - list [ref=e5]: + - listitem [ref=e6]: + - link "Go to home page" [ref=e7] [cursor=pointer]: + - /url: ./ + - text: Docs + - listitem [ref=e8]: + - link "Data Platform" [ref=e9] [cursor=pointer]: + - /url: ./ + - generic [ref=e11]: + - button "Ask Redpanda AI" [ref=e12] [cursor=pointer]: + - img [ref=e13] + - generic [ref=e15]: Ask AI + - generic [ref=e16]: + - button "Ask a Human" [ref=e18] [cursor=pointer]: + - text: Ask a Human + - img [ref=e19] + - link "Log into Cloud" [ref=e21] [cursor=pointer]: + - /url: https://cloud.redpanda.com + - generic [ref=e22]: Log into Cloud + - img [ref=e23] + - link "Labs" [ref=e26] [cursor=pointer]: + - /url: /labs + - button "Switch between dark and light mode" [ref=e28] [cursor=pointer] + - generic [ref=e29]: + - complementary [ref=e31]: + - link "Go to home page" [ref=e33] [cursor=pointer]: + - /url: ./ + - img "Redpanda" [ref=e35] + - generic [ref=e36]: + - generic [ref=e37]: Redpanda + - generic [ref=e38]: Documentation + - button "Search docs" [ref=e39] [cursor=pointer]: + - img [ref=e40] + - generic [ref=e43]: Search docs + - button "Data Platform" [ref=e45] [cursor=pointer]: + - generic [ref=e46]: Data Platform + - img [ref=e47] + - navigation [ref=e51]: + - generic [ref=e53]: + - link "Cloud" [ref=e54] [cursor=pointer]: + - /url: /cloud-data-platform/home/ + - img [ref=e56] + - generic [ref=e58]: Cloud + - button [ref=e59] [cursor=pointer]: + - img [ref=e60] + - generic [ref=e63]: + - link "Self-Managed" [ref=e64] [cursor=pointer]: + - /url: /self-managed/ + - img [ref=e66] + - generic [ref=e69]: Self-Managed + - button [ref=e70] [cursor=pointer]: + - img [ref=e71] + - generic [ref=e73]: + - button "Toggle light/dark mode" [ref=e74] [cursor=pointer]: + - img [ref=e75] + - button "Collapse sidebar" [ref=e81] [cursor=pointer]: + - img [ref=e82] + - main [ref=e85]: + - generic [ref=e87]: + - generic [ref=e89]: + - generic [ref=e91]: REDPANDA DATA PLATFORM + - heading "The streaming foundation for everything you build." [level=1] [ref=e92]: + - text: The streaming foundation + - text: for everything you build. + - paragraph [ref=e93]: Run Redpanda on your infrastructure or let us manage it in the cloud. Then connect it to everything else with declarative pipelines. + - generic [ref=e94]: + - img [ref=e96] + - textbox "Ask AI about Redpanda..." [ref=e99] + - button "Ask" [ref=e100] [cursor=pointer]: + - img [ref=e101] + - generic [ref=e103]: + - generic [ref=e104]: + - strong [ref=e105]: 10x + - generic [ref=e106]: faster than Kafka, same wire + - generic [ref=e107]: + - strong [ref=e108]: 200+ + - generic [ref=e109]: connectors + - generic [ref=e110]: + - generic [ref=e111]: + - generic [ref=e112]: + - heading "What's new" [level=2] [ref=e113] + - paragraph [ref=e114]: Latest features and capabilities across the Data Platform. + - link "NEW Redpanda SQL Query your streaming data in real-time with SQL. Run analytical queries directly on topics without ETL (BYOC clusters only). Cloud BYOC" [ref=e116] [cursor=pointer]: + - /url: ../cloud-data-platform/sql/ + - generic [ref=e117]: NEW + - generic [ref=e118]: + - heading "Redpanda SQL" [level=4] [ref=e119] + - paragraph [ref=e120]: Query your streaming data in real-time with SQL. Run analytical queries directly on topics without ETL (BYOC clusters only). + - generic [ref=e121]: Cloud BYOC + - img [ref=e122] + - generic [ref=e124]: + - generic [ref=e125]: + - heading "Choose how you'll run Redpanda" [level=2] [ref=e126] + - paragraph [ref=e127]: Self-Managed or Cloud — same Kafka-compatible engine, different operations model. Both include Redpanda Connect for building data pipelines. + - generic [ref=e128]: + - link "Cloud Streaming, fully managed. Spin up a cluster in minutes. We handle upgrades, scaling, and failover — you bring the data. Available as Dedicated, Serverless, or Bring Your Own Cloud. Provisioned in 90 seconds AWS, GCP, Azure 24/7 SRE on call 99.99% SLA on Dedicated BYOC Run in your VPC Open Cloud docs" [ref=e129] [cursor=pointer]: + - /url: ../cloud-data-platform/home/ + - generic [ref=e131]: + - heading "Cloud" [level=3] [ref=e132] + - paragraph [ref=e133]: Streaming, fully managed. + - paragraph [ref=e134]: Spin up a cluster in minutes. We handle upgrades, scaling, and failover — you bring the data. Available as Dedicated, Serverless, or Bring Your Own Cloud. + - list [ref=e135]: + - listitem [ref=e136]: + - generic [ref=e137]: Provisioned in 90 seconds + - listitem [ref=e138]: + - generic [ref=e139]: AWS, GCP, Azure + - listitem [ref=e140]: + - generic [ref=e141]: 24/7 SRE on call + - generic [ref=e142]: + - generic [ref=e143]: + - strong [ref=e144]: 99.99% + - generic [ref=e145]: SLA on Dedicated + - generic [ref=e146]: + - strong [ref=e147]: BYOC + - generic [ref=e148]: Run in your VPC + - generic [ref=e149]: + - generic [ref=e150]: Open Cloud docs + - img [ref=e151] + - link "Self-Managed Run Redpanda on your own infrastructure. Bare metal, VMs, or Kubernetes. Full control over networking, storage, and upgrades — with the same single binary used in Cloud. Single binary, no JVM Air-gapped & FedRAMP-ready Tune every knob K8s Operator + Helm Open Self-Managed docs" [ref=e153] [cursor=pointer]: + - /url: ../streaming/current/home/ + - generic [ref=e155]: + - heading "Self-Managed" [level=3] [ref=e156] + - paragraph [ref=e157]: Run Redpanda on your own infrastructure. + - paragraph [ref=e158]: Bare metal, VMs, or Kubernetes. Full control over networking, storage, and upgrades — with the same single binary used in Cloud. + - list [ref=e159]: + - listitem [ref=e160]: + - generic [ref=e161]: Single binary, no JVM + - listitem [ref=e162]: + - generic [ref=e163]: Air-gapped & FedRAMP-ready + - listitem [ref=e164]: + - generic [ref=e165]: Tune every knob + - generic [ref=e167]: + - strong [ref=e168]: K8s + - generic [ref=e169]: Operator + Helm + - generic [ref=e170]: + - generic [ref=e171]: Open Self-Managed docs + - img [ref=e172] + - generic [ref=e174]: + - generic [ref=e175]: + - heading "Not sure which to pick?" [level=2] [ref=e176] + - paragraph [ref=e177]: A quick decision matrix — most teams start with one of these two options. + - generic [ref=e178]: + - generic [ref=e179]: + - paragraph [ref=e180]: Full control over networking, storage, and security posture + - list [ref=e181]: + - listitem [ref=e182]: + - img [ref=e183] + - generic [ref=e185]: Run on your infrastructure + - listitem [ref=e186]: + - img [ref=e187] + - generic [ref=e189]: Air-gapped & FedRAMP-ready + - listitem [ref=e190]: + - img [ref=e191] + - generic [ref=e193]: Tune every configuration + - link "Start with Self-Managed" [ref=e194] [cursor=pointer]: + - /url: ../streaming/current/home/ + - generic [ref=e195]: Start with Self-Managed + - img [ref=e196] + - generic [ref=e198]: or + - generic [ref=e199]: + - paragraph [ref=e200]: Streaming as a service with an SLA and zero ops + - list [ref=e201]: + - listitem [ref=e202]: + - img [ref=e203] + - generic [ref=e205]: Provisioned in 90 seconds + - listitem [ref=e206]: + - img [ref=e207] + - generic [ref=e209]: Automatic scaling & upgrades + - listitem [ref=e210]: + - img [ref=e211] + - generic [ref=e213]: 24/7 SRE on call + - link "Start with Cloud" [ref=e214] [cursor=pointer]: + - /url: ../cloud-data-platform/home/ + - generic [ref=e215]: Start with Cloud + - img [ref=e216] + - generic [ref=e218]: + - generic [ref=e219]: + - heading "Popular across Data Platform" [level=2] [ref=e220] + - paragraph [ref=e221]: The guides teams open most when they're getting started. + - generic [ref=e222]: + - link "Deploy a Kafka-compatible cluster Self-Managed" [ref=e223] [cursor=pointer]: + - /url: ../streaming/current/get-started/quick-start/ + - generic [ref=e224]: + - heading "Deploy a Kafka-compatible cluster" [level=4] [ref=e225] + - generic [ref=e227]: Self-Managed + - img [ref=e228] + - link "Tiered storage on S3 Self-Managed" [ref=e230] [cursor=pointer]: + - /url: ../streaming/current/manage/tiered-storage/ + - generic [ref=e231]: + - heading "Tiered storage on S3" [level=4] [ref=e232] + - generic [ref=e234]: Self-Managed + - img [ref=e235] + - link "Create your first BYOC cluster Cloud" [ref=e237] [cursor=pointer]: + - /url: ../cloud-data-platform/get-started/cluster-types/byoc/ + - generic [ref=e238]: + - heading "Create your first BYOC cluster" [level=4] [ref=e239] + - generic [ref=e241]: Cloud + - img [ref=e242] + - link "Connect Postgres CDC to Snowflake Connect" [ref=e244] [cursor=pointer]: + - /url: ../connect/get-started/quickstarts/ + - generic [ref=e245]: + - heading "Connect Postgres CDC to Snowflake" [level=4] [ref=e246] + - generic [ref=e248]: Connect + - img [ref=e249] + - link "Migrate from Apache Kafka All" [ref=e251] [cursor=pointer]: + - /url: "#" + - generic [ref=e252]: + - heading "Migrate from Apache Kafka" [level=4] [ref=e253] + - generic [ref=e255]: All + - img [ref=e256] + - link "Schema Registry & validation All" [ref=e258] [cursor=pointer]: + - /url: "#" + - generic [ref=e259]: + - heading "Schema Registry & validation" [level=4] [ref=e260] + - generic [ref=e262]: All + - img [ref=e263] + - generic [ref=e265]: + - generic [ref=e266]: + - heading "Core concepts" [level=2] [ref=e267] + - paragraph [ref=e268]: The mental model that applies everywhere — Self-Managed, Cloud, and Connect. + - generic [ref=e269]: + - link "Topics & partitions How Redpanda lays out data on disk and parallelizes reads." [ref=e270] [cursor=pointer]: + - /url: ../streaming/current/develop/produce-data/configure-producers/ + - img [ref=e272] + - heading "Topics & partitions" [level=4] [ref=e274] + - paragraph [ref=e275]: How Redpanda lays out data on disk and parallelizes reads. + - link "Tiered storage Offload cold segments to S3-compatible storage automatically." [ref=e276] [cursor=pointer]: + - /url: ../streaming/current/manage/tiered-storage/ + - img [ref=e278] + - heading "Tiered storage" [level=4] [ref=e280] + - paragraph [ref=e281]: Offload cold segments to S3-compatible storage automatically. + - link "Consumer groups Coordinated, fault-tolerant consumption across many workers." [ref=e282] [cursor=pointer]: + - /url: ../streaming/current/develop/consume-data/consumer-offsets/ + - img [ref=e284] + - heading "Consumer groups" [level=4] [ref=e289] + - paragraph [ref=e290]: Coordinated, fault-tolerant consumption across many workers. + - link "Schemas & contracts Validate every message at the broker with Avro, Protobuf, or JSON Schema." [ref=e291] [cursor=pointer]: + - /url: "#" + - img [ref=e293] + - heading "Schemas & contracts" [level=4] [ref=e295] + - paragraph [ref=e296]: Validate every message at the broker with Avro, Protobuf, or JSON Schema. + - generic [ref=e297]: + - generic [ref=e298]: + - heading "Need help choosing?" [level=3] [ref=e299] + - paragraph [ref=e300]: Our team can walk you through the options and help you get started. + - generic [ref=e301]: + - link "Talk to sales" [ref=e302] [cursor=pointer]: + - /url: https://redpanda.com/contact + - link "Join Slack" [ref=e303] [cursor=pointer]: + - /url: https://redpanda.com/slack + - complementary [ref=e304]: + - generic [ref=e305]: + - generic [ref=e306]: + - img [ref=e308] + - generic [ref=e310]: + - generic [ref=e311]: Redpanda AI + - generic [ref=e312]: Ask about any doc + - button [ref=e314] [cursor=pointer]: + - img [ref=e315] + - generic [ref=e321]: + - generic [ref=e322]: + - img [ref=e324] + - heading [level=2] [ref=e326]: How can I help? + - paragraph [ref=e327]: I can answer questions about Redpanda docs, write quickstarts, and help you troubleshoot. + - generic [ref=e328]: + - button [ref=e329] [cursor=pointer]: How do I build my first agent? + - button [ref=e330] [cursor=pointer]: Set up MCP with Postgres + - button [ref=e331] [cursor=pointer]: Rotate an API key safely + - button [ref=e332] [cursor=pointer]: What's a token budget? + - generic [ref=e333]: + - generic [ref=e335]: + - generic [ref=e336]: Ask a question about Redpanda + - textbox [ref=e337]: + - /placeholder: Ask anything about Redpanda docs... + - button [disabled] [ref=e338] + - generic [ref=e340]: + - paragraph [ref=e341]: + - text: Review the + - link [ref=e342] [cursor=pointer]: + - /url: https://www.redpanda.com/legal/privacy-policy + - text: Redpanda privacy policy + - text: to understand how your data is used. + - paragraph [ref=e343]: + - text: Powered by + - link [ref=e344] [cursor=pointer]: + - /url: https://kapa.ai + - text: kapa.ai + - generic [ref=e320]: AI answers may be imprecise. Always verify in the docs. \ No newline at end of file diff --git a/gulp.d/tasks/build-preview-pages.js b/gulp.d/tasks/build-preview-pages.js index 258f74db..795c75cc 100644 --- a/gulp.d/tasks/build-preview-pages.js +++ b/gulp.d/tasks/build-preview-pages.js @@ -18,7 +18,14 @@ module.exports = (src, previewSrc, previewDest, sink = () => map()) => (done) => Promise.all([ loadSampleUiModel(previewSrc), toPromise( - merge(compileLayouts(src), registerPartials(src), registerHelpers(src), registerVendorsCss(src), registerVendorsJs(src), copyImages(previewSrc, previewDest)) + merge( + compileLayouts(src), + registerPartials(src), + registerHelpers(src), + registerVendorsCss(src), + registerVendorsJs(src), + copyImages(previewSrc, previewDest) + ) ), ]) .then(([baseUiModel, { layouts }]) => { diff --git a/gulp.d/tasks/build.js b/gulp.d/tasks/build.js index 523aa892..cb3659a6 100644 --- a/gulp.d/tasks/build.js +++ b/gulp.d/tasks/build.js @@ -47,7 +47,7 @@ module.exports = (src, dest, preview) => () => { }, }, ]), - postcssVar({ preserve: preview }), + postcssVar({ preserve: true }), // NOTE to make vars.css available to all top-level stylesheets, use the next line in place of the previous one //postcssVar({ importFrom: path.join(src, 'css', 'vars.css'), preserve: preview }), preview ? postcssCalc : () => {}, // cssnano already applies postcssCalc @@ -82,7 +82,7 @@ module.exports = (src, dest, preview) => () => { vfs .src(['css/site.css', 'css/vendor/*.css'], { ...opts, sourcemaps }) .pipe(postcss((file) => ({ plugins: postcssPlugins, options: { file } }))), - vfs.src('font/*.{ttf,woff*(2)}', opts), + vfs.src('font/**/*.{ttf,woff*(2)}', opts), vfs.src('img/**/*.{gif,ico,jpg,png,svg}', opts).pipe( preview ? through() @@ -103,13 +103,16 @@ module.exports = (src, dest, preview) => () => { ), vfs.src('css/vendor/**/*.css', opts), // Copy remaining vendor JS files (excluding already minified/processed ones) - vfs.src([ - 'js/vendor/**/*.js', - '!js/vendor/prism/prism-line-highlight-plugin.js', - '!js/vendor/prism/prism-line-numbers-plugin.js', - '!js/vendor/*.bundle.js', - '!js/vendor/*.min.js', - ], opts), + vfs.src( + [ + 'js/vendor/**/*.js', + '!js/vendor/prism/prism-line-highlight-plugin.js', + '!js/vendor/prism/prism-line-numbers-plugin.js', + '!js/vendor/*.bundle.js', + '!js/vendor/*.min.js', + ], + opts + ), vfs.src('helpers/*.js', opts), vfs.src('layouts/*.hbs', opts), vfs.src('partials/*.hbs', opts), diff --git a/gulp.d/tasks/generate-bloblang-grammar.js b/gulp.d/tasks/generate-bloblang-grammar.js index 3edf0431..572a0464 100644 --- a/gulp.d/tasks/generate-bloblang-grammar.js +++ b/gulp.d/tasks/generate-bloblang-grammar.js @@ -22,7 +22,9 @@ function fetchText (url) { return } let data = '' - res.on('data', (chunk) => { data += chunk }) + res.on('data', (chunk) => { + data += chunk + }) res.on('end', () => resolve(data)) }) req.on('error', reject) diff --git a/gulpfile.js b/gulpfile.js index 1d006441..819b1863 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -137,7 +137,15 @@ const buildWasmTask = createTask({ const bundleBuildTask = createTask({ name: 'bundle:build', - call: series(cleanTask, lintTask, generateBloblangGrammarTask, buildWasmTask, bundleReactTask, compileWidgets, buildTask), + call: series( + cleanTask, + lintTask, + generateBloblangGrammarTask, + buildWasmTask, + bundleReactTask, + compileWidgets, + buildTask + ), }) const bundlePackTask = createTask({ @@ -176,7 +184,9 @@ const previewBuildTask = createTask({ const previewServeTask = createTask({ name: 'preview:serve', - call: task.serve(previewDestDir, serverConfig, () => watch([`${srcDir}/**/*`, `${previewSrcDir}/**/*`, `!${srcDir}/static/**`], previewBuildTask)), + call: task.serve(previewDestDir, serverConfig, () => + watch([`${srcDir}/**/*`, `${previewSrcDir}/**/*`, `!${srcDir}/static/**`], previewBuildTask) + ), }) const previewTask = createTask({ diff --git a/package-lock.json b/package-lock.json index 8125294a..eb4a2f0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -71,6 +71,22 @@ "node": ">= 18.0.0" } }, + "node_modules/@algolia/abtesting": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.18.0.tgz", + "integrity": "sha512-8siuLG+FIns1AjZ/g2SDVwHz9S+ObacDQISEJvS8XsNei1zl3FXqfqQrBpmrG7ACWCyesXHbicMJtvRbg00FEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/@algolia/autocomplete-core": { "version": "1.17.9", "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.9.tgz", @@ -96,9 +112,9 @@ } }, "node_modules/@algolia/autocomplete-plugin-tags": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-tags/-/autocomplete-plugin-tags-1.19.2.tgz", - "integrity": "sha512-LhH09Uuu46QLanfAUhYaRO2+gvyBbwxyiG4eA1IpZltxVgRnPnAPpqZAn8QytOhmeYQozHcwavYWNpS2dqZQSA==", + "version": "1.19.8", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-tags/-/autocomplete-plugin-tags-1.19.8.tgz", + "integrity": "sha512-e7eqfRmHNdkcKOl3Lkx0vIg8ghR7j03FkXNXnsK5Vjx0CTLHQwn8oU4bLZ1//Ov85oHif5OVvT1OMMjWrKlkLA==", "dev": true, "license": "MIT" }, @@ -128,41 +144,41 @@ } }, "node_modules/@algolia/client-abtesting": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.30.0.tgz", - "integrity": "sha512-Q3OQXYlTNqVUN/V1qXX8VIzQbLjP3yrRBO9m6NRe1CBALmoGHh9JrYosEGvfior28+DjqqU3Q+nzCSuf/bX0Gw==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.52.0.tgz", + "integrity": "sha512-wtwPgyPmO7b7sQPVgoK29c1VpfS08DnnJCmxX/oU1pV2DlMRJCzQcLN7JSloYpodyKHwM8+9wOzlAM0co3TDmA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.30.0", - "@algolia/requester-browser-xhr": "5.30.0", - "@algolia/requester-fetch": "5.30.0", - "@algolia/requester-node-http": "5.30.0" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-analytics": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.30.0.tgz", - "integrity": "sha512-/b+SAfHjYjx/ZVeVReCKTTnFAiZWOyvYLrkYpeNMraMT6akYRR8eC1AvFcvR60GLG/jytxcJAp42G8nN5SdcLg==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.52.0.tgz", + "integrity": "sha512-9KY36bRl4AH7RjqSeDDOKnjsz4IxQFBEOB8/fWmEbdQe+Isbs5jGzVJu9NEPQ1Tgwxlf8Uf07Swj3jZyMNUZ2g==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.30.0", - "@algolia/requester-browser-xhr": "5.30.0", - "@algolia/requester-fetch": "5.30.0", - "@algolia/requester-node-http": "5.30.0" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-common": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.30.0.tgz", - "integrity": "sha512-tbUgvkp2d20mHPbM0+NPbLg6SzkUh0lADUUjzNCF+HiPkjFRaIW3NGMlESKw5ia4Oz6ZvFzyREquUX6rdkdJcQ==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.52.0.tgz", + "integrity": "sha512-3a/qM3dzJqqfTx7Yrw7uGQ98I3Q0rDfb4Vkv0wEzko96l7YQMxfBVz/VbLq2N+c59GweYv6Vhp8mPeqnWJSITw==", "dev": true, "license": "MIT", "engines": { @@ -170,179 +186,165 @@ } }, "node_modules/@algolia/client-insights": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.30.0.tgz", - "integrity": "sha512-caXuZqJK761m32KoEAEkjkE2WF/zYg1McuGesWXiLSgfxwZZIAf+DljpiSToBUXhoPesvjcLtINyYUzbkwE0iw==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.52.0.tgz", + "integrity": "sha512-Rki7ACbMcvbQW0BuM84x9dkGHY47ABmv4jU6tYssat2k02p3mIUms2YOLUAMeknhmnFsj6lb6ZzOXdMWMyc1sA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.30.0", - "@algolia/requester-browser-xhr": "5.30.0", - "@algolia/requester-fetch": "5.30.0", - "@algolia/requester-node-http": "5.30.0" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-personalization": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.30.0.tgz", - "integrity": "sha512-7K6P7TRBHLX1zTmwKDrIeBSgUidmbj6u3UW/AfroLRDGf9oZFytPKU49wg28lz/yulPuHY0nZqiwbyAxq9V17w==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.52.0.tgz", + "integrity": "sha512-96s4Uzc3kk+/f4jJXIVVGWP5XlngOGNQ1x6hW9AT59pOixHlOs5tqJg+ZUS/GQ6h/iYP0ceQcmxDQeLyCLTaDQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.30.0", - "@algolia/requester-browser-xhr": "5.30.0", - "@algolia/requester-fetch": "5.30.0", - "@algolia/requester-node-http": "5.30.0" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-query-suggestions": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.30.0.tgz", - "integrity": "sha512-WMjWuBjYxJheRt7Ec5BFr33k3cV0mq2WzmH9aBf5W4TT8kUp34x91VRsYVaWOBRlxIXI8o/WbhleqSngiuqjLA==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.52.0.tgz", + "integrity": "sha512-lqeycNpSPe5Qa0OUWpejVvYQjQWV5nQuLT0a4aq7XzRAvCxprV/6Lf841EygdD2nrFnuS58ok7Au1uOtXzpnkg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.30.0", - "@algolia/requester-browser-xhr": "5.30.0", - "@algolia/requester-fetch": "5.30.0", - "@algolia/requester-node-http": "5.30.0" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.30.0.tgz", - "integrity": "sha512-puc1/LREfSqzgmrOFMY5L/aWmhYOlJ0TTpa245C0ZNMKEkdOkcimFbXTXQ8lZhzh+rlyFgR7cQGNtXJ5H0XgZg==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.52.0.tgz", + "integrity": "sha512-ly1wETVGRo30cx61O7fetESN+ElL9c9K+bD/AVgnT1ar4c6v+/Yqjrhdtu6Fm4D0s4NZP081Isf6tunH1wUXHg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.30.0", - "@algolia/requester-browser-xhr": "5.30.0", - "@algolia/requester-fetch": "5.30.0", - "@algolia/requester-node-http": "5.30.0" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/ingestion": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.30.0.tgz", - "integrity": "sha512-NfqiIKVgGKTLr6T9F81oqB39pPiEtILTy0z8ujxPKg2rCvI/qQeDqDWFBmQPElCfUTU6kk67QAgMkQ7T6fE+gg==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.52.0.tgz", + "integrity": "sha512-U4EeTvgmluRjj39ykZSAd5X+a6LD5m7/mcOWDmB7hqm1R6QY0yT8jLxpNVEjYhzgEN5hcDGW6X67EWQY8KiYGQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.30.0", - "@algolia/requester-browser-xhr": "5.30.0", - "@algolia/requester-fetch": "5.30.0", - "@algolia/requester-node-http": "5.30.0" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/monitoring": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.30.0.tgz", - "integrity": "sha512-/eeM3aqLKro5KBZw0W30iIA6afkGa+bcpvEM0NDa92m5t3vil4LOmJI9FkgzfmSkF4368z/SZMOTPShYcaVXjA==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.52.0.tgz", + "integrity": "sha512-FCPnDcILfpTE94u7BVlV4DmnSV5wE3+j25EEF+3dYPrVzkVCSoAHs318oWDGxnxsAgiL4HpL12Jc4XHmw9shpA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.30.0", - "@algolia/requester-browser-xhr": "5.30.0", - "@algolia/requester-fetch": "5.30.0", - "@algolia/requester-node-http": "5.30.0" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/recommend": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.30.0.tgz", - "integrity": "sha512-iWeAUWqw+xT+2IyUyTqnHCK+cyCKYV5+B6PXKdagc9GJJn6IaPs8vovwoC0Za5vKCje/aXQ24a2Z1pKpc/tdHg==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.52.0.tgz", + "integrity": "sha512-br3DO7n4N8CXwTRbZS0MnB4WQ9YHfNjCwkCEzVR/wek/qNTDQKDb0nROmkFaNZ8ucUqUVKZi074dbwMwRDlK8Q==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.30.0", - "@algolia/requester-browser-xhr": "5.30.0", - "@algolia/requester-fetch": "5.30.0", - "@algolia/requester-node-http": "5.30.0" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.30.0.tgz", - "integrity": "sha512-alo3ly0tdNLjfMSPz9dmNwYUFHx7guaz5dTGlIzVGnOiwLgIoM6NgA+MJLMcH6e1S7OpmE2AxOy78svlhst2tQ==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.52.0.tgz", + "integrity": "sha512-b0T/Ca2c9KyEslKsVrGZvbe1UrrKKSdfXhBZ2pbpKahFUzJfziRZ0urbOm7V65O0tO/jwU+Lo/+bIiiyhzGt8w==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.30.0" + "@algolia/client-common": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-fetch": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.30.0.tgz", - "integrity": "sha512-WOnTYUIY2InllHBy6HHMpGIOo7Or4xhYUx/jkoSK/kPIa1BRoFEHqa8v4pbKHtoG7oLvM2UAsylSnjVpIhGZXg==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.52.0.tgz", + "integrity": "sha512-ozBT8J/mtD4H4IAojw8QPirlcL2gHrI1BGuZ4/ZXXO/rTE1yQ4VIPJj4mTTbwo4FbkS1MoJsD/DsrqLzhnc4/g==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.30.0" + "@algolia/client-common": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-node-http": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.30.0.tgz", - "integrity": "sha512-uSTUh9fxeHde1c7KhvZKUrivk90sdiDftC+rSKNFKKEU9TiIKAGA7B2oKC+AoMCqMymot1vW9SGbeESQPTZd0w==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.52.0.tgz", + "integrity": "sha512-gyyWcLD22tnabmoit4iukCXuoRc5HYJuUjPSEa8a0D/f/NlRafpWi52AlAaa4Uu/rsl7saHsJFTNjTptWbu2+A==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.30.0" + "@algolia/client-common": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@asciidoctor/core": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/@asciidoctor/core/-/core-2.2.8.tgz", - "integrity": "sha512-oozXk7ZO1RAd/KLFLkKOhqTcG4GO3CV44WwOFg2gMcCsqCUTarvMT7xERIoWW2WurKbB0/ce+98r01p8xPOlBw==", + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/@asciidoctor/core/-/core-2.2.9.tgz", + "integrity": "sha512-tIPRHo1T2SFmAm+j77cDsj0RuaszP7xJxsaVTTAF5CwKyTbazw9TnIVlpIWM5yWfIWAWcAZy92RcnPgMJwny1w==", "dev": true, "license": "MIT", "dependencies": { - "asciidoctor-opal-runtime": "0.3.3", - "unxhr": "1.0.1" + "asciidoctor-opal-runtime": "0.3.4", + "unxhr": "~1.2" }, "engines": { "node": ">=8.11", @@ -361,13 +363,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -376,9 +378,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", - "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", + "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", "dev": true, "license": "MIT", "engines": { @@ -386,22 +388,22 @@ } }, "node_modules/@babel/core": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", - "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.0", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.27.3", - "@babel/helpers": "^7.27.6", - "@babel/parser": "^7.28.0", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.0", - "@babel/types": "^7.28.0", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -417,14 +419,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", - "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.0", - "@babel/types": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -447,13 +449,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.2", + "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", @@ -464,18 +466,18 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz", - "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.3.tgz", + "integrity": "sha512-RpLYy2sb51oNLjuu1iD3bwBqCBWUzjO0ocp+iaCP/lJtb2CPLcnC2Fftw+4sAzaMELGeWTgExSKADbdo0GFVzA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-replace-supers": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.27.1", + "@babel/traverse": "^7.29.0", "semver": "^6.3.1" }, "engines": { @@ -486,14 +488,14 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", - "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", + "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "regexpu-core": "^6.2.0", + "@babel/helper-annotate-as-pure": "^7.27.3", + "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "engines": { @@ -504,17 +506,17 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", - "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", + "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "debug": "^4.4.1", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", "lodash.debounce": "^4.0.8", - "resolve": "^1.22.10" + "resolve": "^1.22.11" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -531,43 +533,43 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", - "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", - "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.3" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -590,9 +592,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "dev": true, "license": "MIT", "engines": { @@ -618,15 +620,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", + "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -660,9 +662,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, "license": "MIT", "engines": { @@ -680,42 +682,42 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", - "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz", + "integrity": "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.1", - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", - "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.27.6" + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", - "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.0" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -725,14 +727,14 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", - "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", + "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -773,6 +775,23 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.3.tgz", + "integrity": "sha512-SRS46DFR4HqzUzCVgi90/xMoL+zeBDBvWdKYXSEzh79kXswNFEglUpMKxR04//dPqwYXWUBJ3mpUd933ru9Kmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", @@ -792,14 +811,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.27.1.tgz", - "integrity": "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz", + "integrity": "sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -822,13 +841,13 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", - "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz", + "integrity": "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -838,13 +857,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -854,13 +873,13 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -903,15 +922,15 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", - "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz", + "integrity": "sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.29.0" }, "engines": { "node": ">=6.9.0" @@ -921,14 +940,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", - "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", + "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-remap-async-to-generator": "^7.27.1" }, "engines": { @@ -955,13 +974,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.0.tgz", - "integrity": "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz", + "integrity": "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -971,14 +990,14 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", - "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", + "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -988,14 +1007,14 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.27.1.tgz", - "integrity": "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz", + "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1005,18 +1024,18 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.0.tgz", - "integrity": "sha512-IjM1IoJNw72AZFlj33Cu8X0q2XK/6AaVC3jQu+cgQ5lThWD5ajnuUAml80dqRmOhmPkTH8uAwnpMu9Rvj0LTRA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz", + "integrity": "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.0" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1026,14 +1045,14 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", - "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz", + "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/template": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/template": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1043,14 +1062,14 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", - "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1060,14 +1079,14 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", - "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz", + "integrity": "sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1093,14 +1112,14 @@ } }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.0.tgz", + "integrity": "sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1126,14 +1145,14 @@ } }, "node_modules/@babel/plugin-transform-explicit-resource-management": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", - "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz", + "integrity": "sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1143,13 +1162,13 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", - "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz", + "integrity": "sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1210,13 +1229,13 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", - "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz", + "integrity": "sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1242,13 +1261,13 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", - "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz", + "integrity": "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1291,14 +1310,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", - "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", + "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1308,16 +1327,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", - "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.0.tgz", + "integrity": "sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.29.0" }, "engines": { "node": ">=6.9.0" @@ -1344,14 +1363,14 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.0.tgz", + "integrity": "sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1377,13 +1396,13 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", - "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz", + "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1393,13 +1412,13 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", - "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz", + "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1409,17 +1428,17 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.0.tgz", - "integrity": "sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz", + "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1446,13 +1465,13 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", - "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz", + "integrity": "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1462,13 +1481,13 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", - "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz", + "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { @@ -1495,14 +1514,14 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", - "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz", + "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1512,15 +1531,15 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", - "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz", + "integrity": "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1562,17 +1581,17 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz", - "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.28.6.tgz", + "integrity": "sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-syntax-jsx": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1615,13 +1634,13 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.0.tgz", - "integrity": "sha512-LOAozRVbqxEVjSKfhGnuLoE4Kz4Oc5UJzuvFUhSsQzdCdaAQu06mG8zDv2GFSerM62nImUZ7K92vxnQcLSDlCQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.0.tgz", + "integrity": "sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1631,14 +1650,14 @@ } }, "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", - "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz", + "integrity": "sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1680,13 +1699,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", - "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz", + "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { @@ -1761,14 +1780,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", - "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz", + "integrity": "sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1795,14 +1814,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", - "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz", + "integrity": "sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1812,81 +1831,82 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.0.tgz", - "integrity": "sha512-VmaxeGOwuDqzLl5JUkIRM1X2Qu2uKGxHEQWh+cvvbl7JuJRgKGJSfsEF/bUaxFhJl/XAyxBe7q7qSuTbKFuCyg==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.3.tgz", + "integrity": "sha512-ySZypNLAIH1ClygLDQzVMoGQRViATnkHkYYV6TcNDz+8+jwZCdsguGvsb3EY5d9wyWyhmF1iSuFM0Yh5XPnqSA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.0", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/compat-data": "^7.29.3", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.3", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.27.1", - "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-import-assertions": "^7.28.6", + "@babel/plugin-syntax-import-attributes": "^7.28.6", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.28.0", - "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.29.0", + "@babel/plugin-transform-async-to-generator": "^7.28.6", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.0", - "@babel/plugin-transform-class-properties": "^7.27.1", - "@babel/plugin-transform-class-static-block": "^7.27.1", - "@babel/plugin-transform-classes": "^7.28.0", - "@babel/plugin-transform-computed-properties": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", - "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.6", + "@babel/plugin-transform-class-properties": "^7.28.6", + "@babel/plugin-transform-class-static-block": "^7.28.6", + "@babel/plugin-transform-classes": "^7.28.6", + "@babel/plugin-transform-computed-properties": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-dotall-regex": "^7.28.6", "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.0", "@babel/plugin-transform-dynamic-import": "^7.27.1", - "@babel/plugin-transform-explicit-resource-management": "^7.28.0", - "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.6", + "@babel/plugin-transform-exponentiation-operator": "^7.28.6", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", - "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.28.6", "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.6", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.28.6", + "@babel/plugin-transform-modules-systemjs": "^7.29.0", "@babel/plugin-transform-modules-umd": "^7.27.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.0", "@babel/plugin-transform-new-target": "^7.27.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", - "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.28.0", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", + "@babel/plugin-transform-numeric-separator": "^7.28.6", + "@babel/plugin-transform-object-rest-spread": "^7.28.6", "@babel/plugin-transform-object-super": "^7.27.1", - "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.28.6", + "@babel/plugin-transform-optional-chaining": "^7.28.6", "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/plugin-transform-private-methods": "^7.27.1", - "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-private-methods": "^7.28.6", + "@babel/plugin-transform-private-property-in-object": "^7.28.6", "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.0", - "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.29.0", + "@babel/plugin-transform-regexp-modifiers": "^7.28.6", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-spread": "^7.28.6", "@babel/plugin-transform-sticky-regex": "^7.27.1", "@babel/plugin-transform-template-literals": "^7.27.1", "@babel/plugin-transform-typeof-symbol": "^7.27.1", "@babel/plugin-transform-unicode-escapes": "^7.27.1", - "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.28.6", "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.28.6", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.14", - "babel-plugin-polyfill-corejs3": "^0.13.0", - "babel-plugin-polyfill-regenerator": "^0.6.5", - "core-js-compat": "^3.43.0", + "babel-plugin-polyfill-corejs2": "^0.4.15", + "babel-plugin-polyfill-corejs3": "^0.14.0", + "babel-plugin-polyfill-regenerator": "^0.6.6", + "core-js-compat": "^3.48.0", "semver": "^6.3.1" }, "engines": { @@ -1912,15 +1932,15 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.27.1.tgz", - "integrity": "sha512-oJHWh2gLhU9dW9HHr42q0cI0/iHHXTLGe39qvpAZZzagHy0MzYLCnCVV0symeRvzmjHyVU7mw2K06E6u/JwbhA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.28.5.tgz", + "integrity": "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-transform-react-display-name": "^7.27.1", + "@babel/plugin-transform-react-display-name": "^7.28.0", "@babel/plugin-transform-react-jsx": "^7.27.1", "@babel/plugin-transform-react-jsx-development": "^7.27.1", "@babel/plugin-transform-react-pure-annotations": "^7.27.1" @@ -1933,9 +1953,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", - "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", "dev": true, "license": "MIT", "engines": { @@ -1943,33 +1963,33 @@ } }, "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", - "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.0", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.0", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", "debug": "^4.3.1" }, "engines": { @@ -1977,14 +1997,14 @@ } }, "node_modules/@babel/types": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.0.tgz", - "integrity": "sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -2042,9 +2062,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", - "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ "ppc64" ], @@ -2059,9 +2079,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", - "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ "arm" ], @@ -2076,9 +2096,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", - "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ "arm64" ], @@ -2093,9 +2113,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", - "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ "x64" ], @@ -2110,9 +2130,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", - "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], @@ -2127,9 +2147,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", - "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], @@ -2144,9 +2164,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", - "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ "arm64" ], @@ -2161,9 +2181,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", - "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" ], @@ -2178,9 +2198,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", - "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ "arm" ], @@ -2195,9 +2215,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", - "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ "arm64" ], @@ -2212,9 +2232,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", - "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ "ia32" ], @@ -2229,9 +2249,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", - "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ "loong64" ], @@ -2246,9 +2266,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", - "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ "mips64el" ], @@ -2263,9 +2283,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", - "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ "ppc64" ], @@ -2280,9 +2300,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", - "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ "riscv64" ], @@ -2297,9 +2317,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", - "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ "s390x" ], @@ -2314,9 +2334,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", - "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ "x64" ], @@ -2331,9 +2351,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", - "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", "cpu": [ "arm64" ], @@ -2348,9 +2368,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", - "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ "x64" ], @@ -2365,9 +2385,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", - "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", "cpu": [ "arm64" ], @@ -2382,9 +2402,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", - "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "cpu": [ "x64" ], @@ -2398,10 +2418,27 @@ "node": ">=18" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", - "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "cpu": [ "x64" ], @@ -2416,9 +2453,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", - "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "cpu": [ "arm64" ], @@ -2433,9 +2470,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", - "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "cpu": [ "ia32" ], @@ -2450,9 +2487,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", - "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "cpu": [ "x64" ], @@ -2467,35 +2504,32 @@ } }, "node_modules/@fingerprintjs/fingerprintjs-pro": { - "version": "3.11.10", - "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro/-/fingerprintjs-pro-3.11.10.tgz", - "integrity": "sha512-zuQWT0YQLT0T//KcjEnyn4YBPlxXuXCtPiwEt2eTv03I/k2m370X+pCOfgU26AEjkmPrhCE77FLpRnm0IwiWrg==", + "version": "3.12.9", + "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro/-/fingerprintjs-pro-3.12.9.tgz", + "integrity": "sha512-MiM8ASp9nQgY/abPK+1+LaZHvn6aaTX9Zze1ghCDO/Y86k1dbRnDeBr5Zg5fmEhwMda9J7+6zl54lds6GENZUw==", "dev": true, - "license": "SEE LICENSE IN LICENSE", - "dependencies": { - "tslib": "^2.4.1" - } + "license": "SEE LICENSE IN LICENSE" }, "node_modules/@fingerprintjs/fingerprintjs-pro-react": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro-react/-/fingerprintjs-pro-react-2.7.0.tgz", - "integrity": "sha512-ssSrJ1/16xvfVeKjkJmcDJzJWt6BYq11MS9i00et6OfSmoUMVkm8zSJv0Ko5Y2+2oDoyXhIogaoFDZMUCIjqKA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro-react/-/fingerprintjs-pro-react-2.7.1.tgz", + "integrity": "sha512-/vQtjd+P8C9OFU8Wvd4AScoNRP6RKDIvYQwwaY/b31PcRBNDqVV9xm7DDBg9uTdDv4KZM3ubEY4JyyVWkXs4EA==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { - "@fingerprintjs/fingerprintjs-pro-spa": "^1.3.2", + "@fingerprintjs/fingerprintjs-pro-spa": "^1.3.3", "fast-deep-equal": "3.1.3" } }, "node_modules/@fingerprintjs/fingerprintjs-pro-spa": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro-spa/-/fingerprintjs-pro-spa-1.3.2.tgz", - "integrity": "sha512-s1YGsx1XQLmjU+av4UrUHNxyzwPHyZRB0GXJQFOJK8ZHCYc2SNukxnJmZA++bNBa8twU3wW+QgSJhA4Prjnd0g==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro-spa/-/fingerprintjs-pro-spa-1.3.3.tgz", + "integrity": "sha512-jM5k30S9RT/WW6gnmNWACc7UHeK1md9NbZg8kUsdxvPtDeW8xKnA6tb58Rqfkg6kvqHTq5aHFzw9hgsTH3DbNQ==", "dev": true, "license": "MIT", "dependencies": { - "@fingerprintjs/fingerprintjs-pro": "^3.11.0", + "@fingerprintjs/fingerprintjs-pro": "^3.12.0", "tslib": "^2.7.0" } }, @@ -2592,21 +2626,21 @@ } }, "node_modules/@hcaptcha/loader": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@hcaptcha/loader/-/loader-2.0.0.tgz", - "integrity": "sha512-fFQH6ApU/zCCl6Y1bnbsxsp1Er/lKX+qlgljrpWDeFcenpEtoP68hExlKSXECospzKLeSWcr06cbTjlR/x3IJA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@hcaptcha/loader/-/loader-2.3.0.tgz", + "integrity": "sha512-i4lnNxKBe+COf3R1nFZEWaZoHIoJjvDgWqvcNrdZq8ehoSNMN6KVZ56dcQ02qKie2h3+BkbkwlJA9DOIuLlK/g==", "dev": true, "license": "MIT" }, "node_modules/@hcaptcha/react-hcaptcha": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/@hcaptcha/react-hcaptcha/-/react-hcaptcha-1.12.0.tgz", - "integrity": "sha512-QiHnQQ52k8SJJSHkc3cq4TlYzag7oPd4f5ZqnjVSe4fJDSlZaOQFtu5F5AYisVslwaitdDELPVLRsRJxiiI0Aw==", + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/@hcaptcha/react-hcaptcha/-/react-hcaptcha-1.17.4.tgz", + "integrity": "sha512-rIvgesG1N7SS9sAYYHFoWm+nXqRrxq7RcA9z2pKkDWV+S1GdfmrTNYA1aPyVWVe3eowphTCwyDJvl97Swwy0mw==", "dev": true, "license": "MIT", "dependencies": { "@babel/runtime": "^7.17.9", - "@hcaptcha/loader": "^2.0.0" + "@hcaptcha/loader": "^2.3.0" }, "peerDependencies": { "react": ">= 16.3.0", @@ -2614,9 +2648,9 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", - "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, "license": "MIT", "dependencies": { @@ -2624,6 +2658,17 @@ "@jridgewell/trace-mapping": "^0.3.24" } }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -2635,16 +2680,16 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", - "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "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/@jridgewell/trace-mapping": { - "version": "0.3.29", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", - "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "license": "MIT", "dependencies": { @@ -2653,15 +2698,15 @@ } }, "node_modules/@kapaai/react-sdk": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@kapaai/react-sdk/-/react-sdk-0.9.0.tgz", - "integrity": "sha512-+SUTlcYGWKUri1vFYk+j7amh7t/yOsLe5QqjFSBbdlT2iNZcIM5NhA2RS9tmRCXtc4nXp9ULDApNoqsk8sO9Pg==", + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/@kapaai/react-sdk/-/react-sdk-0.9.9.tgz", + "integrity": "sha512-NMkUCmuXTTONgr8Qn9m0Z7JA0nAr/OpUyX6K9KPjYLwq+r+Wy9X+PQle9N5qRBD1cpeTVum4YscreiQ3nUrolg==", "dev": true, "license": "MIT", "dependencies": { "@fingerprintjs/fingerprintjs-pro-react": "^2.7.0", + "@fingerprintjs/fingerprintjs-pro-spa": "^1.3.0", "@hcaptcha/react-hcaptcha": "^1.12.0", - "@tanstack/react-query": "^5.74.3", "js-cookie": "^3.0.5", "tldts": "^7.0.7" }, @@ -2938,34 +2983,6 @@ "postcss-syntax": ">=0.36.2" } }, - "node_modules/@tanstack/query-core": { - "version": "5.81.5", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.81.5.tgz", - "integrity": "sha512-ZJOgCy/z2qpZXWaj/oxvodDx07XcQa9BF92c0oINjHkoqUPsmm3uG08HpTaviviZ/N9eP1f9CM7mKSEkIo7O1Q==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/react-query": { - "version": "5.81.5", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.81.5.tgz", - "integrity": "sha512-lOf2KqRRiYWpQT86eeeftAGnjuTR35myTP8MXyvHa81VlomoAWNEd8x5vkcAfQefu0qtYCvyqLropFZqgI2EQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tanstack/query-core": "5.81.5" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^18 || ^19" - } - }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", @@ -3023,13 +3040,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.0.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.10.tgz", - "integrity": "sha512-ENHwaH+JIRTDIEEbDK6QSQntAYGtbvdDXnMXnZaZ6k13Du1dPMmprkEHIL7ok2Wl2aZevetwTAb5S+7yIF+enA==", + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.8.0" + "undici-types": "~7.19.0" } }, "node_modules/@types/normalize-package-data": { @@ -3205,9 +3222,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -3222,25 +3239,26 @@ } }, "node_modules/algoliasearch": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.30.0.tgz", - "integrity": "sha512-ILSdPX4je0n5WUKD34TMe57/eqiXUzCIjAsdtLQYhomqOjTtFUg1s6dE7kUegc4Mc43Xr7IXYlMutU9HPiYfdw==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.52.0.tgz", + "integrity": "sha512-0ZzY9mjqV7gop/AH8pIBiAS8giXP7WcSiUfoFYIzYAK9QC5c37E4SIVtJVBMwlURc0/uNt2o4RcNRvdHa4CJ5w==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-abtesting": "5.30.0", - "@algolia/client-analytics": "5.30.0", - "@algolia/client-common": "5.30.0", - "@algolia/client-insights": "5.30.0", - "@algolia/client-personalization": "5.30.0", - "@algolia/client-query-suggestions": "5.30.0", - "@algolia/client-search": "5.30.0", - "@algolia/ingestion": "1.30.0", - "@algolia/monitoring": "1.30.0", - "@algolia/recommend": "5.30.0", - "@algolia/requester-browser-xhr": "5.30.0", - "@algolia/requester-fetch": "5.30.0", - "@algolia/requester-node-http": "5.30.0" + "@algolia/abtesting": "1.18.0", + "@algolia/client-abtesting": "5.52.0", + "@algolia/client-analytics": "5.52.0", + "@algolia/client-common": "5.52.0", + "@algolia/client-insights": "5.52.0", + "@algolia/client-personalization": "5.52.0", + "@algolia/client-query-suggestions": "5.52.0", + "@algolia/client-search": "5.52.0", + "@algolia/ingestion": "1.52.0", + "@algolia/monitoring": "1.52.0", + "@algolia/recommend": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" @@ -3352,63 +3370,166 @@ "normalize-path": "^2.1.1" } }, - "node_modules/anymatch/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "node_modules/anymatch/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "license": "MIT", "dependencies": { - "remove-trailing-separator": "^1.0.1" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/append-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", - "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==", + "node_modules/anymatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "dev": true, "license": "MIT", "dependencies": { - "buffer-equal": "^1.0.0" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "node_modules/anymatch/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "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", - "optional": true + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } }, - "node_modules/archive-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz", - "integrity": "sha512-zV4Ky0v1F8dBrdYElwTvQhweQ0P7Kwc1aluqJsYtOBP01jXcWCyW2IEfI1YiqsG+Iy7ZR+o5LF1N+PGECBxHWA==", + "node_modules/anymatch/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "file-type": "^4.2.0" + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/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/anymatch/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/append-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", + "integrity": "sha512-WLbYiXzD3y/ATLZFufV/rZvWdZOs+Z/+5v1rBZ463Jn398pa6kcde27cvozYnBoxXblGZTFfoPpsaEw0orU5BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "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", + "optional": true + }, + "node_modules/archive-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz", + "integrity": "sha512-zV4Ky0v1F8dBrdYElwTvQhweQ0P7Kwc1aluqJsYtOBP01jXcWCyW2IEfI1YiqsG+Iy7ZR+o5LF1N+PGECBxHWA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "file-type": "^4.2.0" }, "engines": { "node": ">=4" @@ -3684,6 +3805,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array.prototype.reduce": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.8.tgz", @@ -3740,14 +3880,14 @@ } }, "node_modules/asciidoctor-opal-runtime": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/asciidoctor-opal-runtime/-/asciidoctor-opal-runtime-0.3.3.tgz", - "integrity": "sha512-/CEVNiOia8E5BMO9FLooo+Kv18K4+4JBFRJp8vUy/N5dMRAg+fRNV4HA+o6aoSC79jVU/aT5XvUpxSxSsTS8FQ==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/asciidoctor-opal-runtime/-/asciidoctor-opal-runtime-0.3.4.tgz", + "integrity": "sha512-zqd6zn1LV+PZ69AP/kEbB00zuPHMIAJY3IX8+aZV+X1qOwatYvKGjsMmdMc5ApfhtkjZ4mYkqiTPJWnEnBiMJg==", "dev": true, "license": "MIT", "dependencies": { - "glob": "7.1.3", - "unxhr": "1.0.1" + "fast-glob": "~3.3", + "unxhr": "~1.2" }, "engines": { "node": ">=8.11" @@ -3766,9 +3906,9 @@ } }, "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "dev": true, "license": "MIT" }, @@ -3923,22 +4063,15 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/b4a": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", - "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", - "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", + "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.7", - "@babel/helper-define-polyfill-provider": "^0.6.5", + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", "semver": "^6.3.1" }, "peerDependencies": { @@ -3946,27 +4079,27 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", - "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", + "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5", - "core-js-compat": "^3.43.0" + "@babel/helper-define-polyfill-provider": "^0.6.8", + "core-js-compat": "^3.48.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", - "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", + "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5" + "@babel/helper-define-polyfill-provider": "^0.6.8" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -4025,12 +4158,101 @@ "license": "MIT" }, "node_modules/bare-events": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.6.0.tgz", - "integrity": "sha512-EKZ5BTXYExaNqi3I3f9RtEsaI/xBSGjE0XZCZilPzFAV/goswFHuPd9jEZlPIZ/iNZJwDSao9qRiScySz7MbQg==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", + "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", "dev": true, "license": "Apache-2.0", - "optional": true + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fs": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.1.tgz", + "integrity": "sha512-WDRsyVN52eAx/lBamKD6uyw8H4228h/x0sGGGegOamM2cd7Pag88GfMQalobXI+HaEUxpCkbKQUDOQqt9wawRw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.0.tgz", + "integrity": "sha512-JTjuZyNIDpw+GytMO4a6TK1VXdVKKJr6DRxEHasyuYyShV2deuiHJK/ahGZlebc+SG0/wJCB9XK8gprBGDFi/Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.1.tgz", + "integrity": "sha512-Vp0cnjYyrEC4whYTymQ+YZi6pBpfiICZO3cfRG8sy67ZNWe951urv1x4eW1BKNngw3U+3fPYb5JQvHbCtxH7Ow==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "streamx": "^2.25.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-abort-controller": "*", + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + }, + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.2.tgz", + "integrity": "sha512-/9a2j4ac6ckpmAHvod/ob7x439OAHst/drc2Clnq+reRYd/ovddwcF4LfoxHyNk5AuGBnPg+HqFjmE/Zpq6v0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-path": "^3.0.0" + } }, "node_modules/base": { "version": "0.11.2", @@ -4064,6 +4286,20 @@ "node": ">=0.10.0" } }, + "node_modules/base/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -4085,10 +4321,23 @@ ], "license": "MIT" }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.24", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.24.tgz", + "integrity": "sha512-I2NkZOOrj2XuguvWCK6OVh9GavsNjZjK908Rq3mIBK25+GD8vPX5w2WdxVqnQ7xx3SrZJiCiZFu+/Oz50oSYSA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/basic-ftp": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", - "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz", + "integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==", "dev": true, "license": "MIT", "engines": { @@ -4211,18 +4460,6 @@ "node": ">=6" } }, - "node_modules/bin-version/node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/bin-wrapper": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bin-wrapper/-/bin-wrapper-4.1.0.tgz", @@ -4463,9 +4700,9 @@ } }, "node_modules/bn.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", - "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", + "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", "dev": true, "license": "MIT" }, @@ -4482,40 +4719,30 @@ } }, "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", + "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", + "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.15.1", + "raw-body": "~2.5.3", "type-is": "~1.6.18", - "unpipe": "1.0.0" + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/body-parser/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -4526,72 +4753,21 @@ "ms": "2.0.0" } }, - "node_modules/body-parser/node_modules/depd": { + "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } + "license": "MIT" }, - "node_modules/body-parser/node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "node_modules/body-parser/node_modules/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/body-parser/node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -4600,38 +4776,33 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/body-parser/node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "node_modules/body/node_modules/bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", + "integrity": "sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==", + "dev": true + }, + "node_modules/body/node_modules/raw-body": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", + "integrity": "sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg==", + "deprecated": "No longer maintained. Please upgrade to a stable version.", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bytes": "1", + "string_decoder": "0.10" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.8.0" } }, - "node_modules/body-parser/node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, - "license": "ISC" - }, - "node_modules/body-parser/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "node_modules/body/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } + "license": "MIT" }, "node_modules/boolbase": { "version": "1.0.0", @@ -4641,9 +4812,9 @@ "license": "ISC" }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -4868,25 +5039,24 @@ } }, "node_modules/browserify-sign": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", - "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", + "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", "dev": true, "license": "ISC", "dependencies": { - "bn.js": "^5.2.1", - "browserify-rsa": "^4.1.0", + "bn.js": "^5.2.2", + "browserify-rsa": "^4.1.1", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "elliptic": "^6.5.5", - "hash-base": "~3.0", + "elliptic": "^6.6.1", "inherits": "^2.0.4", - "parse-asn1": "^5.1.7", + "parse-asn1": "^5.1.9", "readable-stream": "^2.3.8", "safe-buffer": "^5.2.1" }, "engines": { - "node": ">= 0.12" + "node": ">= 0.10" } }, "node_modules/browserify-zlib": { @@ -4900,9 +5070,9 @@ } }, "node_modules/browserslist": { - "version": "4.25.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", - "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "dev": true, "funding": [ { @@ -4920,10 +5090,11 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001726", - "electron-to-chromium": "^1.5.173", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.3" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" @@ -5016,10 +5187,14 @@ "license": "MIT" }, "node_modules/bytes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", - "integrity": "sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==", - "dev": true + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, "node_modules/cache-base": { "version": "1.0.1", @@ -5119,15 +5294,15 @@ "license": "MIT" }, "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", "set-function-length": "^1.2.2" }, "engines": { @@ -5251,9 +5426,9 @@ "license": "MIT" }, "node_modules/caniuse-lite": { - "version": "1.0.30001726", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001726.tgz", - "integrity": "sha512-VQAUIUzBiZ/UnlM28fSp2CRF3ivUn1BWEvxMcVTNwpw91Py1pGbPIyIKtd+tzct9C3ouceCVdGAXxZOpZAsgdw==", + "version": "1.0.30001791", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001791.tgz", + "integrity": "sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ==", "dev": true, "funding": [ { @@ -5405,14 +5580,15 @@ } }, "node_modules/cipher-base": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", - "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", + "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", "dev": true, "license": "MIT", "dependencies": { "inherits": "^2.0.4", - "safe-buffer": "^5.2.1" + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.2" }, "engines": { "node": ">= 0.10" @@ -5434,33 +5610,6 @@ "node": ">=0.10.0" } }, - "node_modules/class-utils/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -5852,6 +6001,35 @@ "ms": "2.0.0" } }, + "node_modules/connect/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/connect/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -5859,6 +6037,29 @@ "dev": true, "license": "MIT" }, + "node_modules/connect/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/console-browserify": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", @@ -5926,9 +6127,9 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, "license": "MIT", "engines": { @@ -5936,9 +6137,9 @@ } }, "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", "dev": true, "license": "MIT" }, @@ -5964,9 +6165,9 @@ } }, "node_modules/core-js": { - "version": "3.43.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.43.0.tgz", - "integrity": "sha512-N6wEbTTZSYOY2rYAn85CuvWWkCK6QweMn7/4Nr3w+gDBeBhk/x4EJeY6FPo4QzDoJZxVTv8U7CMvgWk6pOHHqA==", + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz", + "integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -5976,13 +6177,13 @@ } }, "node_modules/core-js-compat": { - "version": "3.43.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.43.0.tgz", - "integrity": "sha512-2GML2ZsCc5LR7hZYz4AXmjQw8zuy2T//2QntwdnpuYI7jteT6GVYJL7F6C2C57R7gSYrcqVW3lAALefdbhBLDA==", + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.25.0" + "browserslist": "^4.28.1" }, "funding": { "type": "opencollective", @@ -6033,9 +6234,9 @@ } }, "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "dev": true, "license": "MIT" }, @@ -6500,9 +6701,9 @@ } }, "node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", "dependencies": { @@ -6858,14 +7059,13 @@ } }, "node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "license": "MIT", "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "is-descriptor": "^0.1.0" }, "engines": { "node": ">=0.10.0" @@ -6897,13 +7097,13 @@ } }, "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/deps-sort": { @@ -6934,11 +7134,15 @@ } }, "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } }, "node_modules/detect-file": { "version": "1.0.0", @@ -6998,9 +7202,9 @@ } }, "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "dev": true, "license": "MIT" }, @@ -7100,9 +7304,9 @@ } }, "node_modules/dompurify": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.6.tgz", - "integrity": "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.2.tgz", + "integrity": "sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA==", "dev": true, "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { @@ -7282,9 +7486,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.179", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.179.tgz", - "integrity": "sha512-UWKi/EbBopgfFsc5k61wFpV7WrnnSlSzW/e2XcBmS6qKYTivZlLtoll5/rdqRTxGglGHkmkW0j0pFNJG10EUIQ==", + "version": "1.5.348", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.348.tgz", + "integrity": "sha512-QC2X59nRlycQQMc4ZXjSVBX+tSgJfgRtcrYHbIZLgOV2dCvefoQGegLR7lLXKgpPpSuVmJU19LMzGrSa2C7k3Q==", "dev": true, "license": "ISC" }, @@ -7305,9 +7509,9 @@ } }, "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "dev": true, "license": "MIT" }, @@ -7319,9 +7523,9 @@ "license": "MIT" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "license": "MIT", "engines": { @@ -7365,9 +7569,9 @@ } }, "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "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": { @@ -7375,9 +7579,9 @@ } }, "node_modules/es-abstract": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", "dev": true, "license": "MIT", "dependencies": { @@ -7620,9 +7824,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", - "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -7633,31 +7837,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.5", - "@esbuild/android-arm": "0.25.5", - "@esbuild/android-arm64": "0.25.5", - "@esbuild/android-x64": "0.25.5", - "@esbuild/darwin-arm64": "0.25.5", - "@esbuild/darwin-x64": "0.25.5", - "@esbuild/freebsd-arm64": "0.25.5", - "@esbuild/freebsd-x64": "0.25.5", - "@esbuild/linux-arm": "0.25.5", - "@esbuild/linux-arm64": "0.25.5", - "@esbuild/linux-ia32": "0.25.5", - "@esbuild/linux-loong64": "0.25.5", - "@esbuild/linux-mips64el": "0.25.5", - "@esbuild/linux-ppc64": "0.25.5", - "@esbuild/linux-riscv64": "0.25.5", - "@esbuild/linux-s390x": "0.25.5", - "@esbuild/linux-x64": "0.25.5", - "@esbuild/netbsd-arm64": "0.25.5", - "@esbuild/netbsd-x64": "0.25.5", - "@esbuild/openbsd-arm64": "0.25.5", - "@esbuild/openbsd-x64": "0.25.5", - "@esbuild/sunos-x64": "0.25.5", - "@esbuild/win32-arm64": "0.25.5", - "@esbuild/win32-ia32": "0.25.5", - "@esbuild/win32-x64": "0.25.5" + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" } }, "node_modules/escalade": { @@ -7801,15 +8006,15 @@ } }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz", + "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==", "dev": true, "license": "MIT", "dependencies": { "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" + "is-core-module": "^2.16.1", + "resolve": "^2.0.0-next.6" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { @@ -7822,6 +8027,30 @@ "ms": "^2.1.1" } }, + "node_modules/eslint-import-resolver-node/node_modules/resolve": { + "version": "2.0.0-next.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.6.tgz", + "integrity": "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/eslint-module-utils": { "version": "2.12.1", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", @@ -8147,9 +8376,9 @@ } }, "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "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": { @@ -8274,6 +8503,16 @@ "node": ">=0.4.x" } }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, "node_modules/evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", @@ -8423,33 +8662,6 @@ "ms": "2.0.0" } }, - "node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/expand-brackets/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -8471,40 +8683,40 @@ } }, "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", + "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.13.0", + "qs": "~6.14.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", + "send": "~0.19.0", + "serve-static": "~1.16.2", "setprototypeof": "1.2.0", - "statuses": "2.0.1", + "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -8527,178 +8739,17 @@ "ms": "2.0.0" } }, - "node_modules/express/node_modules/debug/node_modules/ms": { + "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, "license": "MIT" }, - "node_modules/express/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/express/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/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/express/node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/express/node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, - "license": "ISC" - }, - "node_modules/express/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/ext": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", "dev": true, "license": "ISC", "dependencies": { @@ -8802,6 +8853,20 @@ "node": ">=0.10.0" } }, + "node_modules/extglob/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", @@ -8839,17 +8904,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/extract-zip/node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/fancy-log": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", @@ -8897,69 +8951,6 @@ "node": ">=8.6.0" } }, - "node_modules/fast-glob/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/fast-glob/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/fast-glob/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/fast-glob/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/fast-glob/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/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", @@ -8982,9 +8973,9 @@ "license": "MIT" }, "node_modules/fast-xml-parser": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz", - "integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==", + "version": "4.5.6", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.6.tgz", + "integrity": "sha512-Yd4vkROfJf8AuJrDIVMVmYfULKmIJszVsMv7Vo71aocsKgFxpdlpSHXSaInvyYfgw2PRuObQSW2GFpVMUjxu9A==", "dev": true, "funding": [ { @@ -8995,16 +8986,16 @@ "license": "MIT", "optional": true, "dependencies": { - "strnum": "^1.1.1" + "strnum": "^1.0.5" }, "bin": { "fxparser": "src/cli/cli.js" } }, "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "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": { @@ -9125,18 +9116,18 @@ } }, "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "~2.0.2", "unpipe": "~1.0.0" }, "engines": { @@ -9203,6 +9194,109 @@ "node": ">= 0.10" } }, + "node_modules/findup-sync/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/findup-sync/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync/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/findup-sync/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/fined": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", @@ -9479,6 +9573,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -9676,35 +9780,26 @@ "node": ">=6" } }, - "node_modules/gifsicle/node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, "engines": { "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/glob-parent": { @@ -10015,50 +10110,182 @@ "node": ">= 0.10" } }, - "node_modules/gulp-concat": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz", - "integrity": "sha512-a2scActrQrDBpBbR3WUZGyGS1JEPLg5PZJdIa7/Bi3GuKAmPYDK6SFhy/NZq5R8KsKKFvtfR0fakbUCcKGCCjg==", + "node_modules/gulp-concat": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz", + "integrity": "sha512-a2scActrQrDBpBbR3WUZGyGS1JEPLg5PZJdIa7/Bi3GuKAmPYDK6SFhy/NZq5R8KsKKFvtfR0fakbUCcKGCCjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "concat-with-sourcemaps": "^1.0.0", + "through2": "^2.0.0", + "vinyl": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-connect": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/gulp-connect/-/gulp-connect-5.7.0.tgz", + "integrity": "sha512-8tRcC6wgXMLakpPw9M7GRJIhxkYdgZsXwn7n56BA2bQYGLR9NOPhMzx7js+qYDy6vhNkbApGKURjAw1FjY4pNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^2.0.5", + "connect": "^3.6.6", + "connect-livereload": "^0.6.0", + "fancy-log": "^1.3.2", + "map-stream": "^0.0.7", + "send": "^0.16.2", + "serve-index": "^1.9.1", + "serve-static": "^1.13.2", + "tiny-lr": "^1.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gulp-connect/node_modules/ansi-colors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-2.0.5.tgz", + "integrity": "sha512-yAdfUZ+c2wetVNIFsNRn44THW+Lty6S5TwMpUfLA/UaGhiXbBv/F8E60/1hMLd0cnF/CDoWH8vzVaI5bAcHCjw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/gulp-connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/gulp-connect/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/gulp-connect/node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-connect/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/gulp-connect/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/gulp-connect/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true, + "license": "ISC" + }, + "node_modules/gulp-connect/node_modules/mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + } + }, + "node_modules/gulp-connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/gulp-connect/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "dev": true, "license": "MIT", "dependencies": { - "concat-with-sourcemaps": "^1.0.0", - "through2": "^2.0.0", - "vinyl": "^2.0.0" + "ee-first": "1.1.1" }, "engines": { - "node": ">= 0.10" + "node": ">= 0.8" } }, - "node_modules/gulp-connect": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/gulp-connect/-/gulp-connect-5.7.0.tgz", - "integrity": "sha512-8tRcC6wgXMLakpPw9M7GRJIhxkYdgZsXwn7n56BA2bQYGLR9NOPhMzx7js+qYDy6vhNkbApGKURjAw1FjY4pNA==", + "node_modules/gulp-connect/node_modules/send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", "dev": true, "license": "MIT", "dependencies": { - "ansi-colors": "^2.0.5", - "connect": "^3.6.6", - "connect-livereload": "^0.6.0", - "fancy-log": "^1.3.2", - "map-stream": "^0.0.7", - "send": "^0.16.2", - "serve-index": "^1.9.1", - "serve-static": "^1.13.2", - "tiny-lr": "^1.1.1" + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/gulp-connect/node_modules/ansi-colors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-2.0.5.tgz", - "integrity": "sha512-yAdfUZ+c2wetVNIFsNRn44THW+Lty6S5TwMpUfLA/UaGhiXbBv/F8E60/1hMLd0cnF/CDoWH8vzVaI5bAcHCjw==", + "node_modules/gulp-connect/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/gulp-connect/node_modules/statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 0.6" } }, "node_modules/gulp-eslint": { @@ -10298,13 +10525,13 @@ } }, "node_modules/gulp-stylelint/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", "dev": true, "license": "BSD-3-Clause", "engines": { - "node": ">= 8" + "node": ">= 12" } }, "node_modules/gulp-stylelint/node_modules/strip-ansi": { @@ -10434,9 +10661,9 @@ } }, "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10695,9 +10922,9 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", "dev": true, "license": "MIT", "dependencies": { @@ -10833,28 +11060,26 @@ "optional": true }, "node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dev": true, "license": "MIT", "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/http-errors/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true, - "license": "ISC" - }, "node_modules/http-parser-js": { "version": "0.5.10", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", @@ -11337,26 +11562,15 @@ } }, "node_modules/ip-address": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", "dev": true, "license": "MIT", - "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" - }, "engines": { "node": ">= 12" } }, - "node_modules/ip-address/node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/ip-regex": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", @@ -11652,9 +11866,9 @@ } }, "node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dev": true, "license": "MIT", "dependencies": { @@ -11736,14 +11950,15 @@ } }, "node_modules/is-generator-function": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", - "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "get-proto": "^1.0.0", + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" }, @@ -12324,13 +12539,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "dev": true, - "license": "MIT" - }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -12684,9 +12892,9 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "dev": true, "license": "MIT" }, @@ -13098,13 +13306,13 @@ } }, "node_modules/marked-highlight": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/marked-highlight/-/marked-highlight-2.2.2.tgz", - "integrity": "sha512-KlHOP31DatbtPPXPaI8nx1KTrG3EW0Z5zewCwpUj65swbtKOTStteK3sNAjBqV75Pgo3fNEVNHeptg18mDuWgw==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/marked-highlight/-/marked-highlight-2.2.4.tgz", + "integrity": "sha512-PZxisNMJDduSjc0q6uvjsnqqHCXc9s0eyzxDO9sB1eNGJnd/H1/Fu+z6g/liC1dfJdFW4SftMwMlLvsBhUPrqQ==", "dev": true, "license": "MIT", "peerDependencies": { - "marked": ">=4 <17" + "marked": ">=4 <19" } }, "node_modules/matchdep": { @@ -13123,6 +13331,34 @@ "node": ">= 0.10.0" } }, + "node_modules/matchdep/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/matchdep/node_modules/findup-sync": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", @@ -13139,6 +13375,33 @@ "node": ">= 0.10" } }, + "node_modules/matchdep/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/matchdep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/matchdep/node_modules/is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", @@ -13152,6 +13415,54 @@ "node": ">=0.10.0" } }, + "node_modules/matchdep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep/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/matchdep/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -13495,78 +13806,66 @@ } }, "node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "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": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8.6" } }, - "node_modules/micromatch/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "node_modules/micromatch/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": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "fill-range": "^7.1.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/micromatch/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "node_modules/micromatch/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": { - "is-plain-object": "^2.0.4" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/micromatch/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/micromatch/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", - "dependencies": { - "isobject": "^3.0.1" - }, "engines": { - "node": ">=0.10.0" + "node": ">=0.12.0" } }, - "node_modules/micromatch/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==", + "node_modules/micromatch/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": ">=0.10.0" + "node": ">=8.0" } }, "node_modules/miller-rabin": { @@ -13584,9 +13883,9 @@ } }, "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "dev": true, "license": "MIT" }, @@ -13683,9 +13982,9 @@ "license": "MIT" }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -13862,9 +14161,9 @@ } }, "node_modules/nan": { - "version": "2.22.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz", - "integrity": "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==", + "version": "2.26.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.26.2.tgz", + "integrity": "sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==", "dev": true, "license": "MIT", "optional": true @@ -13969,6 +14268,20 @@ "node": ">=0.10.0" } }, + "node_modules/nanomatch/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/nanomatch/node_modules/extend-shallow": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", @@ -13983,6 +14296,20 @@ "node": ">=0.10.0" } }, + "node_modules/nanomatch/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/nanomatch/node_modules/is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", @@ -14044,9 +14371,9 @@ "license": "MIT" }, "node_modules/netmask": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", - "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.1.1.tgz", + "integrity": "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==", "dev": true, "license": "MIT", "engines": { @@ -14067,6 +14394,25 @@ "dev": true, "license": "MIT" }, + "node_modules/node-exports-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", + "integrity": "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -14089,9 +14435,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "version": "2.0.38", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.38.tgz", + "integrity": "sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==", "dev": true, "license": "MIT" }, @@ -14249,33 +14595,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-copy/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/object-copy/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -14362,23 +14681,39 @@ "node": ">=0.10.0" } }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/object.getownpropertydescriptors": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.8.tgz", - "integrity": "sha512-qkHIGe4q0lSYMv0XI4SsBTJz3WaURhLvd0lKSgtVuOsJ2krg4SgMw3PIRQFMp07yi++UR3se2mkcLqsBNpBb/A==", + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.9.tgz", + "integrity": "sha512-mt8YM6XwsTTovI+kdZdHSxoyF2DI59up034orlC9NfweclcWOt7CVascNNLp6U+bjFVCVCIh9PwS76tDM/rH8g==", "dev": true, "license": "MIT", "dependencies": { - "array.prototype.reduce": "^1.0.6", - "call-bind": "^1.0.7", + "array.prototype.reduce": "^1.0.8", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "gopd": "^1.0.1", - "safe-array-concat": "^1.1.2" + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "gopd": "^1.2.0", + "safe-array-concat": "^1.1.3" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -14445,9 +14780,9 @@ } }, "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, "license": "MIT", "dependencies": { @@ -14803,17 +15138,16 @@ } }, "node_modules/parse-asn1": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", - "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", + "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", "dev": true, "license": "ISC", "dependencies": { "asn1.js": "^4.10.1", "browserify-aes": "^1.2.0", "evp_bytestokey": "^1.0.3", - "hash-base": "~3.0", - "pbkdf2": "^3.1.2", + "pbkdf2": "^3.1.5", "safe-buffer": "^5.2.1" }, "engines": { @@ -15000,9 +15334,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", "dev": true, "license": "MIT" }, @@ -15017,55 +15351,21 @@ } }, "node_modules/pbkdf2": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.3.tgz", - "integrity": "sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", + "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", "dev": true, "license": "MIT", "dependencies": { - "create-hash": "~1.1.3", + "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "ripemd160": "=2.0.1", + "ripemd160": "^2.0.3", "safe-buffer": "^5.2.1", - "sha.js": "^2.4.11", - "to-buffer": "^1.2.0" + "sha.js": "^2.4.12", + "to-buffer": "^1.2.1" }, "engines": { - "node": ">=0.12" - } - }, - "node_modules/pbkdf2/node_modules/create-hash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", - "integrity": "sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "sha.js": "^2.4.0" - } - }, - "node_modules/pbkdf2/node_modules/hash-base": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", - "integrity": "sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1" - } - }, - "node_modules/pbkdf2/node_modules/ripemd160": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", - "integrity": "sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hash-base": "^2.0.0", - "inherits": "^2.0.1" + "node": ">= 0.10" } }, "node_modules/pend": { @@ -15083,9 +15383,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "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": { @@ -16041,9 +16341,9 @@ } }, "node_modules/preact": { - "version": "10.26.9", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.26.9.tgz", - "integrity": "sha512-SSjF9vcnF27mJK1XyFMNJzFd5u3pQiATFqoaDy03XuN00u4ziveVVEGt5RKJrDR8MHE/wJo9Nnad56RLzS2RMA==", + "version": "10.29.1", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.1.tgz", + "integrity": "sha512-gQCLc/vWroE8lIpleXtdJhTFDogTdZG9AjMUpVkDf2iTCNwYNWA+u16dL41TqUDJO4gm2IgrcMv3uTpjd4Pwmg==", "dev": true, "license": "MIT", "funding": { @@ -16585,16 +16885,16 @@ } }, "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "dev": true, "license": "MIT" }, "node_modules/pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", "dev": true, "license": "MIT", "dependencies": { @@ -16627,6 +16927,17 @@ "stream-shift": "^1.0.0" } }, + "node_modules/pumpify/node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", @@ -16638,7 +16949,7 @@ "version": "21.11.0", "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-21.11.0.tgz", "integrity": "sha512-9jTHuYe22TD3sNxy0nEIzC7ZrlRnDgeX3xPkbS7PnbdwYjl2o/z/YuCrRBwezdKpbTDTJ4VqIggzNyeRcKq3cg==", - "deprecated": "< 22.8.2 is no longer supported", + "deprecated": "< 24.15.0 is no longer supported", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -16749,9 +17060,9 @@ } }, "node_modules/puppeteer/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -16791,9 +17102,9 @@ } }, "node_modules/puppeteer/node_modules/typescript": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -16819,9 +17130,9 @@ } }, "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -16939,26 +17250,21 @@ } }, "node_modules/raw-body": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", - "integrity": "sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "1", - "string_decoder": "0.10" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 0.8" } }, - "node_modules/raw-body/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true, - "license": "MIT" - }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -17097,23 +17403,126 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/readdirp/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/readdirp/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp/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/readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "node_modules/readdirp/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "license": "MIT", "dependencies": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" }, "engines": { - "node": ">=0.10" + "node": ">=0.10.0" } }, "node_modules/rechoir": { @@ -17188,9 +17597,9 @@ "license": "MIT" }, "node_modules/regenerate-unicode-properties": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", - "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", "dev": true, "license": "MIT", "dependencies": { @@ -17286,18 +17695,18 @@ } }, "node_modules/regexpu-core": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", - "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", "dev": true, "license": "MIT", "dependencies": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.0", + "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", - "regjsparser": "^0.12.0", + "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" + "unicode-match-property-value-ecmascript": "^2.2.1" }, "engines": { "node": ">=4" @@ -17311,31 +17720,18 @@ "license": "MIT" }, "node_modules/regjsparser": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", - "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.1.tgz", + "integrity": "sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "jsesc": "~3.0.2" + "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/remark": { "version": "13.0.0", "resolved": "https://registry.npmjs.org/remark/-/remark-13.0.0.tgz", @@ -17510,13 +17906,14 @@ "license": "MIT" }, "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.16.0", + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -17600,6 +17997,16 @@ "node": ">=8" } }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12" + } + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -17640,14 +18047,33 @@ } }, "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", "dev": true, "license": "MIT", "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" + "hash-base": "^3.1.2", + "inherits": "^2.0.4" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripemd160/node_modules/hash-base": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.8" } }, "node_modules/run-async": { @@ -17705,15 +18131,15 @@ "license": "0BSD" }, "node_modules/safe-array-concat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", "has-symbols": "^1.1.0", "isarray": "^2.0.5" }, @@ -17810,16 +18236,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safe-regex/node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12" - } - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -17943,25 +18359,25 @@ } }, "node_modules/send": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", - "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" }, "engines": { "node": ">= 0.8.0" @@ -17977,86 +18393,50 @@ "ms": "2.0.0" } }, - "node_modules/send/node_modules/mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", - "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - } - }, - "node_modules/send/node_modules/ms": { + "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, "license": "MIT" }, - "node_modules/send/node_modules/statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "node_modules/send/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": ">= 0.6" + "node": ">=4" } }, "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.2.tgz", + "integrity": "sha512-KDj11HScOaLmrPxl70KYNW1PksP4Nb/CLL2yvC+Qd2kHMPEEpfc4Re2e4FOay+bC/+XQl/7zAcWON3JVo5v3KQ==", "dev": true, "license": "MIT", "dependencies": { - "accepts": "~1.3.4", + "accepts": "~1.3.8", "batch": "0.6.1", "debug": "2.6.9", "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" + "http-errors": "~1.8.0", + "mime-types": "~2.1.35", + "parseurl": "~1.3.3" }, "engines": { "node": ">= 0.8.0" - } - }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" }, - "engines": { - "node": ">= 0.8.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/serve-static/node_modules/debug": { + "node_modules/serve-index/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", @@ -18066,137 +18446,64 @@ "ms": "2.0.0" } }, - "node_modules/serve-static/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/serve-static/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serve-static/node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/serve-static/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serve-static/node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serve-static/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/serve-static/node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serve-static/node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.8.0" + "node": ">= 0.6" } }, - "node_modules/serve-static/node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dev": true, "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, "engines": { - "node": ">= 0.8" + "node": ">= 0.6" } }, - "node_modules/serve-static/node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/serve-static/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" } }, "node_modules/set-blocking": { @@ -18285,9 +18592,9 @@ } }, "node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true, "license": "ISC" }, @@ -18324,13 +18631,16 @@ } }, "node_modules/shasum-object": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.0.tgz", - "integrity": "sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.1.tgz", + "integrity": "sha512-SsC+1tW7XKQ/94D4k1JhLmjDFpVGET/Nf54jVDtbavbALf8Zhp0Td9zTlxScjMW6nbEIrpADtPWfLk9iCXzHDQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "fast-safe-stringify": "^2.0.7" + }, + "bin": { + "shasum-object": "bin.js" } }, "node_modules/shebang-command": { @@ -18390,14 +18700,14 @@ } }, "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "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.3" + "object-inspect": "^1.13.4" }, "engines": { "node": ">= 0.4" @@ -18474,9 +18784,9 @@ "license": "MIT" }, "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", "dev": true, "license": "MIT", "dependencies": { @@ -18484,9 +18794,9 @@ } }, "node_modules/simple-swizzle/node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", "dev": true, "license": "MIT" }, @@ -18584,6 +18894,20 @@ "node": ">=0.10.0" } }, + "node_modules/snapdragon-node/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", @@ -18620,33 +18944,6 @@ "ms": "2.0.0" } }, - "node_modules/snapdragon/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/snapdragon/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -18670,13 +18967,13 @@ } }, "node_modules/socks": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.6.tgz", - "integrity": "sha512-pe4Y2yzru68lXCb38aAqRf5gvN8YdjP1lok5o0J7BOHljkyCGKVz7H3vpVIXKD27rj2giOJ7DwVyk/GWrPHDWA==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.8.tgz", + "integrity": "sha512-NlGELfPrgX2f1TAAcz0WawlLn+0r3FyhhCRpFFK2CemXenPYvzMWWZINv3eDNo9ucdwme7oCHRY0Jnbs4aIkog==", "dev": true, "license": "MIT", "dependencies": { - "ip-address": "^9.0.5", + "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" }, "engines": { @@ -18805,9 +19102,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.21", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", - "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", "dev": true, "license": "CC0-1.0" }, @@ -18994,41 +19291,14 @@ "node": ">=0.10.0" } }, - "node_modules/static-extend/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/stop-iteration-iterator": { @@ -19132,17 +19402,15 @@ } }, "node_modules/streamx": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.1.tgz", - "integrity": "sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==", + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz", + "integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==", "dev": true, "license": "MIT", "dependencies": { + "events-universal": "^1.0.0", "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" - }, - "optionalDependencies": { - "bare-events": "^2.2.0" } }, "node_modules/strict-uri-encode": { @@ -19542,19 +19810,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/stylelint/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/stylelint/node_modules/camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -19637,19 +19892,6 @@ "node": ">=8" } }, - "node_modules/stylelint/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/stylelint/node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -19780,16 +20022,6 @@ "node": ">=8" } }, - "node_modules/stylelint/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/stylelint/node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -19865,20 +20097,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/stylelint/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/stylelint/node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -20054,19 +20272,6 @@ "node": ">=8" } }, - "node_modules/stylelint/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/stylelint/node_modules/trim-newlines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", @@ -20253,25 +20458,30 @@ "tar-stream": "^3.1.5" } }, - "node_modules/tar-fs/node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "node_modules/tar-fs/node_modules/b4a": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", + "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", "dev": true, - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } } }, "node_modules/tar-fs/node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.0.tgz", + "integrity": "sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==", "dev": true, "license": "MIT", "dependencies": { "b4a": "^1.6.4", + "bare-fs": "^4.5.5", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } @@ -20296,6 +20506,16 @@ "node": ">= 0.8.0" } }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + } + }, "node_modules/temp-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", @@ -20347,15 +20567,30 @@ } }, "node_modules/text-decoder": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", - "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "b4a": "^1.6.4" } }, + "node_modules/text-decoder/node_modules/b4a": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", + "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -20482,9 +20717,9 @@ } }, "node_modules/tlds": { - "version": "1.259.0", - "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.259.0.tgz", - "integrity": "sha512-AldGGlDP0PNgwppe2quAvuBl18UcjuNtOnDuUkqhd6ipPqrYYBt3aTxK1QTsBVknk97lS2JcafWMghjGWFtunw==", + "version": "1.261.0", + "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.261.0.tgz", + "integrity": "sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA==", "dev": true, "license": "MIT", "bin": { @@ -20492,22 +20727,22 @@ } }, "node_modules/tldts": { - "version": "7.0.10", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.10.tgz", - "integrity": "sha512-n6xyIpjWEn6Ikpkir7zVdxNoRO3ZrL+x65ztg/JYoIMoPkpRQ87W4RxbNiso+axhF2zTAzwR+NJJE3NJazLb6Q==", + "version": "7.0.29", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.29.tgz", + "integrity": "sha512-JIXCerhudr/N6OWLwLF1HVsTTUo7ry6qHa5eWZEkiMuxsIiAACL55tGLfqfHfoH7QaMQUW8fngD7u7TxWexYQg==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^7.0.10" + "tldts-core": "^7.0.29" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "7.0.10", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.10.tgz", - "integrity": "sha512-z7PilFbUHwd+IlQ72D0aHDpqykUUpe9yvwa5k/rFvFLmpvNmWqHEIHoSYwE5sA5LZU4bTTIjhDZEjURHc8f2ag==", + "version": "7.0.29", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.29.tgz", + "integrity": "sha512-W99NuU7b1DcG3uJ3v9k9VztCH3WialNbBkBft5wCs8V8mexu0XQqaZEYb9l9RNNzK8+3EJ9PKWB0/RUtTQ/o+Q==", "dev": true, "license": "MIT" }, @@ -20539,9 +20774,9 @@ } }, "node_modules/to-buffer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz", - "integrity": "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", "dev": true, "license": "MIT", "dependencies": { @@ -20616,6 +20851,20 @@ "node": ">=0.10.0" } }, + "node_modules/to-regex/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/to-regex/node_modules/extend-shallow": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", @@ -20630,6 +20879,20 @@ "node": ">=0.10.0" } }, + "node_modules/to-regex/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/to-regex/node_modules/is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", @@ -21084,9 +21347,9 @@ "license": "MIT" }, "node_modules/undici-types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", - "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", "dev": true, "license": "MIT" }, @@ -21115,9 +21378,9 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", - "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", "dev": true, "license": "MIT", "engines": { @@ -21125,9 +21388,9 @@ } }, "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", "dev": true, "license": "MIT", "engines": { @@ -21218,14 +21481,14 @@ "license": "MIT" }, "node_modules/unique-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", - "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.4.0.tgz", + "integrity": "sha512-V6QarSfeSgDipGA9EZdoIzu03ZDlOFkk+FbEP5cwgrZXN3iIkYR91IjU2EnM6rB835kGQsqHX8qncObTXV+6KA==", "dev": true, "license": "MIT", "dependencies": { "json-stable-stringify-without-jsonify": "^1.0.1", - "through2-filter": "^3.0.0" + "through2-filter": "3.0.0" } }, "node_modules/unist-util-find-all-after": { @@ -21347,9 +21610,9 @@ } }, "node_modules/unxhr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unxhr/-/unxhr-1.0.1.tgz", - "integrity": "sha512-MAhukhVHyaLGDjyDYhy8gVjWJyhTECCdNsLwlMoGFoNJ3o79fpQhtQuzmAE4IxCMDwraF4cW8ZjpAV0m9CRQbg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unxhr/-/unxhr-1.2.0.tgz", + "integrity": "sha512-6cGpm8NFXPD9QbSNx0cD2giy7teZ6xOkCUH3U89WKVkL9N9rBrWjlCwhR94Re18ZlAop4MOc3WU1M3Hv/bgpIw==", "dev": true, "license": "MIT", "engines": { @@ -21368,9 +21631,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -21550,7 +21813,7 @@ "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", "dev": true, "license": "MIT", "optional": true, @@ -22034,9 +22297,9 @@ "license": "ISC" }, "node_modules/which-typed-array": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", - "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", "dev": true, "license": "MIT", "dependencies": { @@ -22234,9 +22497,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", "dev": true, "license": "ISC", "engines": { diff --git a/preview-src/home.adoc b/preview-src/home.adoc index ac4e2211..11717ef1 100644 --- a/preview-src/home.adoc +++ b/preview-src/home.adoc @@ -1,6 +1,35 @@ = Welcome to Redpanda Documentation :page-role: home :description: Home page for the Redpanda docs site. -:page-ai-suggestions: ["How do I write from Redpanda Self-Managed to Snowflake?", "What's the difference between Redpanda and Kafka?", "Which Iceberg catalogs does Redpanda Cloud support?", "How do I create a CDC pipeline from MongoDB to Redpanda Cloud?", "How do I write from Redpanda Cloud to Google BigQuery?", "How do I create a CDC pipeline from Postgres to Redpanda Cloud?", "How do I create a CDC pipeline from MySQL to Redpanda Cloud?"] +:page-ai-suggestions: ["How do I write from Redpanda Streaming to Snowflake?", "What's the difference between Redpanda and Kafka?", "Which Iceberg catalogs does Redpanda Cloud support?", "How do I create a CDC pipeline from MongoDB to Redpanda Cloud?", "How do I write from Redpanda Cloud to Google BigQuery?", "How do I create a CDC pipeline from Postgres to Redpanda Cloud?", "How do I create a CDC pipeline from MySQL to Redpanda Cloud?"] :page-intro: 'Find tutorials, guides, and API references to help you build with Redpanda, the modern streaming data platform for mission-critical workloads.' :page-row: [{"title":"Get started","items":[{"title":"Serverless","image":"serverless.svg","description":"Get fast, efficient, and scalable data streaming without infrastructure management.","urls":[{"url":"redpanda-cloud:get-started:cluster-types/serverless.adoc"}]},{"title":"Self-Managed","image":"self-managed.svg","description":"Run Redpanda on your own infrastructure with complete control over your deployment and configuration.","urls":[{"url":"ROOT:get-started:quick-start.adoc"}]},{"title":"Connect","image":"connect.svg","description":"Integrate data across systems with hundreds of prebuilt connectors, including AI and change data capture (CDC).","urls":[{"url":"redpanda-connect:get-started:quickstarts/rpk.adoc"}]}]}] +// Cloud sub-products (for nested cards) +:product-cloud-streaming-title: Streaming +:product-cloud-streaming-desc: High-performance Kafka-compatible event streaming in the cloud +:cloud-streaming-quickstart: cloud-data-platform:get-started:cluster-types/serverless.adoc +:cloud-streaming-docs: cloud-data-platform:streaming:index.adoc +:product-cloud-connect-title: Connect +:product-cloud-connect-desc: Integrate data across systems with hundreds of prebuilt connectors +:cloud-connect-quickstart: connect:get-started:quickstarts/rpk.adoc +:cloud-connect-docs: connect:ROOT:index.adoc +:product-cloud-sql-title: Redpanda SQL +:product-cloud-sql-desc: Query streaming data with SQL in real-time (Cloud BYOC only) +:cloud-sql-quickstart: cloud-data-platform:sql:quickstart.adoc +:cloud-sql-docs: cloud-data-platform:sql:index.adoc +// What's New - SQL feature for Cloud BYOC +:component-whats-new-1-title: Redpanda SQL +:component-whats-new-1-desc: Query your streaming data in real-time with SQL. Run analytical queries directly on topics without ETL pipelines. +:component-whats-new-1-link: cloud-data-platform:sql:index.adoc +:component-whats-new-1-tag: Cloud BYOC +// Home page links (matching data-platform structure) +:cloud-home: cloud-data-platform:ROOT:index.adoc +:self-managed-home: streaming:ROOT:index.adoc +:self-managed-quickstart: streaming:get-started:quick-start.adoc +:self-managed-tiered-storage: streaming:manage:tiered-storage.adoc +:cloud-byoc: cloud-data-platform:get-started:cluster-types/byoc.adoc +:connect-quickstart: connect:get-started:quickstarts/rpk.adoc +:self-managed-migrate: streaming:migrate:from-kafka.adoc +:self-managed-schema-registry: streaming:manage:schema-registry.adoc +:self-managed-producers: streaming:develop:produce-data:index.adoc +:self-managed-consumers: streaming:develop:consume-data:index.adoc diff --git a/preview-src/ui-model.yml b/preview-src/ui-model.yml index 23553a00..5364c2b0 100644 --- a/preview-src/ui-model.yml +++ b/preview-src/ui-model.yml @@ -2,29 +2,44 @@ antoraVersion: '1.0.0' site: url: https://deploy-preview-327--docs-ui.netlify.app title: UI Preview - homeUrl: &home_url /xyz/24.3/index.html + homeUrl: &home_url /streaming/24.3/index.html components: - - name: abc - title: Project ABC + # Agentic Data Plane component + - name: agentic-data-plane + title: Agentic Data Plane url: '#' versions: - - &latest_version_abc + - &latest_version_adp url: '#' - version: '1.1' - displayVersion: '1.1' - - url: '#' version: '1.0' displayVersion: '1.0' - latestVersion: *latest_version_abc + asciidoc: + attributes: + component-metadata: + title: Agentic Data Plane + description: Build, connect, and govern AI agents. + color: '#7C3AED' + order: 1 + latestVersion: *latest_version_adp + # Streaming component - under Data Platform (formerly Self-Managed/ROOT) - &component - name: ROOT - title: &component_title Redpanda - url: /xyz/6.0/index.html + name: streaming + title: &component_title Streaming + url: /streaming/6.0/index.html versions: - &latest_version_xyz - url: /xyz/6.0/index.html + url: /streaming/6.0/index.html version: '6.0' displayVersion: '6.0' + asciidoc: + attributes: + component-metadata: + title: Streaming + parent-component: self-managed + description: Run Redpanda on your own infrastructure. + color: '#6366f1' + icon: activity + order: 1 - &component_version title: *component_title url: '#' @@ -32,6 +47,13 @@ site: displayVersion: '24.3' asciidoc: attributes: + component-metadata: + title: Streaming + parent-component: self-managed + description: Run Redpanda on your own infrastructure. + color: '#6366f1' + icon: activity + order: 1 toc-tools-title: Connect Tools toc-tools-links: '[{"text": "Bloblang Playground", "url": "/playground", "icon": "terminal"}, {"text": "Claude AI Skills", "url": "https://github.com/redpanda-data/connect/blob/main/.claude-plugin/README.md", "icon": "layers", "external": true}]' - url: '#' @@ -41,21 +63,42 @@ site: version: '5.0' displayVersion: '5.0' latestVersion: *latest_version_xyz - - name: '123' - title: Project 123 + # Cloud component - under Data Platform + - name: cloud-data-platform + title: Cloud url: '#' versions: - - &latest_version_123 + - &latest_version_cloud url: '#' - version: '2.2' - displayVersion: '2.2' - - url: '#' - version: '2.1' - displayVersion: '2.1' - - url: '#' - version: '2.0' - displayVersion: '2.0' - latestVersion: *latest_version_123 + version: '1.0' + displayVersion: '1.0' + asciidoc: + attributes: + component-metadata: + title: Cloud + description: Fully managed Redpanda clusters. + color: '#0891B2' + order: 2 + latestVersion: *latest_version_cloud + # Connect component - under Data Platform (formerly redpanda-connect) + - name: connect + title: Connect + url: '#' + versions: + - &latest_version_connect + url: '#' + version: '4.0' + displayVersion: '4.0' + asciidoc: + attributes: + component-metadata: + title: Connect + parent-component: self-managed + description: Stream processing and integration connectors. + color: '#059669' + icon: plug-connected + order: 2 + latestVersion: *latest_version_connect page: url: *home_url home: true @@ -81,11 +124,17 @@ page: url: '#' urlType: 'internal' breadcrumbs: + - content: Data Platform + url: '#' + urlType: internal + - content: Streaming + url: '#' + urlType: internal - content: Quickstart url: '#' urlType: internal - content: Brand’s Hardware & Software Requirements - url: /xyz/24.3/index.html + url: /streaming/24.3/index.html urlType: internal versions: - version: '6.0' @@ -109,16 +158,16 @@ page: urlType: internal items: - content: Brand’s Hardware & Software Requirements - url: /xyz/24.3/index.html + url: /streaming/24.3/index.html urlType: internal - content: Bloblang Syntax - url: /xyz/24.3/bloblang-syntax-test.html + url: /streaming/24.3/bloblang-syntax-test.html urlType: internal - content: Bloblang Playground - url: /xyz/24.3/playground.html + url: /streaming/24.3/playground.html urlType: internal - content: Home page - url: /xyz/24.3/home.html + url: /streaming/24.3/home.html urlType: internal - content: Get Started url: '#' @@ -337,6 +386,6 @@ page: url: '#' urlType: internal - content: Limited Availability Test - url: /xyz/24.3/limited-availability-test.html + url: /streaming/24.3/limited-availability-test.html urlType: internal diff --git a/src/css/announcement-banner.css b/src/css/announcement-banner.css index e7a927d5..7f03a3a2 100644 --- a/src/css/announcement-banner.css +++ b/src/css/announcement-banner.css @@ -1,48 +1,74 @@ +/* Announcement bar - smooth animated reveal without CLS */ .announcement-bar { + display: flex; flex-basis: 100%; - display: none; align-items: center; justify-content: center; flex-wrap: wrap; - background: #101828; + background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); color: white; z-index: var(--z-index-navbar); font-size: var(--secondary-font-size); position: fixed; top: 0; + left: 0; width: 100%; text-align: center; - height: var(--announcement-bar-height); + /* Start collapsed - JS will reveal */ + max-height: 0; + overflow: hidden; + opacity: 0; + transition: + max-height 0.3s ease-out, + opacity 0.2s ease-out; +} + +/* Show when active (set by JavaScript) */ +.announcement-bar.is-active { + max-height: 60px; /* Mobile height */ + opacity: 1; +} + +.announcement-bar .announcement-content { + padding: 10px 40px 10px 16px; + line-height: 1.4; } .announcement-bar .announcement-content a { padding-left: 5px; - color: white; + color: #93c5fd; text-decoration: underline; + text-underline-offset: 2px; +} + +.announcement-bar .announcement-content a:hover { + color: #bfdbfe; } .announcement-bar button.close { border: none; - color: white; + color: rgba(255, 255, 255, 0.7); background: none; margin-top: 0; - padding: 0; + padding: 8px; position: absolute; - right: 20px; + right: 8px; + top: 50%; + transform: translateY(-50%); + cursor: pointer; + transition: color 0.15s; } -@media screen and (max-width: 550px) { - .announcement-bar button.close { - margin-top: 1.2rem; - } +.announcement-bar button.close:hover { + color: white; } @media screen and (min-width: 1024px) { - .announcement-bar { - height: var(--announcement-bar-height--desktop); + .announcement-bar.is-active { + max-height: 36px; /* Desktop height */ } .announcement-bar button.close { - right: 40px; + right: 16px; } } diff --git a/src/css/base.css b/src/css/base.css index cb795781..989cb0c7 100644 --- a/src/css/base.css +++ b/src/css/base.css @@ -55,7 +55,7 @@ dt, strong, th { font-family: var(--body-font-family-bold); - font-weight: lighter; + font-weight: var(--body-font-weight-bold); } sub, diff --git a/src/css/bloblang-interactive.css b/src/css/bloblang-interactive.css index bfc11c31..4724c989 100644 --- a/src/css/bloblang-interactive.css +++ b/src/css/bloblang-interactive.css @@ -376,7 +376,6 @@ html[data-theme="dark"] .bloblang-doc-tooltip .doc-link:hover { max-height: 100px; border: 1px solid rgba(204, 204, 204, 0.3); border-radius: 6px; - overflow: hidden; font-size: 13px; background: var(--pre-background, #f6f8fa); } diff --git a/src/css/bloblang-playground.css b/src/css/bloblang-playground.css index 94b0d5f1..73cfe6e2 100644 --- a/src/css/bloblang-playground.css +++ b/src/css/bloblang-playground.css @@ -1,7 +1,27 @@ +.bloblang-playground .component-indicator-sticky { + margin-top: 0; +} + +.bloblang-playground .doc h1.page { + margin-bottom: 16px; + visibility: visible !important; + display: block !important; + opacity: 1 !important; + position: relative !important; + z-index: 1 !important; +} + +/* Adjust H1 font size on larger screens */ +@media screen and (min-width: 769px) { + .bloblang-playground .doc h1.page { + font-size: calc(40 / var(--rem-base) * 1rem); + } +} + .bloblang-playground .doc { max-width: unset; margin-right: 48px; - overflow-x: hidden; + overflow-x: clip; /* Use clip instead of hidden to preserve sticky positioning */ } /* Form */ @@ -108,8 +128,21 @@ .bloblang-playground #contact-email { padding: 8px; font-size: 14px; - border: 1px solid #ccc; - border-radius: 4px; + border: 1px solid var(--grey-200-new, #e5e5e5); + border-radius: 6px; + background: var(--body-background); + color: var(--body-font-color); + transition: border-color 0.15s ease; +} + +html[data-theme=dark] .bloblang-playground #contact-email { + border-color: rgba(255, 255, 255, 0.1); +} + +.bloblang-playground #contact-email:focus { + outline: none; + border-color: var(--component-color, #6366f1); + box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.15); } /* Main container setup - horizontal flow on desktop, vertical on mobile */ @@ -169,8 +202,12 @@ padding: 10px 12px !important; margin: 8px 8px 16px 8px !important; background: var(--body-background); - border: 1px solid var(--panel-border-color); - border-radius: 4px; + border: 1px solid var(--grey-200-new, #e5e5e5); + border-radius: 6px; +} + +html[data-theme=dark] .bloblang-playground .choices__list--dropdown .choices__input { + border-color: rgba(255, 255, 255, 0.1); } /* Dropdown items - ensure proper spacing from search input */ @@ -255,76 +292,104 @@ html[data-theme=dark] .bloblang-playground .execution-time-error { .bloblang-playground input#bloblang-email { padding: 6px 8px; - background: rgba(68, 76, 231, 0); - border: 1px solid #8098f9; + background: var(--body-background); + border: 1px solid var(--grey-200-new, #e5e5e5); border-radius: 6px; color: var(--body-font-color); margin-top: 0; font-size: 14px; + transition: border-color 0.15s ease; } +html[data-theme=dark] .bloblang-playground input#bloblang-email { + border-color: rgba(255, 255, 255, 0.1); +} + +.bloblang-playground input#bloblang-email:focus { + outline: none; + border-color: var(--component-color, #6366f1); + box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.15); +} + +/* Modern button styling matching redesign */ .bloblang-playground .button:not(#sample-dropdown), .bloblang-playground button[type=submit]:not(.aa-SubmitButton) { - padding: 8px 16px; + padding: 8px 14px; background: var(--body-background); - border: 1.5px solid rgba(128, 152, 249, 0.5); - border-radius: 6px; + border: 1px solid var(--grey-200-new, #e5e5e5); + border-radius: 8px; color: var(--body-font-color); margin-top: 0; cursor: pointer; - font-size: 14px; - transition: all 0.2s ease; + font-size: 13px; + transition: all 0.15s ease; font-weight: 500; display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04); +} + +html[data-theme=dark] .bloblang-playground .button:not(#sample-dropdown), +html[data-theme=dark] .bloblang-playground button[type=submit]:not(.aa-SubmitButton) { + border-color: rgba(255, 255, 255, 0.1); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); } .bloblang-playground #sample-dropdown { padding: 8px 12px; - background: rgba(68, 76, 231, 0); - border: 1px solid rgba(128, 152, 249, 1); - border-radius: 6px; + background: var(--body-background); + border: 1px solid var(--grey-200-new, #e5e5e5); + border-radius: 8px; color: var(--body-font-color); margin-top: 0; cursor: pointer; - font-size: 14px; - transition: all 0.2s ease; + font-size: 13px; + transition: all 0.15s ease; font-weight: 500; display: inline-block; width: auto; min-width: 200px; } +html[data-theme=dark] .bloblang-playground #sample-dropdown { + border-color: rgba(255, 255, 255, 0.1); +} + .bloblang-playground #sample-dropdown option { padding: 8px; } .bloblang-playground button[type=submit]:not(.aa-SubmitButton) { - background-color: #4474e7; + background-color: var(--component-color, #6366f1); color: #ffffff; + border-color: var(--component-color, #6366f1); } .bloblang-playground button[type=submit]:not(.aa-SubmitButton):hover { - background-color: #365bd6; - transform: translateY(-2px); + filter: brightness(1.1); color: #ffffff; } .bloblang-playground .button { - border: 1px solid rgba(128, 152, 249, 1); - border-radius: 6px; + border: 1px solid var(--grey-200-new, #e5e5e5); + border-radius: 8px; +} + +html[data-theme=dark] .bloblang-playground .button { + border-color: rgba(255, 255, 255, 0.1); } .bloblang-playground .button:hover { - background: rgba(68, 76, 231, 0.06); + background: var(--grey-50-new, #f9fafb); + border-color: var(--grey-300-new, #d1d5db); color: var(--body-font-color); } html[data-theme=dark] .bloblang-playground .button:hover { - background: rgba(68, 76, 231); + background: rgba(255, 255, 255, 0.05); + border-color: rgba(255, 255, 255, 0.15); color: var(--body-font-color); } @@ -341,18 +406,23 @@ html[data-theme=dark] .bloblang-playground .button:hover { } .bloblang-playground .editor-section-always-open { - border: 1px solid rgba(204, 204, 204, 0.3); + border: 1px solid var(--grey-200-new, #e5e5e5); border-radius: 8px; overflow: visible; background: var(--body-background); - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); - transition: box-shadow 0.2s ease; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04); + transition: box-shadow 0.15s ease, border-color 0.15s ease; display: flex; flex-direction: column; min-width: 0; max-width: 100%; } +html[data-theme=dark] .bloblang-playground .editor-section-always-open { + border-color: rgba(255, 255, 255, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); +} + /* Flow arrow divider between input/mapping and output */ .bloblang-playground .flow-arrow { display: none; @@ -391,7 +461,13 @@ html[data-theme=dark] .bloblang-playground .button:hover { } .bloblang-playground .editor-section-always-open:hover { - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06); + border-color: var(--grey-300-new, #d1d5db); +} + +html[data-theme=dark] .bloblang-playground .editor-section-always-open:hover { + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25); + border-color: rgba(255, 255, 255, 0.15); } .bloblang-playground .editor-header { @@ -400,12 +476,14 @@ html[data-theme=dark] .bloblang-playground .button:hover { align-items: flex-start; padding: 10px 12px; background: var(--body-background); - border-bottom: 1px solid rgba(204, 204, 204, 0.15); + border-bottom: 1px solid var(--grey-100-new, #f3f4f6); flex-shrink: 0; min-height: 70px; - max-height: 70px; box-sizing: border-box; - overflow: hidden; +} + +html[data-theme=dark] .bloblang-playground .editor-header { + border-bottom-color: rgba(255, 255, 255, 0.06); } .bloblang-playground .editor-header-content { @@ -413,16 +491,17 @@ html[data-theme=dark] .bloblang-playground .button:hover { flex-direction: column; gap: 4px; flex: 1; - overflow: hidden; - max-height: 48px; + min-width: 0; } -/* Ensure consistent height for the status/validation row in headers */ +/* Status/validation row in headers - allow expansion for errors */ .bloblang-playground .editor-header-content > div:last-child { min-height: 22px; - max-height: 22px; - overflow: hidden; box-sizing: border-box; + display: flex; + align-items: flex-start; + flex-wrap: wrap; + gap: 8px; } .bloblang-playground .editor-header h4 { @@ -476,7 +555,7 @@ html[data-theme=dark] .bloblang-playground .button:hover { gap: 8px; padding: 12px 16px; background: var(--body-background); - border: 1px solid rgba(204, 204, 204, 0.3); + border: 1px solid var(--grey-200-new, #e5e5e5); border-radius: 8px; font-size: 14px; font-weight: 500; @@ -486,9 +565,18 @@ html[data-theme=dark] .bloblang-playground .button:hover { box-sizing: border-box; } +html[data-theme=dark] .bloblang-playground .advanced-options-toggle { + border-color: rgba(255, 255, 255, 0.1); +} + .bloblang-playground .advanced-options-toggle:hover { - background: rgba(68, 76, 231, 0.04); - border-color: rgba(128, 152, 249, 0.4); + background: var(--grey-50-new, #f9fafb); + border-color: var(--grey-300-new, #d1d5db); +} + +html[data-theme=dark] .bloblang-playground .advanced-options-toggle:hover { + background: rgba(255, 255, 255, 0.03); + border-color: rgba(255, 255, 255, 0.15); } .bloblang-playground .advanced-options-toggle .toggle-icon { @@ -517,7 +605,7 @@ html[data-theme=dark] .bloblang-playground .button:hover { .bloblang-playground .editor-section-collapsible { background: var(--body-background); - border: 1px solid rgba(204, 204, 204, 0.3); + border: 1px solid var(--grey-200-new, #e5e5e5); border-radius: 8px; overflow: hidden; margin-bottom: 0; @@ -525,6 +613,10 @@ html[data-theme=dark] .bloblang-playground .button:hover { flex-direction: column; } +html[data-theme=dark] .bloblang-playground .editor-section-collapsible { + border-color: rgba(255, 255, 255, 0.1); +} + .bloblang-playground .editor-section-collapsible[open] { /* When open, allow content to stretch */ } @@ -593,14 +685,19 @@ html[data-theme=dark] .bloblang-playground .button:hover { } .bloblang-playground .optional-badge { - font-size: 11px; - background: rgba(68, 76, 231, 0.1); - color: #4474e7; + font-size: 10px; + background: var(--grey-100-new, #f3f4f6); + color: var(--grey-600-new, #4b5563); padding: 2px 6px; - border-radius: 3px; + border-radius: 4px; font-weight: 500; text-transform: uppercase; - letter-spacing: 0.5px; + letter-spacing: 0.3px; +} + +html[data-theme=dark] .bloblang-playground .optional-badge { + background: rgba(255, 255, 255, 0.08); + color: rgba(255, 255, 255, 0.6); } /* Editor areas */ @@ -612,12 +709,26 @@ html[data-theme=dark] .bloblang-playground .button:hover { max-height: 400px; padding: 10px; overflow-y: auto; - border-radius: 5px; + border-radius: 6px; position: relative; - border: 1px solid rgb(204, 204, 204); + border: 1px solid var(--grey-200-new, #e5e5e5); resize: vertical; min-width: 0; flex: 1; + transition: border-color 0.15s ease; +} + +html[data-theme=dark] .bloblang-playground .editor { + border-color: rgba(255, 255, 255, 0.1); +} + +.bloblang-playground .editor:focus-within { + border-color: var(--component-color, #6366f1); + box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.1); +} + +html[data-theme=dark] .bloblang-playground .editor:focus-within { + box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2); } /* Ensure Ace editor scrollbars are always visible when content overflows */ @@ -666,12 +777,17 @@ html[data-theme=dark] .bloblang-playground .button:hover { flex-direction: column; gap: 1em; padding: 1.5em; - border: 1px solid rgb(204, 204, 204); + border: 1px solid var(--grey-200-new, #e5e5e5); border-radius: 8px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); margin: 2em 0; } +html[data-theme=dark] .bloblang-snippet { + border-color: rgba(255, 255, 255, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); +} + .bloblang-snippet .bloblang-editor { font-family: var(--monospace-font-family); font-size: var(--body-font-size); @@ -694,13 +810,17 @@ html[data-theme=dark] .bloblang-playground .button:hover { .bloblang-snippet .ace-editor { width: 100%; - border: 1px solid rgb(204, 204, 204); - border-radius: 5px; + border: 1px solid var(--grey-200-new, #e5e5e5); + border-radius: 6px; min-height: 75px; color: var(--code-font-color); background-color: var(--pre-background); } +html[data-theme=dark] .bloblang-snippet .ace-editor { + border-color: rgba(255, 255, 255, 0.1); +} + @media (max-width: 1024px) { .bloblang-playground .banner { margin-left: -1rem; @@ -732,53 +852,57 @@ html[data-theme=dark] .bloblang-playground .button:hover { /* Playground tip */ .bloblang-playground .playground-tip { - background: linear-gradient(135deg, rgba(68, 116, 231, 0.08) 0%, rgba(68, 116, 231, 0.04) 100%); - border: 1px solid rgba(68, 116, 231, 0.2); + background: var(--grey-50-new, #f9fafb); + border: 1px solid var(--grey-200-new, #e5e5e5); border-radius: 8px; padding: 12px 16px; margin-bottom: 16px; position: relative; - font-size: 14px; + font-size: 13px; line-height: 1.5; } +html[data-theme=dark] .bloblang-playground .playground-tip { + background: rgba(255, 255, 255, 0.03); + border-color: rgba(255, 255, 255, 0.1); +} + .bloblang-playground .playground-tip-content { color: var(--body-font-color); } .bloblang-playground .playground-tip-content strong { - color: var(--link-highlight-color); + color: var(--body-font-color); + font-weight: 600; } .bloblang-playground .playground-tip-content a { - color: var(--link-highlight-color); - text-decoration: underline; + color: var(--component-color, #6366f1); + text-decoration: none; font-weight: 500; } .bloblang-playground .playground-tip-content a:hover { - color: var(--link_hover-font-color); + text-decoration: underline; } .bloblang-playground .try-example-button { - background: #4474e7; + background: var(--component-color, #6366f1); color: white; - border: 1.5px solid #4474e7; - border-radius: 5px; + border: none; + border-radius: 6px; padding: 6px 12px; font-size: 13px; - font-weight: 600; + font-weight: 500; cursor: pointer; - transition: all 0.2s ease; + transition: all 0.15s ease; display: inline-block; - box-shadow: 0 2px 4px rgba(68, 116, 231, 0.2); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); } .bloblang-playground .try-example-button:hover { - background: #365bd6; - border-color: #365bd6; - box-shadow: 0 3px 6px rgba(68, 116, 231, 0.3); - transform: translateY(-1px); + filter: brightness(1.1); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15); } .bloblang-playground .dismiss-tip { @@ -995,15 +1119,22 @@ html[data-theme=dark] .bloblang-playground .button:hover { right: 20px; padding: 12px 20px; border-radius: 8px; - background: white; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + background: var(--body-background); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); z-index: 10000; opacity: 0; transform: translateX(400px); transition: all 0.3s ease; max-width: 400px; font-size: 14px; - border-left: 4px solid #4474e7; + border: 1px solid var(--grey-200-new, #e5e5e5); + border-left: 4px solid var(--component-color, #6366f1); +} + +html[data-theme=dark] .bloblang-playground .notification { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); + border-color: rgba(255, 255, 255, 0.1); + border-left-color: var(--component-color, #6366f1); } .bloblang-playground { @@ -1067,23 +1198,20 @@ html[data-theme=dark] .bloblang-playground .notification-info { .bloblang-playground .validation-indicator { font-size: 11px; font-weight: 500; - padding: 2px 8px; - border-radius: 4px; + padding: 4px 10px; + border-radius: 6px; display: inline-block; flex-shrink: 1; min-width: 0; - max-width: 200px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - line-height: 1.3; + line-height: 1.4; box-sizing: border-box; - max-height: 20px; } +/* Success state - compact single line */ .bloblang-playground .validation-success { color: var(--color-primitives-global-green-green-700); background: var(--color-primitives-global-green-green-50); + white-space: nowrap; } html[data-theme=dark] .bloblang-playground .validation-success { @@ -1091,11 +1219,14 @@ html[data-theme=dark] .bloblang-playground .validation-success { background: rgba(56, 161, 105, 0.15); } +/* Error state - allow full message to show */ .bloblang-playground .validation-error { color: var(--color-primitives-global-red-red-700); background: var(--color-primitives-global-red-red-50); - max-width: 100%; + white-space: normal; word-break: break-word; + flex: 1 1 auto; + max-width: 100%; } html[data-theme=dark] .bloblang-playground .validation-error { @@ -1117,22 +1248,34 @@ html[data-theme=dark] .bloblang-playground .validation-info { .bloblang-playground .input-format-selector { font-size: 12px; padding: 4px 8px; - border: 1px solid rgba(128, 152, 249, 0.3); - border-radius: 4px; + border: 1px solid var(--grey-200-new, #e5e5e5); + border-radius: 6px; background: var(--body-background); color: var(--body-font-color); cursor: pointer; - transition: border-color 0.2s ease; + transition: border-color 0.15s ease; +} + +html[data-theme=dark] .bloblang-playground .input-format-selector { + border-color: rgba(255, 255, 255, 0.1); } .bloblang-playground .input-format-selector:hover { - border-color: rgba(128, 152, 249, 0.6); + border-color: var(--grey-300-new, #d1d5db); +} + +html[data-theme=dark] .bloblang-playground .input-format-selector:hover { + border-color: rgba(255, 255, 255, 0.15); } .bloblang-playground .input-format-selector:focus { outline: none; - border-color: #4474e7; - box-shadow: 0 0 0 2px rgba(68, 116, 231, 0.2); + border-color: var(--component-color, #6366f1); + box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.15); +} + +html[data-theme=dark] .bloblang-playground .input-format-selector:focus { + box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.25); } /* Streamlined tooltips for playground */ @@ -1167,26 +1310,33 @@ html[data-theme=dark] .bloblang-playground .editor-success { /* Copy output button */ .bloblang-playground .copy-output-button { background: var(--body-background); - border: 1.5px solid rgba(128, 152, 249, 0.4); + border: 1px solid var(--grey-200-new, #e5e5e5); color: var(--body-font-color); padding: 5px 12px; - border-radius: 5px; + border-radius: 6px; cursor: pointer; font-size: 12px; font-weight: 500; - transition: all 0.2s ease; + transition: all 0.15s ease; display: inline-flex; align-items: center; gap: 4px; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04); +} + +html[data-theme=dark] .bloblang-playground .copy-output-button { + border-color: rgba(255, 255, 255, 0.1); } .bloblang-playground .copy-output-button:hover { - background: rgba(68, 76, 231, 0.06); - border-color: #4474e7; + background: var(--grey-50-new, #f9fafb); + border-color: var(--grey-300-new, #d1d5db); color: var(--body-font-color); - box-shadow: 0 2px 4px rgba(68, 116, 231, 0.15); - transform: translateY(-1px); +} + +html[data-theme=dark] .bloblang-playground .copy-output-button:hover { + background: rgba(255, 255, 255, 0.05); + border-color: rgba(255, 255, 255, 0.15); } /* Shortcuts overlay */ @@ -1213,7 +1363,13 @@ html[data-theme=dark] .bloblang-playground .editor-success { max-width: 500px; width: 90%; position: relative; - box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3); + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15); + border: 1px solid var(--grey-200-new, #e5e5e5); +} + +html[data-theme=dark] .bloblang-playground .shortcuts-content { + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4); + border-color: rgba(255, 255, 255, 0.1); } .bloblang-playground .shortcuts-content h3 { @@ -1248,32 +1404,46 @@ html[data-theme=dark] .bloblang-playground .editor-success { .bloblang-playground .shortcuts-list li { padding: 10px 0; - border-bottom: 1px solid rgba(204, 204, 204, 0.2); + border-bottom: 1px solid var(--grey-100-new, #f3f4f6); display: flex; justify-content: space-between; align-items: center; color: var(--body-font-color); } +html[data-theme=dark] .bloblang-playground .shortcuts-list li { + border-bottom-color: rgba(255, 255, 255, 0.06); +} + .bloblang-playground .shortcuts-list li:last-child { border-bottom: none; } .bloblang-playground .shortcuts-list kbd { - background: rgba(68, 76, 231, 0.1); + background: var(--grey-100-new, #f3f4f6); padding: 4px 8px; border-radius: 4px; font-family: var(--monospace-font-family); font-size: 12px; - color: #4474e7; - border: 1px solid rgba(68, 76, 231, 0.2); + color: var(--body-font-color); + border: 1px solid var(--grey-200-new, #e5e5e5); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); +} + +html[data-theme=dark] .bloblang-playground .shortcuts-list kbd { + background: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.1); } .bloblang-playground .shortcuts-divider { - border-top: 2px solid rgba(102, 126, 234, 0.2); + border-top: 1px solid var(--grey-200-new, #e5e5e5); margin: 24px 0 20px 0; } +html[data-theme=dark] .bloblang-playground .shortcuts-divider { + border-top-color: rgba(255, 255, 255, 0.1); +} + .bloblang-playground .shortcuts-claude-section { margin-top: 0; } @@ -1288,7 +1458,7 @@ html[data-theme=dark] .bloblang-playground .editor-success { } .bloblang-playground .shortcuts-claude-title svg { - color: #667eea; + color: var(--component-color, #6366f1); } .bloblang-playground .shortcuts-claude-description { @@ -1313,47 +1483,33 @@ html[data-theme=dark] .bloblang-playground .editor-success { .bloblang-playground .shortcuts-claude-list strong { font-family: var(--monospace-font-family); - color: #667eea; + color: var(--component-color, #6366f1); font-weight: 600; font-size: 12px; - background: rgba(102, 126, 234, 0.08); + background: rgba(99, 102, 241, 0.08); padding: 2px 6px; - border-radius: 3px; + border-radius: 4px; margin-right: 4px; } +html[data-theme="dark"] .bloblang-playground .shortcuts-claude-list strong { + background: rgba(99, 102, 241, 0.15); +} + .bloblang-playground .shortcuts-claude-link { display: inline-flex; align-items: center; - color: #667eea; + color: var(--component-color, #6366f1); text-decoration: none; font-size: 13px; font-weight: 500; - transition: all 0.2s ease; + transition: all 0.15s ease; } .bloblang-playground .shortcuts-claude-link:hover { - color: #5a67d8; text-decoration: underline; } -[data-theme="dark"] .bloblang-playground .shortcuts-claude-title svg { - color: #8b9ef7; -} - -[data-theme="dark"] .bloblang-playground .shortcuts-claude-list strong { - color: #8b9ef7; - background: rgba(139, 158, 247, 0.12); -} - -[data-theme="dark"] .bloblang-playground .shortcuts-claude-link { - color: #8b9ef7; -} - -[data-theme="dark"] .bloblang-playground .shortcuts-claude-link:hover { - color: #a5b4f9; -} - /* Share modal */ .bloblang-playground .share-modal { position: fixed; @@ -1377,7 +1533,13 @@ html[data-theme=dark] .bloblang-playground .editor-success { border-radius: 12px; max-width: 600px; width: 90%; - box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3); + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15); + border: 1px solid var(--grey-200-new, #e5e5e5); +} + +html[data-theme=dark] .bloblang-playground .share-modal-content { + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4); + border-color: rgba(255, 255, 255, 0.1); } .bloblang-playground .share-modal-content h3 { @@ -1394,7 +1556,7 @@ html[data-theme=dark] .bloblang-playground .editor-success { .bloblang-playground .share-url-container input { flex: 1; padding: 10px; - border: 1px solid rgba(204, 204, 204, 0.5); + border: 1px solid var(--grey-200-new, #e5e5e5); border-radius: 6px; font-family: var(--monospace-font-family); font-size: 12px; @@ -1402,34 +1564,43 @@ html[data-theme=dark] .bloblang-playground .editor-success { color: var(--code-font-color); } +html[data-theme=dark] .bloblang-playground .share-url-container input { + border-color: rgba(255, 255, 255, 0.1); +} + .bloblang-playground .button-primary { - background: #4474e7; + background: var(--component-color, #6366f1); color: white; - border: 1.5px solid #4474e7; - font-weight: 600; - box-shadow: 0 2px 4px rgba(68, 116, 231, 0.2); + border: 1px solid var(--component-color, #6366f1); + font-weight: 500; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); } .bloblang-playground .button-primary:hover { - background: #365bd6; - border-color: #365bd6; + filter: brightness(1.1); color: white; - box-shadow: 0 3px 6px rgba(68, 116, 231, 0.3); - transform: translateY(-1px); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15); } .bloblang-playground .button-secondary { background: var(--body-background); - border: 1.5px solid rgba(128, 152, 249, 0.5); + border: 1px solid var(--grey-200-new, #e5e5e5); color: var(--body-font-color); } +html[data-theme=dark] .bloblang-playground .button-secondary { + border-color: rgba(255, 255, 255, 0.1); +} + .bloblang-playground .button-secondary:hover { - background: rgba(68, 76, 231, 0.06); - border-color: #4474e7; + background: var(--grey-50-new, #f9fafb); + border-color: var(--grey-300-new, #d1d5db); color: var(--body-font-color); - box-shadow: 0 2px 4px rgba(68, 116, 231, 0.15); - transform: translateY(-1px); +} + +html[data-theme=dark] .bloblang-playground .button-secondary:hover { + background: rgba(255, 255, 255, 0.05); + border-color: rgba(255, 255, 255, 0.15); } .bloblang-playground #show-shortcuts { @@ -1439,16 +1610,16 @@ html[data-theme=dark] .bloblang-playground .editor-success { align-items: center; justify-content: center; font-size: 18px; - font-weight: 700; - border-radius: 6px; + font-weight: 500; + border-radius: 8px; } /* ACE Editor Autocomplete Styles */ .bloblang-playground .ace_editor.ace_autocomplete { background: var(--body-background) !important; - border: 1px solid rgba(128, 152, 249, 0.3) !important; + border: 1px solid var(--grey-200-new, #e5e5e5) !important; border-radius: 8px !important; - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15), 0 0 0 1px rgba(68, 116, 231, 0.1) !important; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1) !important; padding: 4px 0 !important; font-family: var(--body-font-family) !important; font-size: 13px !important; @@ -1456,8 +1627,9 @@ html[data-theme=dark] .bloblang-playground .editor-success { max-width: 360px !important; } -[data-theme="dark"] .bloblang-playground .ace_editor.ace_autocomplete { - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(68, 116, 231, 0.2) !important; +html[data-theme="dark"] .bloblang-playground .ace_editor.ace_autocomplete { + border-color: rgba(255, 255, 255, 0.1) !important; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3) !important; } /* Autocomplete rows */ @@ -1467,7 +1639,7 @@ html[data-theme=dark] .bloblang-playground .editor-success { line-height: 1.4 !important; border-radius: 0 !important; border: none !important; - border-bottom: 1px solid rgba(128, 152, 249, 0.08) !important; + border-bottom: 1px solid var(--grey-100-new, #f3f4f6) !important; transition: background-color 0.15s ease !important; } @@ -1475,37 +1647,36 @@ html[data-theme=dark] .bloblang-playground .editor-success { border-bottom: none !important; } -[data-theme="dark"] .bloblang-playground .ace_editor.ace_autocomplete .ace_line { +html[data-theme="dark"] .bloblang-playground .ace_editor.ace_autocomplete .ace_line { border-bottom-color: rgba(255, 255, 255, 0.05) !important; } .bloblang-playground .ace_editor.ace_autocomplete .ace_line:hover { - background: rgba(68, 116, 231, 0.08) !important; + background: var(--grey-50-new, #f9fafb) !important; +} + +html[data-theme="dark"] .bloblang-playground .ace_editor.ace_autocomplete .ace_line:hover { + background: rgba(255, 255, 255, 0.05) !important; } /* Selected/highlighted row */ .bloblang-playground .ace_editor.ace_autocomplete .ace_line.ace_selected { - background: linear-gradient(135deg, rgba(68, 116, 231, 0.12) 0%, rgba(102, 126, 234, 0.12) 100%) !important; - border-left: 3px solid #4474e7 !important; + background: var(--grey-100-new, #f3f4f6) !important; + border-left: 3px solid var(--component-color, #6366f1) !important; padding-left: 9px !important; } -[data-theme="dark"] .bloblang-playground .ace_editor.ace_autocomplete .ace_line.ace_selected { - background: linear-gradient(135deg, rgba(68, 116, 231, 0.2) 0%, rgba(102, 126, 234, 0.2) 100%) !important; - border-left-color: #667eea !important; +html[data-theme="dark"] .bloblang-playground .ace_editor.ace_autocomplete .ace_line.ace_selected { + background: rgba(255, 255, 255, 0.08) !important; } /* Completion text */ .bloblang-playground .ace_editor.ace_autocomplete .ace_completion-highlight { - color: #4474e7 !important; + color: var(--component-color, #6366f1) !important; font-weight: 600 !important; text-shadow: none !important; } -[data-theme="dark"] .bloblang-playground .ace_editor.ace_autocomplete .ace_completion-highlight { - color: #8098ff !important; -} - /* Meta labels (function, method, keyword, field) */ .bloblang-playground .ace_editor.ace_autocomplete .ace_completion-meta { float: right !important; @@ -1520,32 +1691,31 @@ html[data-theme=dark] .bloblang-playground .editor-success { /* Meta type colors */ .bloblang-playground .ace_editor.ace_autocomplete .ace_line .ace_completion-meta { - background: rgba(156, 163, 175, 0.15) !important; - color: #6b7280 !important; + background: var(--grey-100-new, #f3f4f6) !important; + color: var(--grey-600-new, #4b5563) !important; } .bloblang-playground .ace_editor.ace_autocomplete .ace_line.ace_selected .ace_completion-meta { - background: rgba(68, 116, 231, 0.15) !important; - color: #4474e7 !important; - font-weight: 700 !important; + background: rgba(99, 102, 241, 0.12) !important; + color: var(--component-color, #6366f1) !important; + font-weight: 600 !important; } -[data-theme="dark"] .bloblang-playground .ace_editor.ace_autocomplete .ace_line .ace_completion-meta { - background: rgba(156, 163, 175, 0.25) !important; - color: #9ca3af !important; +html[data-theme="dark"] .bloblang-playground .ace_editor.ace_autocomplete .ace_line .ace_completion-meta { + background: rgba(255, 255, 255, 0.08) !important; + color: rgba(255, 255, 255, 0.6) !important; } -[data-theme="dark"] .bloblang-playground .ace_editor.ace_autocomplete .ace_line.ace_selected .ace_completion-meta { - background: rgba(128, 152, 255, 0.25) !important; - color: #8098ff !important; +html[data-theme="dark"] .bloblang-playground .ace_editor.ace_autocomplete .ace_line.ace_selected .ace_completion-meta { + background: rgba(99, 102, 241, 0.2) !important; } /* Documentation popup */ .bloblang-playground .ace_editor.ace_autocomplete .ace_doc-tooltip { background: var(--body-background) !important; - border: 1px solid rgba(128, 152, 249, 0.3) !important; + border: 1px solid var(--grey-200-new, #e5e5e5) !important; border-radius: 8px !important; - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15) !important; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1) !important; padding: 12px !important; font-family: var(--body-font-family) !important; font-size: 13px !important; @@ -1554,28 +1724,25 @@ html[data-theme=dark] .bloblang-playground .editor-success { max-width: 400px !important; } -[data-theme="dark"] .bloblang-playground .ace_editor.ace_autocomplete .ace_doc-tooltip { - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4) !important; +html[data-theme="dark"] .bloblang-playground .ace_editor.ace_autocomplete .ace_doc-tooltip { + border-color: rgba(255, 255, 255, 0.1) !important; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3) !important; } .bloblang-playground .ace_editor.ace_autocomplete .ace_doc-tooltip b { - color: #4474e7 !important; + color: var(--component-color, #6366f1) !important; font-weight: 600 !important; } -[data-theme="dark"] .bloblang-playground .ace_editor.ace_autocomplete .ace_doc-tooltip b { - color: #8098ff !important; -} - .bloblang-playground .ace_editor.ace_autocomplete .ace_doc-tooltip em { - color: #6b7280 !important; + color: var(--grey-600-new, #4b5563) !important; font-style: normal !important; font-size: 11px !important; font-weight: 600 !important; } -[data-theme="dark"] .bloblang-playground .ace_editor.ace_autocomplete .ace_doc-tooltip em { - color: #9ca3af !important; +html[data-theme="dark"] .bloblang-playground .ace_editor.ace_autocomplete .ace_doc-tooltip em { + color: rgba(255, 255, 255, 0.6) !important; } /* Scrollbar for autocomplete */ diff --git a/src/css/body.css b/src/css/body.css index bb7d0835..a880a0a9 100644 --- a/src/css/body.css +++ b/src/css/body.css @@ -1,9 +1,3 @@ -@media screen and (min-width: 1024px) { - .body { - display: flex; - } -} - body { position: relative; min-height: 100vh; @@ -12,3 +6,15 @@ body { .hidden { display: none !important; } + +/* Main body container layout */ +.body { + display: block; +} + +@media screen and (min-width: 1024px) { + .body { + display: block; + margin-left: var(--sidebar-width, 260px); + } +} diff --git a/src/css/breadcrumbs.css b/src/css/breadcrumbs.css index c2a1725b..c0fe4c23 100644 --- a/src/css/breadcrumbs.css +++ b/src/css/breadcrumbs.css @@ -1,10 +1,21 @@ .breadcrumbs { line-height: var(--nav-line-height); width: 100%; - display: block; + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; margin-bottom: 32px; } +/* On desktop, hide article-level breadcrumbs (shown in topbar instead) */ +@media screen and (min-width: 1024px) { + article .breadcrumbs, + .article .breadcrumbs:not(.topbar-crumbs .breadcrumbs) { + display: none; + } +} + a + .breadcrumbs { padding-left: 0.05rem; } @@ -50,3 +61,58 @@ a + .breadcrumbs { .breadcrumbs li:last-child a { text-decoration: none; } + +/* Version selector in breadcrumbs */ +.breadcrumbs .sm-ver { + position: relative; + margin-left: auto; + flex-shrink: 0; +} + +/* Adjust pill colors for light background context */ +.breadcrumbs .sm-ver-pill { + background: var(--color-smoke-30, #f4f4f5); + border-color: var(--color-smoke-70, #dcdcde); +} + +.breadcrumbs .sm-ver-pill:hover { + background: var(--color-smoke-50, #e8e8ea); + border-color: var(--color-smoke-90, #c3c4c6); +} + +.breadcrumbs .sm-ver-pill-label, +.breadcrumbs .sm-ver-pill-num { + color: var(--color-jet-80, #48484a); +} + +.breadcrumbs .sm-ver-pill-caret { + color: var(--color-jet-50, #9ca3af); +} + +/* Panel positioning for breadcrumbs context */ +.breadcrumbs .sm-ver-panel { + right: 0; + left: auto; +} + +/* Hide version selector from breadcrumbs on component-home-v3 pages (shown in hero instead) */ +.component-home-v3 .breadcrumbs .sm-ver { + display: none; +} + +/* Mobile: Stack version selector below breadcrumbs */ +@media screen and (max-width: 768px) { + .breadcrumbs { + flex-wrap: wrap; + } + + .breadcrumbs ul { + width: 100%; + margin-bottom: 8px; + } + + .breadcrumbs .sm-ver { + width: 100%; + margin-left: 0; + } +} diff --git a/src/css/chat-panel.css b/src/css/chat-panel.css new file mode 100644 index 00000000..038f0147 --- /dev/null +++ b/src/css/chat-panel.css @@ -0,0 +1,1146 @@ +/* ============================================================================= + CHAT PANEL — Ask AI Drawer + Right-side persistent drawer for Kapa AI integration. + Slides in/out, pushes main content on desktop, overlays on mobile. + ============================================================================= */ + +/* Container */ +.chat-panel { + position: fixed; + top: 0; + right: 0; + width: 420px; + height: 100vh; + background: #fff; + color: var(--grey-900-new, var(--grey-900, #181818)); + border-left: 1px solid var(--grey-100-new, var(--grey-100, #e5e5e5)); + box-shadow: -14px 0 40px -18px rgba(15, 23, 42, 0.18); + display: flex; + flex-direction: column; + transform: translateX(100%); + transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1); + z-index: 120; + font-family: var(--font-sans, "Inter", -apple-system, BlinkMacSystemFont, sans-serif); +} + +.chat-panel.is-open { + transform: translateX(0); +} + +/* Header */ +.chat-head { + display: flex; + align-items: center; + justify-content: space-between; + padding: 14px 14px 14px 18px; + border-bottom: 1px solid var(--grey-100-new, var(--grey-100, #e5e5e5)); + flex-shrink: 0; +} + +.chat-head-title { + display: flex; + align-items: center; + gap: 10px; +} + +.chat-head-icon { + display: inline-grid; + place-items: center; + width: 30px; + height: 30px; + border-radius: 8px; + background: linear-gradient(135deg, #eef2ff 0%, #f5eeff 100%); + color: #4338ca; +} + +.chat-head-name { + font-size: 13.5px; + font-weight: 600; + color: var(--grey-900-new, var(--grey-900, #181818)); + letter-spacing: -0.0125em; + line-height: 1.2; +} + +.chat-head-sub { + font-size: 11.5px; + color: var(--grey-500-new, var(--grey-500, #6b7280)); + letter-spacing: -0.005em; + margin-top: 2px; +} + +.chat-head-actions { + display: flex; + gap: 2px; +} + +.chat-head-btn { + display: inline-grid; + place-items: center; + width: 30px; + height: 30px; + background: transparent; + border: 0; + border-radius: 6px; + color: var(--grey-500-new, var(--grey-500, #6b7280)); + cursor: pointer; + transition: background 0.12s, color 0.12s; +} + +.chat-head-btn:hover { + background: var(--grey-50-new, var(--grey-50, #f9fafb)); + color: var(--grey-900-new, var(--grey-900, #181818)); +} + +/* Scrollable content area */ +.chat-scroll { + flex: 1; + overflow-y: auto; + overflow-x: hidden; + padding: 0; + min-height: 0; /* Critical for flex children to respect parent constraints */ + position: relative; + /* Prevent content from pushing chat panel to grow */ + max-height: calc(100vh - 120px); /* Account for header and footer */ +} + +/* Footer disclaimer */ +.chat-foot { + padding: 8px 14px 12px; + font-size: 10.5px; + color: var(--grey-500-new, var(--grey-500, #6b7280)); + text-align: center; + letter-spacing: -0.005em; + flex-shrink: 0; + border-top: 1px solid var(--grey-100-new, var(--grey-100, #e5e5e5)); + line-height: 1.5; +} + +/* ============================================================================= + KAPA SDK OVERRIDES + Style the embedded chat interface to match our design system + ============================================================================= */ + +#chat-panel-kapa-root { + display: flex; + flex-direction: column; + height: 100%; + min-height: 0; + font-family: var(--font-sans, "Inter", -apple-system, BlinkMacSystemFont, sans-serif); +} + +/* Main container */ +#chat-panel-kapa-root .chat-container { + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; +} + +/* Conversation area - scrollable */ +#chat-panel-kapa-root .conversation-area { + flex: 1; + overflow-y: auto; + padding: 16px 18px 180px; + min-height: 0; + overscroll-behavior: contain; +} + +#chat-panel-kapa-root .conversation { + display: flex; + flex-direction: column; + gap: 0; +} + +/* Q&A Pair styling */ +#chat-panel-kapa-root .qa-pair { + margin-bottom: 20px; +} + +#chat-panel-kapa-root .section-divider { + display: none; +} + +/* Question bubble - user message */ +#chat-panel-kapa-root .question { + background: #e6effe; + color: #1d4ed8; + border: 1px solid #bfd4fb; + border-radius: 12px; + border-top-right-radius: 4px; + padding: 10px 14px; + font-size: 13px; + line-height: 1.55; + margin-bottom: 12px; + margin-left: auto; + max-width: 85%; + width: fit-content; +} + +/* Answer bubble - assistant message */ +#chat-panel-kapa-root .answer { + background: var(--grey-50-new, #f9fafb); + border: 1px solid var(--grey-100-new, #e5e5e5); + border-radius: 12px; + border-top-left-radius: 4px; + padding: 12px 14px; + font-size: 13px; + line-height: 1.65; + color: var(--body-font-color, var(--grey-900-new, #181818)); + max-width: 100%; +} + +/* Strong/bold text */ +#chat-panel-kapa-root .answer strong { + font-weight: 600; + color: inherit; +} + +/* Emphasized/italic text */ +#chat-panel-kapa-root .answer em { + font-style: italic; + color: inherit; +} + +#chat-panel-kapa-root .answer p { + margin: 0 0 10px; +} + +#chat-panel-kapa-root .answer p:last-child { + margin-bottom: 0; +} + +/* Headings - matches site's .doc heading styling */ +#chat-panel-kapa-root .answer h2, +#chat-panel-kapa-root .answer h3, +#chat-panel-kapa-root .answer h4 { + font-size: 14px; + font-weight: var(--heading-font-weight, 600); + font-family: var(--heading-font-family, var(--font-display, "Inter Display", "Inter", sans-serif)); + color: var(--heading-font-color, var(--grey-900-new, #181818)); + margin: 16px 0 8px; + line-height: 1.3; +} + +#chat-panel-kapa-root .answer h2:first-child, +#chat-panel-kapa-root .answer h3:first-child, +#chat-panel-kapa-root .answer h4:first-child { + margin-top: 0; +} + +/* Blockquotes - matches site's .doc .quoteblock styling */ +#chat-panel-kapa-root .answer blockquote { + background: var(--quote-background, var(--panel-background)); + border-left: 5px solid var(--quote-border-color, #6b7280); + color: var(--quote-font-color, #6b7280); + margin: 0.75rem 0; + padding: 0.5rem 1rem; + font-style: italic; +} + +#chat-panel-kapa-root .answer blockquote p { + margin: 0; +} + +#chat-panel-kapa-root .answer ul, +#chat-panel-kapa-root .answer ol { + margin: 8px 0; + padding-left: 20px; +} + +#chat-panel-kapa-root .answer li { + margin-bottom: 6px; +} + +/* Links - matches site's .doc a styling */ +#chat-panel-kapa-root .answer a { + color: var(--body-font-color); + text-decoration: underline; + text-underline-offset: 2px; + text-decoration-color: var(--color-aliases-static-palette-text-tertiary, #606164); +} + +#chat-panel-kapa-root .answer a:hover { + color: var(--link-highlight-color, #444ce7); + text-decoration-color: var(--link-highlight-color, #444ce7); +} + +/* Inline code - matches site's .doc p code styling */ +#chat-panel-kapa-root .answer code { + background: var(--pre-background); + color: var(--code-font-color); + border: 0.1rem solid #0000001a; + border-radius: 0.25em; + padding: 0.125em 0.25em; + font-size: 0.9em; + font-family: var(--monospace-font-family, var(--font-mono, "JetBrains Mono", monospace)); + font-weight: lighter; +} + +/* Code blocks - matches site's .doc pre styling */ +#chat-panel-kapa-root .answer pre { + background: var(--code-background, var(--pre-background)); + color: var(--code-font-color); + padding: 1em; + border-radius: 0.5rem; + overflow-x: auto; + font-size: 0.85em; + line-height: 1.6; + margin: 0.75rem 0; + font-family: var(--monospace-font-family, var(--font-mono, "JetBrains Mono", monospace)); + font-weight: lighter; + white-space: pre-wrap; + overflow-wrap: anywhere; +} + +#chat-panel-kapa-root .answer pre code { + background: none; + border: none; + padding: 0; + color: inherit; + font-size: inherit; +} + +/* Action buttons (Clear, Copy) */ +#chat-panel-kapa-root .actions-feedback { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 8px; + padding-top: 8px; +} + +#chat-panel-kapa-root .action-buttons { + display: flex; + gap: 4px; +} + +#chat-panel-kapa-root .action-button { + display: inline-flex; + align-items: center; + gap: 4px; + padding: 4px 8px; + background: transparent; + border: 1px solid var(--grey-200-new, #e5e5e5); + border-radius: 6px; + font-size: 11px; + color: var(--grey-600-new, #4b5563); + cursor: pointer; + transition: all 0.12s ease; +} + +#chat-panel-kapa-root .action-button:hover { + background: var(--grey-50-new, #f9fafb); + border-color: var(--grey-300-new, #d1d5db); +} + +#chat-panel-kapa-root .action-button svg { + width: 12px; + height: 12px; +} + +/* Feedback buttons (thumbs up/down) */ +#chat-panel-kapa-root .feedback-container { + display: flex; + gap: 2px; +} + +#chat-panel-kapa-root .feedback-group { + display: flex; + gap: 2px; +} + +#chat-panel-kapa-root .feedback-button { + display: inline-grid; + place-items: center; + width: 28px; + height: 28px; + padding: 0; + background: transparent; + border: 1px solid var(--grey-200-new, #e5e5e5); + border-radius: 6px; + color: var(--grey-500-new, #6b7280); + cursor: pointer; + transition: all 0.12s ease; +} + +#chat-panel-kapa-root .feedback-button:hover { + background: var(--grey-50-new, #f9fafb); + border-color: var(--grey-300-new, #d1d5db); + color: var(--grey-700-new, #374151); +} + +#chat-panel-kapa-root .feedback-icon { + width: 14px; + height: 14px; +} + +/* Footer wrapper - fixed at bottom */ +#chat-panel-kapa-root .chat-footer-wrapper { + background: #fff; + border-top: none; + padding: 0; + display: flex; + flex-direction: column; + flex-shrink: 0; +} + +#chat-panel-kapa-root .chat-footer-wrapper.fixed-bottom { + position: absolute; + bottom: 0; + left: 0; + right: 0; + border-top: 1px solid var(--grey-100-new, #e5e5e5); +} + +#chat-panel-kapa-root .chat-footer-wrapper form { + flex-shrink: 0; +} + +/* Chat card / input area */ +#chat-panel-kapa-root .chat-card { + background: #fff; + border: 1px solid var(--grey-200-new, #e5e5e5); + border-radius: 12px; + overflow: hidden; +} + +#chat-panel-kapa-root .chat-content { + padding: 0; +} + +/* Text input */ +#chat-panel-kapa-root .chat-input, +#chat-panel-kapa-root textarea.chat-input { + width: 100%; + border: none; + border-radius: 0; + padding: 12px 14px; + font-size: 13px; + line-height: 1.5; + color: var(--grey-900-new, #181818); + background: #fff; + resize: none; + outline: none; + font-family: var(--font-sans, "Inter", -apple-system, BlinkMacSystemFont, sans-serif); + min-height: 44px; + max-height: 120px; +} + +#chat-panel-kapa-root .chat-input::placeholder, +#chat-panel-kapa-root textarea.chat-input::placeholder { + color: var(--grey-400-new, #9ca3af); +} + +/* Footer buttons row */ +#chat-panel-kapa-root .chat-footer-buttons, +#chat-panel-kapa-root .chat-footer { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 8px; + padding: 10px 12px; + border-top: 1px solid var(--grey-100-new, #e5e5e5); + background: var(--grey-50-new, #f9fafb); +} + +#chat-panel-kapa-root .chat-footer-buttons { + justify-content: flex-end; +} + +/* Deep thinking button */ +#chat-panel-kapa-root .deep-thinking-button { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 6px; + height: 32px; + min-height: 32px; + max-height: 32px; + padding: 0 12px; + background: #fff; + border: 1px solid var(--grey-200-new, #e5e5e5); + border-radius: 8px; + font-size: 12px; + font-weight: 500; + color: var(--grey-700-new, #374151); + cursor: pointer; + transition: all 0.12s ease; + white-space: nowrap; + box-sizing: border-box; + vertical-align: middle; +} + +#chat-panel-kapa-root .deep-thinking-button:hover { + background: var(--grey-50-new, #f9fafb); + border-color: var(--grey-300-new, #d1d5db); +} + +/* Deep thinking active state */ +#chat-panel-kapa-root .deep-thinking-button.active { + background: rgba(68, 76, 231, 0.1); + border-color: var(--indigo-500-new, #6172f3); + color: var(--indigo-600-new, #444ce7); +} + +#chat-panel-kapa-root .deep-thinking-button.active:hover { + background: rgba(68, 76, 231, 0.15); + border-color: var(--indigo-600-new, #444ce7); +} + +#chat-panel-kapa-root .deep-thinking-button svg { + width: 14px; + height: 14px; + flex-shrink: 0; +} + +/* Submit button */ +#chat-panel-kapa-root .main-button, +#chat-panel-kapa-root button[type="submit"].main-button { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 5px; + height: 32px; + min-height: 32px; + max-height: 32px; + padding: 0 12px; + margin: 0; + background: var(--grey-900-new, #181818); + border: none; + border-radius: 8px; + font-size: 12px; + font-weight: 500; + color: #fff; + cursor: pointer; + transition: background 0.12s ease; + white-space: nowrap; + box-sizing: border-box; +} + +#chat-panel-kapa-root .main-button:hover, +#chat-panel-kapa-root button[type="submit"].main-button:hover { + background: #000; +} + +#chat-panel-kapa-root .main-button:disabled, +#chat-panel-kapa-root button[type="submit"].main-button:disabled { + opacity: 0.4; + cursor: not-allowed; +} + +#chat-panel-kapa-root .main-button svg { + width: 14px; + height: 14px; + flex-shrink: 0; +} + +/* ============================================================================= + WELCOME SCREEN + Centered welcome message with sparkle icon and suggestion cards + ============================================================================= */ + +#chat-panel-kapa-root .welcome-screen { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 60px 24px 24px; + text-align: center; + flex: 1; + min-height: 0; +} + +#chat-panel-kapa-root .welcome-icon { + display: flex; + align-items: center; + justify-content: center; + width: 56px; + height: 56px; + background: linear-gradient(135deg, #eef2ff 0%, #e0e7ff 100%); + border-radius: 16px; + color: #4f46e5; + margin-bottom: 20px; +} + +#chat-panel-kapa-root .welcome-title { + font-size: 22px; + font-weight: 600; + color: var(--grey-900-new, #181818); + margin: 0 0 12px; + letter-spacing: -0.02em; +} + +#chat-panel-kapa-root .welcome-description { + font-size: 14px; + color: var(--grey-500-new, #6b7280); + line-height: 1.6; + margin: 0 0 28px; + max-width: 320px; +} + +/* Suggestion cards - full width buttons */ +#chat-panel-kapa-root .suggestion-cards { + display: flex; + flex-direction: column; + gap: 10px; + width: 100%; + max-width: 360px; +} + +#chat-panel-kapa-root .suggestion-card { + display: block; + width: 100%; + padding: 14px 16px; + background: #fff; + border: 1px solid var(--grey-200-new, #e5e5e5); + border-radius: 12px; + font-size: 14px; + color: var(--grey-700-new, #374151); + text-align: left; + cursor: pointer; + transition: all 0.15s ease; + font-family: inherit; +} + +#chat-panel-kapa-root .suggestion-card:hover { + background: var(--grey-50-new, #f9fafb); + border-color: var(--grey-300-new, #d1d5db); +} + +/* ============================================================================= + INPUT FORM - New rounded design + ============================================================================= */ + +#chat-panel-kapa-root .chat-input-form { + padding: 16px; +} + +#chat-panel-kapa-root .chat-input-wrapper { + display: flex; + align-items: center; + gap: 10px; + background: #fff; + border: 2px solid var(--grey-200-new, #e5e5e5); + border-radius: 28px; + padding: 6px 6px 6px 18px; + transition: border-color 0.15s ease; +} + +#chat-panel-kapa-root .chat-input-wrapper:focus-within { + border-color: #6366f1; +} + +#chat-panel-kapa-root .chat-input-wrapper .chat-input { + flex: 1; + border: none; + background: transparent; + padding: 8px 0; + font-size: 14px; + color: var(--grey-900-new, #181818); + outline: none; + font-family: inherit; + min-width: 0; +} + +#chat-panel-kapa-root .chat-input-wrapper .chat-input::placeholder { + color: var(--grey-400-new, #9ca3af); +} + +#chat-panel-kapa-root .submit-button { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + background: #6366f1; + border: none; + border-radius: 50%; + color: #fff; + cursor: pointer; + transition: background 0.15s ease; + flex-shrink: 0; +} + +#chat-panel-kapa-root .submit-button:hover:not(:disabled) { + background: #4f46e5; +} + +#chat-panel-kapa-root .submit-button:disabled { + background: var(--grey-200-new, #e5e5e5); + color: var(--grey-400-new, #9ca3af); + cursor: not-allowed; +} + +#chat-panel-kapa-root .submit-button.stop-button { + background: #ef4444; +} + +#chat-panel-kapa-root .submit-button.stop-button:hover { + background: #dc2626; +} + +/* Disclaimer - always visible at bottom */ +#chat-panel-kapa-root .disclaimer { + padding: 10px 14px 14px; + font-size: 10.5px; + color: var(--grey-500-new, #6b7280); + text-align: center; + line-height: 1.5; + background: #fff; + border-top: none; + flex-shrink: 0; +} + +#chat-panel-kapa-root .disclaimer p { + margin: 0 0 4px; +} + +#chat-panel-kapa-root .disclaimer p:last-child { + margin-bottom: 0; +} + +#chat-panel-kapa-root .disclaimer a { + color: #4f46e5; + text-decoration: none; +} + +#chat-panel-kapa-root .disclaimer a:hover { + text-decoration: underline; +} + +/* Button icons */ +#chat-panel-kapa-root .button-icon, +#chat-panel-kapa-root .button-icon-left { + display: inline-flex; + align-items: center; +} + +#chat-panel-kapa-root .button-text { + display: inline-block; +} + +/* Utility classes used by Kapa */ +#chat-panel-kapa-root .flex { + display: flex; +} + +#chat-panel-kapa-root .items-center { + align-items: center; +} + +#chat-panel-kapa-root .justify-between { + justify-content: space-between; +} + +#chat-panel-kapa-root .visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip-path: inset(50%); + white-space: nowrap; + border: 0; +} + +/* Responsive behavior */ + +/* Narrow desktop: reduce chat panel width to fit better */ +@media (min-width: 1024px) and (max-width: 1399px) { + .chat-panel { + width: 340px; + } +} + +/* Tablet/mobile: full width */ +@media (max-width: 520px) { + .chat-panel { + width: 100%; + } +} + +/* ============================================================================= + DARK MODE + Using !important to override Kapa SDK inline styles + ============================================================================= */ + +.dark-theme .chat-panel { + background: #1a2332 !important; + color: #e8eef6 !important; + border-left-color: rgba(255, 255, 255, 0.08) !important; + box-shadow: -14px 0 40px -18px rgba(0, 0, 0, 0.4) !important; +} + +.dark-theme .chat-head { + border-bottom-color: rgba(255, 255, 255, 0.08) !important; +} + +.dark-theme .chat-head-name { + color: #e8eef6 !important; +} + +.dark-theme .chat-head-sub { + color: #7c8ca8 !important; +} + +.dark-theme .chat-head-btn { + color: #7c8ca8 !important; +} + +.dark-theme .chat-head-btn:hover { + background: rgba(255, 255, 255, 0.05) !important; + color: #e8eef6 !important; +} + +.dark-theme .chat-foot { + color: #7c8ca8 !important; + border-top-color: rgba(255, 255, 255, 0.08) !important; +} + +/* Dark mode - Kapa SDK overrides */ +.dark-theme #chat-panel-kapa-root { + color: #e8eef6 !important; +} + +.dark-theme #chat-panel-kapa-root .question { + background: #3730a3 !important; + color: #e0e7ff !important; + border-color: #4338ca !important; +} + +.dark-theme #chat-panel-kapa-root .answer { + background: rgba(255, 255, 255, 0.04) !important; + border-color: rgba(255, 255, 255, 0.08) !important; + color: #e8eef6 !important; +} + +.dark-theme #chat-panel-kapa-root .answer h2, +.dark-theme #chat-panel-kapa-root .answer h3, +.dark-theme #chat-panel-kapa-root .answer h4 { + color: #e8eef6 !important; +} + +.dark-theme #chat-panel-kapa-root .answer a { + color: #e8eef6 !important; + text-decoration-color: #7c8ca8 !important; +} + +.dark-theme #chat-panel-kapa-root .answer a:hover { + color: var(--link-highlight-color, #818cf8) !important; + text-decoration-color: var(--link-highlight-color, #818cf8) !important; +} + +/* Dark mode inline code */ +.dark-theme #chat-panel-kapa-root .answer code { + background: rgba(255, 255, 255, 0.1) !important; + border-color: rgba(255, 255, 255, 0.15) !important; + color: #e8eef6 !important; +} + +/* Dark mode code blocks */ +.dark-theme #chat-panel-kapa-root .answer pre { + background: rgba(255, 255, 255, 0.06) !important; + color: #e8eef6 !important; +} + +.dark-theme #chat-panel-kapa-root .answer pre code { + background: none !important; + border: none !important; + color: inherit !important; +} + +/* Dark mode blockquotes */ +.dark-theme #chat-panel-kapa-root .answer blockquote { + background: rgba(255, 255, 255, 0.04) !important; + border-left-color: #7c8ca8 !important; + color: #aab8ca !important; +} + +.dark-theme #chat-panel-kapa-root .chat-footer-wrapper { + background: #1a2332 !important; + border-top-color: rgba(255, 255, 255, 0.08) !important; +} + +.dark-theme #chat-panel-kapa-root .chat-card { + background: #232f3e !important; + border-color: rgba(255, 255, 255, 0.1) !important; +} + +.dark-theme #chat-panel-kapa-root .chat-input, +.dark-theme #chat-panel-kapa-root textarea.chat-input { + background: #232f3e !important; + color: #e8eef6 !important; +} + +.dark-theme #chat-panel-kapa-root .chat-input::placeholder, +.dark-theme #chat-panel-kapa-root textarea.chat-input::placeholder { + color: #8fa3bd !important; +} + +.dark-theme #chat-panel-kapa-root .chat-footer-buttons, +.dark-theme #chat-panel-kapa-root .chat-footer { + background: rgba(255, 255, 255, 0.02) !important; + border-top-color: rgba(255, 255, 255, 0.08) !important; +} + +.dark-theme #chat-panel-kapa-root .deep-thinking-button { + background: #232f3e !important; + border-color: rgba(255, 255, 255, 0.1) !important; + color: #aab8ca !important; +} + +.dark-theme #chat-panel-kapa-root .deep-thinking-button:hover { + background: #2a3a4d !important; + border-color: rgba(255, 255, 255, 0.15) !important; + color: #e8eef6 !important; +} + +/* Dark theme deep thinking active state */ +.dark-theme #chat-panel-kapa-root .deep-thinking-button.active { + background: rgba(99, 102, 241, 0.2) !important; + border-color: rgba(99, 102, 241, 0.5) !important; + color: #a5b4fc !important; +} + +.dark-theme #chat-panel-kapa-root .deep-thinking-button.active:hover { + background: rgba(99, 102, 241, 0.25) !important; + border-color: rgba(99, 102, 241, 0.6) !important; + color: #c7d2fe !important; +} + +.dark-theme #chat-panel-kapa-root .main-button, +.dark-theme #chat-panel-kapa-root button[type="submit"].main-button { + background: #e8eef6 !important; + color: #1a2332 !important; + height: 32px !important; + min-height: 32px !important; + max-height: 32px !important; + margin: 0 !important; + border: none !important; +} + +.dark-theme #chat-panel-kapa-root .main-button:hover, +.dark-theme #chat-panel-kapa-root button[type="submit"].main-button:hover { + background: #fff !important; +} + +.dark-theme #chat-panel-kapa-root .chip { + background: #232f3e !important; + border-color: rgba(255, 255, 255, 0.1) !important; + color: #aab8ca !important; +} + +.dark-theme #chat-panel-kapa-root .chip:hover { + background: #2a3a4d !important; + border-color: rgba(255, 255, 255, 0.15) !important; + color: #e8eef6 !important; +} + +.dark-theme #chat-panel-kapa-root .more-chip { + color: #7c8ca8 !important; +} + +.dark-theme #chat-panel-kapa-root .pulldown-item { + background: #232f3e !important; + border-color: rgba(255, 255, 255, 0.1) !important; + color: #aab8ca !important; +} + +.dark-theme #chat-panel-kapa-root .pulldown-item:hover { + background: #2a3a4d !important; + border-color: rgba(255, 255, 255, 0.15) !important; + color: #e8eef6 !important; +} + +/* Dark mode - Welcome screen */ +.dark-theme #chat-panel-kapa-root .welcome-icon { + background: linear-gradient(135deg, #312e81 0%, #3730a3 100%) !important; + color: #a5b4fc !important; +} + +.dark-theme #chat-panel-kapa-root .welcome-title { + color: #e8eef6 !important; +} + +.dark-theme #chat-panel-kapa-root .welcome-description { + color: #7c8ca8 !important; +} + +.dark-theme #chat-panel-kapa-root .suggestion-card { + background: #232f3e !important; + border-color: rgba(255, 255, 255, 0.1) !important; + color: #aab8ca !important; +} + +.dark-theme #chat-panel-kapa-root .suggestion-card:hover { + background: #2a3a4d !important; + border-color: rgba(255, 255, 255, 0.15) !important; + color: #e8eef6 !important; +} + +/* Dark mode - Input form */ +.dark-theme #chat-panel-kapa-root .chat-input-wrapper { + background: #232f3e !important; + border-color: rgba(255, 255, 255, 0.1) !important; +} + +.dark-theme #chat-panel-kapa-root .chat-input-wrapper:focus-within { + border-color: #6366f1 !important; +} + +.dark-theme #chat-panel-kapa-root .chat-input-wrapper .chat-input { + background: transparent !important; + color: #e8eef6 !important; +} + +.dark-theme #chat-panel-kapa-root .chat-input-wrapper .chat-input::placeholder { + color: #7c8ca8 !important; +} + +.dark-theme #chat-panel-kapa-root .submit-button { + background: #6366f1 !important; + color: #fff !important; +} + +.dark-theme #chat-panel-kapa-root .submit-button:hover:not(:disabled) { + background: #818cf8 !important; + color: #fff !important; +} + +.dark-theme #chat-panel-kapa-root .submit-button:disabled { + background: rgba(255, 255, 255, 0.1) !important; + color: #7c8ca8 !important; +} + +.dark-theme #chat-panel-kapa-root .disclaimer { + color: #7c8ca8 !important; + background: #1a2332 !important; + border-top: none !important; +} + +.dark-theme #chat-panel-kapa-root .disclaimer a { + color: #818cf8 !important; +} + +.dark-theme #chat-panel-kapa-root .action-button { + border-color: rgba(255, 255, 255, 0.1) !important; + color: #7c8ca8 !important; +} + +.dark-theme #chat-panel-kapa-root .action-button:hover { + background: rgba(255, 255, 255, 0.05) !important; + border-color: rgba(255, 255, 255, 0.15) !important; + color: #aab8ca !important; +} + +.dark-theme #chat-panel-kapa-root .feedback-button { + border-color: rgba(255, 255, 255, 0.1) !important; + color: #7c8ca8 !important; +} + +.dark-theme #chat-panel-kapa-root .feedback-button:hover { + background: rgba(255, 255, 255, 0.05) !important; + border-color: rgba(255, 255, 255, 0.15) !important; + color: #aab8ca !important; +} + +/* ============================================================================= + TOAST NOTIFICATIONS + Floating toast for copy/feedback confirmations + ============================================================================= */ + +#chat-panel-kapa-root .chat-toast { + position: fixed; + top: 16px; + left: 50%; + transform: translateX(-50%); + display: inline-flex; + align-items: center; + gap: 8px; + padding: 10px 16px; + border-radius: 10px; + font-size: 13px; + font-weight: 500; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15), 0 0 0 1px rgba(0, 0, 0, 0.05); + z-index: 200; + animation: toast-slide-in 0.3s cubic-bezier(0.4, 0, 0.2, 1); + pointer-events: none; +} + +@keyframes toast-slide-in { + from { + opacity: 0; + transform: translateX(-50%) translateY(-12px); + } + + to { + opacity: 1; + transform: translateX(-50%) translateY(0); + } +} + +/* Success toast */ +#chat-panel-kapa-root .chat-toast-success { + background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%); + color: #065f46; + border: 1px solid #a7f3d0; +} + +#chat-panel-kapa-root .chat-toast-success .chat-toast-icon { + display: flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + background: #10b981; + border-radius: 50%; + color: #fff; +} + +#chat-panel-kapa-root .chat-toast-success .chat-toast-icon svg { + width: 12px; + height: 12px; +} + +/* Error toast */ +#chat-panel-kapa-root .chat-toast-error { + background: linear-gradient(135deg, #fef2f2 0%, #fecaca 100%); + color: #991b1b; + border: 1px solid #fca5a5; +} + +#chat-panel-kapa-root .chat-toast-error .chat-toast-icon { + display: flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + background: #ef4444; + border-radius: 50%; + color: #fff; +} + +#chat-panel-kapa-root .chat-toast-error .chat-toast-icon svg { + width: 12px; + height: 12px; +} + +#chat-panel-kapa-root .chat-toast-message { + white-space: nowrap; +} + +/* Dark mode toast */ +.dark-theme #chat-panel-kapa-root .chat-toast-success { + background: linear-gradient(135deg, #064e3b 0%, #065f46 100%) !important; + color: #a7f3d0 !important; + border-color: #10b981 !important; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(16, 185, 129, 0.2) !important; +} + +.dark-theme #chat-panel-kapa-root .chat-toast-error { + background: linear-gradient(135deg, #7f1d1d 0%, #991b1b 100%) !important; + color: #fecaca !important; + border-color: #ef4444 !important; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(239, 68, 68, 0.2) !important; +} diff --git a/src/css/component-home-v3.css b/src/css/component-home-v3.css new file mode 100644 index 00000000..3393c2b7 --- /dev/null +++ b/src/css/component-home-v3.css @@ -0,0 +1,1867 @@ +/* ============================================================================= + COMPONENT HOME V3 — Landing page styles + Matches "docs design (2)" with hero, tabs, and "Choose your path" cards + ============================================================================= */ + +/* Hide all icons on landing pages */ +.ch3-path-icon, +.ch3-deploy-icon, +.ch3-feature-icon, +.ch3-popular-icon { + display: none !important; +} + +/* Component home layout - ensure hero gets its own row */ +.component-content { + display: flex !important; + flex-direction: column !important; +} + +/* Full-width layout for component home pages */ +/* Higher specificity selector to override main > .content (main.css:52-64) */ +main.component-home > .component-content { + padding: 0; + max-width: none; + + --ch3-max-width: 1180px; + --ch3-gutter: 40px; +} + +@media (min-width: 1024px) { + main.component-home > .component-content { + --ch3-gutter: 56px; + } +} + +/* Override .doc a underline for all card links */ +.doc .ch3-deploy-card, +.doc .ch3-popular-card, +.doc .ch3-labs-list a, +.doc .ch3-labs-all, +.doc .ch3-help-btn { + text-decoration: none; +} + +.doc .ch3-deploy-card:hover, +.doc .ch3-popular-card:hover, +.doc .ch3-labs-list a:hover, +.doc .ch3-labs-all:hover { + text-decoration: none; +} + +/* Hero Section ------------------------------------------------------------ */ +.ch3-hero { + position: relative; + background: linear-gradient(180deg, #0f1727 0%, #161e2d 100%); + padding: 48px var(--ch3-gutter, 40px) 40px; + margin: 0 0 24px; + overflow: visible; + width: 100%; + border-radius: 0; + flex-shrink: 0; +} + +.ch3-hero-inner { + position: relative; + z-index: 1; + max-width: 1100px; + overflow: visible; +} + +/* Eyebrow row with product badge and version */ +.ch3-eyebrow-row { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 20px; + flex-wrap: wrap; +} + +.ch3-product-chip { + display: inline-flex; + align-items: center; + gap: 6px; + font-family: var(--font-mono, ui-monospace, SFMono-Regular, monospace); + font-size: 10.5px; + font-weight: 600; + padding: 4px 10px; + border-radius: 5px; + background: var(--component-color, rgba(79, 70, 229, 0.6)); + color: #fff; + letter-spacing: 0.04em; + text-transform: uppercase; + white-space: nowrap; +} + +/* ============================================================================= + SM-VER: Version Selector Pill (matches prototype design) + ============================================================================= */ +.ch3-hero .sm-ver { + position: relative; + margin-left: auto; +} + +/* --- Trigger pill ---------------------------------------------------------- */ +.sm-ver-pill { + display: inline-flex; + align-items: center; + gap: 8px; + height: 30px; + padding: 0 10px 0 11px; + border-radius: 999px; + background: rgba(255, 255, 255, 0.06); + border: 1px solid rgba(255, 255, 255, 0.12); + color: #fff; + cursor: pointer; + font-family: var(--font-sans, "Inter", system-ui, sans-serif); + transition: background 0.15s, border-color 0.15s; +} + +.sm-ver-pill:hover { + background: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, 0.22); +} + +.sm-ver-pill.is-open { + background: rgba(255, 255, 255, 0.12); + border-color: rgba(255, 255, 255, 0.28); +} + +.sm-ver-pill-dot { + width: 7px; + height: 7px; + border-radius: 50%; + background: #4ade80; + box-shadow: 0 0 0 3px rgba(74, 222, 128, 0.18); +} + +.sm-ver-pill-dot[data-status="supported"] { + background: #4ade80; + box-shadow: 0 0 0 3px rgba(74, 222, 128, 0.18); +} + +.sm-ver-pill-dot[data-status="current"] { + background: #34d399; + box-shadow: 0 0 0 3px rgba(52, 211, 153, 0.22); +} + +.sm-ver-pill-dot[data-status="eol"] { + background: #f59e0b; + box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.2); +} + +.sm-ver-pill-label { + font-size: 11px; + font-weight: 500; + color: rgba(255, 255, 255, 0.55); + letter-spacing: 0.02em; +} + +.sm-ver-pill-num { + font-variant-numeric: tabular-nums; + font-weight: 600; + color: #fff; + font-size: 12.5px; + letter-spacing: -0.005em; +} + +.sm-ver-pill-sep { + width: 1px; + height: 14px; + background: rgba(255, 255, 255, 0.16); +} + +.sm-ver-pill-status { + font-size: 10.5px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.08em; +} + +.sm-ver-pill-status[data-status="current"] { + color: #6ee7b7; +} + +.sm-ver-pill-status[data-status="supported"] { + color: #a7f3d0; +} + +.sm-ver-pill-status[data-status="eol"] { + color: #fcd34d; +} + +.sm-ver-pill-caret { + color: rgba(255, 255, 255, 0.65); + transition: transform 180ms ease; + margin-left: -1px; +} + +.sm-ver.is-open .sm-ver-pill-caret { + transform: rotate(180deg); +} + +/* --- Panel ----------------------------------------------------------------- */ +.sm-ver-panel { + position: absolute; + top: calc(100% + 10px); + right: 0; + z-index: 100; + width: 560px; + max-width: calc(100vw - 48px); + background: #fff; + border: 1px solid var(--color-smoke-70, #dcdcde); + border-radius: 12px; + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06); + opacity: 0; + visibility: hidden; + transform: translateY(-6px); + transition: opacity 0.15s, transform 0.15s, visibility 0.15s; +} + +.sm-ver.is-open .sm-ver-panel { + opacity: 1; + visibility: visible; + transform: translateY(0); +} + +.sm-ver-panel-head { + padding: 14px 16px 12px; + border-bottom: 1px solid var(--color-smoke-70, #eef0f3); + background: linear-gradient(180deg, #fafbfc 0%, #fff 100%); + border-radius: 12px 12px 0 0; +} + +.sm-ver-panel-title { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 12px; +} + +.sm-ver-panel-title > span:first-child { + font-size: 13px; + font-weight: 600; + color: var(--color-jet, #0f172a); + letter-spacing: -0.005em; +} + +.sm-ver-panel-meta { + font-size: 11px; + color: var(--color-jet-70, #6b7280); + font-variant-numeric: tabular-nums; +} + +/* --- Tabs ------------------------------------------------------------------ */ +.sm-ver-tabs { + display: flex; + gap: 2px; + margin-top: 10px; + padding: 3px; + background: var(--color-smoke-30, #f5f5f5); + border-radius: 8px; +} + +.sm-ver-tab { + flex: 1; + padding: 6px 8px; + font-size: 10.5px; + font-weight: 500; + color: var(--color-jet-70, #6b7280); + background: transparent; + border: none; + border-radius: 6px; + cursor: pointer; + transition: background 0.1s, color 0.1s; + white-space: nowrap; +} + +.sm-ver-tab:hover { + color: var(--color-jet, #0f172a); +} + +.sm-ver-tab.is-active { + background: #fff; + color: var(--color-jet, #0f172a); + font-weight: 600; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06); +} + +/* --- Version groups -------------------------------------------------------- */ +.sm-ver-group { + margin-bottom: 4px; +} + +.sm-ver-group:empty, +.sm-ver-group.is-hidden { + display: none; +} + +.sm-ver-group-head { + display: flex; + align-items: center; + justify-content: space-between; + padding: 8px 12px 6px; +} + +.sm-ver-group-label { + font-size: 10px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--color-jet-50, #9ca3af); +} + +.sm-ver-group-count { + font-size: 10px; + font-weight: 500; + color: var(--color-jet-50, #9ca3af); + background: var(--color-smoke-30, #f5f5f5); + padding: 2px 6px; + border-radius: 4px; +} + +.sm-ver-rows { + display: flex; + flex-direction: column; +} + +/* --- Version list ---------------------------------------------------------- */ +.sm-ver-list { + max-height: 320px; + overflow-y: auto; + padding: 6px 8px 8px; +} + +.sm-ver-row { + display: grid; + grid-template-columns: 60px 1fr auto auto; + align-items: center; + gap: 16px; + width: 100%; + padding: 10px 14px; + border-radius: 8px; + text-decoration: none; + color: inherit; + cursor: pointer; + transition: background 0.1s; +} + +.sm-ver-row:hover { + background: #f6f8fa; +} + +.sm-ver-row.is-selected { + background: rgba(15, 139, 102, 0.07); +} + +.sm-ver-row.is-selected:hover { + background: rgba(15, 139, 102, 0.1); +} + +.sm-ver-row-num { + display: flex; + flex-direction: column; + gap: 2px; + white-space: nowrap; +} + +.sm-ver-row-v { + font-size: 13px; + font-weight: 600; + font-variant-numeric: tabular-nums; + letter-spacing: -0.01em; + color: var(--color-jet, #0f172a); +} + +.sm-ver-row.is-selected .sm-ver-row-v { + color: var(--component-color, #0f8b66); +} + +.sm-ver-row-note { + font-size: 9px; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.04em; + color: var(--component-color, #0f8b66); + opacity: 0.85; +} + +.sm-ver-row-status { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 10.5px; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + padding: 4px 8px; + border-radius: 5px; +} + +.sm-ver-row-status-dot { + width: 5px; + height: 5px; + border-radius: 50%; + background: currentColor; +} + +.sm-ver-row-status[data-status="current"] { + color: #047857; + background: rgba(5, 150, 105, 0.1); +} + +.sm-ver-row-status[data-status="supported"] { + color: #047857; + background: rgba(5, 150, 105, 0.08); +} + +.sm-ver-row-status[data-status="eol"] { + color: #92400e; + background: rgba(245, 158, 11, 0.1); +} + +.sm-ver-row-check { + display: inline-flex; + align-items: center; + justify-content: center; + width: 18px; + height: 18px; + color: var(--component-color, #0f8b66); +} + +/* --- Date display ---------------------------------------------------------- */ +.sm-ver-row-dates { + display: flex; + gap: 24px; + min-width: 0; +} + +.sm-ver-row-date { + display: flex; + flex-direction: column; + gap: 1px; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +.sm-ver-row-date-l { + font-size: 10px; + font-weight: 400; + color: var(--color-jet-50, #9ca3af); +} + +.sm-ver-row-date-v { + font-size: 12px; + font-weight: 500; + color: var(--color-jet, #374151); +} + +/* --- Footer links ---------------------------------------------------------- */ +.sm-ver-foot { + display: flex; + align-items: center; + gap: 4px; + padding: 10px 14px; + border-top: 1px solid var(--color-smoke-70, #eef0f3); + background: #fafbfc; + border-radius: 0 0 12px 12px; + flex-wrap: wrap; +} + +.sm-ver-foot-link { + display: inline-flex; + align-items: center; + gap: 5px; + padding: 5px 8px; + border-radius: 6px; + font-size: 11.5px; + font-weight: 500; + color: var(--color-jet-70, #525866); + text-decoration: none; + transition: background 0.1s, color 0.1s; +} + +.sm-ver-foot-link:hover { + color: var(--component-color, #0f8b66); + background: rgba(15, 139, 102, 0.08); +} + +.sm-ver-foot-link svg { + opacity: 0.7; +} + +.sm-ver-foot-link:hover svg { + opacity: 1; +} + +/* Dark mode panel overrides */ +html[data-theme="dark"] .sm-ver-panel { + background: #1a2332; + border-color: rgba(255, 255, 255, 0.1); + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4); +} + +html[data-theme="dark"] .sm-ver-panel-head { + background: linear-gradient(180deg, #1e2a3b 0%, #1a2332 100%); + border-color: rgba(255, 255, 255, 0.08); +} + +html[data-theme="dark"] .sm-ver-panel-title > span:first-child { + color: #fff; +} + +html[data-theme="dark"] .sm-ver-panel-meta { + color: #a8b2c7; +} + +html[data-theme="dark"] .sm-ver-row:hover { + background: rgba(255, 255, 255, 0.04); +} + +html[data-theme="dark"] .sm-ver-row.is-selected { + background: rgba(15, 139, 102, 0.12); +} + +html[data-theme="dark"] .sm-ver-row.is-selected:hover { + background: rgba(15, 139, 102, 0.16); +} + +html[data-theme="dark"] .sm-ver-row-v { + color: #fff; +} + +html[data-theme="dark"] .sm-ver-row-note { + color: #6ee7b7; +} + +html[data-theme="dark"] .sm-ver-row-status[data-status="current"], +html[data-theme="dark"] .sm-ver-row-status[data-status="supported"] { + color: #6ee7b7; + background: rgba(52, 211, 153, 0.15); +} + +html[data-theme="dark"] .sm-ver-row-status[data-status="eol"] { + color: #fcd34d; + background: rgba(245, 158, 11, 0.15); +} + +html[data-theme="dark"] .sm-ver-row-date-l { + color: #8a9bb0; +} + +html[data-theme="dark"] .sm-ver-row-date-v { + color: #a8b2c7; +} + +html[data-theme="dark"] .sm-ver-tabs { + background: rgba(255, 255, 255, 0.04); +} + +html[data-theme="dark"] .sm-ver-tab { + color: #9fb3c8; +} + +html[data-theme="dark"] .sm-ver-tab:hover { + color: #fff; +} + +html[data-theme="dark"] .sm-ver-tab.is-active { + background: rgba(255, 255, 255, 0.08); + color: #fff; + box-shadow: none; +} + +html[data-theme="dark"] .sm-ver-group-label { + color: #8a9bb0; +} + +html[data-theme="dark"] .sm-ver-group-count { + color: #8a9bb0; + background: rgba(255, 255, 255, 0.06); +} + +html[data-theme="dark"] .sm-ver-foot { + background: #141c28; + border-color: rgba(255, 255, 255, 0.06); +} + +html[data-theme="dark"] .sm-ver-foot-link { + color: #9fb3c8; +} + +html[data-theme="dark"] .sm-ver-foot-link:hover { + color: #6ee7b7; + background: rgba(52, 211, 153, 0.1); +} + +/* Responsive - Version selector */ +@media (max-width: 640px) { + /* Backdrop overlay for mobile */ + .sm-ver::before { + content: ''; + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0); + z-index: 99; + pointer-events: none; + opacity: 0; + transition: background 0.2s, opacity 0.2s; + } + + .sm-ver.is-open::before { + background: rgba(0, 0, 0, 0.5); + pointer-events: auto; + opacity: 1; + } + + .sm-ver-panel { + position: fixed; + top: 50%; + left: 50%; + right: auto; + transform: translate(-50%, -50%) scale(0.95); + width: calc(100vw - 32px); + max-width: 400px; + max-height: 80vh; + overflow-y: auto; + } + + .sm-ver.is-open .sm-ver-panel { + transform: translate(-50%, -50%) scale(1); + } + + .sm-ver-row { + grid-template-columns: 50px 1fr auto; + gap: 10px; + padding: 10px 12px; + } + + .sm-ver-row-dates { + display: none; + } + + .sm-ver-row-status { + font-size: 9px; + padding: 3px 6px; + } + + .ch3-hero .sm-ver { + margin-left: 0; + } + + .ch3-eyebrow-row { + flex-direction: column; + align-items: flex-start; + gap: 12px; + } +} + +@media (max-width: 480px) { + .sm-ver-pill { + padding: 0 8px; + height: 28px; + gap: 6px; + } + + .sm-ver-pill-label { + display: none; + } + + .sm-ver-pill-status { + font-size: 9px; + } + + .sm-ver-tabs { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + + .sm-ver-tab { + padding: 5px 6px; + font-size: 10px; + } +} + +.ch3-status-chip { + font-size: 11px; + font-weight: 600; + padding: 3px 10px; + border-radius: 9999px; + letter-spacing: 0.01em; + text-transform: uppercase; +} + +.ch3-status-chip.beta { + background: rgba(99, 102, 241, 0.2); + color: #a4bcfd; +} + +/* Use .ch3-hero prefix for specificity over .doc h1 */ +.ch3-hero .ch3-page-title { + font-family: var(--font-display, "Inter Display", "Inter", sans-serif); + font-size: 40px; + line-height: 1.1; + font-weight: 700; + letter-spacing: -0.025em; + color: #fff; + margin: 0 0 16px; +} + +/* When hero has custom gradient (inline style), always use white text */ +.ch3-hero[style*="background"] .ch3-page-title, +.ch3-hero[style*="background"] .ch3-page-lede, +.ch3-hero[style*="background"] .ch3-product-chip { + color: #fff !important; +} + +.ch3-hero[style*="background"] .ch3-page-lede { + color: rgba(255, 255, 255, 0.85) !important; +} + +/* Description text - lighter for readability on dark gradient */ +.ch3-page-lede { + font-size: 16px; + line-height: 1.6; + color: rgba(255, 255, 255, 0.85); + margin: 0; +} + +/* Tab Navigation ---------------------------------------------------------- */ +.ch3-tabs { + display: flex; + gap: 2px; + border-bottom: 1px solid var(--color-smoke-70, #dcdcde); + margin-bottom: 36px; + padding-left: var(--ch3-gutter); + padding-right: var(--ch3-gutter); +} + +.ch3-tab { + padding: 10px 16px 12px; + font-size: 14px; + font-weight: 500; + color: var(--color-jet-70, #606164); + cursor: pointer; + border-bottom: 2px solid transparent; + margin-bottom: -1px; + letter-spacing: -0.0125em; + transition: color 0.12s; + white-space: nowrap; + text-decoration: none; +} + +.ch3-tab:hover { + color: var(--color-jet, #181818); +} + +.ch3-tab.is-active { + color: var(--color-jet, #181818); + border-bottom-color: var(--brand-color, #e24328); + font-weight: 600; +} + +/* Main content area */ +.ch3-content { + padding: 0; +} + +/* Section styling */ +.ch3-section { + margin-bottom: 56px; + padding-left: var(--ch3-gutter); + padding-right: var(--ch3-gutter); +} + +.ch3-section-title { + font-family: var(--font-display, "Inter Display", "Inter", sans-serif); + font-size: 20px; + font-weight: 600; + letter-spacing: -0.015em; + color: var(--color-jet, #181818); + margin: 0 0 20px; +} + +/* Hero Stats Bar ---------------------------------------------------------- */ +.ch3-hero-stats { + display: flex; + gap: 32px; + margin-top: 28px; + padding-top: 24px; + border-top: 1px solid rgba(255, 255, 255, 0.1); + flex-wrap: wrap; +} + +.ch3-hero-stat { + display: flex; + flex-direction: column; + gap: 2px; +} + +.ch3-hero-stat strong { + font-size: 24px; + font-weight: 700; + color: #fff; + letter-spacing: -0.02em; +} + +.ch3-hero-stat span { + font-size: 12px; + color: rgba(255, 255, 255, 0.6); + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.03em; +} + +/* Hero Ask AI Input ------------------------------------------------------- */ +.ch3-hero-ask { + display: flex; + align-items: center; + gap: 12px; + width: 100%; + max-width: 600px; + padding: 12px 16px; + background: rgba(255, 255, 255, 0.06); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + transition: background 0.12s, border-color 0.12s; + margin-top: 32px; +} + +.ch3-hero-ask:hover, +.ch3-hero-ask:focus-within { + background: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.15); +} + +.ch3-hero-ask-icon { + display: flex; + align-items: center; + color: var(--brand-500-new, #f04438); +} + +.ch3-hero-ask-icon svg { + width: 18px; + height: 18px; +} + +.ch3-hero-ask-input { + flex: 1; + background: transparent; + border: none; + outline: none; + font-size: 15px; + color: #fff; + font-family: var(--body-font-family); +} + +.ch3-hero-ask-input::placeholder { + color: rgba(255, 255, 255, 0.5); +} + +/* Hero Ask Submit Button */ +.ch3-hero-ask-submit, +button.ch3-hero-ask-submit, +.ch3-hero-ask button.ch3-hero-ask-submit { + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 32px !important; + height: 32px !important; + min-width: 32px !important; + max-width: 32px !important; + background: var(--brand-600-new, #e24328) !important; + border: none !important; + border-radius: 8px !important; + color: #fff !important; + cursor: pointer !important; + transition: background 0.12s !important; + padding: 0 !important; + margin: 0 !important; + flex-shrink: 0 !important; +} + +.ch3-hero-ask-submit:hover, +button.ch3-hero-ask-submit:hover { + background: var(--brand-700-new, #c9190b) !important; +} + +.ch3-hero-ask-submit svg, +button.ch3-hero-ask-submit svg, +.ch3-hero-ask button.ch3-hero-ask-submit svg { + width: 14px !important; + height: 14px !important; + min-width: 14px !important; + min-height: 14px !important; + display: block !important; + stroke: #fff !important; + fill: none !important; + flex-shrink: 0 !important; +} + +/* Hero Ask Hints (suggestion chips) */ +.ch3-hero-ask-hints { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 10px; + margin-top: 20px; +} + +.ch3-hero-ask-hints-label { + font-size: 13px; + color: rgba(255, 255, 255, 0.5); + font-weight: 500; +} + +.ch3-hero-ask-chip { + background: rgba(255, 255, 255, 0.06); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 8px; + padding: 8px 14px; + font-size: 13px; + color: rgba(255, 255, 255, 0.8); + cursor: pointer; + transition: background 0.12s, border-color 0.12s, color 0.12s; + font-family: var(--body-font-family); +} + +.ch3-hero-ask-chip:hover { + background: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, 0.2); + color: #fff; +} + +/* Hero background decorations --------------------------------------------- */ +.ch3-hero-bg { + position: absolute; + inset: 0; + overflow: hidden; + border-radius: inherit; + pointer-events: none; +} + +.ch3-hero-glow { + position: absolute; + top: -50%; + left: 50%; + transform: translateX(-50%); + width: 150%; + height: 200%; + background: radial-gradient(closest-side, var(--component-600, rgba(79, 70, 229, 0.2)), transparent 70%); + opacity: 0.5; +} + +.ch3-hero-grid { + position: absolute; + inset: 0; + background-image: + linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px), + linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px); + background-size: 32px 32px; +} + +/* Deploy Cards Grid ------------------------------------------------------- */ +.ch3-deploy-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); + gap: 16px; +} + +.ch3-deploy-card { + display: flex; + flex-direction: column; + background: #fff; + border: 1px solid var(--color-smoke-70, #dcdcde); + border-radius: 12px; + padding: 22px; + text-decoration: none; + color: inherit; + transition: border-color 0.14s, box-shadow 0.14s, transform 0.14s; +} + +.ch3-deploy-card:hover { + border-color: var(--component-600, var(--indigo-600-new, #4f46e5)); + box-shadow: 0 8px 24px rgba(13, 18, 38, 0.08); + transform: translateY(-2px); +} + +.ch3-deploy-icon { + width: 36px; + height: 36px; + border-radius: 8px; + background: var(--component-bg-tint, rgba(79, 70, 229, 0.08)); + color: var(--component-600, var(--indigo-600-new, #4f46e5)); + display: inline-flex; + align-items: center; + justify-content: center; + margin-bottom: 14px; +} + +.ch3-deploy-title { + font-size: 16px; + font-weight: 600; + color: var(--color-jet, #181818); + margin: 0 0 6px; + letter-spacing: -0.01em; +} + +.ch3-deploy-desc { + font-size: 13.5px; + color: var(--color-jet-70, #606164); + line-height: 1.5; + margin: 0 0 18px; + flex: 1; +} + +.ch3-deploy-foot { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} + +.ch3-deploy-cta { + display: inline-flex; + align-items: center; + gap: 5px; + font-size: 13px; + font-weight: 500; + color: var(--component-600, var(--indigo-600-new, #4f46e5)); + white-space: nowrap; +} + +.ch3-deploy-card:hover .ch3-deploy-cta svg { + transform: translateX(2px); +} + +.ch3-deploy-cta svg { + transition: transform 0.12s; +} + +.ch3-deploy-time { + display: inline-flex; + align-items: center; + gap: 4px; + font-size: 12px; + color: var(--color-jet-50, #9ca3af); + font-variant-numeric: tabular-nums; +} + +/* Features Grid (with NEW badge support) ----------------------------------- */ +.ch3-features-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 16px; +} + +.ch3-feature-card { + display: flex; + align-items: flex-start; + gap: 16px; + background: #fff; + border: 1px solid var(--color-smoke-70, #dcdcde); + border-radius: 12px; + padding: 20px; + text-decoration: none; + color: inherit; + transition: border-color 0.14s, box-shadow 0.14s, transform 0.14s; +} + +.ch3-feature-card:hover { + border-color: var(--component-600, var(--indigo-600-new, #4f46e5)); + box-shadow: 0 8px 24px rgba(13, 18, 38, 0.08); + transform: translateY(-2px); +} + +.ch3-feature-icon { + flex-shrink: 0; + width: 42px; + height: 42px; + border-radius: 10px; + background: var(--component-bg-tint, rgba(79, 70, 229, 0.08)); + color: var(--component-600, var(--indigo-600-new, #4f46e5)); + display: flex; + align-items: center; + justify-content: center; +} + +.ch3-feature-content { + flex: 1; + min-width: 0; +} + +.ch3-feature-header { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 6px; +} + +.ch3-feature-title { + font-size: 16px; + font-weight: 600; + color: var(--color-jet, #181818); + margin: 0; + letter-spacing: -0.01em; +} + +.ch3-feature-badge { + display: inline-flex; + align-items: center; + padding: 2px 8px; + font-size: 10px; + font-weight: 600; + letter-spacing: 0.02em; + text-transform: uppercase; + background: linear-gradient(135deg, #10b981 0%, #059669 100%); + color: #fff; + border-radius: 4px; + white-space: nowrap; +} + +.ch3-feature-desc { + font-size: 13.5px; + color: var(--color-jet-70, #606164); + line-height: 1.5; + margin: 0; +} + +.ch3-feature-arrow { + flex-shrink: 0; + color: var(--color-jet-30, #c8cacc); + transition: transform 0.12s, color 0.14s; +} + +.ch3-feature-card:hover .ch3-feature-arrow { + color: var(--component-600, var(--indigo-600-new, #4f46e5)); + transform: translateX(2px); +} + +html[data-theme="dark"] .ch3-feature-card { + background: var(--dark-blue-900-new, #0f172a); + border-color: var(--dark-blue-700-new, #334155); +} + +html[data-theme="dark"] .ch3-feature-card:hover { + border-color: var(--component-500, var(--indigo-500-new, #6366f1)); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3); +} + +html[data-theme="dark"] .ch3-feature-icon { + background: rgba(99, 102, 241, 0.15); + color: var(--component-400, var(--indigo-400-new, #818cf8)); +} + +html[data-theme="dark"] .ch3-feature-title { + color: var(--grey-50-new, #f9fafb); +} + +html[data-theme="dark"] .ch3-feature-desc { + color: var(--grey-400-new, #a1a1aa); +} + +html[data-theme="dark"] .ch3-feature-arrow { + color: var(--grey-600-new, #71717a); +} + +html[data-theme="dark"] .ch3-feature-card:hover .ch3-feature-arrow { + color: var(--component-400, var(--indigo-400-new, #818cf8)); +} + +/* Popular Topics Grid ----------------------------------------------------- */ +.ch3-popular-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + gap: 12px; +} + +.ch3-popular-card { + display: flex; + align-items: flex-start; + gap: 12px; + background: #fff; + border: 1px solid var(--color-smoke-70, #dcdcde); + border-radius: 10px; + padding: 14px 16px; + text-decoration: none; + color: inherit; + transition: border-color 0.12s, background 0.12s; +} + +.ch3-popular-card:hover { + border-color: var(--color-smoke-90, #c3c4c6); + background: var(--color-smoke-10, #fafafa); +} + +.ch3-popular-icon { + width: 28px; + height: 28px; + border-radius: 6px; + background: var(--component-bg-tint, rgba(79, 70, 229, 0.08)); + color: var(--component-600, var(--indigo-600-new, #4f46e5)); + display: inline-flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.ch3-popular-text { + flex: 1; + min-width: 0; +} + +.ch3-popular-text h4 { + font-size: 14px; + font-weight: 600; + color: var(--color-jet, #181818); + margin: 0 0 2px; + letter-spacing: -0.005em; +} + +.ch3-popular-text p { + font-size: 12.5px; + color: var(--color-jet-70, #606164); + line-height: 1.45; + margin: 0; +} + +.ch3-popular-arrow { + color: var(--color-jet-50, #9ca3af); + flex-shrink: 0; + margin-top: 6px; + transition: transform 0.12s, color 0.12s; +} + +.ch3-popular-card:hover .ch3-popular-arrow { + color: var(--component-600, var(--indigo-600-new, #4f46e5)); + transform: translateX(2px); +} + +/* Labs Section ------------------------------------------------------------ */ +.ch3-labs-head { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 18px; + gap: 16px; +} + +.ch3-labs-head .ch3-section-title { + margin: 0; +} + +.ch3-labs-all { + border: 0; + background: transparent; + font: inherit; + font-size: 13px; + font-weight: 500; + color: var(--component-600, var(--indigo-600-new, #4f46e5)); + cursor: pointer; + display: inline-flex; + align-items: center; + gap: 4px; + padding: 6px 8px; + border-radius: 6px; + transition: background 0.12s; + text-decoration: none; +} + +.ch3-labs-all:hover { + background: var(--component-bg-tint, rgba(79, 70, 229, 0.08)); +} + +.ch3-labs-list { + list-style: none; + margin: 0; + padding: 0; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 0; + border-top: 1px solid var(--color-smoke-70, #dcdcde); +} + +.ch3-labs-list li { + border-bottom: 1px solid var(--color-smoke-70, #dcdcde); +} + +.ch3-labs-list a { + display: flex; + align-items: center; + gap: 10px; + padding: 13px 4px; + text-decoration: none; + color: var(--color-jet-80, #48484a); + font-size: 13.5px; + transition: color 0.12s, padding 0.12s; +} + +.ch3-labs-list a svg { + color: var(--color-jet-50, #9ca3af); + flex-shrink: 0; + transition: color 0.12s, transform 0.12s; +} + +.ch3-labs-list a:hover { + color: var(--component-600, var(--indigo-600-new, #4f46e5)); + padding-left: 8px; +} + +.ch3-labs-list a:hover svg { + color: var(--component-600, var(--indigo-600-new, #4f46e5)); + transform: translate(2px, -2px); +} + +/* Help Section ------------------------------------------------------------ */ +.ch3-help { + display: flex; + align-items: center; + justify-content: space-between; + gap: 24px; + flex-wrap: wrap; + padding: 24px 28px; + background: var(--color-smoke-10, #f7f8fa); + border: 1px solid var(--color-smoke-70, #dcdcde); + border-radius: 12px; + margin-top: 48px; +} + +.ch3-help h3 { + font-size: 16px; + font-weight: 600; + margin: 0 0 4px; + color: var(--color-jet, #181818); + letter-spacing: -0.01em; +} + +.ch3-help p { + font-size: 13.5px; + color: var(--color-jet-70, #606164); + margin: 0; +} + +.ch3-help-actions { + display: flex; + gap: 8px; + flex-wrap: wrap; +} + +.ch3-help-btn { + display: inline-flex; + align-items: center; + gap: 6px; + font: inherit; + font-size: 13px; + font-weight: 500; + color: #fff; + background: var(--component-600, var(--indigo-600-new, #4f46e5)); + border: 1px solid var(--component-600, var(--indigo-600-new, #4f46e5)); + padding: 8px 14px; + border-radius: 7px; + cursor: pointer; + text-decoration: none; + transition: opacity 0.12s; +} + +.ch3-help-btn:hover { + opacity: 0.9; +} + +.ch3-help-btn-secondary { + background: #fff; + color: var(--color-jet-80, #48484a); + border-color: var(--color-smoke-90, #c3c4c6); +} + +.ch3-help-btn-secondary:hover { + background: var(--color-smoke-10, #f7f8fa); + opacity: 1; +} + +/* Dark mode support ------------------------------------------------------- */ +html[data-theme="dark"] .ch3-hero { + background: linear-gradient(180deg, #0a0f18 0%, #0f1727 100%); +} + +html[data-theme="dark"] .ch3-hero-stats { + border-top-color: rgba(255, 255, 255, 0.08); +} + +html[data-theme="dark"] .ch3-tabs { + border-bottom-color: rgba(255, 255, 255, 0.1); +} + +html[data-theme="dark"] .ch3-tab { + color: #a8b2c7; +} + +html[data-theme="dark"] .ch3-tab:hover { + color: #fff; +} + +html[data-theme="dark"] .ch3-tab.is-active { + color: #fff; +} + +html[data-theme="dark"] .ch3-section-title { + color: #fff; +} + +/* Dark mode - Deploy cards */ +html[data-theme="dark"] .ch3-deploy-card { + background: #1a2332; + border-color: rgba(255, 255, 255, 0.08); +} + +html[data-theme="dark"] .ch3-deploy-card:hover { + border-color: var(--component-500, var(--indigo-500-new, #6172f3)); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.32); +} + +html[data-theme="dark"] .ch3-deploy-icon { + background: var(--component-bg-tint, rgba(79, 70, 229, 0.15)); +} + +html[data-theme="dark"] .ch3-deploy-title { + color: #fff; +} + +html[data-theme="dark"] .ch3-deploy-desc { + color: #8098b3; +} + +html[data-theme="dark"] .ch3-deploy-time { + color: #6b7a8f; +} + +/* Dark mode - Popular cards */ +html[data-theme="dark"] .ch3-popular-card { + background: #1a2332; + border-color: rgba(255, 255, 255, 0.08); +} + +html[data-theme="dark"] .ch3-popular-card:hover { + border-color: rgba(255, 255, 255, 0.15); + background: rgba(255, 255, 255, 0.03); +} + +html[data-theme="dark"] .ch3-popular-icon { + background: var(--component-bg-tint, rgba(79, 70, 229, 0.15)); +} + +html[data-theme="dark"] .ch3-popular-text h4 { + color: #fff; +} + +html[data-theme="dark"] .ch3-popular-text p { + color: #8098b3; +} + +html[data-theme="dark"] .ch3-popular-arrow { + color: #6b7a8f; +} + +/* Dark mode - Labs */ +html[data-theme="dark"] .ch3-labs-list { + border-top-color: rgba(255, 255, 255, 0.08); +} + +html[data-theme="dark"] .ch3-labs-list li { + border-bottom-color: rgba(255, 255, 255, 0.08); +} + +html[data-theme="dark"] .ch3-labs-list a { + color: #c6cedc; +} + +html[data-theme="dark"] .ch3-labs-list a svg { + color: #6b7a8f; +} + +/* Dark mode - Help */ +html[data-theme="dark"] .ch3-help { + background: #141c28; + border-color: rgba(255, 255, 255, 0.08); +} + +html[data-theme="dark"] .ch3-help h3 { + color: #fff; +} + +html[data-theme="dark"] .ch3-help p { + color: #8098b3; +} + +html[data-theme="dark"] .ch3-help-btn-secondary { + background: rgba(255, 255, 255, 0.04); + color: #c6cedc; + border-color: rgba(255, 255, 255, 0.12); +} + +html[data-theme="dark"] .ch3-help-btn-secondary:hover { + background: rgba(255, 255, 255, 0.08); +} + +/* Responsive -------------------------------------------------------------- */ +@media (max-width: 768px) { + .ch3-hero { + padding: 32px 20px; + border-radius: 12px; + /* Reset full-bleed negative margins on mobile to prevent content cutoff */ + margin-left: 0; + margin-right: 0; + width: 100%; + } + + .doc .ch3-page-title { + font-size: 28px; + } + + .ch3-page-lede { + font-size: 15px; + } + + .ch3-hero-stats { + gap: 20px; + } + + .ch3-hero-stat strong { + font-size: 20px; + } + + .ch3-tabs { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + + .ch3-section { + margin-bottom: 40px; + /* Add breathing room from screen edges on mobile */ + padding-left: 4px; + padding-right: 4px; + } + + .ch3-deploy-grid { + grid-template-columns: 1fr; + } + + .ch3-popular-grid { + grid-template-columns: 1fr; + } + + .ch3-labs-list { + grid-template-columns: 1fr; + } + + .ch3-help { + flex-direction: column; + align-items: flex-start; + text-align: left; + } + + .ch3-help-actions { + width: 100%; + } + + .ch3-help-btn { + flex: 1; + justify-content: center; + } +} + +/* ============================================================================= + CHOOSE YOUR PATH SECTION — Two-column comparison layout + ============================================================================= */ + +.ch3-path-compare { + padding-top: 48px; + margin-bottom: 64px; +} + +.ch3-path-compare .ch3-section-title { + text-align: center; + margin-bottom: 32px; +} + +.ch3-path-grid { + display: grid; + grid-template-columns: 1fr 48px 1fr; + gap: 0; + align-items: stretch; +} + +.ch3-path-col { + display: flex; + flex-direction: column; + padding: 32px; + border-radius: 16px; + background: var(--grey-50-new, #f9fafb); + border: 1px solid var(--grey-200-new, #e5e7eb); +} + +.ch3-path-self { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-right: none; +} + +.ch3-path-cloud { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-left: none; + background: linear-gradient(135deg, #0ea5e9 0%, #0369a1 100%); + border-color: transparent; + color: #fff; +} + +.ch3-path-icon { + display: flex; + align-items: center; + justify-content: center; + width: 48px; + height: 48px; + border-radius: 12px; + background: var(--grey-100-new, #e5e7eb); + color: var(--grey-700-new, #374151); + margin-bottom: 20px; +} + +.ch3-path-cloud .ch3-path-icon { + background: rgba(255, 255, 255, 0.15); + color: #fff; +} + +.ch3-path-heading { + font-size: 20px; + font-weight: 600; + color: var(--grey-900-new, #111827); + margin: 0 0 12px; + letter-spacing: -0.01em; +} + +.ch3-path-cloud .ch3-path-heading { + color: #fff; +} + +.ch3-path-desc { + font-size: 15px; + line-height: 1.5; + color: var(--grey-600-new, #4b5563); + margin: 0 0 20px; +} + +.ch3-path-cloud .ch3-path-desc { + color: rgba(255, 255, 255, 0.85); +} + +.ch3-path-features { + list-style: none; + padding: 0; + margin: 0 0 24px; + flex: 1; +} + +.ch3-path-features li { + display: flex; + align-items: flex-start; + gap: 10px; + font-size: 14px; + line-height: 1.5; + color: var(--grey-700-new, #374151); + margin-bottom: 10px; +} + +.ch3-path-features li::before { + content: ""; + display: inline-block; + width: 18px; + height: 18px; + flex-shrink: 0; + margin-top: 2px; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230f8b66' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E"); + background-size: contain; + background-repeat: no-repeat; +} + +.ch3-path-cloud .ch3-path-features li { + color: rgba(255, 255, 255, 0.9); +} + +.ch3-path-cloud .ch3-path-features li::before { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E"); +} + +.ch3-path-cta { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 12px 20px; + border-radius: 8px; + font-size: 14px; + font-weight: 500; + text-decoration: none; + transition: all 0.15s ease; + margin-top: auto; +} + +.ch3-path-self .ch3-path-cta { + background: var(--grey-900-new, #111827); + color: #fff; +} + +.ch3-path-self .ch3-path-cta:hover { + background: var(--grey-800-new, #1f2937); + transform: translateY(-1px); +} + +.ch3-path-cloud .ch3-path-cta { + background: #fff; + color: #0369a1; +} + +.ch3-path-cloud .ch3-path-cta:hover { + background: rgba(255, 255, 255, 0.95); + transform: translateY(-1px); +} + +.ch3-path-divider { + display: flex; + align-items: center; + justify-content: center; + position: relative; + z-index: 1; +} + +.ch3-path-or { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + border-radius: 50%; + background: #fff; + border: 2px solid var(--grey-200-new, #e5e7eb); + font-size: 13px; + font-weight: 600; + color: var(--grey-500-new, #6b7280); + text-transform: lowercase; +} + +/* Dark mode for path compare */ +html[data-theme="dark"] .ch3-path-col:not(.ch3-path-cloud) { + background: rgba(255, 255, 255, 0.03); + border-color: rgba(255, 255, 255, 0.08); +} + +html[data-theme="dark"] .ch3-path-icon { + background: rgba(255, 255, 255, 0.08); + color: var(--grey-300-new, #d1d5db); +} + +html[data-theme="dark"] .ch3-path-heading { + color: #fff; +} + +html[data-theme="dark"] .ch3-path-desc { + color: var(--grey-400-new, #9ca3af); +} + +html[data-theme="dark"] .ch3-path-features li { + color: var(--grey-300-new, #d1d5db); +} + +html[data-theme="dark"] .ch3-path-self .ch3-path-cta { + background: #fff; + color: #111827; +} + +html[data-theme="dark"] .ch3-path-self .ch3-path-cta:hover { + background: rgba(255, 255, 255, 0.9); +} + +html[data-theme="dark"] .ch3-path-cloud { + background: linear-gradient(135deg, #075985 0%, #0c4a6e 100%); +} + +html[data-theme="dark"] .ch3-path-cloud .ch3-path-cta { + background: #fff; + color: #0c4a6e; +} + +html[data-theme="dark"] .ch3-path-cloud .ch3-path-cta:hover { + background: rgba(255, 255, 255, 0.95); +} + +html[data-theme="dark"] .ch3-path-or { + background: #1a2332; + border-color: rgba(255, 255, 255, 0.12); + color: var(--grey-400-new, #9ca3af); +} + +/* Responsive: Stack on mobile */ +@media screen and (max-width: 768px) { + .ch3-path-grid { + grid-template-columns: 1fr; + gap: 16px; + } + + .ch3-path-col { + border-radius: 16px !important; + border: 1px solid var(--grey-200-new, #e5e7eb) !important; + } + + .ch3-path-cloud { + border-color: transparent !important; + } + + .ch3-path-divider { + display: none; + } +} + +/* Two-Column Layout: What's New + Path Compare ---------------------------- */ +.ch3-hero-columns { + display: grid; + grid-template-columns: 1fr; + gap: 24px; + margin-bottom: 32px; + padding: 0 var(--ch3-gutter); +} + +@media (min-width: 1024px) { + .ch3-hero-columns--with-whats-new { + grid-template-columns: 1fr 400px; + gap: 32px; + } + + .ch3-hero-columns--with-whats-new .ch3-whats-new-wrapper { + order: 2; + } + + .ch3-hero-columns--with-whats-new .ch3-path-compare { + order: 1; + margin-bottom: 0; + } +} + +/* Remove margin from path-compare when in grid layout */ +.ch3-hero-columns .ch3-path-compare { + margin-bottom: 0; +} + +/* What's New Section in Component Home V3 --------------------------------- */ +.ch3-whats-new-wrapper { + max-width: none; + margin: 0; + padding: 0; +} + +.ch3-hero-columns .ch3-whats-new-wrapper { + margin-bottom: 0; +} + +@media (max-width: 768px) { + .ch3-whats-new-wrapper { + margin-bottom: 32px; + } +} diff --git a/src/css/dark-mode.css b/src/css/dark-mode.css index 31bfa264..4bfb58f9 100644 --- a/src/css/dark-mode.css +++ b/src/css/dark-mode.css @@ -129,3 +129,8 @@ html[data-theme=dark] { --highlight-container-background: #262626; --color-aliases-static-palette-text-secondary: var(--color-primitives-global-grey-grey-200); } + +/* TOC hover color override for dark mode */ +html[data-theme=dark] .toc a:hover { + color: var(--color-white); +} diff --git a/src/css/data-platform.css b/src/css/data-platform.css new file mode 100644 index 00000000..24d91a6d --- /dev/null +++ b/src/css/data-platform.css @@ -0,0 +1,1358 @@ +/* Data Platform Landing Page + This page serves as the umbrella landing for Self-managed, Cloud, and Connect docs. + =================================================================================== */ + +/* Hide all icons on landing page */ +.dp-product-bullet-icon, +.dp-popular-icon { + display: none !important; +} + +/* Layout: full-width content area */ +.data-platform .dp-content { + padding: 0; + max-width: none; +} + +.data-platform.article { + background: var(--grey-50-new, #fafafa); +} + +html[data-theme="dark"] .data-platform.article { + background: var(--grey-950-new, #09090b); +} + +/* ---- Hero Section ---- */ +.dp-hero { + position: relative; + overflow: hidden; + background: linear-gradient(180deg, #0e1a33 0%, #1a2a52 100%); + color: #fff; + padding: 72px 56px 64px; + border-bottom: 1px solid rgba(255, 255, 255, 0.08); +} + +.dp-hero-bg { + position: absolute; + inset: 0; + pointer-events: none; +} + +.dp-hero-glow { + position: absolute; + border-radius: 50%; + filter: blur(80px); + opacity: 0.55; +} + +.dp-hero-glow-1 { + width: 480px; + height: 480px; + background: radial-gradient(circle, #4338ca 0%, transparent 70%); + top: -120px; + right: -80px; +} + +.dp-hero-glow-2 { + width: 380px; + height: 380px; + background: radial-gradient(circle, #1f5bd6 0%, transparent 70%); + bottom: -120px; + left: -60px; + opacity: 0.35; +} + +.dp-hero-grid { + position: absolute; + inset: 0; + background-image: + linear-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px), + linear-gradient(90deg, rgba(255, 255, 255, 0.04) 1px, transparent 1px); + background-size: 32px 32px; + mask-image: radial-gradient(ellipse at 50% 30%, black 30%, transparent 75%); + -webkit-mask-image: radial-gradient(ellipse at 50% 30%, black 30%, transparent 75%); +} + +.dp-hero-inner { + position: relative; + max-width: 1100px; +} + +.dp-hero-eyebrow { + display: inline-flex; + align-items: center; + gap: 10px; + font-family: var(--font-mono, 'JetBrains Mono', monospace); + font-size: 11px; + font-weight: 600; + line-height: 1; + letter-spacing: 0.1em; + color: rgba(255, 255, 255, 0.7); + margin-bottom: 22px; +} + +.dp-hero-chip { + display: inline-grid; + place-items: center; + width: 28px; + height: 22px; + font-family: var(--font-mono, 'JetBrains Mono', monospace); + font-size: 10.5px; + font-weight: 700; + line-height: 1; + letter-spacing: 0.04em; + color: #fff; + background: var(--indigo-600, #4338ca); + border-radius: 5px; +} + +/* Use .dp-hero prefix for specificity over .doc h1 */ +.dp-hero .dp-hero-title { + font-family: var(--inter-display, var(--sans-serif-font, 'Inter', sans-serif)); + font-size: 52px; + font-weight: 700; + line-height: 1.05; + letter-spacing: -0.02em; + margin: 0 0 18px; + text-wrap: pretty; + color: #fff; +} + +.dp-hero-sub { + font-size: 18px; + line-height: 1.55; + color: rgba(255, 255, 255, 0.78); + max-width: 700px; + margin: 0 0 32px; + text-wrap: pretty; +} + +.dp-hero-stats { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 24px; + max-width: 720px; + border-top: 1px solid rgba(255, 255, 255, 0.1); + padding-top: 24px; +} + +.dp-hero-stats > div { + display: flex; + flex-direction: column; + gap: 4px; +} + +.dp-hero-stats strong { + font-family: var(--sans-serif-font, 'Inter', sans-serif); + font-size: 22px; + font-weight: 600; + line-height: 1.1; + letter-spacing: -0.01em; + color: #fff; +} + +.dp-hero-stats span { + font-size: 12px; + color: rgba(255, 255, 255, 0.6); + line-height: 1.35; +} + +/* ---- Two-column hero layout (What's New + Choose) ---- */ +.dp-hero-columns { + display: grid; + grid-template-columns: 1fr; + gap: 24px; + margin-bottom: 48px; +} + +@media (min-width: 1024px) { + .dp-hero-columns--with-whats-new { + grid-template-columns: 1fr 30%; + gap: 28px; + } + + .dp-hero-columns--with-whats-new .dp-whats-new-wrapper { + order: 2; + } + + .dp-hero-columns--with-whats-new .dp-choose-section { + order: 1; + } +} + +.dp-choose-section { + margin-bottom: 0; +} + +/* Make choose section cards bigger (2 columns instead of 3) */ +.dp-choose-section .dp-products { + grid-template-columns: 1fr 1fr; + gap: 20px; +} + +@media (max-width: 768px) { + .dp-choose-section .dp-products { + grid-template-columns: 1fr; + } +} + +/* ---- Hero Ask AI Input ---- */ +.dp-hero-ask { + display: flex; + align-items: center; + gap: 12px; + width: 100%; + max-width: 600px; + padding: 12px 16px; + background: rgba(255, 255, 255, 0.06); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + transition: background 0.12s, border-color 0.12s; + margin-top: 32px; +} + +.dp-hero-ask:hover, +.dp-hero-ask:focus-within { + background: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.15); +} + +.dp-hero-ask-icon { + display: flex; + align-items: center; + color: var(--brand-500-new, #f04438); +} + +.dp-hero-ask-icon svg { + width: 18px; + height: 18px; +} + +.dp-hero-ask-input { + flex: 1; + background: transparent; + border: none; + outline: none; + font-size: 15px; + color: #fff; + font-family: var(--body-font-family); +} + +.dp-hero-ask-input::placeholder { + color: rgba(255, 255, 255, 0.5); +} + +/* Hero Ask Submit Button */ +.dp-hero-ask-submit, +button.dp-hero-ask-submit, +.dp-hero-ask button.dp-hero-ask-submit { + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 32px !important; + height: 32px !important; + min-width: 32px !important; + max-width: 32px !important; + background: var(--brand-600-new, #e24328) !important; + border: none !important; + border-radius: 8px !important; + color: #fff !important; + cursor: pointer !important; + transition: background 0.12s !important; + padding: 0 !important; + margin: 0 !important; + flex-shrink: 0 !important; +} + +.dp-hero-ask-submit:hover, +button.dp-hero-ask-submit:hover { + background: var(--brand-700-new, #c9190b) !important; +} + +.dp-hero-ask-submit svg, +button.dp-hero-ask-submit svg, +.dp-hero-ask button.dp-hero-ask-submit svg { + width: 14px !important; + height: 14px !important; + min-width: 14px !important; + min-height: 14px !important; + display: block !important; + stroke: #fff !important; + fill: none !important; + flex-shrink: 0 !important; +} + +/* Hero Ask Hints (suggestion chips) */ +.dp-hero-ask-hints { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 10px; + margin-top: 20px; +} + +.dp-hero-ask-hints-label { + font-size: 13px; + color: rgba(255, 255, 255, 0.5); + font-weight: 500; +} + +.dp-hero-ask-chip { + background: rgba(255, 255, 255, 0.06); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 8px; + padding: 8px 14px; + font-size: 13px; + color: rgba(255, 255, 255, 0.8); + cursor: pointer; + transition: background 0.12s, border-color 0.12s, color 0.12s; + font-family: var(--body-font-family); +} + +.dp-hero-ask-chip:hover { + background: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, 0.2); + color: #fff; +} + +/* NEW badge for BYOC SQL */ +.dp-product-badge--new { + display: inline-flex; + align-items: center; + padding: 2px 8px; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.04em; + text-transform: uppercase; + background: linear-gradient(135deg, #10b981 0%, #059669 100%); + color: #fff; + border-radius: 4px; + white-space: nowrap; + margin-left: 6px; + vertical-align: middle; +} + +/* ---- Sections ---- */ +.dp-section { + padding: 56px 56px 0; +} + +.dp-section:last-of-type { + padding-bottom: 64px; +} + +.dp-section-head { + margin-bottom: 28px; + max-width: 720px; +} + +.dp-section-title { + font-family: var(--sans-serif-font, 'Inter', sans-serif); + font-size: 26px; + font-weight: 600; + line-height: 1.2; + letter-spacing: -0.015em; + margin: 0 0 6px; + color: var(--grey-800-new, #18181b); +} + +html[data-theme="dark"] .dp-section-title { + color: var(--grey-100-new, #f4f4f5); +} + +.dp-section-sub { + font-size: 15px; + color: var(--grey-600-new, #52525b); + margin: 0; + text-wrap: pretty; +} + +html[data-theme="dark"] .dp-section-sub { + color: var(--grey-400-new, #a1a1aa); +} + +/* ---- Three-product cards ---- */ +.dp-products { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 18px; +} + +.dp-product { + --dp-accent: #475569; + + position: relative; + display: flex; + flex-direction: column; + background: var(--grey-50-new, #fafafa); + border: 1px solid var(--grey-200-new, #e4e4e7); + border-radius: 14px; + padding: 24px; + cursor: pointer; + transition: border-color 0.15s, transform 0.15s, box-shadow 0.15s; + overflow: hidden; + text-decoration: none; + color: inherit; +} + +html[data-theme="dark"] .dp-product { + background: var(--grey-900-new, #18181b); + border-color: var(--grey-800-new, #27272a); +} + +.dp-product::before { + content: ""; + position: absolute; + left: 0; + right: 0; + top: 0; + height: 3px; + background: var(--dp-accent); + opacity: 0.85; +} + +.dp-product:hover { + border-color: var(--dp-accent); + transform: translateY(-2px); + box-shadow: 0 10px 28px -16px var(--dp-accent); +} + +.dp-product.is-featured { + background: linear-gradient(180deg, rgba(31, 91, 214, 0.04) 0%, var(--grey-50-new, #fafafa) 60%); + border-color: rgba(31, 91, 214, 0.35); +} + +html[data-theme="dark"] .dp-product.is-featured { + background: linear-gradient(180deg, rgba(31, 91, 214, 0.08) 0%, var(--grey-900-new, #18181b) 60%); + border-color: rgba(31, 91, 214, 0.4); +} + +.dp-product-head { + display: flex; + align-items: flex-start; + gap: 12px; + margin-bottom: 14px; +} + +.dp-product-chip { + display: inline-grid; + place-items: center; + width: 32px; + height: 26px; + font-family: var(--font-mono, 'JetBrains Mono', monospace); + font-size: 11px; + font-weight: 700; + line-height: 1; + letter-spacing: 0.05em; + color: #fff; + background: var(--dp-accent); + border-radius: 5px; + flex-shrink: 0; + margin-top: 2px; +} + +.dp-product-chip-sm { + background: #0f8b66; +} + +.dp-product-chip-cl { + background: #1f5bd6; +} + +.dp-product-chip-rc { + background: #6e48e1; +} + +.dp-product-titles { + flex: 1; + min-width: 0; +} + +.dp-product-name { + font-family: var(--sans-serif-font, 'Inter', sans-serif); + font-size: 18px; + font-weight: 600; + line-height: 1.25; + letter-spacing: -0.01em; + margin: 0 0 4px; + color: var(--grey-800-new, #18181b); +} + +html[data-theme="dark"] .dp-product-name { + color: var(--grey-100-new, #f4f4f5); +} + +.dp-product-tagline { + font-size: 13px; + color: var(--grey-600-new, #52525b); + margin: 0; + line-height: 1.4; +} + +html[data-theme="dark"] .dp-product-tagline { + color: var(--grey-400-new, #a1a1aa); +} + +.dp-product-desc { + font-size: 14px; + line-height: 1.55; + color: var(--grey-600-new, #52525b); + margin: 0 0 18px; + text-wrap: pretty; +} + +html[data-theme="dark"] .dp-product-desc { + color: var(--grey-400-new, #a1a1aa); +} + +.dp-product-bullets { + list-style: none; + padding: 0; + margin: 0 0 18px; + display: flex; + flex-direction: column; + gap: 8px; +} + +.dp-product-bullets li { + display: flex; + align-items: center; + gap: 10px; + font-size: 13px; + color: var(--grey-800-new, #18181b); +} + +html[data-theme="dark"] .dp-product-bullets li { + color: var(--grey-200-new, #e4e4e7); +} + +.dp-product-bullet-icon { + display: inline-grid; + place-items: center; + width: 22px; + height: 22px; + border-radius: 5px; + background: rgba(var(--dp-accent-rgb, 71, 85, 105), 0.12); + color: var(--dp-accent); + flex-shrink: 0; +} + +/* Use specific background colors for each accent */ +.dp-product[style*="--dp-accent: #0f8b66"] .dp-product-bullet-icon { + background: rgba(15, 139, 102, 0.12); +} + +.dp-product[style*="--dp-accent: #1f5bd6"] .dp-product-bullet-icon { + background: rgba(31, 91, 214, 0.12); +} + +.dp-product[style*="--dp-accent: #6e48e1"] .dp-product-bullet-icon { + background: rgba(110, 72, 225, 0.12); +} + +.dp-product-stats { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; + padding: 12px 0; + margin-bottom: 16px; + border-top: 1px solid var(--grey-200-new, #e4e4e7); + border-bottom: 1px solid var(--grey-200-new, #e4e4e7); +} + +html[data-theme="dark"] .dp-product-stats { + border-color: var(--grey-800-new, #27272a); +} + +.dp-product-stats > div { + display: flex; + flex-direction: column; + gap: 2px; +} + +.dp-product-stats strong { + font-family: var(--sans-serif-font, 'Inter', sans-serif); + font-size: 16px; + font-weight: 600; + line-height: 1.1; + color: var(--grey-800-new, #18181b); + letter-spacing: -0.01em; +} + +html[data-theme="dark"] .dp-product-stats strong { + color: var(--grey-100-new, #f4f4f5); +} + +.dp-product-stats span { + font-size: 11.5px; + color: var(--grey-600-new, #52525b); +} + +html[data-theme="dark"] .dp-product-stats span { + color: var(--grey-400-new, #a1a1aa); +} + +.dp-product-cta { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + font-family: var(--sans-serif-font, 'Inter', sans-serif); + font-size: 13.5px; + font-weight: 600; + line-height: 1; + color: var(--dp-accent); + margin-top: auto; +} + +.dp-product:hover .dp-product-cta svg { + transform: translateX(2px); + transition: transform 0.15s; +} + +/* ---- What's New section ---- */ +.dp-whats-new-section { + --whats-new-color: 16, 185, 129; /* Default: green */ + + background: linear-gradient(135deg, rgba(var(--whats-new-color), 0.03) 0%, rgba(var(--whats-new-color), 0.02) 100%); + border: 1px solid rgba(var(--whats-new-color), 0.12); + border-radius: 14px; + padding: 20px; + margin-bottom: 0; + height: fit-content; +} + +html[data-theme="dark"] .dp-whats-new-section { + background: linear-gradient(135deg, rgba(var(--whats-new-color), 0.06) 0%, rgba(var(--whats-new-color), 0.03) 100%); + border-color: rgba(var(--whats-new-color), 0.18); +} + +.dp-whats-new-section .dp-section-head { + margin-bottom: 14px; +} + +.dp-whats-new-section .dp-section-title { + font-size: 16px; + margin-bottom: 4px; +} + +.dp-whats-new-section .dp-section-sub { + font-size: 12px; +} + +.dp-whats-new { + display: flex; + flex-direction: column; + gap: 14px; +} + +.dp-new-item { + position: relative; + display: flex; + align-items: center; + gap: 10px; + background: var(--grey-50-new, #fafafa); + border: 1px solid var(--grey-200-new, #e4e4e7); + border-radius: 10px; + padding: 12px 14px; + text-decoration: none; + color: inherit; + transition: all 0.18s ease; +} + +html[data-theme="dark"] .dp-new-item { + background: var(--grey-900-new, #18181b); + border-color: var(--grey-800-new, #27272a); +} + +.dp-new-item:hover { + border-color: #10b981; + transform: translateX(4px); + box-shadow: -4px 0 0 #10b981, 0 4px 12px rgba(16, 185, 129, 0.15); +} + +.dp-new-badge { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 4px 10px; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.05em; + text-transform: uppercase; + background: rgb(var(--whats-new-color)); + color: #fff; + border-radius: 5px; + white-space: nowrap; + flex-shrink: 0; +} + +.dp-new-content { + flex: 1; + min-width: 0; +} + +.dp-new-title { + font-family: var(--sans-serif-font, 'Inter', sans-serif); + font-size: 14.5px; + font-weight: 600; + line-height: 1.3; + letter-spacing: -0.01em; + margin: 0 0 4px; + color: var(--grey-800-new, #18181b); +} + +html[data-theme="dark"] .dp-new-title { + color: var(--grey-100-new, #f4f4f5); +} + +.dp-new-desc { + font-size: 12.5px; + line-height: 1.5; + color: var(--grey-600-new, #52525b); + margin: 0 0 6px; +} + +html[data-theme="dark"] .dp-new-desc { + color: var(--grey-400-new, #a1a1aa); +} + +.dp-new-tag { + display: inline-flex; + align-items: center; + padding: 3px 8px; + font-size: 11px; + font-weight: 600; + letter-spacing: 0.02em; + background: rgba(16, 185, 129, 0.08); + color: #059669; + border-radius: 4px; + white-space: nowrap; +} + +html[data-theme="dark"] .dp-new-tag { + background: rgba(16, 185, 129, 0.12); + color: #10b981; +} + +.dp-new-arrow { + flex-shrink: 0; + color: #10b981; + opacity: 0.7; + transition: all 0.18s ease; +} + +.dp-new-item:hover .dp-new-arrow { + opacity: 1; + transform: translateX(2px); +} + +/* Mobile adjustments for What's New */ +@media (max-width: 768px) { + .dp-whats-new-section { + padding: 20px 18px; + } + + .dp-new-item { + flex-direction: row; + gap: 12px; + padding: 14px 16px; + } + + .dp-new-badge { + padding: 3px 8px; + font-size: 8px; + } + + .dp-new-title { + font-size: 14px; + } + + .dp-new-desc { + font-size: 12px; + } +} + +/* ---- Decision boxes with OR separator ---- */ +.dp-decision-boxes { + display: grid; + grid-template-columns: 1fr; + gap: 32px; + position: relative; +} + +@media (min-width: 768px) { + .dp-decision-boxes { + grid-template-columns: 1fr auto 1fr; + gap: 48px; + align-items: start; + } +} + +.dp-decision-box { + position: relative; + background: var(--grey-50-new, #fafafa); + border: 1px solid var(--grey-200-new, #e4e4e7); + border-radius: 12px; + padding: 28px; + display: flex; + flex-direction: column; + gap: 20px; +} + +html[data-theme="dark"] .dp-decision-box { + background: var(--grey-900-new, #18181b); + border-color: var(--grey-800-new, #27272a); +} + +.dp-decision-desc { + font-size: 15px; + line-height: 1.5; + color: var(--grey-700-new, #3f3f46); + margin: 0; +} + +html[data-theme="dark"] .dp-decision-desc { + color: var(--grey-300-new, #d4d4d8); +} + +.dp-decision-features { + list-style: none; + padding: 0; + margin: 0; + display: flex; + flex-direction: column; + gap: 12px; +} + +.dp-decision-features li { + display: flex; + align-items: flex-start; + gap: 10px; + font-size: 14px; + line-height: 1.5; + color: var(--grey-600-new, #52525b); +} + +html[data-theme="dark"] .dp-decision-features li { + color: var(--grey-400-new, #a1a1aa); +} + +.dp-decision-features li svg { + flex-shrink: 0; + margin-top: 2px; + color: var(--dp-accent); +} + +.dp-decision-cta { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + padding: 12px 20px; + background: var(--grey-50-new, #fafafa); + border: 1.5px solid var(--dp-accent); + border-radius: 8px; + text-decoration: none; + font-family: var(--sans-serif-font, 'Inter', sans-serif); + font-size: 14px; + font-weight: 600; + color: var(--dp-accent); + transition: all 0.15s ease; + margin-top: auto; +} + +html[data-theme="dark"] .dp-decision-cta { + background: var(--grey-900-new, #18181b); +} + +.dp-decision-cta:hover { + background: var(--dp-accent); + color: #fff; + transform: translateY(-1px); +} + +.dp-decision-cta svg { + transition: transform 0.15s ease; +} + +.dp-decision-cta:hover svg { + transform: translateX(2px); +} + +.dp-decision-or { + display: none; + align-items: center; + justify-content: center; + font-family: var(--sans-serif-font, 'Inter', sans-serif); + font-size: 13px; + font-weight: 600; + color: var(--grey-400-new, #a1a1aa); + text-transform: lowercase; + padding: 0 16px; +} + +@media (min-width: 768px) { + .dp-decision-or { + display: flex; + } +} + +html[data-theme="dark"] .dp-decision-or { + color: var(--grey-500-new, #71717a); +} + +/* ---- Decision matrix (legacy, keep for backwards compatibility) ---- */ +.dp-matrix { + display: flex; + flex-direction: column; + gap: 0; + background: var(--grey-50-new, #fafafa); + border: 1px solid var(--grey-200-new, #e4e4e7); + border-radius: 12px; + overflow: hidden; +} + +html[data-theme="dark"] .dp-matrix { + background: var(--grey-900-new, #18181b); + border-color: var(--grey-800-new, #27272a); +} + +.dp-matrix-row { + display: grid; + grid-template-columns: 1fr auto; + gap: 24px; + align-items: center; + padding: 20px 24px; + border-bottom: 1px solid var(--grey-200-new, #e4e4e7); +} + +html[data-theme="dark"] .dp-matrix-row { + border-color: var(--grey-800-new, #27272a); +} + +.dp-matrix-row:last-child { + border-bottom: 0; +} + +.dp-matrix-when { + display: flex; + align-items: baseline; + gap: 14px; +} + +.dp-matrix-when-label { + font-family: var(--font-mono, 'JetBrains Mono', monospace); + font-size: 11px; + font-weight: 600; + line-height: 1; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--grey-600-new, #52525b); + flex-shrink: 0; + width: 56px; +} + +html[data-theme="dark"] .dp-matrix-when-label { + color: var(--grey-400-new, #a1a1aa); +} + +.dp-matrix-when p { + font-size: 15px; + line-height: 1.45; + margin: 0; + color: var(--grey-800-new, #18181b); + text-wrap: pretty; +} + +html[data-theme="dark"] .dp-matrix-when p { + color: var(--grey-200-new, #e4e4e7); +} + +.dp-matrix-pick { + --dp-accent: #475569; + + display: inline-flex; + align-items: center; + gap: 10px; + padding: 8px 14px; + border-radius: 8px; + background: rgba(var(--dp-accent-rgb, 71, 85, 105), 0.07); + border: 1px solid rgba(var(--dp-accent-rgb, 71, 85, 105), 0.25); + white-space: nowrap; + transition: background 0.15s; + text-decoration: none; +} + +/* Specific pick background colors */ +.dp-matrix-pick[style*="--dp-accent: #0f8b66"] { + background: rgba(15, 139, 102, 0.07); + border-color: rgba(15, 139, 102, 0.25); +} + +.dp-matrix-pick[style*="--dp-accent: #1f5bd6"] { + background: rgba(31, 91, 214, 0.07); + border-color: rgba(31, 91, 214, 0.25); +} + +.dp-matrix-pick[style*="--dp-accent: #6e48e1"] { + background: rgba(110, 72, 225, 0.07); + border-color: rgba(110, 72, 225, 0.25); +} + +.dp-matrix-pick:hover { + background: rgba(var(--dp-accent-rgb, 71, 85, 105), 0.12); +} + +.dp-matrix-pick[style*="--dp-accent: #0f8b66"]:hover { + background: rgba(15, 139, 102, 0.12); +} + +.dp-matrix-pick[style*="--dp-accent: #1f5bd6"]:hover { + background: rgba(31, 91, 214, 0.12); +} + +.dp-matrix-pick[style*="--dp-accent: #6e48e1"]:hover { + background: rgba(110, 72, 225, 0.12); +} + +.dp-matrix-pick a { + font-family: var(--sans-serif-font, 'Inter', sans-serif); + font-size: 13.5px; + font-weight: 600; + line-height: 1; + color: var(--dp-accent); + text-decoration: none; + display: inline-flex; + align-items: center; + gap: 6px; +} + +/* ---- Popular cards ---- */ +.dp-popular { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 12px; +} + +.dp-popular-card { + display: flex; + align-items: center; + gap: 14px; + padding: 14px 16px; + background: var(--grey-50-new, #fafafa); + border: 1px solid var(--grey-200-new, #e4e4e7); + border-radius: 10px; + text-decoration: none; + color: inherit; + transition: border-color 0.15s, transform 0.15s; +} + +html[data-theme="dark"] .dp-popular-card { + background: var(--grey-900-new, #18181b); + border-color: var(--grey-800-new, #27272a); +} + +.dp-popular-card:hover { + border-color: var(--indigo-600, #4338ca); + transform: translateY(-1px); +} + +.dp-popular-card:hover .dp-popular-arrow { + transform: translateX(2px); + color: var(--indigo-600, #4338ca); +} + +.dp-popular-icon { + display: grid; + place-items: center; + width: 32px; + height: 32px; + border-radius: 7px; + background: rgba(75, 68, 255, 0.1); + color: var(--indigo-600, #4338ca); + flex-shrink: 0; +} + +.dp-popular-text { + flex: 1; + min-width: 0; +} + +.dp-popular-text h4 { + font-family: var(--sans-serif-font, 'Inter', sans-serif); + font-size: 14px; + font-weight: 600; + line-height: 1.3; + letter-spacing: -0.005em; + margin: 0 0 4px; + color: var(--grey-800-new, #18181b); +} + +html[data-theme="dark"] .dp-popular-text h4 { + color: var(--grey-100-new, #f4f4f5); +} + +.dp-popular-meta { + display: flex; + align-items: center; + gap: 10px; +} + +.dp-popular-tag { + font-family: var(--font-mono, 'JetBrains Mono', monospace); + font-size: 10.5px; + font-weight: 600; + line-height: 1; + letter-spacing: 0.06em; + text-transform: uppercase; + color: var(--grey-600-new, #52525b); +} + +html[data-theme="dark"] .dp-popular-tag { + color: var(--grey-400-new, #a1a1aa); +} + +.dp-popular-time { + display: inline-flex; + align-items: center; + gap: 4px; + font-size: 11.5px; + color: var(--grey-600-new, #52525b); +} + +html[data-theme="dark"] .dp-popular-time { + color: var(--grey-400-new, #a1a1aa); +} + +.dp-popular-arrow { + color: var(--grey-600-new, #52525b); + transition: transform 0.15s, color 0.15s; + flex-shrink: 0; +} + +html[data-theme="dark"] .dp-popular-arrow { + color: var(--grey-400-new, #a1a1aa); +} + +/* ---- Concepts ---- */ +.dp-concepts { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 12px; +} + +.dp-concept { + display: block; + padding: 18px; + background: var(--grey-50-new, #fafafa); + border: 1px solid var(--grey-200-new, #e4e4e7); + border-radius: 10px; + text-decoration: none; + color: inherit; + transition: border-color 0.15s, transform 0.15s; +} + +html[data-theme="dark"] .dp-concept { + background: var(--grey-900-new, #18181b); + border-color: var(--grey-800-new, #27272a); +} + +.dp-concept:hover { + border-color: var(--indigo-600, #4338ca); + transform: translateY(-1px); +} + +.dp-concept-icon { + display: grid; + place-items: center; + width: 32px; + height: 32px; + border-radius: 7px; + background: rgba(75, 68, 255, 0.1); + color: var(--indigo-600, #4338ca); + margin-bottom: 12px; +} + +.dp-concept h4 { + font-family: var(--sans-serif-font, 'Inter', sans-serif); + font-size: 14.5px; + font-weight: 600; + line-height: 1.3; + letter-spacing: -0.005em; + margin: 0 0 6px; + color: var(--grey-800-new, #18181b); +} + +html[data-theme="dark"] .dp-concept h4 { + color: var(--grey-100-new, #f4f4f5); +} + +.dp-concept p { + font-size: 13px; + line-height: 1.5; + color: var(--grey-600-new, #52525b); + margin: 0; + text-wrap: pretty; +} + +html[data-theme="dark"] .dp-concept p { + color: var(--grey-400-new, #a1a1aa); +} + +/* ---- Help footer ---- */ +.dp-help { + max-width: 1180px; + margin: 56px auto 0; + padding: 28px 32px; + display: flex; + align-items: center; + justify-content: space-between; + gap: 32px; + background: linear-gradient(135deg, rgba(75, 68, 255, 0.05) 0%, var(--grey-50-new, #fafafa) 100%); + border: 1px solid var(--grey-200-new, #e4e4e7); + border-radius: 14px; + margin-left: 56px; + margin-right: 56px; + margin-bottom: 56px; +} + +html[data-theme="dark"] .dp-help { + background: linear-gradient(135deg, rgba(75, 68, 255, 0.08) 0%, var(--grey-900-new, #18181b) 100%); + border-color: var(--grey-800-new, #27272a); +} + +.dp-help h3 { + font-family: var(--sans-serif-font, 'Inter', sans-serif); + font-size: 18px; + font-weight: 600; + line-height: 1.2; + letter-spacing: -0.01em; + margin: 0 0 4px; + color: var(--grey-800-new, #18181b); +} + +html[data-theme="dark"] .dp-help h3 { + color: var(--grey-100-new, #f4f4f5); +} + +.dp-help p { + font-size: 14px; + color: var(--grey-600-new, #52525b); + margin: 0; +} + +html[data-theme="dark"] .dp-help p { + color: var(--grey-400-new, #a1a1aa); +} + +.dp-help-actions { + display: flex; + gap: 10px; + flex-shrink: 0; +} + +.dp-help-btn { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 9px 16px; + font-family: var(--sans-serif-font, 'Inter', sans-serif); + font-size: 13px; + font-weight: 600; + line-height: 1; + background: var(--indigo-600, #4338ca); + color: #fff; + border: 0; + border-radius: 7px; + cursor: pointer; + text-decoration: none; + transition: background 0.15s; +} + +.dp-help-btn:hover { + background: var(--indigo-700, #3934d6); +} + +.dp-help-btn-secondary { + background: transparent; + color: var(--grey-800-new, #18181b); + border: 1px solid var(--grey-200-new, #e4e4e7); +} + +html[data-theme="dark"] .dp-help-btn-secondary { + color: var(--grey-200-new, #e4e4e7); + border-color: var(--grey-700-new, #3f3f46); +} + +.dp-help-btn-secondary:hover { + background: var(--grey-100-new, #f4f4f5); + border-color: var(--grey-400-new, #a1a1aa); +} + +html[data-theme="dark"] .dp-help-btn-secondary:hover { + background: var(--grey-800-new, #27272a); + border-color: var(--grey-600-new, #52525b); +} + +/* ---- Responsive ---- */ +@media (max-width: 1100px) { + .dp-products { + grid-template-columns: 1fr; + } + + .dp-popular { + grid-template-columns: 1fr 1fr; + } + + .dp-concepts { + grid-template-columns: 1fr 1fr; + } + + .dp-hero-stats { + grid-template-columns: 1fr 1fr; + } +} + +@media (max-width: 720px) { + .dp-hero { + padding: 56px 24px 48px; + } + + .dp-hero-title { + font-size: 36px; + } + + .dp-section { + padding: 40px 24px 0; + } + + .dp-popular { + grid-template-columns: 1fr; + } + + .dp-concepts { + grid-template-columns: 1fr; + } + + .dp-help { + flex-direction: column; + align-items: flex-start; + margin-left: 24px; + margin-right: 24px; + } + + .dp-matrix-row { + grid-template-columns: 1fr; + gap: 12px; + } + + .dp-matrix-when { + flex-direction: column; + gap: 6px; + } + + .dp-matrix-when-label { + width: auto; + } +} diff --git a/src/css/doc-bump.css b/src/css/doc-bump.css index 1854ebe6..e058c43a 100644 --- a/src/css/doc-bump.css +++ b/src/css/doc-bump.css @@ -203,7 +203,7 @@ html[data-theme=dark] { } */ -.aa-DetachedOverlay .doc a[href*="//"]:not([href*="docs.redpanda.com"]):not([href*="netlify.app"]):not(section.feedback-section a):not(.aa-ItemIcon a)::after { +.aa-DetachedOverlay .doc a[href*="//"]:not([href*="docs.redpanda.com"]):not([href*="netlify.app"]):not([href*="localhost"]):not(section.feedback-section a):not(.aa-ItemIcon a)::after { content: url('/_/img/external-link.svg'); position: relative; margin-left: 2px; diff --git a/src/css/doc.css b/src/css/doc.css index b41c97dd..3fddb8f1 100644 --- a/src/css/doc.css +++ b/src/css/doc.css @@ -59,10 +59,397 @@ html { font-weight: var(--heading-font-weight); } +/* Offset anchor links to account for sticky bar (navbar + component indicator) */ +.doc h2[id], +.doc h3[id], +.doc h4[id], +.doc h5[id], +.doc h6[id] { + scroll-margin-top: calc(var(--navbar-height) + 16px); +} + +@media screen and (min-width: 1024px) { + .doc h2[id], + .doc h3[id], + .doc h4[id], + .doc h5[id], + .doc h6[id] { + scroll-margin-top: calc(var(--navbar-height) + 24px); + } +} + .doc h1 { - font-size: calc(36 / var(--rem-base) * 1rem); + font-size: calc(32 / var(--rem-base) * 1rem); margin-bottom: 0; margin-top: 0; + letter-spacing: -0.025em; +} + +/* Component indicator sticky wrapper - contains pill and version selector */ +.component-indicator-sticky { + display: flex; + align-items: center; + gap: 12px; + position: sticky; + top: var(--body-top, 100px); + z-index: 10; + padding: 12px 0; + margin: -12px 0 12px; + background: var(--body-background, #fff); + overflow: visible; +} + +.component-indicator-sticky.is-stuck { + border-bottom: 1px solid var(--grey-200-new, #e5e5e5); + padding-bottom: 11px; + margin-left: -24px; + margin-right: -24px; + padding-left: 24px; + padding-right: 24px; +} + +html[data-theme="dark"] .component-indicator-sticky { + background: var(--body-background); +} + +html[data-theme="dark"] .component-indicator-sticky.is-stuck { + border-bottom-color: rgba(255, 255, 255, 0.1); +} + +/* Inline metadata in sticky bar - compact badges on the right */ +.component-indicator-sticky .metadata-inline { + display: flex; + align-items: center; + gap: 8px; + margin-left: auto; + padding-left: 12px; +} + +/* Compact context switcher in sticky bar */ +.component-indicator-sticky .context-switcher { + position: relative; +} + +.component-indicator-sticky .context-dropdown-toggle { + display: inline-flex; + align-items: center; + gap: 4px; + padding: 4px 8px; + border: 1px solid var(--grey-200-new, #e5e5e5); + background: var(--body-background); + border-radius: 4px; + color: var(--body-font-color); + font-size: 12px; + font-weight: 500; + cursor: pointer; + transition: all 0.15s ease; + white-space: nowrap; +} + +html[data-theme="dark"] .component-indicator-sticky .context-dropdown-toggle { + border-color: rgba(255, 255, 255, 0.1); +} + +.component-indicator-sticky .context-dropdown-toggle:hover { + background: var(--grey-50-new, #f9fafb); + border-color: var(--grey-300-new, #d1d5db); +} + +html[data-theme="dark"] .component-indicator-sticky .context-dropdown-toggle:hover { + background: rgba(255, 255, 255, 0.05); + border-color: rgba(255, 255, 255, 0.15); +} + +/* Add "Type:" label before dropdown */ +.component-indicator-sticky .context-dropdown-toggle::before { + content: 'Type:'; + font-weight: 600; + opacity: 0.7; + margin-right: 4px; +} + +.component-indicator-sticky .context-dropdown-arrow { + width: 12px; + height: 12px; + transition: transform 0.2s ease; +} + +.component-indicator-sticky .context-dropdown-toggle[aria-expanded="true"] .context-dropdown-arrow { + transform: rotate(180deg); +} + +/* Compact inline badges in sticky bar */ +.component-indicator-sticky .byoc-label--inline, +.component-indicator-sticky .cloud-label--inline { + margin: 0; + font-size: 11px; +} + +.component-indicator-sticky .byoc-label--inline > p, +.component-indicator-sticky .cloud-label--inline > p { + padding: 4px 10px; + min-width: auto; + font-size: 11px; + border-radius: 6px; +} + +/* Context dropdown menu in sticky bar */ +.component-indicator-sticky .context-dropdown-menu { + position: absolute; + top: 100%; + right: 0; + left: auto; + min-width: 180px; + background: var(--body-background); + border: 1px solid var(--grey-200-new, #e5e5e5); + border-radius: 6px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + z-index: 1000; + opacity: 0; + visibility: hidden; + transform: translateY(-8px); + transition: all 0.2s ease; + margin-top: 4px; + max-height: 300px; + overflow-y: auto; +} + +html[data-theme="dark"] .component-indicator-sticky .context-dropdown-menu { + border-color: rgba(255, 255, 255, 0.1); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); +} + +.component-indicator-sticky .context-dropdown-menu.show { + opacity: 1; + visibility: visible; + transform: translateY(0); +} + +.component-indicator-sticky .context-dropdown-item { + display: block; + padding: 6px; + text-decoration: none; + font-weight: 500; + font-size: 13px; + border: none; + background: none; + width: 100%; + text-align: left; + color: var(--body-font-color); + transition: background-color 0.15s ease; + border-bottom: 1px solid var(--grey-100-new, #f3f4f6); +} + +html[data-theme="dark"] .component-indicator-sticky .context-dropdown-item { + border-bottom-color: rgba(255, 255, 255, 0.06); +} + +.component-indicator-sticky .context-dropdown-item:last-child { + border-bottom: none; +} + +.component-indicator-sticky .context-dropdown-item:hover, +.component-indicator-sticky .context-dropdown-item:focus { + background: var(--grey-100-new, #f3f4f6); + outline: none; +} + +html[data-theme="dark"] .component-indicator-sticky .context-dropdown-item:hover, +html[data-theme="dark"] .component-indicator-sticky .context-dropdown-item:focus { + background: rgba(255, 255, 255, 0.08); +} + +.component-indicator-sticky .context-dropdown-item.active { + background: var(--component-color, #6366f1); + color: white; + font-weight: 600; +} + +/* Mobile: stack metadata below */ +@media (max-width: 1024px) { + .component-indicator-sticky { + flex-wrap: wrap; + } + + .component-indicator-sticky .metadata-inline { + flex-basis: 100%; + margin-left: 0; + padding-left: 0; + padding-top: 8px; + border-top: 1px solid var(--grey-100-new, #f3f4f6); + justify-content: flex-start; + } + + html[data-theme="dark"] .component-indicator-sticky .metadata-inline { + border-top-color: rgba(255, 255, 255, 0.06); + } +} + +/* Component indicator pill above page title - matches hero chip styling */ +.component-indicator { + margin-bottom: 0; +} + +.component-indicator-sticky .component-indicator { + flex-shrink: 0; +} + +.component-indicator-pill { + display: inline-flex; + align-items: center; + gap: 6px; + font-family: var(--font-mono, ui-monospace, SFMono-Regular, monospace); + font-size: 10.5px; + font-weight: 600; + padding: 4px 10px; + border-radius: 5px; + color: #fff; + letter-spacing: 0.04em; + text-transform: uppercase; + white-space: nowrap; +} + +/* Version selector inline with component indicator - light background context */ +.component-indicator-sticky .sm-ver { + flex-shrink: 0; +} + +.component-indicator-sticky .sm-ver-pill { + padding: 4px 10px; + font-size: 11px; + background: var(--grey-100-new, #f4f4f5); + border-color: var(--grey-200-new, #e5e5e5); +} + +.component-indicator-sticky .sm-ver-pill:hover { + background: var(--grey-200-new, #e5e5e5); + border-color: var(--grey-300-new, #d4d4d4); +} + +.component-indicator-sticky .sm-ver-pill-label { + display: none; +} + +.component-indicator-sticky .sm-ver-pill-num { + color: var(--grey-900-new, #171717); + font-weight: 600; +} + +.component-indicator-sticky .sm-ver-pill-sep { + display: none; +} + +.component-indicator-sticky .sm-ver-pill-status { + font-weight: 600; +} + +.component-indicator-sticky .sm-ver-pill-status[data-status="current"] { + color: #059669; +} + +.component-indicator-sticky .sm-ver-pill-status[data-status="supported"] { + color: #059669; +} + +.component-indicator-sticky .sm-ver-pill-status[data-status="eol"] { + color: #d97706; +} + +.component-indicator-sticky .sm-ver-pill-caret { + color: var(--grey-500-new, #737373); +} + +/* Dark mode overrides */ +html[data-theme="dark"] .component-indicator-sticky .sm-ver-pill { + background: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.12); +} + +html[data-theme="dark"] .component-indicator-sticky .sm-ver-pill:hover { + background: rgba(255, 255, 255, 0.12); + border-color: rgba(255, 255, 255, 0.18); +} + +html[data-theme="dark"] .component-indicator-sticky .sm-ver-pill-num { + color: #fff; +} + +html[data-theme="dark"] .component-indicator-sticky .sm-ver-pill-status[data-status="current"] { + color: #6ee7b7; +} + +html[data-theme="dark"] .component-indicator-sticky .sm-ver-pill-status[data-status="supported"] { + color: #a7f3d0; +} + +html[data-theme="dark"] .component-indicator-sticky .sm-ver-pill-status[data-status="eol"] { + color: #fcd34d; +} + +html[data-theme="dark"] .component-indicator-sticky .sm-ver-pill-caret { + color: rgba(255, 255, 255, 0.65); +} + +/* Version dropdown panel positioning in sticky header - align left with button */ +.component-indicator-sticky .sm-ver-panel { + left: 0; + right: auto; +} + +/* Status badges (Beta, Limited Availability) in sticky header */ +.status-badge { + display: inline-flex; + align-items: center; + gap: 5px; + padding: 4px 10px; + border-radius: 5px; + font-size: 11px; + font-weight: 600; + letter-spacing: 0.02em; + white-space: nowrap; + cursor: default; +} + +.status-badge svg { + flex-shrink: 0; +} + +.status-badge--beta { + background: #fef3c7; + color: #92400e; + border: 1px solid #fcd34d; +} + +.status-badge--la { + background: #ede9fe; + color: #5b21b6; + border: 1px solid #c4b5fd; +} + +html[data-theme="dark"] .status-badge--beta { + background: rgba(251, 191, 36, 0.15); + color: #fcd34d; + border-color: rgba(251, 191, 36, 0.3); +} + +html[data-theme="dark"] .status-badge--la { + background: rgba(139, 92, 246, 0.15); + color: #c4b5fd; + border-color: rgba(139, 92, 246, 0.3); +} + +.status-badge--byoc, +.status-badge--cloud { + background: #e0f2fe; + color: #0369a1; + border: 1px solid #7dd3fc; +} + +html[data-theme="dark"] .status-badge--byoc, +html[data-theme="dark"] .status-badge--cloud { + background: rgba(14, 165, 233, 0.15); + color: #7dd3fc; + border-color: rgba(14, 165, 233, 0.3); } @media screen and (min-width: 600px) { @@ -80,7 +467,7 @@ html { @media screen and (min-width: 769px) { .doc h1 { - font-size: calc(44 / var(--rem-base) * 1rem); + font-size: calc(40 / var(--rem-base) * 1rem); } .admonitionblock .content a { @@ -105,30 +492,32 @@ html { } .doc h2:not(.discrete) { - font-size: calc(32 / var(--rem-base) * 1rem); + font-size: calc(24 / var(--rem-base) * 1rem); margin-left: -1rem; margin-right: -1rem; padding: 0.4rem 1rem 0.1rem; + letter-spacing: -0.015em; } .doc h3:not(.discrete), .aa-PreviewTitle { - font-size: calc(24 / var(--rem-base) * 1rem); + font-size: calc(20 / var(--rem-base) * 1rem); font-weight: var(--alt-heading-font-weight); + letter-spacing: -0.0125em; } .doc h4:not(.discrete) { - font-size: calc(19 / var(--rem-base) * 1rem); + font-size: calc(17 / var(--rem-base) * 1rem); font-weight: var(--alt-heading-font-weight); } .doc h5:not(.discrete) { - font-size: calc(17.5 / var(--rem-base) * 1rem); + font-size: calc(16 / var(--rem-base) * 1rem); font-weight: var(--alt-heading-font-weight); } .doc h6:not(.discrete) { - font-size: calc(16 / var(--rem-base) * 1rem); + font-size: calc(15 / var(--rem-base) * 1rem); font-weight: var(--alt-heading-font-weight); } @@ -210,7 +599,7 @@ html { } */ -.doc a[href*="//"]:not([href*="docs.redpanda.com"]):not([href*="netlify.app"]):not(section.feedback-section a):not(.aa-ItemIcon a)::after { +.doc a[href*="//"]:not([href*="docs.redpanda.com"]):not([href*="netlify.app"]):not([href*="localhost"]):not(section.feedback-section a):not(.aa-ItemIcon a)::after { content: url('/_/img/external-link.svg'); position: relative; margin-left: 2px; @@ -241,6 +630,15 @@ html { padding: 0.125em 0.25em; } +/* Code inside pre blocks should not have inline code styling */ +.doc pre code, +.doc pre > code { + background: transparent; + border: none; + border-radius: 0; + padding: 0; +} + /* Override Prism.js styles */ .doc code .token.operator, .doc code .token.url { @@ -248,11 +646,33 @@ html { } .doc pre { - font-size: calc(17 / var(--rem-base) * 1rem); - line-height: 1.5; + font-size: 13px; + line-height: 1.65; margin: 0; - padding: 1em; - padding-top: 1.5em; + padding: 16px 18px; + padding-top: 40px; /* Extra space for toolbar */ + color: var(--grey-800-new, #1f2937); /* Light mode: dark text */ + overflow-x: auto; +} + +html[data-theme="dark"] .doc pre { + color: #dbe2ee; +} + +/* Code blocks: override Prism defaults */ +.doc .listingblock pre, +.doc .listingblock pre[class*="language-"], +.doc .listingblock pre.highlight { + background: transparent !important; /* Inherit from parent .content */ + color: var(--grey-800-new, #1f2937) !important; /* Dark text in light mode */ + text-shadow: none !important; /* Remove Prism's light text shadow */ +} + +/* Dark mode: light text */ +html[data-theme="dark"] .doc .listingblock pre, +html[data-theme="dark"] .doc .listingblock pre[class*="language-"], +html[data-theme="dark"] .doc .listingblock pre.highlight { + color: #dbe2ee !important; } .doc pre > code, @@ -268,8 +688,18 @@ html { margin: 0; } -.doc .paragraph.lead > p { - font-size: calc(18 / var(--rem-base) * 1rem); +/* Lead/intro paragraph - larger font for opening text + Only applies to the first paragraph in preamble or paragraphs with .lead class. */ +.doc .paragraph.lead > p, +.doc #preamble > .sectionbody > .paragraph:first-child > p { + font-size: 17px; + line-height: 1.55; + color: var(--grey-600-new, #4b5563); +} + +html[data-theme="dark"] .doc .paragraph.lead > p, +html[data-theme="dark"] .doc #preamble > .sectionbody > .paragraph:first-child > p { + color: var(--grey-300-new, #d1d5db); } .doc .right { @@ -476,38 +906,42 @@ html { .admonitionblock { position: relative; margin: 1.4rem 0 0; - box-shadow: var(--admonition-border-box-shadow); - padding: var(--admonition-padding); + display: flex; + gap: 12px; /* Prototype: 12px */ + padding: 14px 16px; /* Prototype: 14px 16px */ + border-radius: 10px; /* Prototype: 10px */ + font-size: 14px; /* Prototype: 14px */ + line-height: 1.55; /* Prototype: 1.55 */ } .admonitionblock.note { - background-color: var(--note-background); - border-left-width: var(--admonition-border-left-width); - border-radius: var(--admonition-border-radius); + background: var(--indigo-50-new, #eef2ff); /* Prototype: indigo-50 */ + border: 1px solid var(--indigo-100-new, #e0e7ff); /* Prototype: indigo-100 */ + color: var(--indigo-900-new, #312e81); /* Prototype: indigo-900 */ } .admonitionblock.warning { - background-color: var(--warning-background); - border-left-width: var(--admonition-border-left-width); - border-radius: var(--admonition-border-radius); + background: #fff7ed; /* Prototype: exact */ + border: 1px solid #fde2b5; /* Prototype: exact */ + color: #7c2d12; /* Prototype: exact */ } .admonitionblock.tip { - background-color: var(--tip-background); - border-left-width: var(--admonition-border-left-width); - border-radius: var(--admonition-border-radius); + background: #f2faf6; /* Prototype: exact */ + border: 1px solid #cce9d9; /* Prototype: exact */ + color: #14532d; /* Prototype: exact */ } .admonitionblock.caution { - background-color: var(--caution-background); - border-left-width: var(--admonition-border-left-width); - border-radius: var(--admonition-border-radius); + background: #fef2f2; /* Red-based caution */ + border: 1px solid #fecaca; /* Red border */ + color: #7f1d1d; /* Dark red text */ } .admonitionblock.important { - background-color: var(--important-background); - border-left-width: var(--admonition-border-left-width); - border-radius: var(--admonition-border-radius); + background: #fdf4ff; /* Purple-based important */ + border: 1px solid #f5d0fe; /* Purple border */ + color: #581c87; /* Dark purple text */ } .admonitionblock td.content > :not(.title):first-child, @@ -531,28 +965,91 @@ html { display: block; width: 100%; word-wrap: anywhere; - margin-top: 8px; - padding-left: 1.8rem; + margin-top: 0; + padding-left: 0; /* No left padding - icon provides gap */ } .admonitionblock .icon { - display: block; + display: flex; + flex-shrink: 0; font-size: calc(18 / var(--rem-base) * 1rem); height: 1.25rem; line-height: 1; font-weight: var(--admonition-label-font-weight); + margin-top: 1px; + margin-bottom: 5px; } .admonitionblock.caution .icon { - color: var(--caution-on-color); + color: #dc2626; /* Red icon for caution */ } .admonitionblock.important .icon { - color: var(--important-on-color); + color: #9333ea; /* Purple icon for important */ } .admonitionblock.note .icon { - color: var(--note-on-color); + color: var(--indigo-600-new, #444ce7); /* Prototype: indigo-600 */ +} + +.admonitionblock.tip .icon { + color: var(--green-600, #059669); /* Prototype: green-600 */ +} + +.admonitionblock.warning .icon { + color: var(--orange-600, #ea580c); /* Prototype: orange-600 */ +} + +/* Dark mode admonition styles */ +html[data-theme="dark"] .admonitionblock.note { + background: rgba(99, 102, 241, 0.15); /* Indigo tint for dark */ + border-color: rgba(99, 102, 241, 0.3); + color: #c7d2fe; /* Light indigo text */ +} + +html[data-theme="dark"] .admonitionblock.tip { + background: rgba(16, 185, 129, 0.15); /* Green tint for dark */ + border-color: rgba(16, 185, 129, 0.3); + color: #a7f3d0; /* Light green text */ +} + +html[data-theme="dark"] .admonitionblock.warning { + background: rgba(251, 146, 60, 0.15); /* Orange tint for dark */ + border-color: rgba(251, 146, 60, 0.3); + color: #fed7aa; /* Light orange text */ +} + +html[data-theme="dark"] .admonitionblock.caution { + background: rgba(248, 113, 113, 0.15); /* Red tint for dark */ + border-color: rgba(248, 113, 113, 0.3); + color: #fecaca; /* Light red text */ +} + +html[data-theme="dark"] .admonitionblock.important { + background: rgba(192, 132, 252, 0.15); /* Purple tint for dark */ + border-color: rgba(192, 132, 252, 0.3); + color: #e9d5ff; /* Light purple text */ +} + +/* Dark mode admonition icon colors - brighter for visibility */ +html[data-theme="dark"] .admonitionblock.note .icon { + color: #818cf8; /* Brighter indigo for dark mode */ +} + +html[data-theme="dark"] .admonitionblock.tip .icon { + color: #34d399; /* Brighter green for dark mode */ +} + +html[data-theme="dark"] .admonitionblock.warning .icon { + color: #fb923c; /* Brighter orange for dark mode */ +} + +html[data-theme="dark"] .admonitionblock.caution .icon { + color: #f87171; /* Brighter red for dark mode */ +} + +html[data-theme="dark"] .admonitionblock.important .icon { + color: #c084fc; /* Brighter purple for dark mode */ } .icon-note::before { @@ -620,12 +1117,40 @@ table code { word-wrap: unset; } +/* When listingblock has a title, wrap with border and radius */ +.listingblock:has(.title) { + border: 1px solid var(--grey-200-new, #e5e7eb); + border-radius: 10px; + overflow: hidden; +} + +html[data-theme="dark"] .listingblock:has(.title) { + border-color: #1c2638; +} + +/* Remove border from .content when title exists (parent has it) */ +.doc .listingblock:has(.title) > .content { + border: none !important; + border-radius: 0 !important; +} + .listingblock .title { - margin-top: 0.5rem; - font-style: italic; - background: var(--code-background); - padding: 5px; - border-bottom: 1px solid #e0e0e0; + display: flex; + align-items: center; + gap: 10px; + margin: 0; + padding: 8px 14px; + background: var(--grey-50-new, #f9fafb); + border-bottom: 1px solid var(--grey-200-new, #e5e7eb); + font-size: 12px; + font-style: normal; + color: var(--grey-600-new, #4b5563); +} + +html[data-theme="dark"] .listingblock .title { + background: #0f1727; + border-bottom-color: #1c2638; + color: #8098b3; } .doc .imageblock, @@ -688,7 +1213,8 @@ table code { background: var(--abstract-background); border-left: 5px solid var(--abstract-border-color); color: var(--abstract-font-color); - font-size: calc(18 / var(--rem-base) * 1rem); + font-size: calc(17 / var(--rem-base) * 1rem); + line-height: 1.55; padding: 0.75em 1em; } @@ -848,6 +1374,7 @@ table code { .admonitionblock .title { font-weight: bold; + margin-top: 10px; } .doc summary .title { @@ -873,7 +1400,7 @@ table code { /* immediate sibling of an element with the class title, where this title class element is a direct child of a td element with the class content */ .admonitionblock td.content > .title + * { - margin-top: 20px; + margin-top: 10px; } .doc .tableblock caption { @@ -986,6 +1513,47 @@ details[open] > summary { margin-top: 0; } +/* Availability block - shows platform support (Cloud, BYOC, etc.) */ +.doc .sidebarblock.availability-block, +.doc .availability-block { + background: var(--availability-block-background, var(--note-background)); + border-left: 4px solid var(--availability-block-border, var(--note-border-color)); + border-radius: 0; + padding: 0.5rem 1rem; + margin-bottom: 1.5rem; + font-size: 0.9em; +} + +.doc .sidebarblock.availability-block > .content, +.doc .availability-block { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.doc .sidebarblock.availability-block > .content > p, +.doc .availability-block > p { + margin: 0; +} + +.doc .availability-block .availability-info { + display: inline-flex; + align-items: center; + margin-left: 0.5rem; + cursor: help; + color: var(--availability-block-border, var(--note-border-color)); + vertical-align: middle; +} + +.doc .availability-block .availability-info:hover, +.doc .availability-block .availability-info:focus { + color: var(--link-font-color); +} + +.doc .availability-block .availability-info svg { + display: block; +} + /* NEEDS REVIEW prevent pre in table from causing article to exceed bounds */ .doc .tableblock pre, .doc .listingblock.wrap pre { @@ -995,7 +1563,7 @@ details[open] > summary { .doc pre.highlight code, .doc .listingblock pre:not(.highlight), .doc .literalblock pre { - background: var(--code-background); + background: transparent; /* Inherit from dark parent container */ display: block; overflow-x: auto; font-weight: 300; @@ -1384,7 +1952,8 @@ img.dark-mode-filter, cursor: pointer; } -code[class*=language-], +/* Only apply background to standalone code elements, not code inside pre */ +code[class*=language-]:not(pre code), pre[class*=language-] { color: var(--code-font-color) !important; font-size: calc(17 / var(--rem-base) * 1rem) !important; @@ -1394,6 +1963,11 @@ pre[class*=language-] { font-weight: lighter !important; } +/* Code inside pre should have transparent background */ +pre code[class*=language-] { + background: transparent !important; +} + pre.code-first-child { padding-bottom: 0 !important; } @@ -1434,24 +2008,41 @@ html[data-theme=dark] code[class*=language-] .token.function { color: #d7aefb; } +/* Code blocks: Light mode has light background with border */ .doc .listingblock > .content { position: relative; + background: var(--grey-50-new, #f9fafb); + border-radius: 10px; + overflow: hidden; + border: 1px solid var(--grey-200-new, #e5e7eb); +} + +/* Dark mode: dark background */ +html[data-theme="dark"] .doc .listingblock > .content { + background: #0f1727; + border-color: #1c2638; } .doc .source-toolbox { display: flex; + align-items: center; + gap: 10px; visibility: hidden; position: absolute; - top: 0.25rem; - right: 0.5rem; - color: var(--pre-annotation-font-color); + top: 8px; + right: 14px; + color: var(--grey-500-new, #6b7280); /* Light mode */ font-family: var(--body-font-family); - font-size: calc(15 / var(--rem-base) * 1rem); + font-size: 11px; line-height: 1.5; white-space: nowrap; z-index: 1; } +html[data-theme="dark"] .doc .source-toolbox { + color: #a8b2c7; +} + .doc .listingblock:hover .source-toolbox { visibility: visible; } @@ -1462,14 +2053,20 @@ html[data-theme=dark] code[class*=language-] .token.function { } .doc .source-toolbox .source-lang { + font-family: var(--body-font-family-mono, monospace); + font-size: 11px; + color: var(--grey-500-new, #6b7280); /* Light mode */ + letter-spacing: 0.02em; text-transform: uppercase; - letter-spacing: 0.075em; +} + +html[data-theme="dark"] .doc .source-toolbox .source-lang { + color: #a8b2c7; } .doc .source-toolbox > :not(:last-child)::after { - content: "|"; - letter-spacing: 0; - padding: 0 1ch; + content: ""; + display: none; } .doc .source-toolbox .run-button { @@ -1489,17 +2086,33 @@ html[data-theme=dark] code[class*=language-] .token.function { .doc .source-toolbox .copy-button { display: inline-flex; align-items: center; - background: none; - border: none; - color: inherit; + gap: 5px; + background: transparent; + border: 1px solid var(--grey-300-new, #d1d5db); /* Light mode border */ + color: var(--grey-600-new, #4b5563); /* Light mode text */ outline: none; - padding: 0; - font-size: inherit; + padding: 4px 8px; + font-size: 11px; + font-family: var(--body-font-family); line-height: inherit; cursor: pointer; - position: relative; - transform: translateZ(0); - backface-visibility: hidden; + border-radius: 5px; + transition: background 0.12s, color 0.12s; +} + +.doc .source-toolbox .copy-button:hover { + background: var(--grey-100-new, #f3f4f6); /* Light mode hover */ + color: var(--grey-900-new, #111827); +} + +html[data-theme="dark"] .doc .source-toolbox .copy-button { + border-color: rgba(255, 255, 255, 0.08); + color: #a8b2c7; +} + +html[data-theme="dark"] .doc .source-toolbox .copy-button:hover { + background: rgba(255, 255, 255, 0.04); + color: #fff; } .doc .source-toolbox .copy-icon { @@ -1765,3 +2378,304 @@ html[data-theme=dark] code[class*=language-] .token.function { text-align: right; width: 1.5em; } + +/* ============================================================================= + CARD GRID — For landing pages using AsciiDoc roles + Usage: [.card-grid] wrapping [.card] sections + ============================================================================= */ + +.doc .card-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 20px; + margin: 2rem 0; +} + +.doc .card-grid .card { + background: var(--grey-50-new, #f9fafb); + border: 1px solid var(--grey-200-new, #e5e7eb); + border-radius: 12px; + padding: 24px; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.doc .card-grid .card:hover { + border-color: var(--component-600, var(--indigo-600-new, #4f46e5)); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); +} + +.doc .card-grid .card h3, +.doc .card-grid .card .title { + font-size: 18px; + font-weight: 600; + color: var(--heading-font-color); + margin: 0 0 12px; + letter-spacing: -0.01em; +} + +.doc .card-grid .card p { + font-size: 14px; + color: var(--grey-600-new, #4b5563); + line-height: 1.5; + margin: 0 0 16px; +} + +.doc .card-grid .card ul { + font-size: 14px; + color: var(--grey-600-new, #4b5563); + margin: 0 0 16px; + padding-left: 1.25rem; +} + +.doc .card-grid .card li { + margin-bottom: 6px; +} + +.doc .card-grid .card a.button, +.doc .card-grid .card a[role="button"] { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 10px 16px; + background: var(--component-600, var(--indigo-600-new, #4f46e5)); + color: #fff; + border-radius: 8px; + font-size: 13px; + font-weight: 500; + text-decoration: none; + transition: opacity 0.15s; +} + +.doc .card-grid .card a.button:hover, +.doc .card-grid .card a[role="button"]:hover { + opacity: 0.9; + text-decoration: none; +} + +/* Dark mode card grid */ +html[data-theme="dark"] .doc .card-grid .card { + background: rgba(255, 255, 255, 0.03); + border-color: rgba(255, 255, 255, 0.1); +} + +html[data-theme="dark"] .doc .card-grid .card:hover { + border-color: var(--component-500, var(--indigo-500-new, #6172f3)); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.24); +} + +html[data-theme="dark"] .doc .card-grid .card h3, +html[data-theme="dark"] .doc .card-grid .card .title { + color: #fff; +} + +html[data-theme="dark"] .doc .card-grid .card p, +html[data-theme="dark"] .doc .card-grid .card ul { + color: var(--grey-400-new, #9ca3af); +} + +/* ============================================================================= + LINK CARDS — Simpler card style for navigation links + Usage: [.link-cards] wrapping [.link-card] sections + ============================================================================= */ + +.doc .link-cards { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + gap: 12px; + margin: 1.5rem 0; +} + +.doc .link-cards .link-card { + display: flex; + align-items: center; + gap: 12px; + background: var(--grey-50-new, #f9fafb); + border: 1px solid var(--grey-200-new, #e5e7eb); + border-radius: 10px; + padding: 16px; + transition: border-color 0.12s, background 0.12s; +} + +.doc .link-cards .link-card:hover { + border-color: var(--grey-300-new, #d1d5db); + background: #fff; +} + +.doc .link-cards .link-card h4, +.doc .link-cards .link-card .title { + font-size: 15px; + font-weight: 600; + color: var(--heading-font-color); + margin: 0 0 4px; +} + +.doc .link-cards .link-card p { + font-size: 13px; + color: var(--grey-600-new, #4b5563); + line-height: 1.4; + margin: 0; +} + +/* Dark mode link cards */ +html[data-theme="dark"] .doc .link-cards .link-card { + background: rgba(255, 255, 255, 0.02); + border-color: rgba(255, 255, 255, 0.08); +} + +html[data-theme="dark"] .doc .link-cards .link-card:hover { + background: rgba(255, 255, 255, 0.04); + border-color: rgba(255, 255, 255, 0.15); +} + +html[data-theme="dark"] .doc .link-cards .link-card h4, +html[data-theme="dark"] .doc .link-cards .link-card .title { + color: #fff; +} + +html[data-theme="dark"] .doc .link-cards .link-card p { + color: var(--grey-400-new, #9ca3af); +} + +/* Availability Selector Dropdown - matches version selector style */ +.availability-selector { + position: relative; + display: inline-flex; + align-items: center; +} + +.availability-selector-toggle { + display: inline-flex; + align-items: center; + gap: 4px; + padding: 4px 8px; + background: var(--body-background); + border: 1px solid var(--grey-300-new, #d1d5db); + border-radius: 4px; + font-size: 12px; + font-weight: 500; + color: var(--body-font-color); + cursor: pointer; + transition: all 0.15s ease; + white-space: nowrap; +} + +.availability-selector-toggle:hover { + background: var(--grey-50-new, #f9fafb); + border-color: var(--grey-400-new, #9ca3af); +} + +.availability-selector-toggle[aria-expanded="true"] { + background: var(--grey-100-new, #f3f4f6); + border-color: var(--grey-400-new, #9ca3af); +} + +.availability-selector-toggle--disabled { + cursor: default; + opacity: 0.6; +} + +.availability-selector-toggle--disabled:hover { + background: var(--body-background); + border-color: var(--grey-300-new, #d1d5db); +} + +.availability-label { + color: var(--grey-600-new, #4b5563); + font-weight: 500; +} + +.availability-value { + color: var(--body-font-color); + font-weight: 600; +} + +.availability-arrow { + flex-shrink: 0; + transition: transform 0.2s ease; + color: var(--grey-500-new, #6b7280); +} + +.availability-selector-toggle[aria-expanded="true"] .availability-arrow { + transform: rotate(180deg); +} + +.availability-selector-menu { + position: absolute; + top: calc(100% + 4px); + left: 0; + min-width: 240px; + background: var(--body-background); + border: 1px solid var(--grey-200-new, #e5e7eb); + border-radius: 8px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + padding: 6px; + display: none; + z-index: 100; +} + +.availability-selector-menu.show { + display: block; +} + +.availability-selector-item { + display: flex; + align-items: center; + gap: 10px; + border-radius: 6px; + font-size: 13px; + font-weight: 500; + color: var(--body-font-color); + text-decoration: none; + transition: all 0.12s ease; + cursor: pointer; +} + +.availability-selector-item:hover { + background: var(--grey-100-new, #f3f4f6); +} + +.availability-selector-item svg:first-child { + flex-shrink: 0; + color: var(--grey-500-new, #6b7280); +} + +.availability-selector-item span { + flex: 1; +} + +.availability-selector-item--disabled { + cursor: default; + opacity: 0.6; +} + +.availability-selector-item--disabled:hover { + background: transparent; +} + +/* Dark mode */ +html[data-theme="dark"] .availability-selector-toggle { + border-color: rgba(255, 255, 255, 0.12); +} + +html[data-theme="dark"] .availability-selector-toggle:hover { + background: rgba(255, 255, 255, 0.04); + border-color: rgba(255, 255, 255, 0.2); +} + +html[data-theme="dark"] .availability-selector-toggle[aria-expanded="true"] { + background: rgba(255, 255, 255, 0.06); + border-color: rgba(255, 255, 255, 0.2); +} + +html[data-theme="dark"] .availability-label { + color: var(--grey-400-new, #9ca3af); +} + +html[data-theme="dark"] .availability-selector-menu { + border-color: rgba(255, 255, 255, 0.12); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); +} + +html[data-theme="dark"] .availability-selector-item:hover { + background: rgba(255, 255, 255, 0.06); +} diff --git a/src/css/footer.css b/src/css/footer.css index efb564b5..3d0b686c 100644 --- a/src/css/footer.css +++ b/src/css/footer.css @@ -153,7 +153,7 @@ footer.footer { } /* Remove external link icon from footer links */ -.doc .footer a[href*="//"]:not([href*="docs.redpanda.com"]):not([href*="netlify.app"]):not(section.feedback-section a):not(.aa-ItemIcon a)::after { +.doc .footer a[href*="//"]:not([href*="docs.redpanda.com"]):not([href*="netlify.app"]):not([href*="localhost"]):not(section.feedback-section a):not(.aa-ItemIcon a)::after { content: ''; } @@ -220,3 +220,139 @@ footer.footer { max-width: 400px; } } + +/* ============================================================================= + DOCS FOOTER — Simplified stacked footer for docs pages + Always uses dark background regardless of theme + ============================================================================= */ +.docs-footer { + background: #0b1430; + color: rgba(255, 255, 255, 0.6); + padding: 56px 48px 40px; + margin-top: 64px; + position: relative; +} + +.docs-footer::before { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 1px; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.08), transparent); +} + +.docs-footer-inner { + max-width: 1240px; + margin: 0 auto; + display: flex; + flex-direction: column; + align-items: center; + gap: 28px; + text-align: center; +} + +.docs-footer-brand { + display: inline-flex; + align-items: center; + opacity: 0.85; + transition: opacity 0.14s; +} + +.docs-footer-brand:hover { + opacity: 1; +} + +.docs-footer-brand img { + height: 22px; + width: auto; + filter: brightness(0) invert(1); +} + +.docs-footer-social { + display: flex; + align-items: center; + gap: 28px; +} + +.docs-footer .docs-footer-social-link { + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + color: rgba(255, 255, 255, 0.45); + transition: color 0.14s, transform 0.14s; +} + +.docs-footer .docs-footer-social-link:hover { + color: #fff; + transform: translateY(-1px); +} + +.docs-footer-social-link svg { + display: block; +} + +.docs-footer-meta { + display: flex; + align-items: center; + gap: 20px 28px; + flex-wrap: wrap; + justify-content: center; + padding-top: 24px; + border-top: 1px solid rgba(255, 255, 255, 0.06); + width: 100%; + max-width: 720px; +} + +.docs-footer-copy { + font-size: 12.5px; + color: rgba(255, 255, 255, 0.45); + letter-spacing: 0; +} + +.docs-footer-links { + display: flex; + align-items: center; + gap: 24px; + flex-wrap: wrap; + justify-content: center; +} + +.docs-footer .docs-footer-link { + font-size: 12.5px; + color: rgba(255, 255, 255, 0.55); + text-decoration: none; + transition: color 0.14s; +} + +/* Remove external link icons from docs-footer links */ +.docs-footer a::after, +.docs-footer-brand::after, +.docs-footer-social-link::after, +.docs-footer-link::after { + content: none !important; + display: none !important; +} + +.docs-footer .docs-footer-link:hover { + color: #fff; + text-decoration: none; +} + +@media screen and (max-width: 720px) { + .docs-footer { + padding: 44px 24px 32px; + } + + .docs-footer-social { + gap: 18px; + } + + .docs-footer-meta { + flex-direction: column; + gap: 14px; + } +} diff --git a/src/css/header.css b/src/css/header.css index f84c374a..bcc179d6 100644 --- a/src/css/header.css +++ b/src/css/header.css @@ -19,9 +19,335 @@ html.is-clipped--navbar { cursor: pointer; } -.navbar { +/* ============================================================================= + TOPBAR — Sticky header with breadcrumbs and actions + ============================================================================= */ + +.navbar.topbar { + position: fixed; + top: var(--announcement-bar-height); + left: 0; + right: 0; + z-index: var(--z-index-navbar); + height: var(--navbar-height); + display: flex; + align-items: center; + gap: 16px; + padding: 0 16px; + background: var(--topbar-bg, #fff); + border-bottom: 1px solid var(--topbar-border, var(--grey-100-new, #e5e6e8)); + font-size: var(--secondary-font-size); +} + +/* On desktop, topbar starts after sidebar */ +@media screen and (min-width: 1024px) { + .navbar.topbar { + left: var(--sidebar-width, 260px); + padding: 0 32px; /* Prototype: 12px 32px, but height is controlled by --navbar-height */ + top: var(--announcement-bar-height--desktop); + } + + /* Home page: hide breadcrumbs (landing page doesn't need them) */ + body.home .topbar-crumbs { + display: none; + } + + /* Hide mobile brand section on desktop */ + .navbar.topbar .navbar-brand { + display: none; + } +} + +/* Mobile: show brand with logo */ +@media screen and (max-width: 1023px) { + .topbar-crumbs { + display: none; + } +} + +/* Breadcrumbs container in topbar */ +.topbar-crumbs { + flex: 1; + min-width: 0; + /* overflow visible to allow dropdown to appear */ + overflow: visible; + position: relative; + z-index: 1; /* Lower z-index than navbar-end */ +} + +.topbar-crumbs .breadcrumbs { + margin: 0; + padding: 0; + width: 100%; +} + +.topbar-crumbs .breadcrumbs ul { + display: flex; + align-items: center; + flex-wrap: nowrap; + gap: 0; + margin: 0; + padding: 0; + list-style: none; + font-size: 13px; + color: var(--grey-600-new, #606164); + letter-spacing: -0.0125em; + width: 100%; + /* Overflow visible to allow dropdown to appear */ + overflow: visible; +} + +.topbar-crumbs .breadcrumbs li { + display: flex; + align-items: center; + white-space: nowrap; + flex-shrink: 0; +} + +/* Middle items can shrink and show ellipsis (but not the ellipsis li itself) */ +.topbar-crumbs .breadcrumbs li:not(:first-child):not(:last-child):not(.bc-ellipsis-li) { + flex-shrink: 1; + min-width: 0; + overflow: hidden; +} + +.topbar-crumbs .breadcrumbs li:not(:first-child):not(:last-child):not(.bc-ellipsis-li) a, +.topbar-crumbs .breadcrumbs li:not(:first-child):not(:last-child):not(.bc-ellipsis-li) span { + overflow: hidden; + text-overflow: ellipsis; +} + +/* Collapsed state - hide middle items */ +.topbar-crumbs.is-collapsed .breadcrumbs li.bc-hidden { + display: none; +} + +/* In collapsed state, ensure visible items don't truncate */ +.topbar-crumbs.is-collapsed .breadcrumbs li:not(.bc-hidden):not(.bc-ellipsis-li) { + flex-shrink: 0; + min-width: auto; + overflow: visible; +} + +.topbar-crumbs.is-collapsed .breadcrumbs li:not(.bc-hidden):not(.bc-ellipsis-li) a, +.topbar-crumbs.is-collapsed .breadcrumbs li:not(.bc-hidden):not(.bc-ellipsis-li) span { + overflow: visible; + text-overflow: unset; +} + +/* Ellipsis list item container - positioned relative for dropdown */ +.topbar-crumbs .breadcrumbs li.bc-ellipsis-li { + display: none; + position: relative; +} + +.topbar-crumbs.is-collapsed .breadcrumbs li.bc-ellipsis-li { + display: flex; + align-items: center; +} + +/* Remove chevron before ellipsis */ +.topbar-crumbs .breadcrumbs li.bc-ellipsis-li::before { + content: none !important; + display: none !important; +} + +/* Ellipsis button for collapsed breadcrumbs */ +.topbar-crumbs .bc-ellipsis { + display: flex; + align-items: center; + padding: 2px 8px; + margin: 0 4px; + background: var(--grey-100-new, #e5e6e8); + border: none; + border-radius: 4px; + font-size: 13px; + font-weight: 500; + color: var(--grey-600-new, #606164); + cursor: pointer; + transition: background 0.12s, color 0.12s; + line-height: 1; +} + +.topbar-crumbs .bc-ellipsis:hover { + background: var(--grey-200-new, #c3c4c6); + color: var(--grey-900-new, #181818); +} + +.topbar-crumbs .bc-ellipsis.is-open { + background: var(--grey-200-new, #c3c4c6); + color: var(--grey-900-new, #181818); +} + +html[data-theme="dark"] .topbar-crumbs .bc-ellipsis { + background: rgba(255, 255, 255, 0.1); + color: var(--grey-400-new, #919295); +} + +html[data-theme="dark"] .topbar-crumbs .bc-ellipsis:hover, +html[data-theme="dark"] .topbar-crumbs .bc-ellipsis.is-open { + background: rgba(255, 255, 255, 0.15); + color: var(--grey-100-new, #dcdcde); +} + +/* Breadcrumb dropdown for hidden items */ +.bc-dropdown { + position: absolute; + top: calc(100% + 8px); + left: 50%; + transform: translateX(-50%); + min-width: 200px; + max-width: 320px; + background: #fff; + border: 1px solid var(--grey-200-new, #c3c4c6); + border-radius: 8px; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12); + padding: 6px; + z-index: 100; + animation: bcDropdownIn 0.15s ease-out; +} + +@keyframes bcDropdownIn { + from { + opacity: 0; + transform: translateX(-50%) translateY(-4px); + } + + to { + opacity: 1; + transform: translateX(-50%) translateY(0); + } +} + +html[data-theme="dark"] .bc-dropdown { + background: #1a2332; + border-color: rgba(255, 255, 255, 0.1); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.32); +} + +.bc-dropdown a { + display: flex; + align-items: center; + padding: 8px 12px; + border-radius: 6px; + color: var(--grey-700-new, #3f3f46); + text-decoration: none; + font-size: 13px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + transition: background 0.12s; +} + +.bc-dropdown a:hover { + background: var(--grey-50-new, #f5f5f5); + color: var(--grey-900-new, #181818); +} + +html[data-theme="dark"] .bc-dropdown a { + color: var(--grey-300-new, #a4a4a8); +} + +html[data-theme="dark"] .bc-dropdown a:hover { + background: rgba(255, 255, 255, 0.08); + color: #fff; +} + +/* Chevron icon before dropdown items */ +.bc-dropdown a::before { + content: ""; + display: inline-block; + width: 14px; + height: 14px; + margin-right: 8px; + flex-shrink: 0; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23aaabae'%3E%3Cpath d='M6.22 4.22a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06L8.94 8 6.22 5.28a.75.75 0 0 1 0-1.06Z'/%3E%3C/svg%3E"); + background-size: contain; + background-repeat: no-repeat; +} + +.topbar-crumbs .breadcrumbs li::before { + content: none; +} + +.topbar-crumbs .breadcrumbs li + li::before { + content: ""; + display: inline-block; + width: 16px; + height: 16px; + margin: 0 4px; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23aaabae'%3E%3Cpath d='M6.22 4.22a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06L8.94 8 6.22 5.28a.75.75 0 0 1 0-1.06Z'/%3E%3C/svg%3E"); + background-size: contain; + background-repeat: no-repeat; + flex-shrink: 0; +} + +.topbar-crumbs .breadcrumbs a { + color: var(--grey-600-new, #606164); + text-decoration: none; + transition: color 0.12s; +} + +.topbar-crumbs .breadcrumbs a:hover { + color: var(--grey-900-new, #181818); +} + +.topbar-crumbs .breadcrumbs li:last-child { + color: var(--grey-900-new, #181818); + font-weight: 500; +} + +.topbar-crumbs .breadcrumbs li:last-child a { + color: var(--grey-900-new, #181818); + font-weight: 500; +} + +/* Hide the ::after chevrons from breadcrumbs.css - we use ::before instead */ +.topbar-crumbs .breadcrumbs li::after { + content: none; + display: none; +} + +/* ============================================================================= + TOPBAR DARK MODE + ============================================================================= */ + +html[data-theme="dark"] .navbar.topbar { + /* Use dynamic component color from component-metadata, falls back to neutral dark */ + background: var(--topbar-bg, #101828); + border-bottom-color: var(--topbar-border, rgba(255, 255, 255, 0.1)); +} + +html[data-theme="dark"] .topbar-crumbs .breadcrumbs a { + color: var(--grey-400-new, #919295); +} + +html[data-theme="dark"] .topbar-crumbs .breadcrumbs a:hover { + color: var(--grey-100-new, #dcdcde); +} + +html[data-theme="dark"] .topbar-crumbs .breadcrumbs li:last-child, +html[data-theme="dark"] .topbar-crumbs .breadcrumbs li:last-child a { + color: var(--grey-100-new, #dcdcde); +} + +html[data-theme="dark"] .topbar-crumbs .breadcrumbs li + li::before { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23666'%3E%3Cpath d='M6.22 4.22a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06L8.94 8 6.22 5.28a.75.75 0 0 1 0-1.06Z'/%3E%3C/svg%3E"); +} + +/* Theme toggle icon - better visibility in topbar */ +.navbar.topbar .theme-image { + filter: brightness(0) saturate(100%) invert(40%) sepia(10%) saturate(500%) hue-rotate(180deg); +} + +html[data-theme="dark"] .navbar.topbar .theme-image { + filter: brightness(0) saturate(100%) invert(80%) sepia(10%) saturate(200%) hue-rotate(180deg); +} + +/* Legacy navbar styles kept for compatibility */ +.navbar:not(.topbar) { background: var(--navbar-background); - color: var(--navbar-font-color); + color: var(--nav-text-color, var(--navbar-font-color)); font-size: var(--secondary-font-size); height: var(--navbar-height); align-content: center; @@ -39,8 +365,9 @@ html.is-clipped--navbar { } .navbar-menu { - color: #a8b2c7; + color: var(--nav-text-color, #a8b2c7); justify-content: flex-start; + flex-shrink: 0; /* Never squeeze the right nav items */ } .navbar-brand { @@ -52,7 +379,7 @@ html.is-clipped--navbar { } .navbar-brand .navbar-item { - color: var(--navbar-font-color); + color: var(--nav-text-color, var(--navbar-font-color)); margin-left: 8px; } @@ -104,55 +431,11 @@ html.is-clipped--navbar { outline: none; } -.navbar-burger { - background: none; - border: none; - outline: none; - line-height: 1; - position: relative; - width: 3rem; - padding: 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - margin-left: auto; - min-width: 0; -} - -.navbar-burger span { - background-color: var(--navbar-font-color); - height: 1.5px; - width: 1rem; -} - -.navbar-burger:not(.is-active) span { - transition: transform ease-out 0.25s, opacity 0s 0.25s, margin-top ease-out 0.25s 0.25s; -} - -.navbar-burger span + span { - margin-top: 0.25rem; -} - -.navbar-burger.is-active span + span { - margin-top: -1.5px; -} - -.navbar-burger.is-active span:nth-child(1) { - transform: rotate(45deg); -} - -.navbar-burger.is-active span:nth-child(2) { - opacity: 0; -} - -.navbar-burger.is-active span:nth-child(3) { - transform: rotate(-45deg); -} +/* Burger menu removed - topnav items displayed inline */ .navbar-item, .navbar-link { - color: var(--navbar-menu-font-color); + color: var(--nav-text-color, var(--navbar-menu-font-color)); display: block; line-height: var(--doc-line-height); padding: 6px 8px; @@ -233,11 +516,15 @@ html.is-clipped--navbar { .navbar-end { display: flex; - flex: auto; - gap: 10px; + gap: 12px; align-items: center; - flex-wrap: wrap; + flex-shrink: 0; /* Prevent right side items from being squeezed */ justify-content: flex-end; + position: relative; + z-index: 10; /* Ensure navbar-end items are above breadcrumb elements */ + margin-left: auto; /* Push to right edge */ + padding-left: 24px; /* Min space from breadcrumbs */ + height: 100%; } @media screen and (max-width: 768.5px) { @@ -247,6 +534,124 @@ html.is-clipped--navbar { } } +/* ============================================================================= + MOBILE OVERFLOW MENU + On narrow screens, secondary items go into a "..." overflow dropdown + ============================================================================= */ + +/* Desktop: show individual items, hide overflow menu */ +.tb-desktop-items { + display: flex; + align-items: center; + gap: 4px; +} + +.tb-dropdown.tb-overflow-menu { + display: none; +} + +/* Mobile: hide individual items, show overflow menu */ +@media screen and (max-width: 480px) { + .tb-desktop-items { + display: none; + } + + .tb-overflow-menu { + display: block !important; + } + + /* Reduce gap in navbar-end for more space */ + .navbar-end { + gap: 4px; + } + + /* Compact AI button - icon only */ + .tb-ai-btn { + padding: 5px 8px; + } + + .tb-ai-btn span { + display: none; + } + + /* Ensure theme toggle stays visible */ + .theme-switcher { + flex-shrink: 0; + } + + #switch-theme { + width: 28px; + height: 28px; + } + + /* Truncate long platform names on narrow screens */ + .platform-indicator-mobile { + max-width: 100px; + } +} + +/* Overflow trigger button styling */ +.tb-overflow-trigger { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + padding: 0; + border: none; + background: transparent; + border-radius: 6px; + color: var(--grey-600, #475467); + cursor: pointer; + transition: background 0.15s, color 0.15s; +} + +.tb-overflow-trigger:hover { + background: var(--grey-50, rgba(0, 0, 0, 0.04)); + color: var(--grey-900, #101828); +} + +html[data-theme="dark"] .tb-overflow-trigger { + color: var(--grey-400, #98a2b3); +} + +html[data-theme="dark"] .tb-overflow-trigger:hover { + background: rgba(255, 255, 255, 0.06); + color: #fff; +} + +/* Overflow dropdown styling */ +.tb-overflow-dropdown { + min-width: 180px; +} + +.tb-overflow-section { + padding: 4px 0; +} + +.tb-overflow-label { + padding: 6px 12px 4px; + font-size: 11px; + font-weight: 600; + color: var(--grey-500, #667085); + text-transform: uppercase; + letter-spacing: 0.03em; +} + +html[data-theme="dark"] .tb-overflow-label { + color: var(--grey-400, #98a2b3); +} + +.tb-overflow-divider { + height: 1px; + margin: 4px 0; + background: var(--grey-100, #f2f4f7); +} + +html[data-theme="dark"] .tb-overflow-divider { + background: rgba(255, 255, 255, 0.08); +} + @media screen and (min-width: 769px) { #search-input { width: 200px; @@ -266,11 +671,12 @@ html.is-clipped--navbar { } .platform-indicator-mobile { - display: inline-block; - margin-left: 12px; - margin-right: 16px; - color: #fff; - vertical-align: middle; + display: inline-flex; + align-items: center; + margin-left: 8px; + color: var(--grey-600-new, #52525b); + font-size: 13px; + font-weight: 500; order: 1; flex: 1 1 auto; min-width: 0; @@ -280,8 +686,13 @@ html.is-clipped--navbar { text-overflow: ellipsis; } + html[data-theme="dark"] .platform-indicator-mobile { + color: var(--grey-300-new, #d4d4d8); + } + .theme-switcher { - margin-right: 16px; + display: flex; + align-items: center; } .header { @@ -293,22 +704,31 @@ html.is-clipped--navbar { display: flex; } + /* No burger menu - always show navbar-menu inline */ .navbar-menu { - background: var(--navbar-menu-background); - box-shadow: 0 8px 16px rgba(10, 10, 10, 0.1); - max-height: var(--body-min-height); - overflow-y: auto; - overscroll-behavior: none; - padding: 0.5rem 0; + display: flex; + align-items: center; + height: 100%; } - .navbar-menu:not(.is-active) { - display: none; + .navbar-end { + display: flex; + align-items: center; + gap: 4px; + height: 100%; + } + + /* Ensure all items align properly */ + .navbar-end > * { + display: flex; + align-items: center; } - .navbar-burger { - order: 2; - margin-left: 4px; + /* Mobile overflow menu - hide desktop items on narrow screens */ + @media screen and (max-width: 480px) { + .tb-desktop-items { + display: none; + } } } @@ -317,10 +737,6 @@ html.is-clipped--navbar { padding-top: var(--body-top--desktop); } - .navbar-burger { - display: none; - } - .navbar, .navbar-menu { display: flex; @@ -374,7 +790,7 @@ html.is-clipped--navbar { .navbar-end > .navbar-item, .navbar-end .navbar-link { - color: var(--navbar-font-color); + color: var(--nav-text-color, var(--navbar-menu-font-color)); } .navbar-end > a.navbar-item:hover, @@ -470,8 +886,24 @@ html.is-clipped--navbar { } #switch-theme { + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; border: none; - background: none; + border-radius: 7px; + background: transparent; + cursor: pointer; + transition: background 0.12s; +} + +#switch-theme:hover { + background: var(--grey-100-new, #e5e6e8); +} + +html[data-theme="dark"] #switch-theme:hover { + background: rgba(255, 255, 255, 0.08); } #switch-theme label { @@ -482,6 +914,259 @@ html.is-clipped--navbar { width: 20px; height: 20px; cursor: pointer; - transform: rotate(110deg); - filter: invert(100%) sepia(5%) saturate(1016%) hue-rotate(181deg) brightness(100%) contrast(106%); + /* Light mode - dark icon */ + filter: brightness(0) saturate(100%) invert(30%) sepia(10%) saturate(500%) hue-rotate(180deg); +} + +html[data-theme="dark"] .theme-image { + /* Dark mode - light icon */ + filter: brightness(0) saturate(100%) invert(80%) sepia(10%) saturate(200%) hue-rotate(180deg); +} + +/* ============================================================================= + TOPBAR BUTTONS — Ask AI and utility buttons + ============================================================================= */ + +.tb-ai-btn, +.tb-btn { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 5px 11px 5px 9px; + border: 1px solid transparent; + border-radius: 7px; + font-size: 13px; + font-weight: 500; + cursor: pointer; + transition: background 0.12s, border-color 0.12s, transform 0.12s; + text-decoration: none; + line-height: 1.4; + letter-spacing: -0.0125em; +} + +/* Ask AI button - Light mode (default) */ +.tb-ai-btn { + background: linear-gradient(135deg, #eef2ff 0%, #f3e8ff 100%); + border-color: #d1d9ff; + color: #4338ca; +} + +.tb-ai-btn:hover { + background: linear-gradient(135deg, #e0e7ff 0%, #ede3ff 100%); + border-color: #c7d2fe; + transform: translateY(-1px); +} + +/* Ask AI button - Dark mode */ +html[data-theme="dark"] .tb-ai-btn { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border-color: transparent; + color: white; + box-shadow: 0 1px 3px rgba(102, 126, 234, 0.2); +} + +html[data-theme="dark"] .tb-ai-btn:hover { + background: linear-gradient(135deg, #5a67d8 0%, #6b3fa0 100%); + box-shadow: 0 2px 6px rgba(102, 126, 234, 0.3); +} + +/* Utility button (.tb-btn) - Light mode */ +.tb-btn { + background: transparent; + color: var(--grey-700-new, #3f3f46); +} + +.tb-btn:hover { + background: var(--grey-50-new, #f5f5f5); + color: var(--grey-900-new, #181818); +} + +.tb-btn.outlined { + border: 1px solid var(--grey-200-new, #c3c4c6); +} + +/* Utility button - Dark mode */ +html[data-theme="dark"] .tb-btn { + color: var(--grey-400-new, #919295); +} + +html[data-theme="dark"] .tb-btn:hover { + background: rgba(255, 255, 255, 0.08); + color: #fff; +} + +.tb-ai-btn svg, +.tb-btn svg { + width: 16px; + height: 16px; + flex-shrink: 0; +} + +/* Hide Ask AI button when chat panel is open */ +.chat-panel.is-open ~ header .tb-ai-btn, +body:has(.chat-panel.is-open) .tb-ai-btn { + display: none; +} + +@media screen and (max-width: 1024px) { + .tb-ai-btn span, + .tb-btn { + display: none; + } + + .tb-ai-btn { + padding: 8px; + width: 36px; + height: 36px; + justify-content: center; + } +} + +/* Top nav text links */ +.tb-link { + display: inline-flex; + align-items: center; + padding: 6px 12px; + font-size: 13px; + font-weight: 500; + color: var(--grey-700, #475467); + text-decoration: none; + border-radius: 6px; + transition: background 0.15s, color 0.15s; +} + +.tb-link:hover { + background: var(--grey-50, rgba(0, 0, 0, 0.04)); + color: var(--grey-900, #101828); + text-decoration: none; +} + +html[data-theme="dark"] .tb-link { + color: var(--grey-300, #d0d5dd); +} + +html[data-theme="dark"] .tb-link:hover { + background: rgba(255, 255, 255, 0.06); + color: #fff; +} + +/* Log into Cloud link styling */ +.tb-link-cloud svg { + flex-shrink: 0; +} + +/* Top nav dropdown (Ask a Human) */ +.tb-dropdown { + position: relative; + display: inline-block; +} + +.tb-dropdown-trigger { + cursor: pointer; + border: none; + background: transparent; +} + +.tb-dropdown-trigger svg { + transition: transform 0.2s; +} + +.tb-dropdown:hover .tb-dropdown-trigger svg, +.tb-dropdown-trigger[aria-expanded="true"] svg { + transform: rotate(180deg); +} + +.tb-dropdown-menu { + position: absolute; + top: calc(100% + 4px); + right: 0; + min-width: 160px; + background: #fff; + border: 1px solid var(--grey-200, #e5e7eb); + border-radius: 8px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + padding: 4px; + opacity: 0; + visibility: hidden; + transform: translateY(-4px); + transition: opacity 0.2s, transform 0.2s, visibility 0.2s; + z-index: 100; +} + +.tb-dropdown:hover .tb-dropdown-menu, +.tb-dropdown-trigger[aria-expanded="true"] + .tb-dropdown-menu { + opacity: 1; + visibility: visible; + transform: translateY(0); +} + +html[data-theme="dark"] .tb-dropdown-menu { + background: var(--dark-blue-800-new, #1e293b); + border-color: rgba(255, 255, 255, 0.1); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); +} + +.tb-dropdown-item { + display: block; + padding: 8px 12px; + font-size: 13px; + font-weight: 500; + color: var(--grey-700, #475467); + text-decoration: none; + border-radius: 6px; + transition: background 0.15s, color 0.15s; +} + +.tb-dropdown-item:hover { + background: var(--grey-50, rgba(0, 0, 0, 0.04)); + color: var(--grey-900, #101828); + text-decoration: none; +} + +html[data-theme="dark"] .tb-dropdown-item { + color: var(--grey-300, #d0d5dd); +} + +html[data-theme="dark"] .tb-dropdown-item:hover { + background: rgba(255, 255, 255, 0.08); + color: #fff; +} + +/* Responsive sizing for topbar - compact mode at medium widths */ +@media screen and (min-width: 1024px) and (max-width: 1400px) { + /* Hide version selector label to save space */ + .topbar-crumbs .sm-ver-pill-label { + display: none; + } + + /* Compact version status badge */ + .topbar-crumbs .sm-ver-pill-status { + font-size: 10px; + padding: 2px 6px; + } + + /* Smaller topbar links */ + .tb-link { + padding: 4px 8px; + font-size: 12px; + } + + /* Smaller Ask AI button */ + .tb-ai-btn { + padding: 4px 8px; + font-size: 12px; + } + + .tb-ai-btn svg { + width: 14px; + height: 14px; + } +} + +@media screen and (max-width: 1023px) { + .tb-link { + padding: 6px 8px; + font-size: 12px; + min-height: 30px; + } } diff --git a/src/css/highlight.css b/src/css/highlight.css index 9788ec0d..78021bcb 100644 --- a/src/css/highlight.css +++ b/src/css/highlight.css @@ -84,3 +84,74 @@ .hljs-strong { font-weight: var(--monospace-font-weight-bold); } + +/* Dark mode syntax highlighting - matches Prism theme colors */ +html[data-theme="dark"] .hljs-comment, +html[data-theme="dark"] .hljs-quote { + color: #6a9955; /* Olive green - matches Prism comments */ +} + +html[data-theme="dark"] .hljs-keyword, +html[data-theme="dark"] .hljs-selector-tag, +html[data-theme="dark"] .hljs-subst { + color: #78d9ec; /* Cyan - matches Prism keywords */ +} + +html[data-theme="dark"] .hljs-number, +html[data-theme="dark"] .hljs-literal, +html[data-theme="dark"] .hljs-variable, +html[data-theme="dark"] .hljs-template-variable, +html[data-theme="dark"] .hljs-tag .hljs-attr { + color: #9ccc65; /* Light green - matches Prism strings/numbers */ +} + +html[data-theme="dark"] .hljs-string, +html[data-theme="dark"] .hljs-doctag { + color: #9ccc65; /* Light green - matches Prism strings */ +} + +html[data-theme="dark"] .hljs-title, +html[data-theme="dark"] .hljs-section, +html[data-theme="dark"] .hljs-selector-id { + color: #d7aefb; /* Light purple - matches Prism functions */ +} + +html[data-theme="dark"] .hljs-type, +html[data-theme="dark"] .hljs-class .hljs-title { + color: #78d9ec; /* Cyan - matches Prism keywords */ +} + +html[data-theme="dark"] .hljs-tag, +html[data-theme="dark"] .hljs-name, +html[data-theme="dark"] .hljs-attribute { + color: #78d9ec; /* Cyan - matches Prism tags */ +} + +html[data-theme="dark"] .hljs-regexp, +html[data-theme="dark"] .hljs-link { + color: #9ccc65; /* Light green - consistent with strings */ +} + +html[data-theme="dark"] .hljs-symbol, +html[data-theme="dark"] .hljs-bullet { + color: #d7aefb; /* Light purple - matches Prism functions */ +} + +html[data-theme="dark"] .hljs-built_in, +html[data-theme="dark"] .hljs-builtin-name { + color: #d7aefb; /* Light purple - matches Prism functions */ +} + +html[data-theme="dark"] .hljs-meta { + color: #78d9ec; /* Cyan - matches Prism keywords */ +} + +html[data-theme="dark"] .hljs-deletion { + background: rgba(255, 107, 96, 0.15); + color: #ff6b60; +} + +html[data-theme="dark"] .hljs-addition { + background: rgba(56, 161, 105, 0.15); + color: #56a86f; +} diff --git a/src/css/home.css b/src/css/home.css index 2b683971..82e335d4 100644 --- a/src/css/home.css +++ b/src/css/home.css @@ -2,290 +2,1180 @@ body.article.home { background-color: var(--home-background); } -.article.home .content .doc { - display: flex; - max-width: unset; - margin: 0; - padding: 0; - margin-bottom: 48px; +/* Layout: full-width content area for home page */ +/* Higher specificity selector to override main > .content (main.css:52-64) */ +main.article.home > .content { + padding: 0 !important; + max-width: none !important; } -.article.home footer.footer { - padding-top: 48px; - padding-bottom: 48px; - background-color: var(--home-background); - border-top: 1px solid var(--nav-border-color); +/* ============================================================================ + HOME PAGE HERO SECTION + ============================================================================ */ + +.home-page { + width: 100%; } -/* Center footer content to match home page width */ -.article.home footer.footer .container-large { - max-width: 860px; +/* Dark Hero Section */ +.home-hero { + position: relative; + overflow: hidden; + background: #0b1430; + color: #fff; + padding: 80px 40px 72px; + border-bottom: 1px solid rgba(255, 255, 255, 0.06); } -/* Simplify footer on home - hide logo and columns, keep only socials and legal */ -.article.home footer.footer .footer__logo-link, -.article.home footer.footer .footer__columns { - display: none; +/* Hero Background Effects */ +.home-hero-bg { + position: absolute; + inset: 0; + pointer-events: none; } -.article.home footer.footer .footer__top { - margin-bottom: 1.5rem; +/* Grid Pattern */ +.home-hero-grid { + position: absolute; + inset: 0; + background-image: + linear-gradient(to right, rgba(255, 255, 255, 0.03) 1px, transparent 1px), + linear-gradient(to bottom, rgba(255, 255, 255, 0.03) 1px, transparent 1px); + background-size: 48px 48px; + mask-image: radial-gradient(ellipse 80% 70% at 50% 40%, #000 40%, transparent 90%); + -webkit-mask-image: radial-gradient(ellipse 80% 70% at 50% 40%, #000 40%, transparent 90%); } -/* Adjust footer layout on home */ -.article.home footer.footer .footer__bottom { - flex-direction: column; +/* Glow Effects */ +.home-hero-glow { + position: absolute; + border-radius: 50%; + filter: blur(80px); + opacity: 0.5; +} + +.home-hero-glow-1 { + width: 520px; + height: 520px; + background: radial-gradient(circle, var(--brand-600-new, #e24328) 0%, transparent 70%); + top: -120px; + right: -80px; +} + +.home-hero-glow-2 { + width: 420px; + height: 420px; + background: radial-gradient(circle, var(--indigo-600-new, #444ce7) 0%, transparent 70%); + bottom: -140px; + left: -60px; + opacity: 0.35; +} + +/* Hero Content */ +.home-hero-inner { + position: relative; + z-index: 2; +} + +/* Eyebrow Label */ +.home-hero-eyebrow { + display: inline-flex; align-items: center; - gap: 1.5rem; + gap: 10px; + font-family: var(--monospace-font-family, monospace); + font-size: 11.5px; + letter-spacing: 0.14em; + text-transform: uppercase; + color: rgba(255, 255, 255, 0.7); + padding: 8px 16px; + background: rgba(255, 255, 255, 0.04); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 99px; + margin-bottom: 28px; +} + +.home-hero-dot { + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--brand-500-new, #f04438); + box-shadow: 0 0 0 3px rgba(226, 67, 40, 0.2); +} + +/* Hero Title */ +.home-hero-title, +.doc .home-hero-title, +.article.home .home-hero-title, +h1.home-hero-title { + font-size: clamp(36px, 5vw, 56px) !important; + font-weight: 600 !important; + letter-spacing: -0.03em !important; + line-height: 1.1 !important; + margin: 0 0 22px !important; + text-wrap: pretty; + color: #fff !important; + font-family: var(--body-font-family); } -/* Reduce visual weight - smaller, lighter text */ -.article.home footer.footer .footer__link, -.article.home footer.footer .footer__header, -.article.home footer.footer .text-style-footer-legal { - font-size: 0.8125rem; - color: var(--color-aliases-static-palette-text-subtle); +/* Hero Subtitle */ +.home-hero-sub, +.doc .home-hero-sub, +.article.home .home-hero-sub { + font-size: clamp(16px, 1.4vw, 19px) !important; + line-height: 1.55 !important; + color: #a8b2c7 !important; + max-width: 680px; + margin: 0 0 36px !important; + letter-spacing: -0.005em; + text-wrap: pretty; } -/* Subtler social icon colors on home */ -.article.home footer.footer .footer__social-link { - color: var(--color-aliases-static-palette-text-subtle); - opacity: 0.7; - transition: opacity 0.2s, color 0.2s; +/* Hero Ask Input */ +.home-hero-ask { + display: flex; + align-items: center; + gap: 12px; + width: 100%; + max-width: 600px; + padding: 12px 16px; + background: rgba(255, 255, 255, 0.06); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + transition: background 0.12s, border-color 0.12s; } -.article.home footer.footer .footer__social-link:hover { - opacity: 1; - color: var(--body-font-color); +.home-hero-ask:hover, +.home-hero-ask:focus-within { + background: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.15); } -/* Labs Home Page Footer Styling - Same simplified approach as home */ -main.article.labs footer.footer { - padding-top: 48px; - padding-bottom: 48px; - background-color: var(--body-background); - border-top: 1px solid var(--nav-border-color); +.home-hero-ask-icon { + display: flex; + align-items: center; + color: var(--brand-500-new, #f04438); } -/* Center footer content to match labs page width */ -main.article.labs footer.footer .container-large { - max-width: 860px; +.home-hero-ask-icon svg { + width: 18px; + height: 18px; } -/* Simplify footer on labs home - hide logo and columns, keep only socials and legal */ -main.article.labs footer.footer .footer__logo-link, -main.article.labs footer.footer .footer__columns { - display: none; +.home-hero-ask-input { + flex: 1; + background: transparent; + border: none; + outline: none; + font-size: 15px; + color: #fff; + font-family: var(--body-font-family); } -main.article.labs footer.footer .footer__top { - margin-bottom: 1.5rem; +.home-hero-ask-input::placeholder { + color: rgba(255, 255, 255, 0.5); } -/* Adjust footer layout on labs home */ -main.article.labs footer.footer .footer__bottom { - flex-direction: column; +/* Hero Ask Submit Button - use !important to override any inherited styles */ +.home-hero-ask-submit, +button.home-hero-ask-submit, +.home-hero-ask button.home-hero-ask-submit { + display: flex !important; + align-items: center !important; + justify-content: center !important; + width: 32px !important; + height: 32px !important; + min-width: 32px !important; + max-width: 32px !important; + background: var(--brand-600-new, #e24328) !important; + border: none !important; + border-radius: 8px !important; + color: #fff !important; + cursor: pointer !important; + transition: background 0.12s !important; + padding: 0 !important; + margin: 0 !important; + flex-shrink: 0 !important; +} + +.home-hero-ask-submit:hover, +button.home-hero-ask-submit:hover { + background: var(--brand-700-new, #c9190b) !important; +} + +/* SVG inside submit button - explicit sizing */ +.home-hero-ask-submit svg, +button.home-hero-ask-submit svg, +.home-hero-ask button.home-hero-ask-submit svg { + width: 14px !important; + height: 14px !important; + min-width: 14px !important; + min-height: 14px !important; + display: block !important; + stroke: #fff !important; + fill: none !important; + flex-shrink: 0 !important; +} + +/* Hero Content Container */ +.home-hero-content { + position: relative; + z-index: 2; + max-width: 960px; + text-align: left; +} + +/* Suggestion Chips in Hero */ +.home-hero-chips { + display: flex; + flex-wrap: wrap; align-items: center; - gap: 1.5rem; + gap: 8px; + margin-top: 20px; } -/* Reduce visual weight - smaller, lighter text */ -main.article.labs footer.footer .footer__link, -main.article.labs footer.footer .footer__header, -main.article.labs footer.footer .text-style-footer-legal { - font-size: 0.8125rem; - color: var(--color-aliases-static-palette-text-subtle); +/* Ask Hints Section (Try: label + chips) */ +.home-hero-ask-hints { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 10px; + margin-top: 20px; } -/* Subtler social icon colors on labs home */ -main.article.labs footer.footer .footer__social-link { - color: var(--color-aliases-static-palette-text-subtle); - opacity: 0.7; - transition: opacity 0.2s, color 0.2s; +.home-hero-ask-hints-label { + font-size: 13px; + color: rgba(255, 255, 255, 0.5); + font-weight: 500; } -main.article.labs footer.footer .footer__social-link:hover { - opacity: 1; - color: var(--body-font-color); +.home-hero-chip { + background: rgba(255, 255, 255, 0.06); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 8px; + padding: 8px 14px; + font-size: 13px; + color: rgba(255, 255, 255, 0.8); + cursor: pointer; + transition: background 0.12s, border-color 0.12s, color 0.12s; + font-family: var(--body-font-family); } -.article.home footer nav.footer-nav { - flex-direction: column; - justify-content: space-evenly; +.home-hero-chip:hover { + background: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, 0.2); + color: #fff; } -@media (min-width: 400px) { - .article.home footer nav.footer-nav { - gap: 50px; - flex-direction: row; - } +/* Glow effect for hero (single element with pseudo-elements) */ +.home-hero-glow::before, +.home-hero-glow::after { + content: ''; + position: absolute; + border-radius: 50%; + filter: blur(80px); + pointer-events: none; } -.chat-footer-wrapper { - width: 100%; - padding-bottom: 130px; +.home-hero-glow::before { + width: 520px; + height: 520px; + background: radial-gradient(circle, var(--brand-600-new, #e24328) 0%, transparent 70%); + top: -120px; + right: -80px; + opacity: 0.5; } -.chat-footer-wrapper.fixed-bottom { - position: fixed; - bottom: 0; - z-index: 9999999; - max-width: 860px; - width: 100%; - padding: 0 20px 20px 0; - background-color: var(--home-background); +.home-hero-glow::after { + width: 420px; + height: 420px; + background: radial-gradient(circle, var(--indigo-600-new, #444ce7) 0%, transparent 70%); + bottom: -140px; + left: -60px; + opacity: 0.35; } -.home .chat-footer-wrapper.fixed-bottom .chat-card { - height: 100px; - overflow-y: auto; +/* ============================================================================ + WHAT ARE YOU HERE FOR - INTENT SECTION + ============================================================================ */ + +.home-intent { + padding: 64px 40px 48px; + background: var(--home-background); } -.home .chat-container { - display: flex; - flex-direction: column; - gap: var(--spacings-spacing-lg); - height: 100%; - position: relative; +.home-intent-container { + margin: 0 auto; } -.home .conversation { - display: flex; - flex-direction: column; - gap: var(--spacings-spacing-lg); - font-size: 14px; - line-height: 1.8; - padding: 0.5rem; +/* Section heading - uppercase label style */ +.home-intent-heading, +.doc .home-intent-heading, +h2.home-intent-heading, +.doc h2.home-intent-heading, +.article.home .doc h2.home-intent-heading { + font-size: 11px !important; + font-weight: 600 !important; + text-transform: uppercase !important; + letter-spacing: 0.1em !important; + color: var(--grey-500-new, #6b7280) !important; + margin: 0 0 20px !important; + padding: 0 !important; + line-height: 1 !important; } -.home .disclaimer { - font-size: 0.7rem; - color: #6b7280; - line-height: 1.4; - padding: 1em; - margin-top: 60px; +html[data-theme="dark"] .article.home .doc h2.home-intent-heading, +html[data-theme="dark"] .home-intent-heading, +html[data-theme="dark"] .doc h2.home-intent-heading { + color: var(--grey-400-new, #9ca3af) !important; } -.home .disclaimer a { - color: #6b7280; +.home-intent-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 20px; } -.home .intro { - color: #6b7280; - font-size: 14px; +/* Intent Cards - Two column choice cards */ +.home-intent-card, +a.home-intent-card, +.doc a.home-intent-card { + display: flex; + align-items: flex-start; + gap: 16px; + padding: 24px; + background: #fff; + border: 1px solid var(--grey-200-new, #e5e7eb); + border-radius: 14px; + text-decoration: none !important; + color: inherit; + transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s; } -.home .disclaimer p { - text-align: center; +.home-intent-card:hover, +a.home-intent-card:hover { + border-color: var(--grey-300-new, #d1d5db); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06); + transform: translateY(-2px); } -.home .conversation-area { - flex: 1; - overflow-y: auto; +html[data-theme="dark"] .home-intent-card, +html[data-theme="dark"] a.home-intent-card { + background: var(--dark-blue-800-new, #161e2d); + border-color: rgba(255, 255, 255, 0.08); } -.conversation-area::-webkit-scrollbar { - width: 8px; +html[data-theme="dark"] .home-intent-card:hover, +html[data-theme="dark"] a.home-intent-card:hover { + border-color: rgba(255, 255, 255, 0.15); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3); } -.conversation-area::-webkit-scrollbar-track { - background: transparent; +/* Intent card icon */ +.home-intent-card-icon { + width: 44px; + height: 44px; + border-radius: 10px; + display: grid; + place-items: center; + background: rgba(68, 76, 231, 0.08); + color: var(--indigo-600-new, #444ce7); + flex-shrink: 0; } -.conversation-area::-webkit-scrollbar-thumb { - background-color: rgba(0, 0, 0, 0.2); - border-radius: 4px; +.home-intent-card-icon svg { + width: 20px; + height: 20px; } -.home .conversation-area a { - text-decoration: underline; +html[data-theme="dark"] .home-intent-card-icon { + background: rgba(99, 102, 241, 0.15); + color: var(--indigo-400-new, #818cf8); } -.home .conversation-area a:hover { - text-decoration: underline; +/* Brand variant for ADP - uses color from component-metadata via --adp-color */ +.home-intent-card-icon--brand, +.home-intent-card-icon.home-intent-card-icon--brand { + background: color-mix(in sRGB, var(--adp-color) 8%, transparent); + color: var(--adp-color); } -.home .grecaptcha-badge { - z-index: 0 !important; - display: none !important; +html[data-theme="dark"] .home-intent-card-icon--brand, +html[data-theme="dark"] .home-intent-card-icon.home-intent-card-icon--brand { + background: color-mix(in sRGB, var(--adp-color) 12%, transparent); + color: var(--adp-color); } -.home .section-divider { - border: none; - border-top: 1px solid var(--panel-border-color); - margin: var(--spacings-spacing-xl) 0; +/* Intent card content */ +.home-intent-card-content { + flex: 1; + min-width: 0; } -.home .kapa-chat-root { - padding-top: var(--spacings-spacing-lg); +.home-intent-card-title, +.doc .home-intent-card-title, +h3.home-intent-card-title, +.doc h3.home-intent-card-title, +.article.home .doc h3.home-intent-card-title { + font-size: 17px !important; + font-weight: 600 !important; + margin: 0 0 6px !important; + padding: 0 !important; + letter-spacing: -0.015em !important; + line-height: 1.3 !important; + color: var(--grey-900-new, #111827) !important; } -.home .qa-pair { - margin-bottom: var(--spacings-spacing-lg); - display: flex; - flex-direction: column; +html[data-theme="dark"] .article.home .doc h3.home-intent-card-title, +html[data-theme="dark"] .home-intent-card-title, +html[data-theme="dark"] .doc h3.home-intent-card-title { + color: #fff !important; } -.home .question { - font-size: 14px; - width: fit-content; - font-weight: 400; - color: var(--body-font-color); - display: inline-flex; - background: var(--kapa-question-color); - border-radius: 25px; - padding: 16px 20px; +.home-intent-card-desc, +.doc .home-intent-card-desc, +p.home-intent-card-desc, +.doc p.home-intent-card-desc { + font-size: 14px !important; + line-height: 1.5 !important; + margin: 0 0 10px !important; + color: var(--grey-600-new, #4b5563) !important; } -.home .answer { - margin-top: 2rem; - color: var(--body-font-color); +html[data-theme="dark"] .home-intent-card-desc, +html[data-theme="dark"] .doc p.home-intent-card-desc { + color: var(--grey-400-new, #9ca3af) !important; } -.home .answer h1, -.home .answer h2, -.home .answer h3, -.home .answer li, -.home .answer ol, -.home .answer code, -.home .answer pre { - margin-bottom: 8px; +/* Tags/pills showing included products */ +.home-intent-card-tags { + font-size: 12px; + color: var(--grey-500-new, #6b7280); + margin-bottom: 12px; + letter-spacing: -0.01em; } -.home .chat-container .conversation .answer pre > code { - padding: 0; - background: var(--pre-background); +html[data-theme="dark"] .home-intent-card-tags { + color: var(--grey-400-new, #9ca3af); } -.home .chat-container .conversation .answer pre { - padding: 1em; +/* CTA link */ +.home-intent-card-cta { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 13px; + font-weight: 500; + color: var(--indigo-600-new, #444ce7); + transition: gap 0.15s, color 0.15s; } -.home .loading { - color: #6b7280; - font-style: italic; - margin: 0.5rem 0; +.home-intent-card-cta svg { + transition: transform 0.15s; } -.home .chat-card { - display: flex; - flex-direction: column; - align-items: stretch; /* allow content to stretch it */ - max-height: 280px; - min-height: 140px; - border-radius: var(--border-radius-radius-lg); - background-color: var(--input-color); - box-shadow: 4px 4px 0px 0px rgba(0, 0, 0, 0.12); - transition: height 0.2s ease; - overflow-y: auto; +.home-intent-card:hover .home-intent-card-cta { + gap: 8px; } -.home .chat-content { - display: flex; - align-items: flex-start; - gap: var(--spacings-spacing-xs); - padding: var(--spacings-spacing-lg); - flex: 1 1 auto; +.home-intent-card:hover .home-intent-card-cta svg { + transform: translateX(2px); +} + +/* ADP card variant - uses color from component-metadata via --adp-color */ +.home-intent-card--adp .home-intent-card-cta { + color: var(--adp-color); +} + +html[data-theme="dark"] .home-intent-card-cta { + color: var(--indigo-400-new, #818cf8); +} + +html[data-theme="dark"] .home-intent-card--adp .home-intent-card-cta { + color: var(--adp-color); +} + +/* ============================================================================ + JUMP STRAIGHT TO A PRODUCT - PRODUCT CARDS + ============================================================================ */ + +.home-products { + padding: 80px 40px 96px; + background: var(--body-background); +} + +.home-products-container { + margin: 0 auto; +} + +/* Main section heading */ +.home-products-heading, +.doc .home-products-heading, +h2.home-products-heading, +.doc h2.home-products-heading, +.article.home .doc h2.home-products-heading { + font-size: 11px !important; + font-weight: 600 !important; + text-transform: uppercase !important; + letter-spacing: 0.1em !important; + color: var(--grey-500-new, #6b7280) !important; + margin: 0 0 24px !important; + padding: 0 !important; + line-height: 1 !important; +} + +html[data-theme="dark"] .article.home .doc h2.home-products-heading, +html[data-theme="dark"] .home-products-heading, +html[data-theme="dark"] .doc h2.home-products-heading { + color: var(--grey-400-new, #9ca3af) !important; +} + +/* Sub-section heading (Data Platform, Agentic Data Plane) */ +.home-products-section-heading, +.doc .home-products-section-heading, +h3.home-products-section-heading, +.doc h3.home-products-section-heading, +.article.home .doc h3.home-products-section-heading { + font-size: 18px !important; + font-weight: 600 !important; + color: var(--grey-900-new, #111827) !important; + margin: 0 0 16px !important; + line-height: 1.2 !important; +} + +html[data-theme="dark"] .article.home .doc h3.home-products-section-heading, +html[data-theme="dark"] .home-products-section-heading, +html[data-theme="dark"] .doc h3.home-products-section-heading { + color: var(--grey-100-new, #f3f4f6) !important; +} + +.home-products-section-heading:not(:first-of-type) { + margin-top: 40px !important; + padding-top: 32px !important; + border-top: 1px solid var(--grey-200-new, #e5e7eb); +} + +html[data-theme="dark"] .home-products-section-heading:not(:first-of-type) { + border-top-color: var(--grey-700-new, #374151); +} + +/* Sub-sub-section heading (Self-Managed within Data Platform) */ +.home-products-subsection-heading, +.doc .home-products-subsection-heading, +h4.home-products-subsection-heading, +.doc h4.home-products-subsection-heading, +.article.home .doc h4.home-products-subsection-heading { + font-size: 11px !important; + font-weight: 600 !important; + letter-spacing: 0.04em !important; + text-transform: uppercase !important; + color: var(--grey-500-new, #6b7280) !important; + margin: 20px 0 10px 16px !important; + padding: 0 !important; + line-height: 1 !important; +} + +html[data-theme="dark"] .article.home .doc h4.home-products-subsection-heading, +html[data-theme="dark"] .home-products-subsection-heading, +html[data-theme="dark"] .doc h4.home-products-subsection-heading { + color: var(--grey-400-new, #9ca3af) !important; +} + +/* Nested product cards (indent for Self-Managed children) */ +.home-product-cards--nested { + margin-left: 16px; + padding-left: 12px; + border-left: 2px solid var(--grey-200-new, #e5e7eb); +} + +html[data-theme="dark"] .home-product-cards--nested { + border-left-color: var(--grey-700-new, #374151); +} + +/* Product cards grid */ +.home-product-cards { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 12px; + padding-bottom: 20px; +} + +/* Data Platform hierarchical layout */ +.home-products-data-platform { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 16px; + padding-bottom: 20px; +} + +@media (max-width: 768px) { + .home-products-data-platform { + grid-template-columns: 1fr; + } +} + +/* Product group container */ +.home-product-group { + display: flex; + flex-direction: column; + gap: 12px; +} + +/* Self-Managed group with nested children */ +.home-product-group--with-children { + background: var(--grey-50-new, #f9fafb); + border: 1px solid var(--grey-200-new, #e5e7eb); + border-radius: 12px; + padding: 12px; +} + +html[data-theme="dark"] .home-product-group--with-children { + background: rgba(255, 255, 255, 0.02); + border-color: rgba(255, 255, 255, 0.08); +} + +/* Parent product card (Self-Managed) */ +.home-product-card--parent { + border-left-width: 3px; +} + +/* Nested children container */ +.home-product-children { + display: flex; + flex-direction: column; + gap: 8px; + padding-left: 16px; + border-left: 2px solid var(--grey-300-new, #d1d5db); +} + +html[data-theme="dark"] .home-product-children { + border-left-color: rgba(255, 255, 255, 0.12); +} + +/* Child product cards (Streaming, Connect) */ +.home-product-card--child { + font-size: 13px; + padding: 12px 14px; +} + +.home-product-card--child .home-product-card-title { + font-size: 13px; +} + +.home-product-card--child .home-product-card-desc { + font-size: 12px; +} + +.home-product-card--child .home-product-card-links a { + font-size: 11px; +} + +/* Individual product card */ +.home-product-card, +a.home-product-card, +.doc a.home-product-card { + --product-color: #64748b; /* fallback */ + + display: flex; + align-items: center; + gap: 12px; + padding: 14px 16px; + background: var(--body-background); + border: 1px solid var(--grey-200-new, #e5e7eb); + border-left: 3px solid var(--product-color); + border-radius: 10px; + text-decoration: none !important; + color: inherit; + transition: border-color 0.12s, box-shadow 0.12s, background 0.12s; +} + +.home-product-card:hover, +a.home-product-card:hover { + border-color: var(--product-color); + box-shadow: 0 2px 8px color-mix(in sRGB, var(--product-color) 15%, transparent); + background: color-mix(in sRGB, var(--product-color) 4%, var(--body-background)); +} + +html[data-theme="dark"] .home-product-card, +html[data-theme="dark"] a.home-product-card { + background: var(--dark-blue-800-new, #161e2d); + border-color: rgba(255, 255, 255, 0.08); + border-left-color: var(--product-color); +} + +html[data-theme="dark"] .home-product-card:hover, +html[data-theme="dark"] a.home-product-card:hover { + border-color: var(--product-color); + background: color-mix(in sRGB, var(--product-color) 10%, var(--dark-blue-800-new)); +} + +/* Product card chip - hidden, using left border accent instead */ +.home-product-card-chip { + display: none; +} + +/* Product card content */ +.home-product-card-content { + flex: 1; + min-width: 0; +} + +.home-product-card-header { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 2px; +} + +.home-product-card-title { + font-size: 14px; + font-weight: 600; + color: var(--grey-900-new, #111827); + letter-spacing: -0.01em; +} + +html[data-theme="dark"] .home-product-card-title { + color: #fff; +} + +.home-product-card-version { + font-size: 11px; + font-weight: 500; + color: var(--grey-500-new, #6b7280); + background: var(--grey-100-new, #f3f4f6); + padding: 2px 6px; + border-radius: 4px; +} + +html[data-theme="dark"] .home-product-card-version { + color: var(--grey-400-new, #9ca3af); + background: rgba(255, 255, 255, 0.08); +} + +.home-product-card-desc, +.doc .home-product-card-desc, +p.home-product-card-desc, +.doc p.home-product-card-desc { + font-size: 12px !important; + color: var(--grey-500-new, #6b7280) !important; + margin: 0 !important; + line-height: 1.4 !important; +} + +html[data-theme="dark"] .home-product-card-desc, +html[data-theme="dark"] .doc p.home-product-card-desc { + color: var(--grey-400-new, #9ca3af) !important; +} + +/* Product card quickstart links */ +.home-product-card-links { + display: flex; + gap: 12px; + margin-top: 10px; +} + +.home-product-card-links a { + font-size: 12px; + font-weight: 500; + color: var(--product-color); + text-decoration: none; + transition: opacity 0.12s; +} + +.home-product-card-links a:first-child { + font-weight: 600; +} + +.home-product-card-links a:hover { + opacity: 0.8; + text-decoration: underline; +} + +html[data-theme="dark"] .home-product-card-links a { + color: var(--product-color); +} + +/* NEW badge for home product cards */ +.home-product-badge--new { + display: inline-flex; + align-items: center; + padding: 2px 8px; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.04em; + text-transform: uppercase; + background: linear-gradient(135deg, #10b981 0%, #059669 100%); + color: #fff; + border-radius: 4px; + white-space: nowrap; + margin-left: 6px; +} + +/* NEW badge for intent cards */ +.home-intent-card-badge--new { + display: inline-flex; + align-items: center; + padding: 2px 8px; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.04em; + text-transform: uppercase; + background: linear-gradient(135deg, #10b981 0%, #059669 100%); + color: #fff; + border-radius: 4px; + white-space: nowrap; +} + +/* Down arrow indicator */ +.home-products-more { + display: flex; + justify-content: center; + margin-top: 32px; + color: var(--grey-400-new, #9ca3af); +} + +html[data-theme="dark"] .home-products-more { + color: var(--grey-500-new, #6b7280); +} + +/* Responsive - New Hero & Products */ +@media (max-width: 1024px) { + .home-product-card--featured { + grid-column: span 1; + } +} + +@media (max-width: 768px) { + .home-hero { + padding: 60px 24px 48px; + } + + .home-hero-title { + font-size: 32px; + } + + .home-hero-ask { + flex-wrap: wrap; + max-width: 100%; + } + + .home-hero-chips { + flex-direction: column; + align-items: stretch; + } + + .home-hero-chip { + text-align: center; + } + + .home-products { + padding: 64px 24px 72px; + } + + .home-product-cards { + grid-template-columns: 1fr; + } + + .home-product-card { + flex-direction: column; + } + + .home-product-card-arrow { + display: none; + } +} + +.article.home .content .doc { + display: flex; + flex-direction: column; + max-width: unset; + margin: 0; + padding: 0; + width: 100%; +} + +/* Hero styling - extend full width like data-platform */ +.article.home .home-hero { + width: 100%; + margin: 0 0 24px; + border-radius: 0; +} + +.article.home footer.footer { + padding-top: 48px; + padding-bottom: 48px; + background-color: var(--home-background); + border-top: 1px solid var(--nav-border-color); +} + +/* Center footer content to match home page width */ +.article.home footer.footer .container-large { + max-width: 860px; +} + +/* Simplify footer on home - hide logo and columns, keep only socials and legal */ +.article.home footer.footer .footer__logo-link, +.article.home footer.footer .footer__columns { + display: none; +} + +.article.home footer.footer .footer__top { + margin-bottom: 1.5rem; +} + +/* Adjust footer layout on home */ +.article.home footer.footer .footer__bottom { + flex-direction: column; + align-items: center; + gap: 1.5rem; +} + +/* Reduce visual weight - smaller, lighter text */ +.article.home footer.footer .footer__link, +.article.home footer.footer .footer__header, +.article.home footer.footer .text-style-footer-legal { + font-size: 0.8125rem; + color: var(--color-aliases-static-palette-text-subtle); +} + +/* Subtler social icon colors on home */ +.article.home footer.footer .footer__social-link { + color: var(--color-aliases-static-palette-text-subtle); + opacity: 0.7; + transition: opacity 0.2s, color 0.2s; +} + +.article.home footer.footer .footer__social-link:hover { + opacity: 1; + color: var(--body-font-color); +} + +/* Labs Home Page Footer Styling - Same simplified approach as home */ +main.article.labs footer.footer { + padding-top: 48px; + padding-bottom: 48px; + background-color: var(--body-background); + border-top: 1px solid var(--nav-border-color); +} + +/* Center footer content to match labs page width */ +main.article.labs footer.footer .container-large { + max-width: 860px; +} + +/* Simplify footer on labs home - hide logo and columns, keep only socials and legal */ +main.article.labs footer.footer .footer__logo-link, +main.article.labs footer.footer .footer__columns { + display: none; +} + +main.article.labs footer.footer .footer__top { + margin-bottom: 1.5rem; +} + +/* Adjust footer layout on labs home */ +main.article.labs footer.footer .footer__bottom { + flex-direction: column; + align-items: center; + gap: 1.5rem; +} + +/* Reduce visual weight - smaller, lighter text */ +main.article.labs footer.footer .footer__link, +main.article.labs footer.footer .footer__header, +main.article.labs footer.footer .text-style-footer-legal { + font-size: 0.8125rem; + color: var(--color-aliases-static-palette-text-subtle); +} + +/* Subtler social icon colors on labs home */ +main.article.labs footer.footer .footer__social-link { + color: var(--color-aliases-static-palette-text-subtle); + opacity: 0.7; + transition: opacity 0.2s, color 0.2s; +} + +main.article.labs footer.footer .footer__social-link:hover { + opacity: 1; + color: var(--body-font-color); +} + +.article.home footer nav.footer-nav { + flex-direction: column; + justify-content: space-evenly; +} + +@media (min-width: 400px) { + .article.home footer nav.footer-nav { + gap: 50px; + flex-direction: row; + } +} + +.chat-footer-wrapper { + width: 100%; + padding-bottom: 130px; +} + +.chat-footer-wrapper.fixed-bottom { + position: fixed; + bottom: 0; + z-index: 9999999; + max-width: 860px; + width: 100%; + padding: 0 20px 20px 0; + background-color: var(--home-background); +} + +.home .chat-footer-wrapper.fixed-bottom .chat-card { + height: 100px; + overflow-y: auto; +} + +.home .chat-container { + display: flex; + flex-direction: column; + gap: var(--spacings-spacing-lg); + height: 100%; + position: relative; +} + +.home .conversation { + display: flex; + flex-direction: column; + gap: var(--spacings-spacing-lg); + font-size: 14px; + line-height: 1.8; + padding: 0.5rem; +} + +.home .disclaimer { + font-size: 0.7rem; + color: #6b7280; + line-height: 1.4; + padding: 1em; + margin-top: 60px; +} + +.home .disclaimer a { + color: #6b7280; +} + +.home .intro { + color: #6b7280; + font-size: 14px; +} + +.home .disclaimer p { + text-align: center; +} + +.home .conversation-area { + flex: 1; + overflow-y: auto; +} + +.conversation-area::-webkit-scrollbar { + width: 8px; +} + +.conversation-area::-webkit-scrollbar-track { + background: transparent; +} + +.conversation-area::-webkit-scrollbar-thumb { + background-color: rgba(0, 0, 0, 0.2); + border-radius: 4px; +} + +.home .conversation-area a { + text-decoration: underline; +} + +.home .conversation-area a:hover { + text-decoration: underline; +} + +.home .grecaptcha-badge { + z-index: 0 !important; + display: none !important; +} + +.home .section-divider { + border: none; + border-top: 1px solid var(--panel-border-color); + margin: var(--spacings-spacing-xl) 0; +} + +.home .kapa-chat-root { + padding-top: var(--spacings-spacing-lg); +} + +.home .qa-pair { + margin-bottom: var(--spacings-spacing-lg); + display: flex; + flex-direction: column; +} + +.home .question { + font-size: 14px; + width: fit-content; + font-weight: 400; + color: var(--body-font-color); + display: inline-flex; + background: var(--kapa-question-color); + border-radius: 25px; + padding: 16px 20px; +} + +.home .answer { + margin-top: 2rem; + color: var(--body-font-color); +} + +.home .answer h1, +.home .answer h2, +.home .answer h3, +.home .answer li, +.home .answer ol, +.home .answer code, +.home .answer pre { + margin-bottom: 8px; +} + +.home .chat-container .conversation .answer pre > code { + padding: 0; + background: var(--pre-background); +} + +.home .chat-container .conversation .answer pre { + padding: 1em; +} + +.home .loading { + color: #6b7280; + font-style: italic; + margin: 0.5rem 0; +} + +.home .chat-card { + display: flex; + flex-direction: column; + align-items: stretch; /* allow content to stretch it */ + max-height: 280px; + min-height: 140px; + border-radius: var(--border-radius-radius-lg); + background-color: var(--input-color); + box-shadow: 4px 4px 0px 0px rgba(0, 0, 0, 0.12); + transition: height 0.2s ease; + overflow-y: auto; +} + +.home .chat-content { + display: flex; + align-items: flex-start; + gap: var(--spacings-spacing-xs); + padding: var(--spacings-spacing-lg); + flex: 1 1 auto; } .home .chat-input { @@ -295,514 +1185,1265 @@ main.article.labs footer.footer .footer__social-link:hover { min-height: 40px; max-height: 200px; padding: 10px; - line-height: 1.4; + line-height: 1.4; + flex: 1; + border: none; + outline: none; + font-family: var(--body-font-family); + font-size: 14px; + color: var(--color-aliases-static-palette-text-subtle); + background: transparent; +} + +.home input.chat-input::placeholder { + color: var(--color-aliases-static-palette-text-subtle) !important; +} + +.home .chat-input:disabled { + color: var(--color-aliases-static-palette-text-disabled); +} + +.home .chat-footer { + display: flex; + justify-content: flex-end; + padding: 0 var(--spacings-spacing-lg) var(--spacings-spacing-lg); +} + +.home button[type=submit].main-button { + margin-top: 0; +} + +.home .main-button { + height: 24.6px; + padding: 0 var(--spacings-spacing-sm); + background-color: var(--color-primitives-global-orange-orange-800); + border: none !important; + border-radius: var(--border-radius-radius-md); + display: flex; + align-items: center; + gap: var(--spacings-spacing-3xs); + cursor: pointer; + color: var(--color-primitives-global-grey-white); +} + +.home .main-button:hover { + background-color: var(--color-primitives-global-orange-orange-900) !important; + color: white !important; +} + +.home .main-button:disabled { + background-color: var(--color-aliases-static-palette-text-disabled); + cursor: not-allowed; +} + +.home .chat-footer-buttons { + display: flex; + align-items: center; + gap: var(--spacings-spacing-sm); +} + +.home .deep-thinking-button { + padding: 0 12px; + background: transparent; + border: 1px solid var(--body-font-color); + border-radius: var(--border-radius-radius-md); + display: inline-flex; + align-items: center; + gap: 6px; + cursor: pointer; + color: var(--body-font-color); + font-size: 14px; + font-weight: 500; + transition: all 0.2s ease; +} + +.home .deep-thinking-button .button-icon-left { + display: flex; + align-items: center; + margin-right: 4px; +} + +.home .deep-thinking-button .button-icon { + width: 18px; + height: 18px; +} + +.home .deep-thinking-button .button-text { + font-size: 14px; + font-weight: 500; +} + +.home .deep-thinking-button:hover { + background: rgba(24, 24, 24, 0.05); + border-color: var(--body-font-color); + color: var(--body-font-color); +} + +.home .deep-thinking-button.active { + background: rgba(218, 93, 8, 0.1); + border-color: var(--color-primitives-global-orange-orange-800); + color: var(--color-primitives-global-orange-orange-800); +} + +.home .deep-thinking-button.active:hover { + background: rgba(218, 93, 8, 0.15); + border-color: var(--color-primitives-global-orange-orange-800); +} + +.home .feedback-group { + display: flex; + gap: 5px; +} + +.home .feedback-button { + border: none; + display: inline-flex; + align-items: center; + gap: 5px; + cursor: pointer; + background-color: unset; + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + color: var(--color-aliases-static-palette-text-subtle) !important; + transition: all 0.2s; +} + +.home .feedback-button:hover { + background: #f3f4f6; + border-color: #d1d5db; + border-radius: 0.25rem; + color: #6b7280; +} + +.home .feedback-container { + display: flex; + flex-direction: column; + align-items: flex-end; + gap: 0.5rem; +} + +.home .actions-feedback { + display: inline-flex; + min-height: 40px; + padding: 0px 18px; + justify-content: center; + flex-direction: row; + align-items: center; + gap: 16px; + margin: 0 auto; + margin-top: 30px; + flex-shrink: 0; + background: var(--body-background); + border-radius: 20px; + border: 1px solid #e0e0e0; + box-shadow: 2px 2px 0px 0px rgba(0, 0, 0, 0.12); +} + +.home .actions-feedback.flex.justify-end.items-center { + justify-content: flex-end; +} + +.home .action-buttons { + display: flex; + background-color: unset; + align-items: center; + gap: 5px; +} + +.home .scroll-down-button { + position: absolute; + top: -3rem; + display: flex; + left: 50%; + transform: translateX(-50%); + background: white; + color: #181818; + border: 1px solid var(--card-border-color); + border-radius: 50%; + padding: 0.5rem; + z-index: 10000000; + box-shadow: 2px 2px 0px 0px rgba(0, 0, 0, 0.12); + cursor: pointer; +} + +.home .scroll-down-button:focus { + outline: 2px solid var(--color-primitives-global-orange-orange-900); +} + +.home .scroll-down-button:focus-visible { + outline: 2px solid var(--color-primitives-global-orange-orange-900); +} + +.home .scroll-down-button svg.lucide { + width: 24px; + height: 24px; +} + +.home .action-button { + display: inline-flex; + background-color: unset; + border: none; + align-items: center; + gap: 5px; + border-radius: 1rem; + cursor: pointer; + padding: 0.25rem 0.5rem; + font-size: 0.875rem; + color: var(--color-aliases-static-palette-text-subtle) !important; + transition: all 0.2s; +} + +.home .action-button:hover { + background: #f3f4f6; + border-color: #d1d5db; + color: #6b7280; +} + +.home .button-icon { + width: 16px; + height: 16px; +} + +.home .button-text { + font-family: var(--body-font-family); + font-weight: 600; + font-size: 12px !important; + line-height: 24px; +} + +.home svg.lucide { + width: 16px; + height: 16px; +} + +.home .doc .suggestion-chips { + position: relative; + margin-top: 1rem; +} + +.home .doc .chip { + background: var(--chip-color); + border-radius: 12px; + color: var(--chip-text-color); + padding: 10px; + font-size: 12px; + cursor: pointer; + white-space: normal; + flex: 1 1 auto; +} + +.home .chip:hover { + background: #e5e7eb; + color: black; +} + +html[data-theme="dark"] .home .chip:hover { + background: rgba(255, 255, 255, 0.15); + color: #fff; +} + +.home .doc .more-chip { flex: 1; + background: var(--chip-color); + border-radius: 12px; + color: var(--chip-text-color); + padding: 10px; + cursor: pointer; + white-space: nowrap; +} + +.home .doc .more-chip:hover { + background: #e5e7eb; + color: black; +} + +html[data-theme="dark"] .home .doc .more-chip:hover { + background: rgba(255, 255, 255, 0.15); + color: #fff; +} + +.home .doc .pulldown-menu-desktop, +.home .doc .pulldown-menu-mobile { + position: absolute; + top: 100%; + left: 0; + background-color: var(--chip-color); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + border-radius: 12px; + z-index: 10; + min-width: 160px; + font-size: 12px; + width: 100%; + margin-top: 4px; +} + +.home .doc .pulldown-item { + padding: 8px 12px; + color: var(--chip-text-color); + white-space: normal; + cursor: pointer; +} + +.home .doc .pulldown-item:hover { + background-color: #edf2f7; +} + +/* Header */ +.home .home-header-container { + display: flex; + margin-top: 100px; + width: 100%; + height: 100%; + flex-direction: row; + justify-content: center; + z-index: 2; + position: relative; + background-color: var(--home-background); + overflow: visible; /* Ensure no overflow restrictions */ +} + +.home .home-header-container .answer p { + margin-bottom: 10px; +} + +.home .home-header { + max-width: 860px; + display: flex; + flex-direction: column; + position: relative; + width: 100%; + padding: 0 20px; + flex: 3; +} + +.home .home-header h1 { + font-size: calc(24 / var(--rem-base) * 1rem); + font-weight: 500; + letter-spacing: -0.2px; + line-height: 28px; + margin-bottom: 0; +} + +.home .search-card { + background: white; + border-radius: 8px; + border: 1px solid #e0e0e0; + box-shadow: 4px 4px 0px rgba(0, 0, 0, 0.12); + height: 180px; + padding: 23px 24px; + position: relative; + margin-bottom: 24px; + width: 100%; +} + +.home .search-input { + position: relative; +} + +.home .input-line { + position: absolute; + width: 2px; + height: 20px; + background: #000; + left: 19px; + top: 1px; +} + +.home .search-input input { + width: 100%; border: none; + padding: 0 24px; + font-size: 14px; +} + +.home .search-input input:focus { outline: none; - font-family: var(--body-font-family); +} + +.home .features { + display: flex; + flex-direction: column; + flex: none; + position: sticky; + visibility: visible; + height: fit-content; + margin-left: 60px; + top: calc(var(--navbar-height) + var(--announcement-bar-height--desktop) + 70px); +} + +.home .features .container > h2 { + margin-top: 0; + font-size: 1rem; + padding-top: 0; + color: var(--chip-text-color); + margin-bottom: 12px; +} + +.home .features .feature-image > h3 { + margin-top: 0; + font-size: calc(17 / var(--rem-base) * 1rem); + color: inherit; +} + +.home .feature-row { + display: flex; + flex-direction: column; + gap: 16px; + max-width: 250px; +} + +.home .feature-box { + width: 100%; + height: 100%; + color: var(--chip-text-color); + box-shadow: 1px 1px 2px 0 rgba(0, 0, 0, 0.1); + border-radius: 8px; + display: flex; + flex-direction: column; + padding: 1rem; + align-items: flex-start; + background-color: var(--chip-color); +} + +.home .feature-box:hover { + background: #e5e7eb; + color: black; +} + +html[data-theme="dark"] .home .feature-box:hover { + background: rgba(255, 255, 255, 0.15); + color: #fff; +} + +.home .feature-image { + display: flex; + align-items: center; + margin-left: -4px; + gap: 8px; +} + +.home .feature-image img { + height: 24px; + width: 24px; + object-fit: contain; +} + +.home .feature-text h2 { font-size: 14px; - color: var(--color-aliases-static-palette-text-subtle); - background: transparent; + font-weight: 600; + line-height: 20px; + margin-top: 5px; +} + +.home .feature-text p { + font-size: 12px; + line-height: 16px; + font-weight: 400; + margin-top: 5px; +} + +.home a.feature-link { + text-decoration: none; + white-space: normal; +} + +/* Toast notifications */ +.home .chat-toast { + position: fixed; + top: 16px; + left: 50%; + transform: translateX(-50%); + display: inline-flex; + align-items: center; + gap: 8px; + padding: 10px 16px; + border-radius: 10px; + font-size: 13px; + font-weight: 500; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15), 0 0 0 1px rgba(0, 0, 0, 0.05); + z-index: 200; + animation: toastSlideIn 0.3s cubic-bezier(0.4, 0, 0.2, 1); + pointer-events: none; +} + +@keyframes toastSlideIn { + from { + opacity: 0; + transform: translateX(-50%) translateY(-12px); + } + + to { + opacity: 1; + transform: translateX(-50%) translateY(0); + } +} + +/* Success toast */ +.home .chat-toast-success { + background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%); + color: #065f46; + border: 1px solid #a7f3d0; +} + +.home .chat-toast-success .chat-toast-icon { + display: flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + background: #10b981; + border-radius: 50%; + color: #fff; +} + +.home .chat-toast-success .chat-toast-icon svg { + width: 12px; + height: 12px; +} + +/* Error toast */ +.home .chat-toast-error { + background: linear-gradient(135deg, #fef2f2 0%, #fecaca 100%); + color: #991b1b; + border: 1px solid #fca5a5; +} + +.home .chat-toast-error .chat-toast-icon { + display: flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + background: #ef4444; + border-radius: 50%; + color: #fff; } -.home input.chat-input::placeholder { - color: var(--color-aliases-static-palette-text-subtle) !important; +.home .chat-toast-error .chat-toast-icon svg { + width: 12px; + height: 12px; } -.home .chat-input:disabled { - color: var(--color-aliases-static-palette-text-disabled); +.home .chat-toast-message { + white-space: nowrap; } -.home .chat-footer { - display: flex; - justify-content: flex-end; - padding: 0 var(--spacings-spacing-lg) var(--spacings-spacing-lg); +/* Dark mode toast */ +.dark-theme .home .chat-toast-success { + background: linear-gradient(135deg, #064e3b 0%, #065f46 100%); + color: #a7f3d0; + border-color: #10b981; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(16, 185, 129, 0.2); } -.home button[type=submit].main-button { - margin-top: 0; +.dark-theme .home .chat-toast-error { + background: linear-gradient(135deg, #7f1d1d 0%, #991b1b 100%); + color: #fecaca; + border-color: #ef4444; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(239, 68, 68, 0.2); } -.home .main-button { - height: 24.6px; - padding: 0 var(--spacings-spacing-sm); - background-color: var(--color-primitives-global-orange-orange-800); - border: none !important; - border-radius: var(--border-radius-radius-md); - display: flex; - align-items: center; - gap: var(--spacings-spacing-3xs); - cursor: pointer; - color: var(--color-primitives-global-grey-white); +/* Responsive adjustments */ +@media (max-width: 1150px) { + .home .features { + margin-left: 0; + position: unset; + } + + .home .feature-row { + flex-direction: row; + margin-bottom: 100px; + max-width: 100%; + } + + .home .home-header-container { + flex-direction: column; + align-items: center; + } + + .home .doc .suggestion-chips { + flex-direction: column; + } } -.home .main-button:hover { - background-color: var(--color-primitives-global-orange-orange-900) !important; - color: white !important; +@media (max-width: 900px) { + .chat-footer-wrapper.fixed-bottom { + right: 5px; + left: 10px; + } } -.home .main-button:disabled { - background-color: var(--color-aliases-static-palette-text-disabled); - cursor: not-allowed; +@media (max-width: 550px) { + .home .feature-row { + flex-direction: column; + } } -.home .chat-footer-buttons { - display: flex; - align-items: center; - gap: var(--spacings-spacing-sm); +/* Visually hidden but accessible to screen readers */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip-path: inset(50%); + white-space: nowrap; + border: 0; } -.home .deep-thinking-button { - padding: 0 12px; - background: transparent; - border: 1px solid var(--body-font-color); - border-radius: var(--border-radius-radius-md); - display: inline-flex; - align-items: center; - gap: 6px; +/* ============================================================================ + CHOOSE YOUR PATH SECTION + ============================================================================ */ + +.home-paths { + padding: 64px 40px; + background: var(--body-background); +} + +.home-paths-container { + margin: 0 auto; +} + +/* Section heading - override .doc h2 styles */ +.home-paths-heading, +.doc .home-paths-heading, +h2.home-paths-heading, +.doc h2.home-paths-heading, +.article.home .doc h2.home-paths-heading { + font-size: 32px !important; + font-weight: 600 !important; + letter-spacing: -0.02em !important; + color: var(--body-font-color) !important; + margin: 0 0 12px !important; + padding: 0 !important; + text-align: center !important; + line-height: 1.2 !important; +} + +.home-paths-subheading, +.doc .home-paths-subheading, +p.home-paths-subheading, +.doc p.home-paths-subheading { + font-size: 17px !important; + color: var(--grey-500-new, #6b7280) !important; + margin: 0 0 48px !important; + text-align: center !important; + line-height: 1.5 !important; +} + +html[data-theme="dark"] .home-paths-subheading, +html[data-theme="dark"] .doc p.home-paths-subheading { + color: var(--grey-400-new, #9ca3af) !important; +} + +.home-paths-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 24px; +} + +/* Path Cards - matching prototype */ +.home-path-card { + display: flex; + flex-direction: column; + background: #fff; + border: 1px solid var(--grey-100-new, #f3f4f6); + border-radius: 14px; + padding: 24px 22px 22px; + transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s; cursor: pointer; - color: var(--body-font-color); - font-size: 14px; - font-weight: 500; - transition: all 0.2s ease; + position: relative; } -.home .deep-thinking-button .button-icon-left { +.home-path-card:hover { + border-color: var(--grey-200-new, #e5e7eb); + box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.06), 0 8px 20px -10px rgba(0, 0, 0, 0.08); +} + +html[data-theme="dark"] .home-path-card { + background: var(--dark-blue-800-new, #161e2d); + border-color: rgba(255, 255, 255, 0.08); +} + +html[data-theme="dark"] .home-path-card:hover { + border-color: rgba(255, 255, 255, 0.15); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3); +} + +/* Card Head - icon + title/desc row */ +.home-path-card-head { display: flex; - align-items: center; - margin-right: 4px; + align-items: flex-start; + gap: 14px; + margin-bottom: 18px; } -.home .deep-thinking-button .button-icon { +.home-path-card-header-text { + flex: 1; + min-width: 0; +} + +/* Card Icon - 38x38px box */ +.home-path-card-icon { + width: 38px; + height: 38px; + border-radius: 9px; + display: grid; + place-items: center; + background: rgba(68, 76, 231, 0.08); + color: var(--indigo-600-new, #444ce7); + flex-shrink: 0; +} + +.home-path-card-icon svg { width: 18px; height: 18px; } -.home .deep-thinking-button .button-text { - font-size: 14px; - font-weight: 500; +/* Brand icon variant for ADP */ +.home-path-card-icon--brand, +.home-path-card-icon.home-path-card-icon--brand { + background: rgba(226, 67, 40, 0.08); + color: var(--brand-700-new, #c9190b); } -.home .deep-thinking-button:hover { - background: rgba(24, 24, 24, 0.05); - border-color: var(--body-font-color); - color: var(--body-font-color); +html[data-theme="dark"] .home-path-card-icon { + background: rgba(99, 102, 241, 0.15); + color: var(--indigo-400-new, #818cf8); } -.home .deep-thinking-button.active { - background: rgba(218, 93, 8, 0.1); - border-color: var(--color-primitives-global-orange-orange-800); - color: var(--color-primitives-global-orange-orange-800); +html[data-theme="dark"] .home-path-card-icon--brand, +html[data-theme="dark"] .home-path-card-icon.home-path-card-icon--brand { + background: rgba(226, 67, 40, 0.12); + color: var(--brand-500-new, #f04438); } -.home .deep-thinking-button.active:hover { - background: rgba(218, 93, 8, 0.15); - border-color: var(--color-primitives-global-orange-orange-800); +/* Card titles - matching prototype (17px) */ +.home-path-card-title, +.doc .home-path-card-title, +h3.home-path-card-title, +.doc h3.home-path-card-title, +.article.home .doc h3.home-path-card-title { + font-size: 17px !important; + font-weight: 600 !important; + margin: 0 0 4px !important; + padding: 0 !important; + letter-spacing: -0.015em !important; + line-height: 1.3 !important; + text-decoration: none !important; + color: var(--grey-900-new, #111827) !important; } -.home .feedback-group { +html[data-theme="dark"] .home-path-card-title, +html[data-theme="dark"] .doc h3.home-path-card-title, +html[data-theme="dark"] .article.home .doc h3.home-path-card-title { + color: #fff !important; +} + +/* Card descriptions - matching prototype (13.5px) */ +.home-path-card-desc, +.doc .home-path-card-desc, +p.home-path-card-desc, +.doc p.home-path-card-desc, +.article.home .doc p.home-path-card-desc { + font-size: 13.5px !important; + line-height: 1.5 !important; + margin: 0 !important; + color: var(--grey-600-new, #4b5563) !important; +} + +html[data-theme="dark"] .home-path-card-desc, +html[data-theme="dark"] .doc p.home-path-card-desc { + color: var(--grey-400-new, #9ca3af) !important; +} + +/* Path Steps - numbered CTA links */ +.home-path-steps { display: flex; - gap: 5px; + flex-direction: column; + gap: 2px; } -.home .feedback-button { - border: none; - display: inline-flex; +/* Individual step link */ +.home-path-step, +a.home-path-step, +.doc a.home-path-step, +.article.home .doc a.home-path-step { + display: flex; align-items: center; - gap: 5px; + gap: 12px; + padding: 8px 10px; + border-radius: 7px; + color: var(--grey-700-new, #374151) !important; + font-size: 14px; + transition: background 0.12s, color 0.12s; cursor: pointer; - background-color: unset; - padding: 0.25rem 0.5rem; - font-size: 0.875rem; - color: var(--color-aliases-static-palette-text-subtle) !important; - transition: all 0.2s; + text-decoration: none !important; + letter-spacing: -0.0125em; } -.home .feedback-button:hover { - background: #f3f4f6; - border-color: #d1d5db; - border-radius: 0.25rem; - color: #6b7280; +.home-path-step:hover, +a.home-path-step:hover, +.doc a.home-path-step:hover { + background: rgba(68, 76, 231, 0.08); + color: var(--indigo-800-new, #3730a3) !important; } -.home .feedback-container { +html[data-theme="dark"] .home-path-step, +html[data-theme="dark"] a.home-path-step, +html[data-theme="dark"] .doc a.home-path-step { + color: var(--grey-300-new, #d1d5db) !important; +} + +html[data-theme="dark"] .home-path-step:hover, +html[data-theme="dark"] a.home-path-step:hover { + background: rgba(99, 102, 241, 0.15); + color: var(--indigo-300-new, #a5b4fc) !important; +} + +/* Step number circle */ +.home-path-step-num { + width: 22px; + height: 22px; + border-radius: 50%; + font-family: var(--monospace-font-family, monospace); + font-size: 11px; + font-weight: 600; + display: grid; + place-items: center; + background: var(--grey-50-new, #f9fafb); + color: var(--grey-600-new, #4b5563); + border: 1px solid var(--grey-100-new, #f3f4f6); + flex-shrink: 0; + transition: background 0.12s, color 0.12s, border-color 0.12s; +} + +.home-path-step:hover .home-path-step-num { + background: var(--indigo-600-new, #444ce7); + color: #fff; + border-color: var(--indigo-600-new, #444ce7); +} + +html[data-theme="dark"] .home-path-step-num { + background: rgba(255, 255, 255, 0.06); + color: var(--grey-400-new, #9ca3af); + border-color: rgba(255, 255, 255, 0.1); +} + +html[data-theme="dark"] .home-path-step:hover .home-path-step-num { + background: var(--indigo-500-new, #6366f1); + color: #fff; + border-color: var(--indigo-500-new, #6366f1); +} + +/* Step text */ +.home-path-step-text { + flex: 1; + min-width: 0; +} + +/* Step arrow - appears on hover */ +.home-path-step-arrow { + margin-left: auto; + opacity: 0; + color: var(--indigo-600-new, #444ce7); + transition: opacity 0.12s; + flex-shrink: 0; +} + +.home-path-step-arrow svg { + width: 14px; + height: 14px; +} + +.home-path-step:hover .home-path-step-arrow { + opacity: 1; +} + +html[data-theme="dark"] .home-path-step-arrow { + color: var(--indigo-400-new, #818cf8); +} + +/* ============================================================================ + SUBPRODUCTS (Data Platform card) + ============================================================================ */ + +.home-subproducts { display: flex; flex-direction: column; - align-items: flex-end; - gap: 0.5rem; + gap: 10px; + margin: 4px 0 0; } -.home .actions-feedback { - display: inline-flex; - min-height: 40px; - padding: 0px 18px; - justify-content: center; - flex-direction: row; - align-items: center; - gap: 16px; - margin: 0 auto; - margin-top: 30px; - flex-shrink: 0; - background: var(--body-background); - border-radius: 20px; - border: 1px solid #e0e0e0; - box-shadow: 2px 2px 0px 0px rgba(0, 0, 0, 0.12); +/* Individual subproduct box */ +.home-subproduct, +a.home-subproduct, +.doc a.home-subproduct { + --subproduct-color: #444ce7; /* fallback */ + + display: block; + text-decoration: none !important; + color: inherit; + padding: 14px 16px; + background: color-mix(in sRGB, var(--subproduct-color) 8%, white); + border: 1px solid color-mix(in sRGB, var(--subproduct-color) 15%, transparent); + border-radius: 10px; + transition: border-color 0.12s, background 0.12s, transform 0.12s, box-shadow 0.12s; + position: relative; } -.home .actions-feedback.flex.justify-end.items-center { - justify-content: flex-end; +.home-subproduct:hover, +a.home-subproduct:hover { + border-color: color-mix(in sRGB, var(--subproduct-color) 30%, transparent); + background: color-mix(in sRGB, var(--subproduct-color) 12%, white); + transform: translateX(2px); + box-shadow: 0 4px 14px -8px color-mix(in sRGB, var(--subproduct-color) 25%, transparent); } -.home .action-buttons { +html[data-theme="dark"] .home-subproduct, +html[data-theme="dark"] a.home-subproduct { + background: color-mix(in sRGB, var(--subproduct-color) 12%, transparent); + border-color: color-mix(in sRGB, var(--subproduct-color) 20%, transparent); +} + +html[data-theme="dark"] .home-subproduct:hover, +html[data-theme="dark"] a.home-subproduct:hover { + background: color-mix(in sRGB, var(--subproduct-color) 18%, transparent); + border-color: color-mix(in sRGB, var(--subproduct-color) 30%, transparent); +} + +/* Subproduct header row */ +.home-subproduct-head { display: flex; - background-color: unset; align-items: center; - gap: 5px; + gap: 10px; + margin-bottom: 4px; } -.home .scroll-down-button { - position: absolute; - top: -3rem; - display: flex; - left: 50%; - transform: translateX(-50%); - background: white; - color: #181818; - border: 1px solid var(--card-border-color); - border-radius: 50%; - padding: 0.5rem; - z-index: 10000000; - box-shadow: 2px 2px 0px 0px rgba(0, 0, 0, 0.12); - cursor: pointer; +/* Chip/badge (SM, CL, RC) */ +.home-subproduct-chip { + font-family: var(--monospace-font-family, monospace); + font-size: 9.5px; + font-weight: 700; + letter-spacing: 0.04em; + padding: 3px 6px; + border-radius: 4px; + color: #fff; + flex-shrink: 0; } -.home .scroll-down-button:focus { - outline: 2px solid var(--color-primitives-global-orange-orange-900); +.home-subproduct-chip--self { + background: #64748b; } -.home .scroll-down-button:focus-visible { - outline: 2px solid var(--color-primitives-global-orange-orange-900); +.home-subproduct-chip--cloud { + background: #0ea5e9; } -.home .scroll-down-button svg.lucide { - width: 24px; - height: 24px; +.home-subproduct-chip--connect { + background: #0b8c6b; } -.home .action-button { +/* Subproduct name */ +.home-subproduct-name { + display: block; + font-size: 14.5px; + font-weight: 600; + color: var(--grey-900-new, #111827); + letter-spacing: -0.0125em; + margin-bottom: 4px; +} + +html[data-theme="dark"] .home-subproduct-name { + color: #fff; +} + +/* Subproduct description */ +.home-subproduct-desc, +.doc .home-subproduct-desc, +p.home-subproduct-desc { + font-size: 12.5px !important; + color: var(--grey-600-new, #4b5563) !important; + line-height: 1.45 !important; + margin: 0 0 8px !important; + letter-spacing: -0.005em; +} + +html[data-theme="dark"] .home-subproduct-desc, +html[data-theme="dark"] .doc p.home-subproduct-desc { + color: var(--grey-400-new, #9ca3af) !important; +} + +/* CTA link */ +.home-subproduct-cta { display: inline-flex; - background-color: unset; - border: none; align-items: center; + gap: 2px; + font-size: 12px; + font-weight: 500; + letter-spacing: -0.0125em; + color: var(--grey-500-new, #6b7280); + transition: color 0.12s, gap 0.12s; +} + +.home-subproduct-cta svg { + width: 11px; + height: 11px; + transition: transform 0.12s; +} + +.home-subproduct:hover .home-subproduct-cta { + color: var(--subproduct-color, var(--indigo-600-new, #444ce7)); gap: 5px; - border-radius: 1rem; - cursor: pointer; - padding: 0.25rem 0.5rem; - font-size: 0.875rem; - color: var(--color-aliases-static-palette-text-subtle) !important; - transition: all 0.2s; } -.home .action-button:hover { - background: #f3f4f6; - border-color: #d1d5db; - color: #6b7280; +.home-subproduct:hover .home-subproduct-cta svg { + transform: translateX(2px); } -.home .button-icon { - width: 16px; - height: 16px; +html[data-theme="dark"] .home-subproduct-cta { + color: var(--grey-400-new, #9ca3af); } -.home .button-text { - font-family: var(--body-font-family); - font-weight: 600; - font-size: 12px !important; - line-height: 24px; +html[data-theme="dark"] .home-subproduct:hover .home-subproduct-cta { + color: color-mix(in sRGB, var(--subproduct-color) 100%, white 30%); } -.home svg.lucide { - width: 16px; - height: 16px; +/* ============================================================================ + QUICK NAVIGATION SECTION + ============================================================================ */ + +.home-nav-section { + padding: 64px 40px; + background: var(--grey-50-new, #f9fafb); + border-top: 1px solid var(--grey-200-new, #e5e7eb); } -.home .doc .suggestion-chips { - position: relative; - margin-top: 1rem; +html[data-theme="dark"] .home-nav-section { + background: var(--dark-blue-900-new, #0f1727); + border-top-color: rgba(255, 255, 255, 0.06); } -.home .doc .chip { - background: var(--chip-color); - border-radius: 12px; - color: var(--chip-text-color); - padding: 10px; - font-size: 12px; - cursor: pointer; - white-space: normal; - flex: 1 1 auto; +.home-nav-container { + margin: 0 auto; } -.home .chip:hover { - background: #e5e7eb; - color: black; +.home-nav-heading { + font-size: 24px; + font-weight: 600; + letter-spacing: -0.02em; + color: var(--body-font-color); + margin: 0 0 8px; + text-align: center; } -.home .doc .more-chip { - flex: 1; - background: var(--chip-color); - border-radius: 12px; - color: var(--chip-text-color); - padding: 10px; - cursor: pointer; - white-space: nowrap; +.home-nav-subheading { + font-size: 15px; + color: var(--grey-500-new, #6b7280); + margin: 0 0 40px; + text-align: center; } -.home .doc .more-chip:hover { - background: #e5e7eb; - color: black; +html[data-theme="dark"] .home-nav-subheading { + color: var(--grey-400-new, #9ca3af); } -.home .doc .pulldown-menu-desktop, -.home .doc .pulldown-menu-mobile { - position: absolute; - top: 100%; - left: 0; - background-color: var(--chip-color); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - border-radius: 12px; - z-index: 10; - min-width: 160px; - font-size: 12px; - width: 100%; - margin-top: 4px; +.home-nav-tree { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 24px; } -.home .doc .pulldown-item { - padding: 8px 12px; - color: var(--chip-text-color); - white-space: normal; - cursor: pointer; +/* Nav Tree Section */ +.home-nav-tree-section { + background: var(--body-background); + border: 1px solid var(--grey-200-new, #e5e7eb); + border-radius: 12px; + padding: 20px; + overflow: hidden; } -.home .doc .pulldown-item:hover { - background-color: #edf2f7; +html[data-theme="dark"] .home-nav-tree-section { + background: var(--dark-blue-800-new, #161e2d); + border-color: rgba(255, 255, 255, 0.08); } -/* Header */ -.home .home-header-container { +.home-nav-tree-title { display: flex; - margin-top: 100px; - width: 100%; - height: 100%; - flex-direction: row; - justify-content: center; - z-index: 2; - position: relative; - background-color: var(--home-background); - overflow: visible; /* Ensure no overflow restrictions */ + align-items: center; + gap: 10px; + font-size: 16px; + font-weight: 600; + margin: 0 0 16px; + padding-bottom: 12px; + border-bottom: 1px solid var(--grey-200-new, #e5e7eb); + color: var(--body-font-color); + cursor: pointer; + user-select: none; } -.home .home-header-container .answer p { - margin-bottom: 10px; +html[data-theme="dark"] .home-nav-tree-title { + border-bottom-color: rgba(255, 255, 255, 0.08); } -.home .home-header { - max-width: 860px; +.home-nav-tree-icon { display: flex; - flex-direction: column; - position: relative; - width: 100%; - padding: 0 20px; - flex: 3; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + background: var(--indigo-100-new, #e0e7ff); + border-radius: 8px; + color: var(--indigo-600-new, #444ce7); } -.home .home-header h1 { - font-size: calc(24 / var(--rem-base) * 1rem); - font-weight: 500; - letter-spacing: -0.2px; - line-height: 28px; - margin-bottom: 0; +html[data-theme="dark"] .home-nav-tree-icon { + background: rgba(99, 102, 241, 0.15); + color: var(--indigo-400-new, #818cf8); } -.home .search-card { - background: white; - border-radius: 8px; - border: 1px solid #e0e0e0; - box-shadow: 4px 4px 0px rgba(0, 0, 0, 0.12); - height: 180px; - padding: 23px 24px; - position: relative; - margin-bottom: 24px; - width: 100%; +/* Nav tree styling within home page */ +.home-nav-tree-section .nav-list { + list-style: none; + margin: 0; + padding: 0; } -.home .search-input { - position: relative; +.home-nav-tree-section .nav-item { + margin: 0; } -.home .input-line { - position: absolute; - width: 2px; - height: 20px; - background: #000; - left: 19px; - top: 1px; +.home-nav-tree-section .nav-item .item { + display: flex; + align-items: center; + gap: 4px; } -.home .search-input input { - width: 100%; - border: none; - padding: 0 24px; +.home-nav-tree-section .nav-link, +.home-nav-tree-section .nav-text { + display: block; font-size: 14px; + padding: 6px 0; + color: var(--grey-700-new, #374151); + text-decoration: none; + transition: color 0.15s; } -.home .search-input input:focus { - outline: none; +html[data-theme="dark"] .home-nav-tree-section .nav-link, +html[data-theme="dark"] .home-nav-tree-section .nav-text { + color: var(--grey-300-new, #d1d5db); } -.home .features { - display: flex; - flex-direction: column; - flex: none; - position: sticky; - visibility: visible; - height: fit-content; - margin-left: 60px; - top: calc(var(--navbar-height) + var(--announcement-bar-height--desktop) + 70px); +.home-nav-tree-section .nav-link:hover { + color: var(--indigo-600-new, #444ce7); } -.home .features .container > h2 { - margin-top: 0; - font-size: 1rem; - padding-top: 0; - color: var(--chip-text-color); - margin-bottom: 12px; +html[data-theme="dark"] .home-nav-tree-section .nav-link:hover { + color: var(--indigo-400-new, #818cf8); } -.home .features .feature-image > h3 { - margin-top: 0; - font-size: calc(17 / var(--rem-base) * 1rem); - color: inherit; +/* Nested nav items */ +.home-nav-tree-section .nav-list .nav-list { + padding-left: 16px; + border-left: 1px solid var(--grey-200-new, #e5e7eb); + margin-left: 8px; } -.home .feature-row { - display: flex; - flex-direction: column; - gap: 16px; - max-width: 250px; +html[data-theme="dark"] .home-nav-tree-section .nav-list .nav-list { + border-left-color: rgba(255, 255, 255, 0.08); } -.home .feature-box { - width: 100%; - height: 100%; - color: var(--chip-text-color); - box-shadow: 1px 1px 2px 0 rgba(0, 0, 0, 0.1); - border-radius: 8px; - display: flex; - flex-direction: column; - padding: 1rem; - align-items: flex-start; - background-color: var(--chip-color); +/* Dark mode text color fixes for accessibility */ +html[data-theme="dark"] .home .disclaimer { + color: var(--grey-400-new, #9ca3af); } -.home .feature-box:hover { - background: #e5e7eb; - color: black; +html[data-theme="dark"] .home .disclaimer a { + color: var(--grey-400-new, #9ca3af); } -.home .feature-image { - display: flex; - align-items: center; - margin-left: -4px; - gap: 8px; +html[data-theme="dark"] .home .intro { + color: var(--grey-400-new, #9ca3af); } -.home .feature-image img { - height: 24px; - width: 24px; - object-fit: contain; +html[data-theme="dark"] .home .loading { + color: var(--grey-400-new, #9ca3af); } -.home .feature-text h2 { - font-size: 14px; - font-weight: 600; - line-height: 20px; - margin-top: 5px; +/* Collapsed state */ +.home-nav-tree-section.is-collapsed .nav-list { + display: none; } -.home .feature-text p { - font-size: 12px; - line-height: 16px; - font-weight: 400; - margin-top: 5px; +.home-nav-tree-section.is-collapsed .home-nav-tree-title { + border-bottom: none; + margin-bottom: 0; + padding-bottom: 0; } -.home a.feature-link { - text-decoration: none; - white-space: normal; +/* Hide nav toggle in home nav tree */ +.home-nav-tree-section .nav-item-toggle { + display: none; } -.home .toast-inline { - font-size: 0.875rem; - color: #374151; - justify-content: center; - display: flex; - background: #f3f4f6; - padding: 0.25rem 0.5rem; - border-radius: 4px; - animation: fadeIn 0.3s ease; +/* Limit depth shown on home page */ +.home-nav-tree-section .nav-list .nav-list .nav-list { + display: none; } -@keyframes fadeIn { - from { opacity: 0; } - to { opacity: 1; } -} +/* Responsive */ +@media (max-width: 768px) { + .home-paths { + padding: 48px 24px; + } -/* Responsive adjustments */ -@media (max-width: 1150px) { - .home .features { - margin-left: 0; - position: unset; + .home-paths-grid { + grid-template-columns: 1fr; } - .home .feature-row { - flex-direction: row; - margin-bottom: 100px; - max-width: 100%; + .home-path-card { + padding: 20px 18px 18px; } - .home .home-header-container { - flex-direction: column; - align-items: center; + .home-path-card-head { + gap: 12px; } - .home .doc .suggestion-chips { - flex-direction: column; + .home-nav-section { + padding: 48px 24px; + } + + .home-nav-tree { + grid-template-columns: 1fr; } } +/* Responsive for intent and products sections */ @media (max-width: 900px) { - .chat-footer-wrapper.fixed-bottom { - right: 5px; - left: 10px; + .home-product-cards { + grid-template-columns: repeat(2, 1fr); } } -@media (max-width: 550px) { - .home .feature-row { - flex-direction: column; +@media (max-width: 768px) { + .home-intent { + padding: 48px 24px 36px; } -} -/* Visually hidden but accessible to screen readers */ -.visually-hidden { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip-path: inset(50%); - white-space: nowrap; - border: 0; + .home-intent-grid { + grid-template-columns: 1fr; + } + + .home-intent-card { + padding: 20px; + } + + .home-products { + padding: 56px 24px 64px; + } + + .home-product-cards { + grid-template-columns: 1fr; + } } diff --git a/src/css/labs-home.css b/src/css/labs-home.css new file mode 100644 index 00000000..97ed1b47 --- /dev/null +++ b/src/css/labs-home.css @@ -0,0 +1,1193 @@ +/* ============================================================================= + LABS HOME PAGE STYLES + Styling for the Labs landing page with hero, filters, and card grid + ============================================================================= */ + +/* Labs page wrapper */ +.labs-wrap { + background: var(--body-background); +} + +.labs-wrap .page-view { + width: 100%; + max-width: none; +} + +.labs-page { + width: 100%; +} + +/* ============================================================================= + HERO SECTION + ============================================================================= */ +.labs-hero { + position: relative; + padding: 72px 5vw 56px; + text-align: center; + background: linear-gradient(180deg, #0b1430 0%, #10173a 100%); + overflow: hidden; +} + +.labs-hero-bg { + position: absolute; + inset: 0; + pointer-events: none; +} + +.labs-hero-glow { + position: absolute; + width: 600px; + height: 600px; + top: -220px; + left: 50%; + transform: translateX(-50%); + background: radial-gradient(circle, rgba(226, 67, 40, 0.18) 0%, transparent 70%); +} + +.labs-hero-grid { + position: absolute; + inset: 0; + background-image: + linear-gradient(rgba(255, 255, 255, 0.025) 1px, transparent 1px), + linear-gradient(90deg, rgba(255, 255, 255, 0.025) 1px, transparent 1px); + background-size: 48px 48px; + mask-image: linear-gradient(180deg, white 0%, transparent 80%); + -webkit-mask-image: linear-gradient(180deg, white 0%, transparent 80%); +} + +.labs-hero-inner { + position: relative; + max-width: 920px; + margin: 0 auto; +} + +.labs-hero-eyebrow { + display: inline-flex; + align-items: center; + gap: 10px; + font-size: 14px; + font-weight: 600; + letter-spacing: 0.1em; + text-transform: uppercase; + color: rgba(255, 255, 255, 0.7); + margin-bottom: 20px; +} + +.labs-hero-dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: #e24328; + box-shadow: 0 0 10px rgba(226, 67, 40, 0.6); +} + +/* Use .labs-hero prefix for specificity over .doc h1 */ +.labs-hero .labs-hero-title { + font-size: clamp(28px, 5vw, 40px); + font-weight: 700; + line-height: 1.2; + color: #fff; + margin: 0 0 16px; + font-family: var(--body-font-family-bold, var(--body-font-family)); +} + +.labs-hero-sub { + font-size: 15px; + line-height: 1.6; + color: rgba(255, 255, 255, 0.6); + max-width: 640px; + margin: 0 auto 32px; +} + +.labs-hero-stats { + display: flex; + justify-content: center; + gap: 40px; + flex-wrap: wrap; +} + +.labs-hero-stats > div { + text-align: center; +} + +.labs-hero-stats strong { + display: block; + font-size: 28px; + font-weight: 700; + color: #fff; +} + +.labs-hero-stats span { + font-size: 12px; + color: rgba(255, 255, 255, 0.5); + text-transform: uppercase; + letter-spacing: 0.04em; +} + +/* ============================================================================= + BODY / RESULTS LAYOUT (single column - filters are in nav sidebar) + ============================================================================= */ +.labs-body { + padding: 40px 5vw 64px; + max-width: none; + margin: 0; +} + +/* Labs Search Bar in Main Content */ +.labs-search-bar { + display: flex; + align-items: center; + gap: 12px; + padding: 12px 16px; + background: var(--panel-background, #fff); + border: 1px solid var(--panel-border-color, rgba(0, 0, 0, 0.1)); + border-radius: 8px; + margin-bottom: 24px; + max-width: 600px; +} + +.labs-search-bar:focus-within { + border-color: var(--link-highlight-color, #4b44ff); + box-shadow: 0 0 0 3px rgba(75, 68, 255, 0.1); +} + +.labs-search-bar > svg { + color: var(--grey-400, #9ca3af); + flex-shrink: 0; +} + +.labs-search-bar input { + flex: 1; + min-width: 0; + border: 0; + background: transparent; + font-size: 14px; + color: var(--body-font-color); + outline: none; +} + +.labs-search-bar input::placeholder { + color: var(--grey-400, #9ca3af); +} + +.labs-search-clear { + background: transparent; + border: 0; + padding: 4px; + cursor: pointer; + color: var(--grey-400); + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; +} + +.labs-search-clear:hover { + background: var(--grey-100, #f3f4f6); + color: var(--grey-700, #374151); +} + +html[data-theme="dark"] .labs-search-bar { + background: rgba(255, 255, 255, 0.04); + border-color: rgba(255, 255, 255, 0.1); +} + +html[data-theme="dark"] .labs-search-bar > svg, +html[data-theme="dark"] .labs-search-bar input::placeholder { + color: rgba(255, 255, 255, 0.4); +} + +html[data-theme="dark"] .labs-search-clear:hover { + background: rgba(255, 255, 255, 0.1); + color: rgba(255, 255, 255, 0.9); +} + +/* ============================================================================= + LABS NAV SIDEBAR FILTERS + Integrated into the main nav sidebar structure + ============================================================================= */ +.labs-nav-search { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + margin: 0 12px 12px; + background: var(--nav-background, rgba(0, 0, 0, 0.03)); + border: 1px solid var(--nav-border-color, rgba(0, 0, 0, 0.08)); + border-radius: 6px; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.labs-nav-search:focus-within { + border-color: var(--link-highlight-color, #4b44ff); + box-shadow: 0 0 0 2px rgba(75, 68, 255, 0.1); +} + +.labs-nav-search > svg { + color: var(--nav-muted-color, rgba(0, 0, 0, 0.4)); + flex-shrink: 0; +} + +.labs-nav-search input { + flex: 1; + min-width: 0; + border: 0; + background: transparent; + font-size: 13px; + color: var(--body-font-color); + outline: none; +} + +.labs-nav-search input::placeholder { + color: var(--nav-muted-color, rgba(0, 0, 0, 0.4)); +} + +.labs-nav-search-clear { + background: transparent; + border: 0; + padding: 2px; + cursor: pointer; + color: var(--nav-muted-color, rgba(0, 0, 0, 0.4)); + border-radius: 3px; + display: flex; + align-items: center; + justify-content: center; +} + +.labs-nav-search-clear:hover { + background: rgba(0, 0, 0, 0.06); + color: var(--body-font-color); +} + +.labs-nav-filters { + padding: 0 12px; +} + +.labs-nav-filters-head { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 12px; + padding-bottom: 8px; + border-bottom: 1px solid var(--nav-border-color, rgba(0, 0, 0, 0.08)); + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.04em; + color: var(--nav-muted-color, rgba(0, 0, 0, 0.5)); +} + +.labs-nav-clear { + font-size: 11px; + color: var(--link-highlight-color, #4b44ff); + background: transparent; + border: 0; + cursor: pointer; + padding: 2px 6px; + border-radius: 3px; + text-transform: none; + letter-spacing: normal; +} + +.labs-nav-clear:hover { + background: rgba(75, 68, 255, 0.08); +} + +.labs-nav-filter-group { + margin-bottom: 16px; +} + +.labs-nav-filter-title { + font-size: 12px; + font-weight: 600; + color: var(--body-font-color); + margin-bottom: 8px; + padding: 0 4px; +} + +.labs-nav-filter-list { + list-style: none; + margin: 0; + padding: 0; +} + +/* Reuse existing filter row styles for nav filters */ +.labs-nav-filter-list .labs-filter-row { + padding: 6px 8px; + font-size: 13px; + margin-bottom: 2px; +} + +.labs-nav-filter-list .labs-filter-check { + width: 14px; + height: 14px; +} + +.labs-nav-filter-list .labs-filter-count { + font-size: 11px; +} + +/* Show more button for filters */ +.ais-RefinementList-showMore { + display: block; + width: 100%; + padding: 6px 8px; + margin-top: 4px; + font-size: 12px; + color: var(--link-font-color, #4b44ff); + background: transparent; + border: none; + cursor: pointer; + text-align: left; +} + +.ais-RefinementList-showMore:hover { + color: var(--link-hover-font-color, #3730d9); + text-decoration: underline; +} + +.ais-RefinementList-showMore--disabled { + display: none; +} + +html[data-theme="dark"] .ais-RefinementList-showMore { + color: rgba(150, 150, 255, 0.9); +} + +html[data-theme="dark"] .ais-RefinementList-showMore:hover { + color: rgba(180, 180, 255, 1); +} + +/* Dark mode adjustments for nav filters */ +html[data-theme="dark"] .labs-nav-filters-head { + border-color: rgba(255, 255, 255, 0.12); + color: rgba(255, 255, 255, 0.6); +} + +html[data-theme="dark"] .labs-nav-filter-title { + color: rgba(255, 255, 255, 0.9); +} + +html[data-theme="dark"] .labs-filter-row { + color: rgba(255, 255, 255, 0.75); +} + +html[data-theme="dark"] .labs-filter-row:hover { + background: rgba(255, 255, 255, 0.06); + color: rgba(255, 255, 255, 0.95); +} + +html[data-theme="dark"] .labs-filter-row.is-on { + color: rgba(255, 255, 255, 0.95); +} + +html[data-theme="dark"] .labs-filter-label { + color: rgba(255, 255, 255, 0.85); +} + +html[data-theme="dark"] .labs-filter-count { + color: rgba(255, 255, 255, 0.6); + background: rgba(255, 255, 255, 0.1); +} + +html[data-theme="dark"] .labs-filter-row.is-on .labs-filter-count { + background: rgba(150, 150, 255, 0.15); + color: rgba(180, 180, 255, 0.9); +} + +html[data-theme="dark"] .labs-filter-check { + border-color: rgba(255, 255, 255, 0.3); +} + +/* Legacy sidebar styles (kept for backwards compatibility) */ +.labs-sidebar { + position: sticky; + top: 88px; + max-height: calc(100vh - 108px); + overflow-y: auto; + padding-right: 8px; + scrollbar-width: thin; + scrollbar-color: rgba(0, 0, 0, 0.12) transparent; +} + +.labs-sidebar::-webkit-scrollbar { + width: 6px; +} + +.labs-sidebar::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, 0.12); + border-radius: 3px; +} + +/* Search box */ +.labs-search { + display: flex; + align-items: center; + gap: 10px; + padding: 10px 14px; + background: var(--grey-50, #f9fafb); + border: 1px solid var(--grey-200, #e5e7eb); + border-radius: 8px; + margin-bottom: 20px; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.labs-search:focus-within { + border-color: var(--link-highlight-color, #4b44ff); + box-shadow: 0 0 0 3px rgba(75, 68, 255, 0.1); +} + +.labs-search > svg { + color: var(--grey-500, #6b7280); + flex-shrink: 0; +} + +.labs-search input { + flex: 1; + border: 0; + background: transparent; + font-size: 13px; + color: var(--body-font-color); + outline: none; +} + +.labs-search input::placeholder { + color: var(--grey-400, #9ca3af); +} + +/* Filters header */ +.labs-filters-head { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 16px; + font-size: 12px; + font-weight: 600; + color: var(--grey-600, #4b5563); +} + +.labs-clear { + font-size: 11px; + color: var(--link-highlight-color, #4b44ff); + background: transparent; + border: 0; + cursor: pointer; + padding: 4px 8px; + border-radius: 4px; +} + +.labs-clear:hover { + background: rgba(75, 68, 255, 0.08); +} + +/* Filter groups */ +.labs-filter-group { + border-bottom: 1px solid var(--grey-200, #e5e7eb); + padding-bottom: 16px; + margin-bottom: 16px; +} + +.labs-filter-group:last-child { + border-bottom: 0; +} + +.labs-filter-title { + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.04em; + color: var(--grey-500, #6b7280); + margin-bottom: 10px; +} + +.labs-filter-list { + list-style: none; + margin: 0; + padding: 0; +} + +.labs-filter-row { + display: flex; + align-items: center; + gap: 10px; + padding: 7px 10px; + font-size: 13px; + color: var(--grey-600, #4b5563); + border-radius: 6px; + cursor: pointer; + transition: background 0.12s, color 0.12s; +} + +.labs-filter-row:hover { + background: var(--grey-50, rgba(0, 0, 0, 0.025)); + color: var(--grey-900, #111827); +} + +.labs-filter-row.is-on { + color: var(--grey-900, #111827); + font-weight: 500; +} + +.labs-filter-row input { + display: none; +} + +.labs-filter-check { + width: 16px; + height: 16px; + border: 1.5px solid var(--grey-300, #d1d5db); + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + transition: background 0.12s, border-color 0.12s; +} + +.labs-filter-row.is-on .labs-filter-check { + background: var(--link-highlight-color, #4b44ff); + border-color: var(--link-highlight-color, #4b44ff); + color: #fff; +} + +.labs-filter-label { + flex: 1; + min-width: 0; +} + +.labs-filter-count { + font-size: 11px; + color: var(--grey-400, #9ca3af); + background: var(--grey-100, #f3f4f6); + padding: 2px 6px; + border-radius: 4px; +} + +.labs-filter-row.is-on .labs-filter-count { + background: rgba(75, 68, 255, 0.1); + color: var(--link-highlight-color, #4b44ff); +} + +/* ============================================================================= + RESULTS SECTION + ============================================================================= */ +.labs-results { + min-width: 0; +} + +.labs-results-head { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 24px; + flex-wrap: wrap; + gap: 16px; +} + +.labs-results-count { + font-size: 14px; + color: var(--grey-700, #374151); +} + +.labs-results-count strong { + color: var(--grey-900, #111827); + font-weight: 600; +} + +.labs-results-filter-note { + color: var(--grey-500, #6b7280); +} + +.labs-results-controls { + display: flex; + align-items: center; + gap: 12px; +} + +.labs-sort { + display: flex; + align-items: center; + gap: 8px; +} + +.labs-sort label { + font-size: 12px; + color: var(--grey-500, #6b7280); +} + +.labs-sort select { + font-size: 13px; + padding: 6px 28px 6px 10px; + border: 1px solid var(--grey-200, #e5e7eb); + border-radius: 6px; + background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") no-repeat right 8px center; + appearance: none; + cursor: pointer; + color: var(--body-font-color); +} + +.labs-sort select:focus { + outline: 2px solid rgba(75, 68, 255, 0.3); + outline-offset: 1px; +} + +.labs-view-toggle { + display: flex; + border: 1px solid var(--grey-200, #e5e7eb); + border-radius: 6px; + overflow: hidden; + background: var(--grey-50, #f9fafb); +} + +.labs-view-toggle button { + padding: 6px 10px; + background: transparent; + border: 0; + color: var(--grey-500, #6b7280); + cursor: pointer; + transition: background 0.12s, color 0.12s; +} + +.labs-view-toggle button:not(:last-child) { + border-right: 1px solid var(--grey-200, #e5e7eb); +} + +.labs-view-toggle button.is-on { + background: #fff; + color: var(--grey-900, #111827); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} + +/* ============================================================================= + LABS GRID / CARDS + ============================================================================= */ +.labs-grid { + display: block; /* Let Algolia's list be the grid */ +} + +/* Algolia InstantSearch creates .ais-Hits-list - make it the grid */ +.labs-grid .ais-Hits-list { + display: grid; + gap: 20px; + list-style: none; + margin: 0; + padding: 0; + border: none !important; + background: transparent !important; + box-shadow: none !important; +} + +.labs-grid.view-cards .ais-Hits-list { + grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); +} + +.labs-grid.view-list .ais-Hits-list { + grid-template-columns: 1fr; +} + +/* Algolia wraps each hit in .ais-Hits-item - reset all default styles */ +.labs-grid .ais-Hits, +.labs-grid .ais-Hits-item { + display: block; + list-style: none; + margin: 0; + padding: 0; + border: none !important; + background: transparent !important; + box-shadow: none !important; + border-radius: 0; +} + +.labs-card { + display: flex; + flex-direction: column; + padding: 20px; + background: var(--body-background); + border: 1px solid var(--grey-200, #e5e7eb); + border-radius: 12px; + text-decoration: none; + color: inherit; + transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s; +} + +.labs-card:hover { + border-color: var(--grey-300, #d1d5db); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06); + transform: translateY(-2px); + text-decoration: none; +} + +.labs-card.is-featured { + border-color: rgba(226, 67, 40, 0.3); + background: linear-gradient(135deg, rgba(226, 67, 40, 0.03) 0%, transparent 60%); +} + +.labs-card-head { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 12px; + margin-bottom: 10px; +} + +.labs-card-title { + font-size: 15px; + font-weight: 600; + color: var(--body-font-color); + line-height: 1.35; + margin: 0; +} + +.labs-card-featured { + font-size: 9px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.05em; + color: #e24328; + background: rgba(226, 67, 40, 0.1); + padding: 3px 6px; + border-radius: 4px; + flex-shrink: 0; +} + +.labs-card-desc { + font-size: 13px; + line-height: 1.5; + color: var(--body-faint-font-color, #64748b); + margin: 0 0 16px; + flex: 1; +} + +.labs-card-foot { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} + +.labs-card-meta { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; +} + +.labs-card-diff { + font-size: 11px; + font-weight: 500; + text-transform: capitalize; + padding: 3px 8px; + border-radius: 4px; + background: var(--grey-100, #f3f4f6); + color: var(--grey-600, #4b5563); +} + +.labs-card-diff.is-beginner { + background: rgba(34, 197, 94, 0.1); + color: #15803d; +} + +.labs-card-diff.is-intermediate { + background: rgba(234, 179, 8, 0.12); + color: #a16207; +} + +.labs-card-diff.is-advanced { + background: rgba(226, 67, 40, 0.1); + color: #b1351c; +} + +.labs-card-time { + display: flex; + align-items: center; + gap: 4px; + font-size: 11px; + color: var(--grey-500, #6b7280); +} + +.labs-card-tags { + display: flex; + gap: 6px; + flex-wrap: wrap; +} + +.labs-card-tag { + font-size: 10px; + color: var(--grey-500, #6b7280); + background: var(--grey-100, #f3f4f6); + padding: 2px 6px; + border-radius: 4px; + white-space: nowrap; +} + +/* List view adjustments */ +.labs-grid.view-list .labs-card { + flex-direction: row; + align-items: center; + padding: 16px 20px; + gap: 20px; +} + +.labs-grid.view-list .labs-card-head { + margin-bottom: 4px; +} + +.labs-grid.view-list .labs-card-foot { + margin-left: auto; + flex-direction: column; + align-items: flex-end; + gap: 8px; +} + +.labs-grid.view-list .labs-card-desc { + margin-bottom: 0; + flex: 1; +} + +/* ============================================================================= + EMPTY STATE + ============================================================================= */ +.labs-empty { + text-align: center; + padding: 64px 24px; + background: var(--grey-50, #f9fafb); + border-radius: 12px; +} + +.labs-empty-icon { + width: 56px; + height: 56px; + margin: 0 auto 16px; + background: var(--grey-100, #f3f4f6); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + color: var(--grey-400, #9ca3af); +} + +.labs-empty h3 { + font-size: 16px; + font-weight: 600; + color: var(--grey-900, #111827); + margin: 0 0 8px; +} + +.labs-empty p { + font-size: 13px; + color: var(--grey-500, #6b7280); + margin: 0 0 20px; +} + +.labs-empty-clear { + font-size: 13px; + font-weight: 500; + color: var(--link-highlight-color, #4b44ff); + background: transparent; + border: 1px solid var(--link-highlight-color, #4b44ff); + padding: 8px 16px; + border-radius: 6px; + cursor: pointer; + transition: background 0.15s, color 0.15s; +} + +.labs-empty-clear:hover { + background: var(--link-highlight-color, #4b44ff); + color: #fff; +} + +/* ============================================================================= + PAGINATION + ============================================================================= */ +.labs-pager { + display: flex; + align-items: center; + justify-content: center; + gap: 6px; + margin-top: 32px; +} + +.labs-pager-btn, +.labs-pager-num { + padding: 8px 12px; + font-size: 13px; + font-weight: 500; + color: var(--grey-600, #4b5563); + background: transparent; + border: 1px solid var(--grey-200, #e5e7eb); + border-radius: 6px; + cursor: pointer; + transition: background 0.12s, color 0.12s; +} + +.labs-pager-btn:hover:not(:disabled), +.labs-pager-num:hover { + background: var(--grey-100, #f3f4f6); +} + +.labs-pager-btn:disabled { + opacity: 0.4; + cursor: not-allowed; +} + +.labs-pager-num.is-on { + background: var(--link-highlight-color, #4b44ff); + border-color: var(--link-highlight-color, #4b44ff); + color: #fff; +} + +/* ============================================================================= + CTA SECTION + ============================================================================= */ +.labs-cta { + margin-top: 48px; + padding: 32px; + background: linear-gradient(135deg, var(--grey-50, #f9fafb) 0%, var(--grey-100, #f3f4f6) 100%); + border: 1px solid var(--grey-200, #e5e7eb); + border-radius: 12px; + display: flex; + align-items: center; + justify-content: space-between; + gap: 24px; + flex-wrap: wrap; +} + +.labs-cta h3 { + font-size: 16px; + font-weight: 600; + color: var(--body-font-color); + margin: 0 0 4px; +} + +.labs-cta p { + font-size: 13px; + color: var(--body-faint-font-color, #64748b); + margin: 0; +} + +.labs-cta-btn { + display: inline-flex; + align-items: center; + gap: 8px; + font-size: 13px; + font-weight: 500; + color: var(--body-font-color); + background: #fff; + border: 1px solid var(--grey-200, #e5e7eb); + padding: 10px 16px; + border-radius: 8px; + text-decoration: none; + transition: background 0.15s; + flex-shrink: 0; +} + +.labs-cta-btn:hover { + background: var(--grey-100, #f3f4f6); + text-decoration: none; +} + +/* ============================================================================= + RESPONSIVE + ============================================================================= */ +@media screen and (max-width: 1024px) { + .labs-body { + grid-template-columns: 1fr; + gap: 24px; + } + + .labs-sidebar { + position: static; + max-height: none; + overflow: visible; + } + + .labs-hero { + padding: 48px 5vw 40px; + } + + .labs-hero-stats { + gap: 24px; + } +} + +@media screen and (max-width: 640px) { + .labs-grid.view-list .labs-card { + flex-direction: column; + gap: 12px; + } + + .labs-grid.view-list .labs-card-foot { + margin-left: 0; + flex-direction: column; + align-items: flex-start; + } + + .labs-cta { + flex-direction: column; + text-align: center; + } +} + +/* ============================================================================= + DARK MODE + ============================================================================= */ + +/* Labs body background */ +html[data-theme="dark"] .labs-body { + background: var(--body-background, #0f172a); +} + +/* Results count text */ +html[data-theme="dark"] .labs-results-count { + color: rgba(255, 255, 255, 0.7); +} + +html[data-theme="dark"] .labs-results-count strong { + color: rgba(255, 255, 255, 0.95); +} + +html[data-theme="dark"] .labs-results-filter-note { + color: rgba(255, 255, 255, 0.5); +} + +html[data-theme="dark"] .labs-sort select { + background-color: rgba(255, 255, 255, 0.04); + border-color: rgba(255, 255, 255, 0.1); +} + +html[data-theme="dark"] .labs-view-toggle { + background: rgba(255, 255, 255, 0.04); + border-color: rgba(255, 255, 255, 0.1); +} + +html[data-theme="dark"] .labs-view-toggle button { + color: rgba(255, 255, 255, 0.6); +} + +html[data-theme="dark"] .labs-view-toggle button:not(:last-child) { + border-color: rgba(255, 255, 255, 0.1); +} + +html[data-theme="dark"] .labs-view-toggle button.is-on { + background: rgba(255, 255, 255, 0.1); + color: rgba(255, 255, 255, 0.95); +} + +/* Algolia hits wrapper - remove any default styling */ +html[data-theme="dark"] .labs-grid .ais-Hits, +html[data-theme="dark"] .labs-grid .ais-Hits-list, +html[data-theme="dark"] .labs-grid .ais-Hits-item { + background: transparent; + border: none; +} + +/* Labs cards in dark mode */ +html[data-theme="dark"] .labs-card { + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(255, 255, 255, 0.08); +} + +html[data-theme="dark"] .labs-card:hover { + background: rgba(255, 255, 255, 0.05); + border-color: rgba(255, 255, 255, 0.15); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); +} + +html[data-theme="dark"] .labs-card-title { + color: rgba(255, 255, 255, 0.95); +} + +html[data-theme="dark"] .labs-card-desc { + color: rgba(255, 255, 255, 0.6); +} + +html[data-theme="dark"] .labs-card-time { + color: rgba(255, 255, 255, 0.5); +} + +html[data-theme="dark"] .labs-card-tag { + background: rgba(255, 255, 255, 0.08); + color: rgba(255, 255, 255, 0.6); +} + +html[data-theme="dark"] .labs-card-diff { + background: rgba(255, 255, 255, 0.08); + color: rgba(255, 255, 255, 0.7); +} + +html[data-theme="dark"] .labs-card-diff.is-beginner { + background: rgba(34, 197, 94, 0.15); + color: #4ade80; +} + +html[data-theme="dark"] .labs-card-diff.is-intermediate { + background: rgba(234, 179, 8, 0.15); + color: #fbbf24; +} + +html[data-theme="dark"] .labs-card-diff.is-advanced { + background: rgba(226, 67, 40, 0.15); + color: #f87171; +} + +html[data-theme="dark"] .labs-card-featured { + background: rgba(226, 67, 40, 0.2); + color: #f87171; +} + +html[data-theme="dark"] .labs-card.is-featured { + border-color: rgba(226, 67, 40, 0.25); + background: linear-gradient(135deg, rgba(226, 67, 40, 0.08) 0%, transparent 60%); +} + +html[data-theme="dark"] .labs-empty { + background: rgba(255, 255, 255, 0.02); + border: 1px solid rgba(255, 255, 255, 0.06); +} + +html[data-theme="dark"] .labs-empty-icon { + background: rgba(255, 255, 255, 0.06); + color: rgba(255, 255, 255, 0.4); +} + +html[data-theme="dark"] .labs-empty h3 { + color: rgba(255, 255, 255, 0.95); +} + +html[data-theme="dark"] .labs-empty p { + color: rgba(255, 255, 255, 0.6); +} + +html[data-theme="dark"] .labs-pager-btn, +html[data-theme="dark"] .labs-pager-num { + border-color: rgba(255, 255, 255, 0.1); + color: rgba(255, 255, 255, 0.7); +} + +html[data-theme="dark"] .labs-pager-btn:hover:not(:disabled), +html[data-theme="dark"] .labs-pager-num:hover { + background: rgba(255, 255, 255, 0.08); +} + +html[data-theme="dark"] .labs-cta { + background: linear-gradient(135deg, rgba(255, 255, 255, 0.02) 0%, rgba(255, 255, 255, 0.04) 100%); + border-color: rgba(255, 255, 255, 0.08); +} + +html[data-theme="dark"] .labs-cta h3 { + color: rgba(255, 255, 255, 0.95); +} + +html[data-theme="dark"] .labs-cta p { + color: rgba(255, 255, 255, 0.6); +} + +html[data-theme="dark"] .labs-cta-btn { + background: rgba(255, 255, 255, 0.06); + border-color: rgba(255, 255, 255, 0.1); + color: rgba(255, 255, 255, 0.9); +} + +html[data-theme="dark"] .labs-cta-btn:hover { + background: rgba(255, 255, 255, 0.1); +} diff --git a/src/css/main.css b/src/css/main.css index 3fee1d9f..61449914 100644 --- a/src/css/main.css +++ b/src/css/main.css @@ -34,7 +34,7 @@ body.status-404 main > .content { } main:not(.labs):not(.home-content) { - width: calc(100% - var(--nav-width)); + width: 100%; } .home main { @@ -53,8 +53,12 @@ body.status-404 main > .content { display: flex; /* display: grid; */ /* grid-template-columns: 3fr 1fr; */ - gap: 50px; + gap: 56px; /* Prototype exact value */ justify-content: center; + max-width: 1280px; /* Prototype page-wrap max-width */ + width: 100%; + margin: 0 auto; + padding: 40px 48px 120px; /* Prototype exact padding */ /* Prevent CLS by isolating content layout */ contain: layout; } @@ -68,12 +72,26 @@ body.status-404 main > .content { } } +/* Narrow desktop: reduce gap and padding to fit content area */ +@media screen and (min-width: 1024px) and (max-width: 1399px) { + main > .content { + gap: 32px; + padding: 32px 32px 80px; + } +} + @media screen and (min-width: 1400px) { aside.toc.sidebar { flex-basis: var(--toc-width--widescreen); } main > .content { - gap: 150px; + gap: 64px; /* Slightly larger gap on wide screens */ } } + +/* Chat panel overlay - no content push, panel floats over TOC */ +/* The .chat-push class is added by JS but we don't modify layout */ +main.article.chat-push { + /* Intentionally empty - chat panel overlays content via position: fixed */ +} diff --git a/src/css/markdown-dropdown.css b/src/css/markdown-dropdown.css index bdf7c04c..e2fdedb4 100644 --- a/src/css/markdown-dropdown.css +++ b/src/css/markdown-dropdown.css @@ -6,43 +6,51 @@ gap: 10px; } -/* Position in metadata container */ -.article .metadata .markdown-dropdown { +/* Markdown dropdown in sticky header */ +.component-indicator-sticky .markdown-dropdown { position: relative; display: inline-block; - margin-left: auto; /* Push to right */ - height: 30px; + margin-left: auto; + /* Ensure focus outline isn't clipped - use padding without negative margins */ + padding: 4px; } -/* Toggle Button */ +/* Toggle Button - styled to match version selector pill */ .markdown-dropdown-toggle { display: inline-flex; align-items: center; - gap: 0.375rem; - padding: 0.375rem 0.75rem; - border: 1px solid var(--color-smoke-70, #ddd); - border-radius: 0.25rem; - background: var(--color-white, #fff); - color: var(--color-jet-70, #333); - font-size: 0.875rem; + gap: 6px; + padding: 6px 12px; + border: 1px solid var(--color-smoke-70, #dcdcde); + border-radius: 99px; + background: var(--color-smoke-30, #f4f4f5); + color: var(--color-jet-80, #48484a); + font-size: 11px; + font-weight: 600; font-family: inherit; cursor: pointer; - transition: all 0.2s ease; + transition: background 0.15s ease, border-color 0.15s ease; +} + +/* In sticky header context - ensure consistent sizing */ +.component-indicator-sticky .markdown-dropdown-toggle { + padding: 4px 10px; + font-size: 11px; } .markdown-dropdown-toggle:hover { - background: var(--color-smoke-10, #f8f8f8); - border-color: var(--color-smoke-90, #bbb); + background: var(--color-smoke-50, #e8e8ea); + border-color: var(--color-smoke-90, #c3c4c6); } .markdown-dropdown-toggle:focus { - outline: 2px solid var(--color-blue-50, #0066cc); + outline: 2px solid var(--link-highlight-color, #444ce7); outline-offset: 2px; } .markdown-dropdown-toggle[aria-expanded="true"] { - background: var(--color-smoke-10, #f8f8f8); - border-color: var(--color-smoke-90, #bbb); + background: var(--color-smoke-50, #e8e8ea); + border-color: var(--color-smoke-90, #c3c4c6); } .markdown-icon { @@ -55,6 +63,7 @@ .dropdown-caret { flex-shrink: 0; + opacity: 0.6; transition: transform 0.2s ease; } @@ -62,24 +71,29 @@ transform: rotate(180deg); } -/* Dropdown Menu */ +html[data-theme=dark] .dropdown-caret { + opacity: 0.5; +} + +/* Dropdown Menu - styled to match version selector panel */ .markdown-dropdown-menu { - top: calc(100% + 0.25rem); + top: calc(100% + 6px); position: absolute; right: 0; z-index: 1000; - min-width: 200px; - padding: 0.25rem; - border: 1px solid var(--color-smoke-70, #ddd); - border-radius: 0.375rem; + min-width: 220px; + max-width: calc(100vw - 32px); /* Prevent overflow on narrow viewports */ + padding: 6px; + border: 1px solid var(--color-smoke-70, #dcdcde); + border-radius: 12px; background: var(--color-white, #fff); box-shadow: - 0 4px 6px -1px rgba(0, 0, 0, 0.1), - 0 2px 4px -1px rgba(0, 0, 0, 0.06); + 0 4px 12px rgba(0, 0, 0, 0.08), + 0 2px 4px rgba(0, 0, 0, 0.04); opacity: 0; visibility: hidden; - transform: translateY(-0.5rem); - transition: all 0.15s ease; + transform: translateY(-4px); + transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s; } .markdown-dropdown-menu.is-open { @@ -92,14 +106,14 @@ .markdown-dropdown-item { display: flex; align-items: center; - gap: 0.75rem; + gap: 10px; width: 100%; - padding: 0.5rem 0.75rem; + padding: 10px 12px; border: none; - border-radius: 0.25rem; + border-radius: 8px; background: transparent; - color: var(--color-jet-70, #333); - font-size: 0.875rem; + color: var(--color-jet-80, #48484a); + font-size: 14px; font-family: inherit; text-align: left; cursor: pointer; @@ -107,12 +121,12 @@ } .markdown-dropdown-item:hover { - background: var(--color-smoke-10, #f8f8f8); + background: var(--color-smoke-30, #f4f4f5); } .markdown-dropdown-item:focus { outline: none; - background: var(--color-smoke-30, #e8e8e8); + background: var(--color-smoke-50, #e8e8ea); } .markdown-dropdown-item svg { @@ -152,13 +166,15 @@ /* Responsive */ @media (max-width: 768px) { - .article .metadata .markdown-dropdown { - margin-left: 0; /* Reset margin on mobile */ + .page-options-container { + justify-content: flex-start; } + /* On mobile, position dropdown to stay within viewport */ .markdown-dropdown-menu { - right: auto; - left: 0; + right: -8px; /* Slight offset to stay within viewport */ + left: auto; + min-width: 200px; } .markdown-text { @@ -170,37 +186,48 @@ } } -/* Dark mode support */ +/* Very narrow viewports - ensure dropdown doesn't overflow */ +@media (max-width: 480px) { + .markdown-dropdown-menu { + /* Keep absolute positioning relative to parent */ + right: -12px; + left: auto; + min-width: calc(100vw - 32px); + max-width: calc(100vw - 32px); + } +} + +/* Dark mode support - styled to match version selector */ html[data-theme=dark] .markdown-dropdown-toggle { - border-color: var(--color-smoke-90); - background: var(--body-background); - color: var(--body-font-color); + border-color: rgba(255, 255, 255, 0.12); + background: rgba(255, 255, 255, 0.06); + color: #e2e4e9; } html[data-theme=dark] .markdown-dropdown-toggle:hover, html[data-theme=dark] .markdown-dropdown-toggle[aria-expanded="true"] { - background: var(--panel-background); - border-color: var(--color-smoke-70); + background: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, 0.18); } html[data-theme=dark] .markdown-dropdown-menu { - border-color: var(--color-smoke-90); - background: var(--body-background); + border-color: rgba(255, 255, 255, 0.1); + background: #1d1e26; box-shadow: - 0 4px 6px -1px rgba(0, 0, 0, 0.5), - 0 2px 4px -1px rgba(0, 0, 0, 0.3); + 0 8px 24px rgba(0, 0, 0, 0.4), + 0 2px 8px rgba(0, 0, 0, 0.3); } html[data-theme=dark] .markdown-dropdown-item { - color: var(--body-font-color); + color: #e2e4e9; } html[data-theme=dark] .markdown-dropdown-item:hover { - background: var(--panel-background); + background: rgba(255, 255, 255, 0.06); } html[data-theme=dark] .markdown-dropdown-item:focus { - background: var(--nav-background); + background: rgba(255, 255, 255, 0.1); } /* Accessibility: Reduce motion */ diff --git a/src/css/metadata.css b/src/css/metadata.css index bb3950b7..fcbe7c02 100644 --- a/src/css/metadata.css +++ b/src/css/metadata.css @@ -282,6 +282,112 @@ margin: 0; } +/* BYOC Badge */ +.badge--byoc { + color: var(--byoc-label-background); + font-weight: bold; + background-color: var(--byoc-highlight-background-color); +} + +.badge--large.badge--byoc { + background-color: var(--byoc-label-background); + color: var(--byoc-label-color); +} + +.byoc-label { + display: inline-flex; + margin: 0; + font-size: calc(18 / var(--rem-base) * 1rem); +} + +.byoc-label > p { + flex: 0 1 auto; + border-radius: 10px; + font-weight: bold; + text-align: center; + color: var(--byoc-label-color); + background-color: var(--byoc-label-background); + padding: 3px; + min-width: 100px; + margin: 0; + cursor: help; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.nav-byoc-container { + display: inline-flex; +} + +.nav-byoc-label { + font-size: calc(18 / var(--rem-base) * 1rem); + font-weight: bold; + min-width: 100px; + padding: 3px; + border-radius: 10px; + color: var(--byoc-label-color); + background-color: var(--byoc-label-background); + cursor: help; + display: inline-flex; + align-items: center; + justify-content: center; + margin: 0; +} + +/* Cloud Badge */ +.badge--cloud { + color: var(--cloud-label-background); + font-weight: bold; + background-color: var(--cloud-highlight-background-color); +} + +.badge--large.badge--cloud { + background-color: var(--cloud-label-background); + color: var(--cloud-label-color); +} + +.cloud-label { + display: inline-flex; + margin: 0; + font-size: calc(18 / var(--rem-base) * 1rem); +} + +.cloud-label > p { + flex: 0 1 auto; + border-radius: 10px; + font-weight: bold; + text-align: center; + color: var(--cloud-label-color); + background-color: var(--cloud-label-background); + padding: 3px; + min-width: 100px; + margin: 0; + cursor: help; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.nav-cloud-container { + display: inline-flex; +} + +.nav-cloud-label { + font-size: calc(18 / var(--rem-base) * 1rem); + font-weight: bold; + min-width: 100px; + padding: 3px; + border-radius: 10px; + color: var(--cloud-label-color); + background-color: var(--cloud-label-background); + cursor: help; + display: inline-flex; + align-items: center; + justify-content: center; + margin: 0; +} + @media (max-width: 768px) { .article .metadata { flex-direction: column; diff --git a/src/css/nav.css b/src/css/nav.css index f10f303c..994b4254 100644 --- a/src/css/nav.css +++ b/src/css/nav.css @@ -1,22 +1,167 @@ :root { - --nav-side-padding: 22px; + --nav-side-padding: 18px; /* Prototype uses 18px */ --nav-item-side-padding: 10px; + --sidebar-width: 280px; /* Match prototype */ +} + +/* ============================================================================= + SIDEBAR — Dark theme navigation panel + ============================================================================= */ + +.sidebar { + background: var(--sidebar-bg, #161e2d); + color: var(--sidebar-fg, #c6cedc); + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; /* Prevent sidebar from growing beyond viewport */ +} + +/* Sidebar Header */ +.sb-head { + padding: 18px var(--nav-side-padding) 14px; /* Prototype: 18px 18px 14px */ + flex-shrink: 0; +} + +.sb-head-link { + display: flex; + align-items: center; + gap: 10px; + text-decoration: none; + color: inherit; + border-radius: 8px; + padding: 4px; + margin: -4px; + transition: background 0.12s; +} + +.sb-head-link:hover { + background: var(--sidebar-item-hover-bg, rgba(255, 255, 255, 0.05)); +} + +.sb-logomark { + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.sb-logomark img { + width: 28px; + height: 28px; +} + +.sb-brand-title { + font-size: 15px; + font-weight: 600; + color: #fff; + letter-spacing: -0.01em; + line-height: 1.2; +} + +.sb-brand-sub { + font-size: 11.5px; + color: var(--sidebar-fg-muted, #a8b2c7); + letter-spacing: -0.005em; + margin-top: 1px; +} + +/* Sidebar Search Bar */ +/* Search button - reset default button styles */ +button.sb-search { + font: inherit; + color: inherit; + cursor: pointer; + text-align: left; + width: calc(100% - 28px); /* Account for margins */ +} + +button.sb-search:focus-visible { + outline: 2px solid var(--link-font-color); + outline-offset: 2px; +} + +.sb-search { + display: flex; + align-items: center; + gap: 8px; + margin: 2px 14px 12px; /* Prototype exact values */ + padding: 8px 10px; /* Prototype exact values */ + background: rgba(255, 255, 255, 0.04); /* Prototype exact */ + border: 1px solid rgba(255, 255, 255, 0.06); /* Prototype exact */ + border-radius: 8px; /* Prototype uses 8px */ + cursor: pointer; + font-size: 13px; + color: #8098b3; /* Prototype search text color */ + transition: background 0.12s, border-color 0.12s; + flex-shrink: 0; +} + +.sb-search:hover { + background: rgba(255, 255, 255, 0.07); /* Prototype exact */ +} + +.sb-search svg { + color: var(--sidebar-fg-muted, #a8b2c7); + flex-shrink: 0; +} + +.sb-search-text { + flex: 1; + font-size: 13px; + color: var(--sidebar-fg-muted, #a8b2c7); + letter-spacing: -0.005em; +} + +.sb-search-kbd { + display: flex; + gap: 2px; +} + +.sb-search-kbd kbd { + font-family: var(--font-sans, "Inter", sans-serif); + font-size: 10.5px; + font-weight: 500; + padding: 2px 5px; + background: rgba(255, 255, 255, 0.1); + border: 1px solid rgba(255, 255, 255, 0.12); + border-radius: 4px; + color: var(--sidebar-fg-muted, #a8b2c7); +} + +/* Sidebar Scrollable Content */ +.sb-scroll { + flex: 1; + min-height: 0; /* Critical for flex children to respect parent constraints */ + overflow-y: auto; + overflow-x: hidden; + -ms-overflow-style: none; + scrollbar-width: none; +} + +.sb-scroll::-webkit-scrollbar { + display: none; } .nav-container { position: fixed; - top: calc(var(--navbar-height) + var(--toolbar-height)); + top: 0; left: 0; bottom: 0; - width: 100%; + width: var(--sidebar-width, 260px); font-size: var(--secondary-font-size); z-index: var(--z-index-nav); visibility: hidden; - overflow-y: scroll; } -.nav-collapse, -.nav-expand { +/* Mobile nav overlay - higher z-index to cover toolbar when active */ +html .nav-container.is-active { + z-index: 5; +} + +.nav-collapse { font-size: var(--secondary-font-size); color: var(--body-font-color); z-index: 8; @@ -31,13 +176,11 @@ padding: 12px var(--nav-side-padding); cursor: pointer; transition: opacity 0.2s ease; - opacity: 0.6; background: var(--nav-background); border-top: 1px solid var(--nav-border-color); } -.nav-collapse:hover, -.nav-expand:hover { +.nav-collapse:hover { opacity: 1; } @@ -49,29 +192,17 @@ opacity: 0.6; } -.nav-expand { - position: fixed; - background: var(--body-background); - border: 1.5px solid rgba(128, 152, 249, 0.5); - border-radius: 6px; - padding: 8px 12px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); - z-index: 100; - left: 5px; - bottom: 30px; - width: auto; -} - -.nav-expand img { - transform: rotate(180deg); -} - @media screen and (max-width: 1023px) { .nav-container { width: var(--nav-width); top: calc(var(--navbar-height) + var(--announcement-bar-height)); } + /* When nav is open on mobile, ensure it overlays the toolbar */ + .nav-container.is-active { + z-index: 5 !important; + } + .nav-panel-explore { top: 20px !important; } @@ -81,25 +212,27 @@ .nav-container { font-size: var(--secondary-font-size); flex: none; - border-right: 1px solid var(--nav-border-color); + border-right: none; display: block; - position: sticky; + position: fixed; visibility: visible; - height: calc(100vh - var(--navbar-height) - var(--announcement-bar-height--desktop)); - top: calc(var(--navbar-height) + var(--announcement-bar-height--desktop)); - width: var(--nav-width); - } - - .nav-expand:not(.hidden) { - display: flex; + height: calc(100vh - var(--announcement-bar-height--desktop)); + top: var(--announcement-bar-height--desktop); + width: var(--sidebar-width, 260px); } .nav { overflow-y: hidden; + height: 100%; } .nav-collapse { - display: flex; + display: none; + } + + /* Override for sidebar footer collapse button - keep it visible */ + .sb-footer .sb-collapse-toggle { + display: inline-grid; } } @@ -113,16 +246,14 @@ } .nav { - background: var(--nav-background); font-size: var(--secondary-font-size); position: relative; -ms-overflow-style: none; /* IE and Edge */ scrollbar-width: none; /* Firefox */ overscroll-behavior: none; - overflow-y: scroll; -webkit-clip-path: inset(0); clip-path: inset(0); - height: inherit !important; + height: 100% !important; } @media screen and (min-width: 769px) { @@ -141,15 +272,74 @@ color: inherit; } +/* Version container base styling */ +.context .container { + display: flex; + align-items: center; + gap: 4px; + font-size: 12px; + font-weight: 500; + color: var(--sidebar-fg-muted, #a8b2c7); +} + +/* Version container WITH dropdown - full button styling */ .context .container.has-dropdown { - border: 1px solid var(--highlight-border); + border: 1px solid rgba(255, 255, 255, 0.1); width: 100%; - border-radius: var(--border-radius-radius-md); + border-radius: 10px; display: flex; justify-content: space-between; align-items: center; - padding: 2px var(--nav-item-side-padding); + padding: 10px 14px; position: relative; + cursor: pointer; + transition: background 0.15s, border-color 0.15s; + background: transparent; +} + +/* Version container WITHOUT dropdown - subtle pill styling */ +.context .container:not(.has-dropdown) { + padding: 6px 10px; + border-radius: 6px; + background: rgba(255, 255, 255, 0.06); + transition: background 0.15s; +} + +.sidebar[data-theme="light"] .context .container:not(.has-dropdown) { + background: var(--grey-100-new, var(--grey-100, #f0f0f0)); + color: var(--grey-700-new, var(--grey-700, #4a4a4a)); +} + +/* Version selector button - reset button styles for accessibility */ +.version-selector-trigger { + all: unset; + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + cursor: pointer; + color: inherit; + font: inherit; +} + +.version-selector-trigger:focus-visible { + outline: 2px solid var(--link-font-color); + outline-offset: 2px; + border-radius: 4px; +} + +.context .container.has-dropdown:hover { + background: rgba(255, 255, 255, 0.03); + border-color: rgba(255, 255, 255, 0.15); +} + +.sidebar[data-theme="light"] .context .container.has-dropdown { + border-color: var(--grey-200-new, var(--grey-200, #c3c4c6)); +} + +.sidebar[data-theme="light"] .context .container.has-dropdown:hover { + background: var(--grey-50-new, var(--grey-50, #f5f5f5)); + border-color: var(--grey-300-new, var(--grey-300, #aaabae)); } .context .container.has-dropdown .components, @@ -158,17 +348,39 @@ position: absolute; left: 0; right: 0; - margin-top: 35px; + top: calc(100% + 8px); align-items: center; - z-index: 2; - background-color: var(--body-background); + z-index: 100; + background: #1a2332; white-space: nowrap; - border-radius: var(--border-radius-radius-md); - padding: 8px 0; - -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); - border: 1px solid #ccc; - color: var(--body-font-color); + border-radius: 12px; + padding: 8px; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.32); + border: 1px solid rgba(255, 255, 255, 0.08); + color: #e8eef6; + animation: versionMenuIn 0.15s ease-out; +} + +@keyframes versionMenuIn { + from { + opacity: 0; + transform: translateY(-4px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +.sidebar[data-theme="light"] .context .container.has-dropdown .components, +.sidebar[data-theme="light"] .context .container.has-dropdown .versions { + background: #fff; + border-color: var(--grey-200-new, var(--grey-200, #c3c4c6)); + box-shadow: + 0 1px 3px rgba(0, 0, 0, 0.04), + 0 8px 24px rgba(0, 0, 0, 0.12); + color: var(--grey-900-new, var(--grey-900, #181818)); } .context:hover { @@ -177,7 +389,23 @@ .context .container.has-dropdown .components a, .context .container.has-dropdown .versions a { - padding: 4px var(--nav-item-side-padding); + padding: 10px 12px; + border-radius: 8px; + transition: background 0.12s; + display: block; + font-size: 13px; + font-weight: 500; + letter-spacing: -0.005em; +} + +.context .container.has-dropdown .components a:hover, +.context .container.has-dropdown .versions a:hover { + background: rgba(255, 255, 255, 0.05); +} + +.sidebar[data-theme="light"] .context .container.has-dropdown .components a:hover, +.sidebar[data-theme="light"] .context .container.has-dropdown .versions a:hover { + background: var(--grey-50-new, var(--grey-50, #f5f5f5)); } .context .container.has-dropdown.is-active .components, @@ -185,7 +413,7 @@ display: flex; flex-direction: column; position: absolute; - top: 0; + top: calc(100% + 8px); /* Position below parent, not covering it */ } .article.lab .nav .panels { @@ -199,7 +427,7 @@ html.is-clipped--nav { .nav-menu { position: relative; line-height: var(--nav-line-height); - padding: calc(var(--toolbar-top-padding) - 8px) var(--nav-side-padding) 32px; + padding: 4px var(--nav-side-padding) 32px; /* Isolate rendering for performance */ contain: layout style; } @@ -212,11 +440,33 @@ html.is-clipped--nav { } .nav-menu h3.title { - color: var(--nav-heading-font-color); - font-size: inherit; - font-family: var(--body-font-family-bold); + display: flex; + align-items: center; + gap: 8px; /* Prototype: 8px gap */ + padding: 8px 10px; /* Prototype: 8px 10px */ + color: #a8b2c7; /* Prototype exact color */ + font-size: 13px; /* Prototype: 13px */ + font-weight: 500; /* Prototype: 500 */ + font-family: var(--body-font-family); + border-radius: 5px; /* Prototype: 5px */ margin: 0; - padding: 0.25em 0 0.125em; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + cursor: pointer; + transition: background 0.12s; +} + +.nav-menu h3.title:hover { + background: rgba(255, 255, 255, 0.04); /* Prototype exact */ +} + +html[data-theme="light"] .nav-menu h3.title { + color: var(--grey-700-new, var(--grey-700, #44454a)); /* Prototype light mode */ +} + +html[data-theme="light"] .nav-menu h3.title:hover { + background: var(--grey-50-new, var(--grey-50, #f5f5f5)); /* Prototype light mode */ } .nav-list { @@ -224,13 +474,32 @@ html.is-clipped--nav { margin: 0; padding: 0; width: 100%; - color: var(--color-aliases-static-palette-text-secondary); + color: var(--sidebar-fg, #c6cedc); margin-left: 8px; } +/* Nested nav-list has left border like prototype .sb-children */ +.nav-item > .nav-list { + padding-left: 10px; /* Prototype: 10px */ + border-left: 1px solid rgba(255, 255, 255, 0.06); /* Prototype exact */ + margin-left: 0; +} + +html[data-theme="light"] .nav-item > .nav-list { + border-left-color: var(--grey-100-new, var(--grey-100, #e9eaeb)); /* Prototype light mode */ +} + /* Target the very first nav-menu and remove the margin-left */ +/* Style top-level nav (parent component's own nav before buckets) like a bucket */ .nav-menu > .nav-list { margin-left: 0; + padding-left: 10px; + margin-bottom: 12px; + border-left: 2px solid rgba(122, 145, 176, 0.15); +} + +html[data-theme="light"] .nav-menu > .nav-list { + border-left-color: rgba(107, 108, 111, 0.15); } li.nav-item { @@ -246,19 +515,30 @@ li.nav-item { min-height: 30px; justify-content: space-between; align-items: center; - padding: 8px var(--nav-item-side-padding); - border-radius: var(--border-radius-radius-md); - margin-bottom: 4px; + gap: 6px; /* Prototype: 6px gap between icon/text/caret */ + padding: 6px 10px; /* Prototype: 6px 10px */ + border-radius: 5px; /* Prototype: 5px */ + color: #8098b3; /* Prototype: exact color */ + font-size: 13px; /* Prototype: 13px */ + letter-spacing: -0.0125em; /* Prototype: exact tracking */ + line-height: 1.35; /* Prototype: 1.35 */ + cursor: pointer; + transition: background 0.12s, color 0.12s; +} + +.nav-list > li > .item:hover { + background: var(--component-bg-tint, rgba(255, 255, 255, 0.04)); + color: #dbe2ee; } -.nav-list > li > .item:hover, .nav-list > li > .is-current-page { - background-color: var(--link-highlight-background-color); - color: var(--link-highlight-color); + background: var(--component-bg-tint-hover, rgba(255, 255, 255, 0.08)); + color: #fff; + font-weight: 500; } .nav-list .is-current-path > div.item:first-child { - color: var(--link-highlight-color); + color: #fff; } .nav-list a { @@ -295,18 +575,26 @@ a.nav-text { display: flex; justify-content: center; align-items: center; - filter: var(--nav-toggle-filter); outline: none; line-height: inherit; padding: 0; - width: 2em; - height: 100%; - margin-right: -8px; + width: 12px; /* Prototype: 12px */ + height: 12px; /* Prototype: 12px */ + margin-left: auto; + flex-shrink: 0; + color: #5972a6; /* Prototype: caret color */ + transition: transform 0.15s ease; /* Prototype animation */ } .nav-item-toggle > img { filter: var(--nav-toggle-filter); - width: 0.6em; + width: 12px; /* Prototype: 12px */ + height: 12px; + opacity: 0.6; +} + +html[data-theme="light"] .nav-item-toggle { + color: var(--grey-500-new, var(--grey-500, #79797d)); /* Prototype light mode */ } .nav-item.is-active > .item > .nav-item-toggle { @@ -314,10 +602,9 @@ a.nav-text { } .nav-panel-explore { - position: sticky; + position: relative; z-index: 9; - background-color: var(--nav-background); - padding: 24px var(--nav-side-padding) 0; + padding: 0 var(--nav-side-padding) 12px; } .nav-panel-explore:not(:first-child) { @@ -342,8 +629,17 @@ a.nav-text { .nav-panel-explore .context .current-version, .nav-panel-explore .context .title { display: flex; - gap: 2px; + gap: 8px; justify-content: space-between; + font-size: 12px; + font-weight: 500; + color: inherit; + letter-spacing: -0.005em; +} + +.sidebar[data-theme="light"] .nav-panel-explore .context .current-version, +.sidebar[data-theme="light"] .nav-panel-explore .context .title { + color: var(--grey-900-new, var(--grey-900, #181818)); } .nav-panel-explore .context .version.is-latest, @@ -390,3 +686,910 @@ a.nav-text { background-size: contain; content: '(Limited)'; } + +.nav-link.cloud-byoc::after, +.nav-link.cloud-only::after { + display: inline-flex; + align-items: center; + font-family: var(--font-mono, ui-monospace, SFMono-Regular, monospace); + font-size: 8px; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + padding: 2px 5px; + border-radius: 3px; + margin-left: 6px; + white-space: nowrap; + flex-shrink: 0; +} + +.nav-link.cloud-byoc::after { + content: 'SELF-MANAGED'; + color: #a8b2c7; + background: rgba(255, 255, 255, 0.06); + border: 1px solid rgba(255, 255, 255, 0.08); +} + +.nav-link.cloud-only::after { + content: 'MANAGED'; + color: #ffb8a3; + background: rgba(226, 67, 40, 0.14); + border: 1px solid rgba(226, 67, 40, 0.28); +} + +/* Status Footer - Shows system status at bottom of sidebar */ +.nav-status-footer { + position: sticky; + bottom: 0; + padding: 10px 16px; /* Prototype: 10px 16px */ + background: var(--sidebar-bg, #0f1727); + border-top: 1px solid rgba(255, 255, 255, 0.06); /* Prototype exact */ + z-index: 10; + flex-shrink: 0; + margin-top: auto; + font-size: 11.5px; /* Prototype: 11.5px */ + color: #5972a6; /* Prototype: muted color */ +} + +.nav-status-link { + display: flex; + align-items: center; + gap: 8px; + padding: 10px 12px; + background: transparent; + border-radius: 8px; + text-decoration: none; + color: inherit; + transition: background 0.12s; + font-size: 12.5px; +} + +.nav-status-link:hover { + background: rgba(255, 255, 255, 0.05); +} + +.sidebar[data-theme="light"] .nav-status-link:hover { + background: var(--grey-50-new, var(--grey-50, #f5f5f5)); +} + +.nav-status-dot { + width: 7px; /* Prototype: 7px */ + height: 7px; /* Prototype: 7px */ + border-radius: 50%; + background: var(--green-500, #10b981); /* Default: operational */ + flex-shrink: 0; + animation: statusPulse 2s ease-in-out infinite; +} + +/* Status indicator colors from Statuspage API */ +.nav-status-dot.status-none { + background: var(--green-500, #10b981); /* All systems operational */ +} + +.nav-status-dot.status-minor { + background: var(--yellow-500, #f59e0b); /* Minor issues */ +} + +.nav-status-dot.status-major { + background: var(--orange-500, #f97316); /* Major issues */ +} + +.nav-status-dot.status-critical { + background: var(--red-500, #ef4444); /* Critical issues */ +} + +.nav-status-dot.status-unknown { + background: var(--grey-400, #9ca3af); /* Unable to fetch */ + animation: none; +} + +@keyframes statusPulse { + 0%, + 100% { + opacity: 1; + } + + 50% { + opacity: 0.6; + } +} + +.nav-status-text { + flex: 1; + color: #aab8ca; + font-weight: 500; + letter-spacing: -0.005em; +} + +.sidebar[data-theme="light"] .nav-status-text { + color: var(--grey-600-new, var(--grey-600, #606164)); +} + +.nav-status-icon { + color: #7c8ca8; + flex-shrink: 0; +} + +.sidebar[data-theme="light"] .nav-status-icon { + color: var(--grey-500-new, var(--grey-500, #79797d)); +} + +/* ============================================================================= + SIDEBAR FOOTER — Theme toggle + Collapse button + ============================================================================= */ + +.sb-footer { + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px 16px; /* Prototype: 10px 16px */ + border-top: 1px solid rgba(255, 255, 255, 0.06); /* Prototype exact */ + flex-shrink: 0; + gap: 8px; /* Prototype: 8px */ + font-size: 11.5px; /* Prototype: 11.5px */ + color: #5972a6; /* Prototype: muted color */ + position: relative; + z-index: 1; /* Keep below dropdown menus (z-index: 100) */ +} + +.sb-theme-toggle, +.sb-collapse-toggle { + display: flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + background: transparent; + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 8px; + color: var(--sidebar-fg-muted, #a8b2c7); + cursor: pointer; + transition: background 0.12s, border-color 0.12s, color 0.12s; +} + +.sb-theme-toggle:hover, +.sb-collapse-toggle:hover { + background: rgba(255, 255, 255, 0.05); + border-color: rgba(255, 255, 255, 0.15); + color: #fff; +} + +/* Theme toggle icons - show sun in dark mode (to switch to light), moon in light mode (to switch to dark) */ +.sb-theme-icon--moon { + display: none; +} + +.sb-theme-icon--sun { + display: block; +} + +/* Dark mode: show sun icon (to switch to light) */ +html[data-theme="dark"] .sb-theme-icon--moon { + display: none; +} + +html[data-theme="dark"] .sb-theme-icon--sun { + display: block; +} + +/* Light mode: show moon icon (to switch to dark) */ +html[data-theme="light"] .sb-theme-icon--moon { + display: block; +} + +html[data-theme="light"] .sb-theme-icon--sun { + display: none; +} + +/* Light mode sidebar footer styles */ +html[data-theme="light"] .sb-footer { + border-top-color: var(--grey-100-new, var(--grey-100, #e9eaeb)); /* Prototype: grey-100 */ + color: var(--grey-500-new, var(--grey-500, #79797d)); /* Prototype: grey-500 */ +} + +html[data-theme="light"] .sb-theme-toggle, +html[data-theme="light"] .sb-collapse-toggle { + border-color: var(--grey-200-new, var(--grey-200, #c3c4c6)); + color: var(--grey-600-new, var(--grey-600, #606164)); +} + +html[data-theme="light"] .sb-theme-toggle:hover, +html[data-theme="light"] .sb-collapse-toggle:hover { + background: var(--grey-50-new, var(--grey-50, #f5f5f5)); + border-color: var(--grey-300-new, var(--grey-300, #aaabae)); + color: var(--grey-900-new, var(--grey-900, #181818)); +} + +/* Light mode sidebar footer styles - for sidebar-level theme attribute */ +.sidebar[data-theme="light"] .sb-footer { + border-top-color: var(--grey-100-new, var(--grey-100, #e9eaeb)); + color: var(--grey-500-new, var(--grey-500, #79797d)); +} + +.sidebar[data-theme="light"] .sb-theme-toggle, +.sidebar[data-theme="light"] .sb-collapse-toggle { + border-color: var(--grey-200-new, var(--grey-200, #c3c4c6)); + color: var(--grey-600-new, var(--grey-600, #606164)); +} + +.sidebar[data-theme="light"] .sb-theme-toggle:hover, +.sidebar[data-theme="light"] .sb-collapse-toggle:hover { + background: var(--grey-50-new, var(--grey-50, #f5f5f5)); + border-color: var(--grey-300-new, var(--grey-300, #aaabae)); + color: var(--grey-900-new, var(--grey-900, #181818)); +} + +/* Mobile adjustments - keep footer visible but adjust header */ +@media screen and (max-width: 1023px) { + /* Add padding to sidebar header on mobile to clear the toolbar */ + .sb-head { + padding-top: calc(var(--toolbar-height) + 8px); + } +} + +/* ============================================================================= + NAV EXPAND BUTTON — Shows when sidebar is collapsed + ============================================================================= */ + +.nav-expand { + position: fixed; + left: 16px; + bottom: 16px; + width: 40px; + height: 40px; + display: none; + align-items: center; + justify-content: center; + background: var(--body-background, #fff); + border: 1px solid var(--grey-200-new, var(--grey-200, #e5e5e5)); + border-radius: 10px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08), 0 4px 16px rgba(0, 0, 0, 0.04); + color: var(--grey-600-new, var(--grey-600, #606164)); + cursor: pointer; + transition: background 0.12s, border-color 0.12s, color 0.12s, box-shadow 0.12s; + z-index: 100; +} + +.nav-expand:hover { + background: var(--grey-50-new, var(--grey-50, #f8f8f8)); + border-color: var(--grey-300-new, var(--grey-300, #aaabae)); + color: var(--grey-900-new, var(--grey-900, #181818)); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12), 0 8px 24px rgba(0, 0, 0, 0.06); +} + +html[data-theme="dark"] .nav-expand { + background: #1a2332; + border-color: rgba(255, 255, 255, 0.1); + color: #a8b2c7; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2), 0 4px 16px rgba(0, 0, 0, 0.1); +} + +html[data-theme="dark"] .nav-expand:hover { + background: #232d3f; + border-color: rgba(255, 255, 255, 0.2); + color: #fff; +} + +/* Light mode expand button - ensure visibility */ +html[data-theme="light"] .nav-expand { + background: #fff; + border: 2px solid var(--grey-400-new, var(--grey-400, #94959a)); + color: var(--grey-700-new, var(--grey-700, #44454a)); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12), 0 4px 16px rgba(0, 0, 0, 0.08); +} + +html[data-theme="light"] .nav-expand:hover { + background: var(--grey-100-new, var(--grey-100, #e9eaeb)); + border-color: var(--grey-500-new, var(--grey-500, #79797d)); + color: var(--grey-900-new, var(--grey-900, #181818)); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18), 0 8px 24px rgba(0, 0, 0, 0.1); +} + +@media screen and (min-width: 1024px) { + .nav-expand:not(.hidden) { + display: flex; + } +} + +/* ============================================================================= + LIGHT MODE SIDEBAR + ============================================================================= */ + +html[data-theme="light"] .sidebar { + background: var(--grey-50-new, var(--grey-50, #f8f8f8)); + color: var(--grey-700-new, var(--grey-700, #44454a)); +} + +html[data-theme="light"] .sb-brand-title { + color: var(--grey-900-new, var(--grey-900, #181818)); +} + +html[data-theme="light"] .sb-brand-sub { + color: var(--grey-600-new, var(--grey-600, #606164)); +} + +html[data-theme="light"] .sb-search { + background: #fff; + border-color: var(--grey-200-new, var(--grey-200, #c3c4c6)); +} + +html[data-theme="light"] .sb-search:hover { + background: #fff; + border-color: var(--grey-300-new, var(--grey-300, #aaabae)); +} + +html[data-theme="light"] .sb-search svg { + color: var(--grey-500-new, var(--grey-500, #79797d)); +} + +html[data-theme="light"] .sb-search-text { + color: var(--grey-500-new, var(--grey-500, #79797d)); +} + +html[data-theme="light"] .sb-search-kbd kbd { + background: var(--grey-100-new, var(--grey-100, #e9eaeb)); + border-color: var(--grey-200-new, var(--grey-200, #c3c4c6)); + color: var(--grey-600-new, var(--grey-600, #606164)); +} + +/* Sidebar Version Selector Wrapper */ +.sb-version-wrap { + padding: 0 14px 12px; +} + +.sb-version-wrap:empty { + display: none; +} + +/* Adjust version selector pill styling for sidebar context */ +.sb-version-wrap .sm-ver-pill { + width: 100%; + justify-content: flex-start; + background: rgba(255, 255, 255, 0.04); + border: 1px solid rgba(255, 255, 255, 0.06); + border-radius: 8px; + padding: 8px 10px; +} + +.sb-version-wrap .sm-ver-pill:hover { + background: rgba(255, 255, 255, 0.07); +} + +html[data-theme="light"] .sb-version-wrap .sm-ver-pill { + background: #fff; + border-color: var(--grey-200-new, var(--grey-200, #c3c4c6)); +} + +html[data-theme="light"] .sb-version-wrap .sm-ver-pill:hover { + background: #fff; + border-color: var(--grey-300-new, var(--grey-300, #aaabae)); +} + +html[data-theme="light"] .nav-list { + color: var(--grey-600-new, var(--grey-600, #606164)); /* Prototype: grey-600 for items */ +} + +html[data-theme="light"] .nav .item { + color: var(--grey-600-new, var(--grey-600, #606164)); /* Prototype exact */ +} + +html[data-theme="light"] .nav-list > li > .item:hover { + background: var(--component-bg-tint, var(--grey-50-new, #f5f5f5)); + color: var(--grey-900-new, var(--grey-900, #181818)); +} + +html[data-theme="light"] .nav-list > li > .is-current-page { + background: var(--component-bg-tint-hover, var(--indigo-50-new, #eef2ff)); + color: var(--component-color, var(--indigo-600-new, #444ce7)); + font-weight: 500; +} + +html[data-theme="light"] .nav-list .is-current-path > div.item:first-child { + color: var(--grey-900-new, var(--grey-900, #181818)); +} + +html[data-theme="light"] .nav-status-footer { + background: var(--grey-50-new, var(--grey-50, #f8f8f8)); + border-top-color: var(--grey-200-new, var(--grey-200, #c3c4c6)); +} + +/* ============================================================================= + UNIFIED NAVIGATION BUCKETS — Data Platform grouped sidebar + ============================================================================= */ + +/* Umbrella nav items (shown at top without bucket header) */ +.nav-umbrella { + margin-bottom: 8px; + padding-bottom: 8px; + border-bottom: 1px solid rgba(255, 255, 255, 0.06); +} + +/* Always show umbrella nav items - override the collapse behavior */ +.nav-menu .nav-umbrella .nav-item > .nav-list, +.nav-menu .nav-umbrella .nav-item:not(.is-active) > .nav-list { + display: block !important; +} + +/* Hide the empty depth-0 wrapper in umbrella */ +.nav-umbrella > .nav-list > .nav-item[data-depth="0"] > .nav-list { + margin-left: 0; + border-left: none; + padding-left: 0; +} + +html[data-theme="light"] .nav-umbrella { + border-bottom-color: var(--grey-200-new, var(--grey-200, #c3c4c6)); +} + +.nav-bucket { + position: relative; + z-index: 1; + margin-bottom: 4px; +} + +.nav-bucket-header { + display: flex; + align-items: center; + gap: 8px; + padding: 6px 10px; + border-radius: 8px; + transition: background 0.12s; + /* Sticky bucket headers */ + position: sticky; + top: 0; + z-index: 5; + background: var(--sidebar-bg, #161e2d); + margin: 0 -10px; + padding-left: 20px; + padding-right: 20px; +} + +.nav-bucket-header:hover { + background: color-mix(in sRGB, var(--sidebar-bg, #161e2d) 90%, white); +} + +html[data-theme="light"] .nav-bucket-header { + background: var(--nav-background, #fff); +} + +html[data-theme="light"] .nav-bucket-header:hover { + background: var(--grey-100-new, var(--grey-100, #f0f0f0)); +} + +.nav-bucket-header.is-current { + background: color-mix(in sRGB, var(--sidebar-bg, #161e2d) 85%, white); +} + +html[data-theme="light"] .nav-bucket-header.is-current { + background: var(--grey-100-new, var(--grey-100, #f0f0f0)); +} + +/* Bucket link - clickable icon + title that navigates to bucket home */ +.nav-bucket-link { + display: flex; + align-items: center; + gap: 8px; + flex: 1; + min-width: 0; + padding: 0; + color: inherit; + text-decoration: none; + cursor: pointer; +} + +/* Bucket icon container */ +.nav-bucket-icon { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + border-radius: 6px; + background: var(--bucket-color, #54478c); + color: #fff; + flex-shrink: 0; +} + +.nav-bucket-icon svg { + width: 14px; + height: 14px; +} + +/* Bucket title */ +.nav-bucket-title { + font-size: 13px; + font-weight: 600; + color: #e8eef6; + letter-spacing: -0.01em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex: 1; + min-width: 0; +} + +html[data-theme="light"] .nav-bucket-title { + color: var(--grey-900-new, var(--grey-900, #181818)); +} + +/* Bucket expand/collapse caret button - separate from toggle for alignment */ +.nav-bucket-caret-btn { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + padding: 0; + border: none; + background: none; + cursor: pointer; + flex-shrink: 0; + margin-left: auto; + border-radius: 4px; + transition: background 0.12s; +} + +.nav-bucket-caret-btn:hover { + background: rgba(255, 255, 255, 0.08); +} + +html[data-theme="light"] .nav-bucket-caret-btn:hover { + background: var(--grey-200-new, var(--grey-200, rgba(0, 0, 0, 0.08))); +} + +/* Hide caret for link-only buckets (no/trivial nav content) */ +.nav-bucket--link-only .nav-bucket-caret-btn { + display: none; +} + +/* Bucket expand/collapse caret */ +.nav-bucket-caret { + color: #5972a6; + flex-shrink: 0; + transition: transform 0.15s ease; +} + +html[data-theme="light"] .nav-bucket-caret { + color: var(--grey-500-new, var(--grey-500, #79797d)); +} + +/* Rotate caret when bucket is expanded - default is down (180deg when expanded) */ +.nav-bucket:not(:has(.nav-bucket-content.is-collapsed)) .nav-bucket-caret { + transform: rotate(180deg); +} + +/* Bucket content (nav tree container) */ +.nav-bucket-content { + margin-top: 4px; + margin-left: 12px; + padding-left: 12px; + border-left: 2px solid var(--bucket-color, #54478c); + opacity: 0.25; +} + +.nav-bucket-content.is-collapsed { + display: none; +} + +/* Active bucket has full opacity border */ +.nav-bucket-header.is-current + .nav-bucket-content, +.nav-bucket-content:not(.is-collapsed) { + opacity: 1; +} + +/* Per-bucket version selector */ +.nav-bucket-version { + position: relative; + flex-shrink: 0; +} + +/* When version dropdown is open, elevate the entire bucket above others */ +.nav-bucket:has(.nav-bucket-version-btn[aria-expanded="true"]) { + z-index: 100; +} + +/* Fallback for JS-controlled class */ +.nav-bucket.is-dropdown-open { + z-index: 100; +} + +.nav-bucket-version-btn { + display: flex; + align-items: center; + gap: 4px; + padding: 4px 8px; + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 6px; + background: rgba(255, 255, 255, 0.04); + color: #a8b2c7; + font-size: 11px; + font-weight: 500; + cursor: pointer; + transition: background 0.12s, border-color 0.12s; +} + +.nav-bucket-version-btn:hover { + background: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.15); +} + +html[data-theme="light"] .nav-bucket-version-btn { + border-color: var(--grey-200-new, var(--grey-200, #c3c4c6)); + background: #fff; + color: var(--grey-700-new, var(--grey-700, #44454a)); +} + +html[data-theme="light"] .nav-bucket-version-btn:hover { + background: var(--grey-50-new, var(--grey-50, #f5f5f5)); + border-color: var(--grey-300-new, var(--grey-300, #aaabae)); +} + +.nav-bucket-version-btn svg { + transition: transform 0.15s ease; +} + +.nav-bucket-version-btn[aria-expanded="true"] svg { + transform: rotate(180deg); +} + +/* Version dropdown menu */ +.nav-bucket-version-menu { + position: absolute; + top: calc(100% + 4px); + right: 0; + min-width: 120px; + padding: 6px; + background: #1a2332; + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 8px; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.32); + z-index: 200; + animation: bucket-version-menu-in 0.15s ease-out; +} + +/* On mobile, prevent dropdown from extending beyond viewport */ +@media (max-width: 768px) { + .nav-bucket-version-menu { + left: 0; + right: auto; + max-width: calc(100vw - 40px); + } + + /* Fix explore panel version dropdown positioning on mobile */ + .context .container.has-dropdown .versions, + .context .container.has-dropdown .components { + left: 0; + right: auto; + max-width: calc(100vw - var(--nav-side-padding) - var(--nav-side-padding) - 32px); + } +} + +@keyframes bucket-version-menu-in { + from { + opacity: 0; + transform: translateY(-4px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +html[data-theme="light"] .nav-bucket-version-menu { + background: #fff; + border-color: var(--grey-200-new, var(--grey-200, #c3c4c6)); + box-shadow: + 0 1px 3px rgba(0, 0, 0, 0.04), + 0 8px 24px rgba(0, 0, 0, 0.12); +} + +/* Version dropdown options */ +.nav-bucket-version-opt { + display: block; + padding: 8px 10px; + border-radius: 6px; + font-size: 12px; + font-weight: 500; + color: #c6cedc; + text-decoration: none; + transition: background 0.12s; +} + +.nav-bucket-version-opt:hover { + background: rgba(255, 255, 255, 0.05); + color: #fff; +} + +.nav-bucket-version-opt.is-selected { + background: rgba(255, 255, 255, 0.08); + color: #fff; +} + +html[data-theme="light"] .nav-bucket-version-opt { + color: var(--grey-700-new, var(--grey-700, #44454a)); +} + +html[data-theme="light"] .nav-bucket-version-opt:hover { + background: var(--grey-50-new, var(--grey-50, #f5f5f5)); + color: var(--grey-900-new, var(--grey-900, #181818)); +} + +html[data-theme="light"] .nav-bucket-version-opt.is-selected { + background: var(--grey-100-new, var(--grey-100, #f0f0f0)); + color: var(--grey-900-new, var(--grey-900, #181818)); +} + +/* EOL badge in version dropdown */ +.version-eol { + font-size: 10px; + font-weight: 600; + color: #f59e0b; + margin-left: 4px; +} + +html[data-theme="light"] .version-eol { + color: #d97706; +} + +/* Version toggle button - show/hide older versions */ +.nav-bucket-version-toggle { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + padding: 8px 10px; + margin-top: 4px; + border: none; + border-top: 1px solid rgba(255, 255, 255, 0.05); + background: none; + font-size: 11px; + font-weight: 500; + color: #8098b3; + text-align: left; + cursor: pointer; + transition: color 0.12s; + border-radius: 0 0 6px 6px; +} + +.nav-bucket-version-toggle:hover { + color: #c6cedc; +} + +.nav-bucket-version-toggle svg { + flex-shrink: 0; + margin-left: 6px; + transition: transform 0.2s ease; +} + +html[data-theme="light"] .nav-bucket-version-toggle { + border-top-color: var(--grey-200-new, var(--grey-200, #c3c4c6)); + color: var(--grey-600-new, var(--grey-600, #6b6c6f)); +} + +html[data-theme="light"] .nav-bucket-version-toggle:hover { + color: var(--grey-900-new, var(--grey-900, #181818)); +} + +/* Older versions container */ +.nav-bucket-version-older { + border-top: 1px solid rgba(255, 255, 255, 0.05); + padding-top: 4px; + margin-top: 4px; +} + +html[data-theme="light"] .nav-bucket-version-older { + border-top-color: var(--grey-200-new, var(--grey-200, #c3c4c6)); +} + +/* ============================================================================= + NESTED BUCKET SUPPORT — Parent buckets containing child buckets + ============================================================================= */ + +/* Children container for nested buckets */ +/* Parent bucket with children - subtle distinction */ +.nav-bucket:has(.nav-bucket-children) > .nav-bucket-header .nav-bucket-title { + font-weight: 600; + letter-spacing: -0.005em; +} + +.nav-bucket:has(.nav-bucket-children) > .nav-bucket-header:hover { + background: color-mix(in sRGB, var(--sidebar-bg, #161e2d) 93%, white); +} + +html[data-theme="light"] .nav-bucket:has(.nav-bucket-children) > .nav-bucket-header:hover { + background: var(--grey-50-new, #f9fafb); +} + +.nav-bucket-children { + margin-top: 4px; + display: flex; + flex-direction: column; + gap: 4px; +} + +/* Top-level nav items (parent component's own nav before child buckets) */ +/* Style the nav items to match bucket content items */ +.nav-menu > .nav-list > .nav-item .item { + font-size: 13px; + padding: 6px 10px; + min-height: 28px; + color: #9daabe; + border-radius: 6px; + transition: background 0.12s, color 0.12s; +} + +.nav-menu > .nav-list > .nav-item .item:hover { + background: rgba(122, 145, 176, 0.08); + color: #c6d4e6; +} + +.nav-menu > .nav-list > .nav-item .item.is-current-page { + background: rgba(122, 145, 176, 0.12); + color: #ffffff; + font-weight: 500; +} + +html[data-theme="light"] .nav-menu > .nav-list > .nav-item .item { + color: var(--grey-700-new, #4b4c4e); +} + +html[data-theme="light"] .nav-menu > .nav-list > .nav-item .item:hover { + background: var(--grey-100-new, #f0f0f0); + color: var(--grey-900-new, #1a1b1d); +} + +html[data-theme="light"] .nav-menu > .nav-list > .nav-item .item.is-current-page { + background: var(--grey-200-new, #e0e1e2); + color: var(--grey-900-new, #1a1b1d); + font-weight: 500; +} + +/* Parent context navigation - shown on child pages without bucket header */ +.nav-parent-context { + margin-bottom: 16px; +} + +/* Add spacing between parent context nav and sibling buckets */ +.nav-parent-context + .nav-bucket { + margin-top: 8px; +} + +/* Add spacing between parent component's nav and child buckets */ +.nav-menu > .nav-list + .nav-bucket { + margin-top: 16px; +} + +/* Child buckets - indent and reduce visual weight */ +.nav-bucket-children > .nav-bucket { + margin-left: 24px; /* Indent child buckets */ +} + +/* Child bucket headers - smaller and less prominent */ +.nav-bucket-children > .nav-bucket .nav-bucket-header { + padding: 4px 8px; +} + +/* Child bucket icons - slightly smaller */ +.nav-bucket-children > .nav-bucket .nav-bucket-icon { + width: 20px; + height: 20px; + border-radius: 5px; +} + +.nav-bucket-children > .nav-bucket .nav-bucket-icon svg { + width: 12px; + height: 12px; +} + +/* Child bucket titles - slightly smaller font */ +.nav-bucket-children > .nav-bucket .nav-bucket-title { + font-size: 12px; +} + +/* Child bucket content - thinner border */ +.nav-bucket-children > .nav-bucket .nav-bucket-content { + border-left-width: 1.5px; + margin-left: 10px; + padding-left: 10px; +} diff --git a/src/css/pagination.css b/src/css/pagination.css index 87a47ea2..c747ce15 100644 --- a/src/css/pagination.css +++ b/src/css/pagination.css @@ -1,31 +1,47 @@ nav.pagination { - display: flex; - border-top: 1px solid var(--toolbar-border-color); - line-height: 1; - margin: 1rem 0 4rem; - padding: 2rem 1rem 0; + margin-top: 48px; /* Prototype: 48px */ + display: grid; + grid-template-columns: 1fr 1fr; /* Prototype: two columns */ + gap: 14px; /* Prototype: 14px */ + border-top: none; + padding: 0; } nav.pagination span { display: flex; - flex: 50%; flex-direction: column; + gap: 4px; /* Prototype: 4px */ + background: #fff; /* Prototype: white background */ + border: 1px solid var(--grey-100-new, var(--grey-100, #e9eaeb)); /* Prototype: grey-100 */ + border-radius: 10px; /* Prototype: 10px */ + padding: 14px 16px; /* Prototype: 14px 16px */ + cursor: pointer; + transition: border-color 0.12s, box-shadow 0.12s; +} + +nav.pagination span:hover { + border-color: var(--grey-200-new, var(--grey-200, #c3c4c6)); /* Prototype: grey-200 */ + box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.04); /* Prototype: subtle shadow */ } nav.pagination .prev { - padding-left: 0.5rem; + padding-left: 0; + text-align: left; } nav.pagination .next { - margin-left: auto; - padding-right: 0.5rem; + margin-left: 0; + padding-right: 0; text-align: right; + align-items: flex-end; } nav.pagination span::before { - color: var(--toolbar-muted-color); - font-size: 0.75em; - padding-bottom: 0.1em; + font-size: 11px; /* Prototype: 11px */ + color: var(--grey-500-new, var(--grey-500, #79797d)); /* Prototype: grey-500 */ + text-transform: uppercase; + letter-spacing: 0.05em; /* Prototype: 0.05em */ + padding-bottom: 0; } nav.pagination .prev::before { @@ -37,27 +53,57 @@ nav.pagination .next::before { } nav.pagination a { - font-family: var(--body-font-family-bold); + font-family: var(--body-font-family); + font-size: 14.5px; /* Prototype: 14.5px */ + font-weight: 500; /* Prototype: 500 */ + color: var(--grey-900-new, var(--grey-900, #181818)); /* Prototype: grey-900 */ + letter-spacing: -0.0125em; /* Prototype: tight tracking */ line-height: 1.3; position: relative; + display: flex; + gap: 6px; /* Prototype: 6px */ + align-items: center; + text-decoration: none; +} + +nav.pagination .next a { + justify-content: flex-end; } nav.pagination a::before, nav.pagination a::after { - color: var(--toolbar-muted-color); + color: var(--grey-500-new, var(--grey-500, #79797d)); font-weight: normal; - font-size: 1.5em; - line-height: 0.75; - position: absolute; - top: 0; - width: 1rem; + font-size: 1.2em; + line-height: 1; + position: static; + width: auto; } nav.pagination .prev a::before { - content: "\2039"; - transform: translateX(-100%); + content: "‹"; + transform: none; } nav.pagination .next a::after { - content: "\203a"; + content: "›"; +} + +/* Dark mode support */ +html[data-theme="dark"] nav.pagination span { + background: var(--dark-blue-800-new, #161e2d); + border-color: rgba(255, 255, 255, 0.08); +} + +html[data-theme="dark"] nav.pagination span:hover { + border-color: rgba(255, 255, 255, 0.15); + box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.2); +} + +html[data-theme="dark"] nav.pagination a { + color: #e8eef6; +} + +html[data-theme="dark"] nav.pagination span::before { + color: #a8b2c7; } diff --git a/src/css/product-switcher.css b/src/css/product-switcher.css new file mode 100644 index 00000000..2229feee --- /dev/null +++ b/src/css/product-switcher.css @@ -0,0 +1,531 @@ +/* ============================================================================= + PRODUCT SWITCHER — Dropdown for switching between Redpanda products + ============================================================================= */ + +.sb-product-wrap { + position: relative; + width: 100%; + margin-bottom: 8px; + padding: 0 16px; +} + +.sb-product-switch { + display: flex; + align-items: center; + gap: 10px; + width: 100%; + padding: 10px 14px; + background: var(--component-color, #4f46e5); + border: none; + border-radius: 10px; + cursor: pointer; + transition: background 0.15s, filter 0.15s; + text-align: left; +} + +.sb-product-switch:hover { + filter: brightness(1.1); +} + +.sb-product-switch.is-open { + filter: brightness(1.15); +} + +/* Small color indicator chip - hidden when button has full color bg */ +.sb-product-chip { + display: none; +} + +.sb-product-name { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 1px; + font-size: 13px; + color: #fff; + font-weight: 500; + flex: 1; + letter-spacing: -0.01em; + min-width: 0; + overflow: hidden; + line-height: 1.2; +} + +/* Hierarchy display for child products (e.g., Cloud under Data Platform) */ +.sb-product-name--hierarchy { + gap: 0; +} + +.sb-product-parent-label { + font-size: 9px; + font-weight: 500; + color: rgba(255, 255, 255, 0.6); + letter-spacing: 0.03em; + text-transform: uppercase; + line-height: 1.3; +} + +.sb-product-child-label { + font-size: 13px; + font-weight: 600; + color: #fff; + line-height: 1.2; +} + +.sb-product-section { + font-size: 10px; + font-weight: 500; + color: #8098b3; + letter-spacing: 0.02em; + text-transform: uppercase; + white-space: nowrap; +} + +.sb-product-sep { + /* Hidden in stacked layout */ + display: none; +} + +.sb-product-title { + font-size: 13px; + font-weight: 600; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +/* On very narrow viewports, hide section */ +@media (max-width: 900px) { + .sb-product-section { + display: none; + } +} + +/* Version badge - shown when multiple versions exist */ +.sb-product-version { + font-family: var(--font-mono, ui-monospace, SFMono-Regular, monospace); + font-size: 10.5px; + font-weight: 500; + padding: 2px 6px; + background: rgba(255, 255, 255, 0.08); + border-radius: 4px; + color: #a8b2c7; + letter-spacing: 0.02em; + flex-shrink: 0; +} + +.sb-product-caret { + color: rgba(255, 255, 255, 0.7); + transition: transform 0.15s, color 0.15s; + flex-shrink: 0; +} + +.sb-product-caret.rot { + transform: rotate(180deg); + color: #fff; +} + +/* Light theme overrides - keep full color background in light mode too */ +.sidebar[data-theme="light"] .sb-product-switch { + background: var(--component-color, #4f46e5); +} + +.sidebar[data-theme="light"] .sb-product-switch:hover { + filter: brightness(1.1); +} + +.sidebar[data-theme="light"] .sb-product-name { + color: #fff; +} + +.sidebar[data-theme="light"] .sb-product-section { + color: rgba(255, 255, 255, 0.7); +} + +.sidebar[data-theme="light"] .sb-product-title { + color: #fff; +} + +.sidebar[data-theme="light"] .sb-product-caret { + color: rgba(255, 255, 255, 0.7); +} + +.sidebar[data-theme="light"] .sb-product-caret.rot { + color: #fff; +} + +.sidebar[data-theme="light"] .sb-product-version { + background: rgba(255, 255, 255, 0.15); + color: rgba(255, 255, 255, 0.9); +} + +/* Dropdown menu */ +.sb-product-menu { + position: absolute; + top: calc(100% + 8px); + left: 0; + right: 0; + background: #1a2332; + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 12px; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.32); + padding: 8px; + z-index: 150; + animation: sb-product-menu-in 0.12s ease-out; +} + +@keyframes sb-product-menu-in { + from { + opacity: 0; + transform: translateY(-4px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +.sidebar[data-theme="light"] .sb-product-menu { + background: #fff; + border-color: var(--grey-200-new, var(--grey-200, #c3c4c6)); + box-shadow: + 0 1px 3px rgba(0, 0, 0, 0.04), + 0 8px 24px rgba(0, 0, 0, 0.12); +} + +.sb-product-menu-head { + padding: 8px 12px 6px; + font-size: 11px; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + color: #a3b1c6; +} + +/* Section header within dropdown (e.g., "Data Platform") */ +.sb-product-menu-head.sb-product-menu-section { + margin-top: 8px; + padding-top: 12px; + border-top: 1px solid rgba(255, 255, 255, 0.08); +} + +.sidebar[data-theme="light"] .sb-product-menu-head { + color: var(--grey-500-new, var(--grey-500, #79797d)); +} + +.sidebar[data-theme="light"] .sb-product-menu-head.sb-product-menu-section { + border-top-color: var(--grey-100-new, var(--grey-100, #dcdcde)); +} + +.sb-product-opt { + display: flex; + align-items: flex-start; + gap: 10px; + width: 100%; + padding: 10px 12px; + background: transparent; + border: none; + border-radius: 8px; + cursor: pointer; + text-align: left; + transition: background 0.12s; + color: inherit; +} + +.sb-product-opt:hover { + background: rgba(255, 255, 255, 0.05); +} + +.sidebar[data-theme="light"] .sb-product-opt:hover { + background: var(--grey-50-new, var(--grey-50, #f5f5f5)); +} + +.sb-product-opt.is-current { + background: rgba(255, 255, 255, 0.04); +} + +.sidebar[data-theme="light"] .sb-product-opt.is-current { + background: var(--grey-50-new, var(--grey-50, #f5f5f5)); +} + +.sb-product-opt .sb-product-chip { + /* Show color indicator chip in dropdown */ + display: block; + width: 10px; + height: 10px; + border-radius: 3px; + flex-shrink: 0; + margin-top: 4px; +} + +.sb-product-opt-text { + display: flex; + flex-direction: column; + gap: 2px; + flex: 1; + min-width: 0; +} + +.sb-product-opt-name { + display: flex; + align-items: baseline; + gap: 4px 6px; + font-size: 13px; + font-weight: 500; + color: #e8eef6; + letter-spacing: -0.005em; + flex-wrap: wrap; + line-height: 1.35; +} + +.sidebar[data-theme="light"] .sb-product-opt-name { + color: var(--grey-900-new, var(--grey-900, #181818)); +} + +.sb-product-opt-tag { + /* Hide CURRENT tag - checkmark already indicates selection */ + display: none; +} + +.sidebar[data-theme="light"] .sb-product-opt-tag { + background: rgba(226, 67, 40, 0.1); + color: var(--brand-600-new, #e24328); +} + +.sb-product-opt-desc { + font-size: 11.5px; + color: #9aa8bc; + line-height: 1.4; + letter-spacing: -0.003em; +} + +.sidebar[data-theme="light"] .sb-product-opt-desc { + color: var(--grey-500-new, var(--grey-500, #79797d)); +} + +.sb-product-opt-check { + color: var(--component-500, var(--indigo-500-new, #6172f3)); + margin-top: 4px; + flex-shrink: 0; +} + +/* Footer */ +.sb-product-menu-foot { + margin-top: 4px; + padding-top: 8px; + border-top: 1px solid rgba(255, 255, 255, 0.08); +} + +.sidebar[data-theme="light"] .sb-product-menu-foot { + border-top-color: var(--grey-100-new, var(--grey-100, #dcdcde)); +} + +.sb-product-menu-link { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + padding: 10px 12px; + background: transparent; + border-radius: 8px; + font-size: 12.5px; + font-weight: 500; + color: #c0cad8; + text-decoration: none; + transition: background 0.12s, color 0.12s; + letter-spacing: -0.005em; +} + +.sb-product-menu-link:hover { + background: rgba(255, 255, 255, 0.05); + color: #fff; +} + +.sidebar[data-theme="light"] .sb-product-menu-link { + color: var(--grey-600-new, var(--grey-600, #606164)); +} + +.sidebar[data-theme="light"] .sb-product-menu-link:hover { + background: var(--grey-50-new, var(--grey-50, #f5f5f5)); + color: var(--grey-900-new, var(--grey-900, #181818)); +} + +/* Clickable section header link (e.g., "Data Platform" → landing page) */ +.sb-product-menu-section-link { + display: flex; + align-items: center; + justify-content: space-between; + text-decoration: none; + transition: background 0.12s, color 0.12s; + border-radius: 6px; + margin-left: -4px; + margin-right: -4px; + padding-left: 16px; + padding-right: 12px; +} + +.sb-product-menu-section-link:hover { + background: rgba(255, 255, 255, 0.05); + color: #e8eef6; +} + +.sidebar[data-theme="light"] .sb-product-menu-section-link:hover { + background: var(--grey-50-new, var(--grey-50, #f5f5f5)); + color: var(--grey-900-new, var(--grey-900, #181818)); +} + +.sb-product-menu-section-cta { + display: flex; + align-items: center; + gap: 4px; + font-size: 10px; + font-weight: 500; + letter-spacing: 0.04em; + text-transform: uppercase; + color: var(--indigo-400, #818cf8); + opacity: 0; + transition: opacity 0.12s; +} + +.sb-product-menu-section-link:hover .sb-product-menu-section-cta { + opacity: 1; +} + +.sidebar[data-theme="light"] .sb-product-menu-section-cta { + color: var(--indigo-600, #4f46e5); +} + +/* ============================================================================= + HIERARCHICAL PRODUCT STRUCTURE + ============================================================================= */ + +/* Product group container (parent + children) */ +.sb-product-group { + display: flex; + flex-direction: column; +} + +/* Parent item styling (Data Platform) */ +.sb-product-opt.sb-product-parent { + border-radius: 8px 8px 0 0; + margin-bottom: 0; +} + +.sb-product-opt.sb-product-parent.is-current-group { + background: rgba(255, 255, 255, 0.02); +} + +.sidebar[data-theme="light"] .sb-product-opt.sb-product-parent.is-current-group { + background: rgba(0, 0, 0, 0.02); +} + +/* Children container */ +.sb-product-children { + display: flex; + flex-direction: column; + padding-left: 12px; + margin-left: 16px; + border-left: 2px solid rgba(255, 255, 255, 0.08); + margin-bottom: 4px; +} + +.sidebar[data-theme="light"] .sb-product-children { + border-left-color: var(--grey-200-new, var(--grey-200, #c3c4c6)); +} + +/* Child item styling (Streaming, Connect) */ +.sb-product-opt.sb-product-child { + padding: 8px 12px; + border-radius: 6px; +} + +.sb-product-opt.sb-product-child .sb-product-chip { + width: 8px; + height: 8px; + margin-top: 5px; +} + +.sb-product-opt.sb-product-child .sb-product-opt-name { + font-size: 12.5px; +} + +.sb-product-opt.sb-product-child .sb-product-opt-desc { + font-size: 11px; +} + +/* Highlight current child */ +.sb-product-opt.sb-product-child.is-current { + background: rgba(255, 255, 255, 0.06); +} + +.sidebar[data-theme="light"] .sb-product-opt.sb-product-child.is-current { + background: var(--grey-100-new, var(--grey-100, #dcdcde)); +} + +/* ============================================================================= + NESTED SUBGROUPS (e.g., Self-Managed containing Streaming + Connect) + ============================================================================= */ + +.sb-product-subgroup { + display: flex; + flex-direction: column; + margin-top: 4px; +} + +/* Clickable Self-Managed button (parent of Streaming/Connect) */ +.sb-product-subgroup-btn { + margin-bottom: 2px; +} + +.sb-product-subgroup-btn.is-current-group { + background: rgba(255, 255, 255, 0.03); +} + +.sidebar[data-theme="light"] .sb-product-subgroup-btn.is-current-group { + background: var(--grey-50-new, var(--grey-50, #f5f5f5)); +} + +.sb-product-subgroup-label { + padding: 6px 12px 4px; + font-size: 10px; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + color: #8098b3; +} + +.sidebar[data-theme="light"] .sb-product-subgroup-label { + color: var(--grey-500-new, var(--grey-500, #79797d)); +} + +.sb-product-subgroup-children { + display: flex; + flex-direction: column; + padding-left: 8px; + margin-left: 16px; + border-left: 2px solid rgba(255, 255, 255, 0.06); +} + +.sidebar[data-theme="light"] .sb-product-subgroup-children { + border-left-color: var(--grey-200-new, var(--grey-200, #c3c4c6)); +} + +/* Grandchild items (Streaming, Connect under Self-Managed) */ +.sb-product-opt.sb-product-grandchild { + padding: 6px 10px; +} + +.sb-product-opt.sb-product-grandchild .sb-product-chip { + width: 6px; + height: 6px; + margin-top: 6px; +} + +.sb-product-opt.sb-product-grandchild .sb-product-opt-name { + font-size: 12px; +} + +.sb-product-opt.sb-product-grandchild .sb-product-opt-desc { + font-size: 10.5px; +} diff --git a/src/css/search-bump.css b/src/css/search-bump.css index fd13997e..5b7c4ac8 100644 --- a/src/css/search-bump.css +++ b/src/css/search-bump.css @@ -372,14 +372,15 @@ article.search .ais-Pagination-list { justify-content: space-evenly; } -.aa-DetachedSearchButton:hover { - box-shadow: inset 0 0 0 2px !important; -} - +/* Header search button is visually hidden but clickable for programmatic access */ .aa-DetachedSearchButton { - border-radius: 10px !important; - height: 32px !important; - gap: 5px !important; + position: fixed !important; + top: -100px !important; + left: -100px !important; + opacity: 0 !important; + pointer-events: auto !important; + width: 1px !important; + height: 1px !important; } .aa-DetachedSearchButtonIcon { diff --git a/src/css/search.css b/src/css/search.css index 80d793c8..bb1056fc 100644 --- a/src/css/search.css +++ b/src/css/search.css @@ -358,14 +358,15 @@ article.search .ais-Pagination-list { justify-content: space-evenly; } -.aa-DetachedSearchButton:hover { - box-shadow: inset 0 0 0 2px !important; -} - +/* Header search button is visually hidden but clickable for programmatic access */ .aa-DetachedSearchButton { - border-radius: 10px !important; - height: 32px !important; - gap: 5px !important; + position: fixed !important; + top: -100px !important; + left: -100px !important; + opacity: 0 !important; + pointer-events: auto !important; + width: 1px !important; + height: 1px !important; } .aa-DetachedSearchButtonIcon { diff --git a/src/css/site.css b/src/css/site.css index 0bb76c11..aae09433 100644 --- a/src/css/site.css +++ b/src/css/site.css @@ -13,6 +13,9 @@ @import "mermaid-zoom.css"; @import "component-home.css"; @import "component-home-v2.css"; +@import "component-home-v3.css"; +@import "data-platform.css"; +@import "whats-new.css"; @import "nav.css"; @import "main.css"; @import "toolbar.css"; @@ -40,6 +43,7 @@ @import "typeface-ibmplexmono.css"; @import "typeface-simplon-mono.css"; @import "typeface-inter.css"; +@import "typeface-inter-display.css"; @import "contributors-guide.css"; @import "announcement-banner.css"; @import "prism.css"; @@ -47,3 +51,6 @@ @import "tooltips.css"; @import "markdown-dropdown.css"; @import "component-tools-fab.css"; +@import "chat-panel.css"; +@import "product-switcher.css"; +@import "labs-home.css"; diff --git a/src/css/toc.css b/src/css/toc.css index dbbd911e..42845a5a 100644 --- a/src/css/toc.css +++ b/src/css/toc.css @@ -71,16 +71,35 @@ .toc.sidebar .thumbs { align-items: flex-start; padding: 0.25rem 0 1rem 1rem; - margin-top: 40px; + margin-top: 1.5rem; + flex-shrink: 0; /* Don't shrink, stay at bottom */ +} + +.toc.sidebar .toc-additional-resources { + padding: 0.25rem 0 0 1rem; + margin-top: 1.5rem; +} + +.toc.sidebar .toc-additional-resources ul { + margin: 0; + padding: 0; +} + +.toc.sidebar .toc-additional-resources a { + color: var(--toc-font-color); + font-size: var(--secondary-font-size); } .toc h3 { color: var(--toc-heading-font-color); - font-size: var(--secondary-font-size); + font-size: 11px; /* Prototype: 11px */ font-family: var(--body-font-family-bold); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.06em; /* Prototype tracking */ line-height: 1.3; - margin: 0 -0.5px; - padding-bottom: 0.25rem; + margin: 0 0 12px 0; /* Prototype: margin-bottom 12px */ + padding-bottom: 0; } .toc.sidebar h3 { @@ -97,20 +116,39 @@ padding: 0; } +/* Prototype: toc-list has border-left */ +.toc.sidebar .toc-menu > ul { + border-left: 1px solid var(--toc-border-color, var(--grey-100-new, #dcdcde)); +} + .toc.sidebar ul { overflow-x: hidden; text-overflow: ellipsis; } -@supports (scrollbar-width: none) { - .toc.sidebar ul { - scrollbar-width: none; +/* TOC scrollbar - thin and subtle */ +@supports (scrollbar-width: thin) { + .toc.sidebar .toc-menu { + scrollbar-width: thin; + scrollbar-color: var(--scrollbar-thumb-color, #c0c0c0) transparent; } } -.toc ul::-webkit-scrollbar { - width: 0; - height: 0; +.toc.sidebar .toc-menu::-webkit-scrollbar { + width: 6px; +} + +.toc.sidebar .toc-menu::-webkit-scrollbar-track { + background: transparent; +} + +.toc.sidebar .toc-menu::-webkit-scrollbar-thumb { + background-color: var(--scrollbar-thumb-color, #c0c0c0); + border-radius: 3px; +} + +.toc.sidebar .toc-menu::-webkit-scrollbar-thumb:hover { + background-color: var(--scrollbar_hover-thumb-color, #a0a0a0); } @media screen and (min-width: 1024px) { @@ -137,27 +175,34 @@ } .toc li[data-level="2"] a { - padding-left: 1.5rem; + padding-left: 22px; /* Prototype: 22px for nested */ } .toc li[data-level="3"] a { - padding-left: 2rem; + padding-left: 32px; /* Prototype: additional indent */ + font-size: 12.5px; /* Prototype: smaller for deeper levels */ } .toc li[data-level="4"] a { - padding-left: 2.5rem; + padding-left: 42px; + font-size: 12.5px; } .toc li[data-level="5"] a { - padding-left: 3rem; + padding-left: 52px; + font-size: 12.5px; } .toc a { color: var(--toc-font-color); - border-left: 2px solid var(--toc-border-color); - display: inline-block; - padding: 6px 0 6px 1rem; + border-left: 2px solid transparent; /* Prototype: left border on list */ + display: block; + padding: 5px 12px; /* Prototype: 5px 12px */ + margin-left: -1px; text-decoration: none; + letter-spacing: -0.0125em; /* Prototype letter-spacing */ + line-height: 1.4; + transition: color 0.1s; } .toc .thumbs a { @@ -171,12 +216,13 @@ } .toc a:hover { - color: var(--link-highlight-color); + color: var(--grey-900-new, var(--grey-900, #181818)); /* Prototype: grey-900 on hover */ } .toc a.is-active { border-left-color: var(--link-highlight-color); color: var(--link-highlight-color); + font-weight: 500; /* Prototype: active items are bolder */ } .sidebar.toc a:focus { @@ -189,29 +235,42 @@ .toc.sidebar { position: sticky; - height: fit-content; - max-height: var(--nav-height); - font-size: var(--secondary-font-size); - font-weight: 300; + top: 80px; /* Prototype: 80px */ + max-height: calc(100vh - 100px); /* Prototype formula */ + font-size: 13px; /* Prototype: 13px */ + font-weight: 400; color: var(--toc-font-color); max-width: var(--toc-width); - overflow-y: auto; - overflow-x: hidden; - text-overflow: ellipsis; flex: 0 0 var(--toc-width); word-wrap: break-word; - top: calc(var(--navbar-height) + var(--announcement-bar-height) + 1rem); /* Reserve space for TOC to prevent CLS when JavaScript populates it */ min-width: var(--toc-width); - margin-right: 1rem; + /* Override sidebar background - TOC should be transparent */ + background: transparent !important; + padding-top: 4px; /* Prototype padding */ + /* Flexbox layout: menu scrolls, thumbs stays at bottom */ + display: flex; + flex-direction: column; + overflow: hidden; /* Don't scroll the whole sidebar */ } -/* Reserve space for TOC menu before JavaScript populates it */ -/* Apply containment to inner wrapper to preserve position: sticky on parent */ +/* TOC menu scrolls independently, thumbs stays at bottom */ .toc.sidebar .toc-menu { - min-height: 300px; - /* Isolate rendering without breaking parent sticky positioning */ - contain: layout style; + flex: 1 1 auto; + overflow-y: auto; + overflow-x: hidden; + min-height: 0; /* Required for flex scroll to work */ +} + +/* Narrow desktop: reduce TOC width to fit content area */ +@media screen and (min-width: 1024px) and (max-width: 1349px) { + .toc.sidebar { + --toc-width: 180px; + + max-width: 180px; + flex: 0 0 180px; + min-width: 160px; + } } @media screen and (min-width: 1350px) { diff --git a/src/css/toolbar.css b/src/css/toolbar.css index 165db247..68eda2c9 100644 --- a/src/css/toolbar.css +++ b/src/css/toolbar.css @@ -47,6 +47,11 @@ html[data-theme=dark] .nav-toggle { background-size: 41.5%; } +/* Ensure toolbar is above nav panel when nav is open */ +.toolbar:has(.nav-toggle.is-active) { + z-index: 10; +} + html[data-theme=dark] .home-link { filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(248deg) brightness(105%) contrast(101%); } diff --git a/src/css/typeface-inter-display.css b/src/css/typeface-inter-display.css new file mode 100644 index 00000000..f336450c --- /dev/null +++ b/src/css/typeface-inter-display.css @@ -0,0 +1,41 @@ +/* ============================================================================= + INTER DISPLAY TYPEFACE + Brand display font for headings and hero text. + Includes Regular (400), Medium (500), SemiBold (600), and Bold (700). + ============================================================================= */ + +/* Regular - 400 */ +@font-face { + font-family: "Inter Display"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url("../font/inter-display/InterDisplay-Regular.ttf") format("truetype"); +} + +/* Medium - 500 */ +@font-face { + font-family: "Inter Display"; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url("../font/inter-display/InterDisplay-Medium.ttf") format("truetype"); +} + +/* SemiBold - 600 */ +@font-face { + font-family: "Inter Display"; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url("../font/inter-display/InterDisplay-SemiBold.ttf") format("truetype"); +} + +/* Bold - 700 */ +@font-face { + font-family: "Inter Display"; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url("../font/inter-display/InterDisplay-Bold.ttf") format("truetype"); +} diff --git a/src/css/typeface-inter.css b/src/css/typeface-inter.css index bc6ce1ab..9cd3c5b4 100644 --- a/src/css/typeface-inter.css +++ b/src/css/typeface-inter.css @@ -1,39 +1,76 @@ +/* ============================================================================= + INTER TYPEFACE + Primary body font. Includes weights from Light (300) to Bold (700). + ============================================================================= */ + +/* Light - 300 */ @font-face { - font-family: "Inter Light"; + font-family: Inter; font-style: normal; font-weight: 300; + font-display: swap; src: - local("Inter"), + local("Inter Light"), + local("Inter-Light"), url(../font/Inter-Light.ttf) format("truetype"); - font-display: swap; } +/* Regular - 400 */ @font-face { - font-family: "Inter"; + font-family: Inter; font-style: normal; font-weight: 400; + font-display: swap; src: - local("Inter"), + local("Inter Regular"), + local("Inter-Regular"), url(../font/Inter-Regular.ttf) format("truetype"); - font-display: swap; } +/* Medium - 500 */ @font-face { - font-family: "Inter Medium"; + font-family: Inter; font-style: normal; font-weight: 500; + font-display: swap; src: - local("Inter"), + local("Inter Medium"), + local("Inter-Medium"), url(../font/Inter-Medium.ttf) format("truetype"); - font-display: swap; } +/* SemiBold - 600 */ @font-face { - font-family: "Inter SemiBold"; + font-family: Inter; font-style: normal; font-weight: 600; + font-display: swap; src: - local("Inter"), + local("Inter SemiBold"), + local("Inter-SemiBold"), url(../font/Inter-SemiBold.ttf) format("truetype"); +} + +/* Bold - 700 */ +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 700; font-display: swap; + src: + local("Inter Bold"), + local("Inter-Bold"), + url(../font/Inter-Bold.ttf) format("truetype"); +} + +/* ExtraBold - 800 */ +@font-face { + font-family: Inter; + font-style: normal; + font-weight: 800; + font-display: swap; + src: + local("Inter ExtraBold"), + local("Inter-ExtraBold"), + url(../font/Inter-ExtraBold.ttf) format("truetype"); } diff --git a/src/css/vars.css b/src/css/vars.css index 151d6bf5..3cf8d8db 100644 --- a/src/css/vars.css +++ b/src/css/vars.css @@ -1,3 +1,9 @@ +/* ============================================================================= + LEGACY DESIGN TOKENS (Pre-2025) + These will be gradually phased out as components are updated to use the new + design system tokens in the :root selector below. + ============================================================================= */ + html:not([data-theme=dark]), html[data-theme=dark] { --ash-900: #212121; @@ -100,15 +106,15 @@ html[data-theme=dark] { --color-black: var(--slate-900); /* fonts */ --rem-base: 18; /* used to compute rem value from desired pixel value (e.g., calc(18 / var(--rem-base) * 1rem) = 18px) */ - --body-font-size: calc(17.5 / var(--rem-base) * 1rem); + --body-font-size: 15px; /* Prototype: 15px body text */ --body-font-size--desktop: var(--body-font-size); - --secondary-font-size: calc(15.5 / var(--rem-base) * 1rem); + --secondary-font-size: calc(14 / var(--rem-base) * 1rem); --body-font-size--print: 0.9375em; --body-line-height: 1.15; - --body-font-family: "Inter", sans-serif; - --body-font-weight-bold: bold; - --body-font-family-bold: "Inter SemiBold", "Calibre Regular", "Open Sans", arial, helvetica, sans-serif; - --monospace-font-family: "IBM Plex Mono", "Courier Prime", courier, monospace; + --body-font-family: var(--font-sans, "Inter", sans-serif); + --body-font-weight-bold: 600; + --body-font-family-bold: var(--font-sans, "Inter", sans-serif); + --monospace-font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); --monospace-font-weight-bold: 500; --alt-heading-font-weight: bold; /* nav */ @@ -126,12 +132,20 @@ html[data-theme=dark] { --limited-availability-label-border: var(--amber-800); --limited-availability-highlight-background-color: rgba(202, 133, 4, 0.08); --limited-availability-highlight-background-color: rgba(248, 134, 57, 0.08); + /* BYOC badge */ + --byoc-label-color: #fff; + --byoc-label-background: #014f86; + --byoc-highlight-background-color: rgba(1, 79, 134, 0.08); + /* Cloud badge */ + --cloud-label-color: #fff; + --cloud-label-background: #6c63ff; + --cloud-highlight-background-color: rgba(108, 99, 255, 0.08); /* doc */ --doc-font-size: inherit; --doc-font-size--desktop: var(--body-font-size); - --doc-line-height: 1.6; - --heading-font-weight: 500; - --heading-font-family: "Inter", sans-serif; + --doc-line-height: 1.7; + --heading-font-weight: 600; + --heading-font-family: var(--font-display, "Inter Display", "Inter", sans-serif); --admonition-label-font-weight: var(--body-font-weight-bold); --caption-font-style: normal; --caption-font-weight: var(--body-font-weight-bold); @@ -151,17 +165,17 @@ html[data-theme=dark] { --nav-height: calc(var(--body-min-height) - var(--toolbar-height)); --nav-collapse-height: 40px; --default-header-color: var(--redpanda-800); - --announcement-bar-height: 0px; /* stylelint-disable-line */ - --announcement-bar-height--desktop: 0px; /* stylelint-disable-line */ + --announcement-bar-height: 0px; /* Set by JS when announcement is shown */ + --announcement-bar-height--desktop: 0px; /* Set by JS when announcement is shown */ --nav-height--desktop: var(--body-min-height); --nav-panel-menu-height: calc(100% - var(--drawer-height)); --nav-panel-explore-height: calc(50% + var(--drawer-height)); - --nav-width: 250px; + --nav-width: 280px; --toc-top: calc(var(--body-top) + var(--toolbar-height) + 3rem); --toc-height: calc(100vh - var(--toc-top) - 2.5rem); - --toc-width: calc(250 / var(--rem-base) * 1rem); - --toc-width--widescreen: calc(350 / var(--rem-base) * 1rem); - --doc-max-width: 1000px; + --toc-width: 232px; + --toc-width--widescreen: calc(280 / var(--rem-base) * 1rem); + --doc-max-width: 920px; /* stacking */ --z-index-page-version-menu: 2; --z-index-nav: 3; @@ -174,6 +188,25 @@ html[data-theme=dark] { --highlight-background: rgba(255, 255, 0, 0.23); } +/* Dark mode overrides */ +html[data-theme=dark] { + /* Heading color for dark mode */ + --heading-font-color: var(--grey-100-new, #f3f4f6); + /* BYOC badge - brighter blue for dark mode visibility with dark text for contrast */ + --byoc-label-color: #101828; + --byoc-label-background: #4da8da; + --byoc-highlight-background-color: rgba(77, 168, 218, 0.15); + /* Cloud badge - brighter purple for dark mode visibility with dark text for contrast */ + --cloud-label-color: #101828; + --cloud-label-background: #9d97ff; + --cloud-highlight-background-color: rgba(157, 151, 255, 0.15); + /* Availability block - brighter for dark mode */ + --availability-block-background: rgba(173, 181, 189, 0.15); + --availability-block-border: #adb5bd; + /* Topbar background - solid for dark mode */ + --topbar-bg: var(--ash-800, #252525); +} + html:not([data-theme=dark]) { --body-font-color: #181818; --body-faint-font-color: #667085; @@ -216,6 +249,8 @@ html:not([data-theme=dark]) { --navbar-boxshadow: 1px 3px 5px var(--ash-50); --navbar-dropdown-boxshadow: 0 4px 10px #0003; --navbar-dropdown-background-hover-color: #0000000d; + /* Topbar background - solid for light mode */ + --topbar-bg: #fff; /* navbar animations */ --transition-timing-default: cubic-bezier(0.08, 0.52, 0.52, 1); @@ -256,6 +291,9 @@ html:not([data-theme=dark]) { --caution-background: rgba(249, 161, 101, 0.1); --caution-on-color: var(--body-font-color); --caution-icon: url(../img/warning-orange.svg) no-repeat center right / auto 100%; + /* availability block */ + --availability-block-background: rgba(108, 117, 125, 0.08); + --availability-block-border: #6c757d; /* doc */ --doc-font-color: var(--color-jet-50); --heading-font-color: var(--color-jet-80); @@ -309,8 +347,160 @@ html:not([data-theme=dark]) { --highlight-container-background: #f9fafb; } -/* RedPanda DS */ +/* ============================================================================= + NEW DESIGN SYSTEM TOKENS - GLOBAL (All Themes) + ============================================================================= */ + :root { + /* Typography - Font Families */ + --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif; + --font-display: "Inter Display", "Inter", ui-sans-serif, system-ui, sans-serif; + --font-mono: "JetBrains Mono", ui-monospace, sfmono-regular, menlo, monospace; + /* Typography - Tracking */ + --tracking-heading: -0.01em; + --tracking-label: -0.0125em; + --tracking-caption: 0.01em; + --tracking-number: -0.05em; + --tracking-number-tight: -0.025em; + --tracking-caption-wide: 0.05em; + /* Typography scale */ + --text-9xl: 4.5rem; + --text-8xl: 3.5rem; + --text-7xl: 3rem; + --text-6xl: 2.5rem; + --text-5xl: 2rem; + --text-4xl: 1.5rem; + --text-3xl: 1.25rem; + --text-2xl: 1.125rem; + --text-xl: 1rem; + /* New color scales - Grey */ + --grey-50-new: #f5f5f5; + --grey-100-new: #dcdcde; + --grey-200-new: #c3c4c6; + --grey-300-new: #aaabae; + --grey-400-new: #919295; + --grey-500-new: #79797d; + --grey-600-new: #606164; + --grey-700-new: #48484a; + --grey-800-new: #303032; + --grey-900-new: #181818; + /* Brand (Redpanda Red) - New scale */ + --brand-50-new: #fff5f5; + --brand-100-new: #fcebe9; + --brand-200-new: #fae0db; + --brand-300-new: #f4b9ae; + --brand-400-new: #ee9281; + --brand-500-new: #e86b54; + --brand-600-new: #e24328; + --brand-700-new: #c1331a; + --brand-800-new: #9e2e1a; + --brand-900-new: #711e0f; + /* Indigo (Primary UI) - New scale */ + --indigo-50-new: #eef4ff; + --indigo-100-new: #e0eaff; + --indigo-200-new: #c7d2fe; + --indigo-300-new: #a4bcfd; + --indigo-400-new: #8098f9; + --indigo-500-new: #6172f3; + --indigo-600-new: #444ce7; + --indigo-700-new: #3538cd; + --indigo-800-new: #2c30a0; + --indigo-900-new: #2d3282; + /* Teal/Green (Redpanda Connect) - New scale */ + --teal-50-new: #f0fdf9; + --teal-100-new: #ccfbef; + --teal-200-new: #99f6df; + --teal-300-new: #5fe9ca; + --teal-400-new: #2ed3ae; + --teal-500-new: #14b895; + --teal-600-new: #0b8c6b; + --teal-700-new: #0e7058; + --teal-800-new: #105947; + --teal-900-new: #12493b; + /* Sky Blue (Cloud) - New scale */ + --sky-50-new: #f0f9ff; + --sky-100-new: #e0f2fe; + --sky-200-new: #bae6fd; + --sky-300-new: #7dd3fc; + --sky-400-new: #38bdf8; + --sky-500-new: #0ea5e9; + --sky-600-new: #0284c7; + --sky-700-new: #0369a1; + --sky-800-new: #075985; + --sky-900-new: #0c4a6e; + /* Slate (Self-managed) - New scale */ + --slate-50-new: #f8fafc; + --slate-100-new: #f1f5f9; + --slate-200-new: #e2e8f0; + --slate-300-new: #cbd5e1; + --slate-400-new: #94a3b8; + --slate-500-new: #64748b; + --slate-600-new: #475569; + --slate-700-new: #334155; + --slate-800-new: #1e293b; + --slate-900-new: #0f172a; + /* ============================================================================= + COMPONENT COLORS - Dynamic theming based on current product + These colors are applied via data-component attribute on the body element + ============================================================================= */ + /* Default/fallback component colors (Data Platform - Indigo) */ + --component-50: var(--indigo-50-new); + --component-100: var(--indigo-100-new); + --component-200: var(--indigo-200-new); + --component-500: var(--indigo-500-new); + --component-600: var(--indigo-600-new); + --component-700: var(--indigo-700-new); + --component-bg-tint: rgba(79, 70, 229, 0.06); + --component-bg-tint-hover: rgba(79, 70, 229, 0.1); + --component-bg-tint-active: rgba(79, 70, 229, 0.14); + /* Dark Blue (Sidebar) - New scale */ + --dark-blue-50-new: #eff1f6; + --dark-blue-100-new: #e5e9f0; + --dark-blue-200-new: #c6cedc; + --dark-blue-300-new: #a8b2c7; + --dark-blue-400-new: #5972a6; + --dark-blue-500-new: #475b85; + --dark-blue-600-new: #2d3a53; + --dark-blue-700-new: #20293c; + --dark-blue-800-new: #161e2d; + --dark-blue-900-new: #101828; + /* Semantic colors - New design system */ + --fg-strong-new: var(--grey-900-new); + --fg-new: var(--grey-700-new); + --fg-muted-new: var(--grey-600-new); + --fg-subtle-new: var(--grey-500-new); + --fg-disabled-new: var(--grey-400-new); + --brand-new: var(--brand-600-new); + --brand-hover-new: var(--brand-700-new); + --primary-new: var(--indigo-600-new); + --primary-hover-new: var(--indigo-700-new); + /* Sidebar theme variables */ + --sidebar-bg: #0f1727; /* Exact prototype color - slightly deeper than dark-blue-800 */ + --sidebar-fg: #c6cedc; /* Exact prototype color */ + --sidebar-fg-muted: var(--dark-blue-300-new); + --sidebar-accent: rgba(255, 255, 255, 0.08); + --sidebar-border: rgba(255, 255, 255, 0.04); /* Exact prototype border */ + --sidebar-item-hover-bg: rgba(255, 255, 255, 0.05); + --sidebar-item-active-bg: rgba(255, 255, 255, 0.1); + /* Border radius - New scale */ + --radius-xs-new: 0.125rem; + --radius-sm-new: 0.25rem; + --radius-md-new: 0.375rem; + --radius-lg-new: 0.5rem; + --radius-xl-new: 0.75rem; + --radius-2xl-new: 1rem; + --radius-3xl-new: 1.25rem; + --radius-full-new: 9999px; + /* Shadows - New design */ + --shadow-sm-new: 0 1px 4px 0 rgba(0, 0, 0, 0.08); + --shadow-md-new: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1); + --shadow-lg-new: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.05); + --shadow-elevated-new: 4px 4px 0px 0px rgba(0, 0, 0, 0.08); + + /* ============================================================================= + LEGACY REDPANDA DS TOKENS + ============================================================================= */ + /* Light Mode */ /* color */ --color-aliases-interactive-palette-opacity-brand-disabled: var(--color-primitives-alpha-primary-brand-primary-brand-alpha-500); @@ -729,3 +919,68 @@ html:not([data-theme=dark]) { --spacings-spacing-9xl: 8rem; --spacings-spacing-10xl: 9rem; } + +/* ============================================================================= + COMPONENT COLOR OVERRIDES + Applied based on data-component attribute on body element + ============================================================================= */ + +/* ADP - Agentic Data Plane (Redpanda Brand Red) */ +body[data-component="redpanda-adp"] { + --component-50: var(--brand-50-new); + --component-100: var(--brand-100-new); + --component-200: var(--brand-200-new); + --component-500: var(--brand-500-new); + --component-600: var(--brand-600-new); + --component-700: var(--brand-700-new); + --component-bg-tint: rgba(226, 67, 40, 0.06); + --component-bg-tint-hover: rgba(226, 67, 40, 0.1); + --component-bg-tint-active: rgba(226, 67, 40, 0.14); + --topbar-bg: color-mix(in srgb, #e24328 8%, white); + --topbar-border: rgba(226, 67, 40, 0.15); +} + +/* Data Platform / Streaming (Indigo - default, explicit for clarity) */ +body[data-component="streaming"] { + --component-50: var(--indigo-50-new); + --component-100: var(--indigo-100-new); + --component-200: var(--indigo-200-new); + --component-500: var(--indigo-500-new); + --component-600: var(--indigo-600-new); + --component-700: var(--indigo-700-new); + --component-bg-tint: rgba(79, 70, 229, 0.06); + --component-bg-tint-hover: rgba(79, 70, 229, 0.1); + --component-bg-tint-active: rgba(79, 70, 229, 0.14); + --topbar-bg: color-mix(in srgb, #4f46e5 8%, white); + --topbar-border: rgba(79, 70, 229, 0.15); +} + +/* Redpanda Connect (Teal/Green) */ +body[data-component="connect"] { + --component-50: var(--teal-50-new); + --component-100: var(--teal-100-new); + --component-200: var(--teal-200-new); + --component-500: var(--teal-500-new); + --component-600: var(--teal-600-new); + --component-700: var(--teal-700-new); + --component-bg-tint: rgba(11, 140, 107, 0.06); + --component-bg-tint-hover: rgba(11, 140, 107, 0.1); + --component-bg-tint-active: rgba(11, 140, 107, 0.14); + --topbar-bg: color-mix(in srgb, #0b8c6b 8%, white); + --topbar-border: rgba(11, 140, 107, 0.15); +} + +/* Cloud Data Platform (Sky Blue) */ +body[data-component="cloud-data-platform"] { + --component-50: var(--sky-50-new); + --component-100: var(--sky-100-new); + --component-200: var(--sky-200-new); + --component-500: var(--sky-500-new); + --component-600: var(--sky-600-new); + --component-700: var(--sky-700-new); + --component-bg-tint: rgba(14, 165, 233, 0.06); + --component-bg-tint-hover: rgba(14, 165, 233, 0.1); + --component-bg-tint-active: rgba(14, 165, 233, 0.14); + --topbar-bg: color-mix(in srgb, #0ea5e9 8%, white); + --topbar-border: rgba(14, 165, 233, 0.15); +} diff --git a/src/css/whats-new.css b/src/css/whats-new.css new file mode 100644 index 00000000..df5e8d44 --- /dev/null +++ b/src/css/whats-new.css @@ -0,0 +1,193 @@ +/* ============================================================================ + What's New Section Styles + + Used by both component landing pages and Data Platform umbrella page + to display latest features and updates. + ============================================================================ */ + +.whats-new-compact { + background: var(--grey-50-new, #fafafa); + border: 1px solid var(--grey-200-new, #e4e4e7); + border-radius: 14px; + padding: 24px; + margin-bottom: 32px; +} + +html[data-theme="dark"] .whats-new-compact { + background: var(--grey-900-new, #18181b); + border-color: var(--grey-800-new, #27272a); +} + +.whats-new-header { + margin-bottom: 20px; +} + +.whats-new-title { + font-family: var(--sans-serif-font, 'Inter', sans-serif); + font-size: 20px; + font-weight: 700; + line-height: 1.3; + letter-spacing: -0.02em; + color: var(--grey-900-new, #09090b); + margin: 0 0 6px; +} + +html[data-theme="dark"] .whats-new-title { + color: var(--grey-50-new, #fafafa); +} + +.whats-new-subtitle { + font-size: 13px; + line-height: 1.5; + color: var(--grey-600-new, #52525b); + margin: 0; +} + +html[data-theme="dark"] .whats-new-subtitle { + color: var(--grey-400-new, #a1a1aa); +} + +.whats-new-items { + display: flex; + flex-direction: column; + gap: 12px; +} + +.whats-new-item { + position: relative; + display: flex; + align-items: center; + gap: 12px; + background: #fff; + border: 1px solid var(--grey-200-new, #e4e4e7); + border-radius: 10px; + padding: 14px 16px; + text-decoration: none; + color: inherit; + transition: all 0.18s ease; +} + +html[data-theme="dark"] .whats-new-item { + background: var(--grey-950-new, #000); + border-color: var(--grey-800-new, #27272a); +} + +.whats-new-item:hover { + border-color: #10b981; + transform: translateX(4px); + box-shadow: -4px 0 0 #10b981, 0 4px 12px rgba(16, 185, 129, 0.15); +} + +html[data-theme="dark"] .whats-new-item:hover { + border-color: #10b981; + box-shadow: -4px 0 0 #10b981, 0 4px 16px rgba(16, 185, 129, 0.25); +} + +.whats-new-badge { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 4px 10px; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.05em; + text-transform: uppercase; + background: linear-gradient(135deg, #10b981 0%, #059669 100%); + color: #fff; + border-radius: 5px; + white-space: nowrap; + flex-shrink: 0; +} + +.whats-new-content { + flex: 1; + min-width: 0; +} + +.whats-new-item-title { + font-family: var(--sans-serif-font, 'Inter', sans-serif); + font-size: 14.5px; + font-weight: 600; + line-height: 1.3; + letter-spacing: -0.01em; + margin: 0 0 4px; + color: var(--grey-800-new, #18181b); +} + +html[data-theme="dark"] .whats-new-item-title { + color: var(--grey-100-new, #f4f4f5); +} + +.whats-new-item-desc { + font-size: 12.5px; + line-height: 1.5; + color: var(--grey-600-new, #52525b); + margin: 0 0 6px; + text-wrap: pretty; +} + +html[data-theme="dark"] .whats-new-item-desc { + color: var(--grey-400-new, #a1a1aa); +} + +.whats-new-tag { + display: inline-block; + padding: 2px 8px; + font-size: 10px; + font-weight: 600; + letter-spacing: 0.02em; + text-transform: uppercase; + background: var(--grey-100-new, #f4f4f5); + color: var(--grey-700-new, #3f3f46); + border-radius: 4px; + white-space: nowrap; +} + +html[data-theme="dark"] .whats-new-tag { + background: var(--grey-800-new, #27272a); + color: var(--grey-300-new, #d4d4d8); +} + +.whats-new-arrow { + flex-shrink: 0; + stroke: var(--grey-400-new, #a1a1aa); + transition: all 0.18s ease; +} + +.whats-new-item:hover .whats-new-arrow { + stroke: #10b981; + transform: translateX(2px); +} + +/* Responsive adjustments */ +@media (max-width: 768px) { + .whats-new-compact { + padding: 20px; + } + + .whats-new-item { + flex-direction: column; + align-items: flex-start; + gap: 10px; + padding: 12px 14px; + } + + .whats-new-badge { + padding: 3px 8px; + font-size: 8px; + } + + .whats-new-item-title { + font-size: 14px; + } + + .whats-new-item-desc { + font-size: 12px; + } + + .whats-new-arrow { + position: absolute; + top: 16px; + right: 14px; + } +} diff --git a/src/font/inter-display/InterDisplay-Black.ttf b/src/font/inter-display/InterDisplay-Black.ttf new file mode 100644 index 00000000..73bfe033 Binary files /dev/null and b/src/font/inter-display/InterDisplay-Black.ttf differ diff --git a/src/font/inter-display/InterDisplay-BlackItalic.ttf b/src/font/inter-display/InterDisplay-BlackItalic.ttf new file mode 100644 index 00000000..b3c0e9c8 Binary files /dev/null and b/src/font/inter-display/InterDisplay-BlackItalic.ttf differ diff --git a/src/font/inter-display/InterDisplay-Bold.ttf b/src/font/inter-display/InterDisplay-Bold.ttf new file mode 100644 index 00000000..51b5fd58 Binary files /dev/null and b/src/font/inter-display/InterDisplay-Bold.ttf differ diff --git a/src/font/inter-display/InterDisplay-BoldItalic.ttf b/src/font/inter-display/InterDisplay-BoldItalic.ttf new file mode 100644 index 00000000..2e7df178 Binary files /dev/null and b/src/font/inter-display/InterDisplay-BoldItalic.ttf differ diff --git a/src/font/inter-display/InterDisplay-ExtraBold.ttf b/src/font/inter-display/InterDisplay-ExtraBold.ttf new file mode 100644 index 00000000..5fe56955 Binary files /dev/null and b/src/font/inter-display/InterDisplay-ExtraBold.ttf differ diff --git a/src/font/inter-display/InterDisplay-ExtraBoldItalic.ttf b/src/font/inter-display/InterDisplay-ExtraBoldItalic.ttf new file mode 100644 index 00000000..76228997 Binary files /dev/null and b/src/font/inter-display/InterDisplay-ExtraBoldItalic.ttf differ diff --git a/src/font/inter-display/InterDisplay-ExtraLight.ttf b/src/font/inter-display/InterDisplay-ExtraLight.ttf new file mode 100644 index 00000000..004e55f2 Binary files /dev/null and b/src/font/inter-display/InterDisplay-ExtraLight.ttf differ diff --git a/src/font/inter-display/InterDisplay-ExtraLightItalic.ttf b/src/font/inter-display/InterDisplay-ExtraLightItalic.ttf new file mode 100644 index 00000000..efe00297 Binary files /dev/null and b/src/font/inter-display/InterDisplay-ExtraLightItalic.ttf differ diff --git a/src/font/inter-display/InterDisplay-Italic.ttf b/src/font/inter-display/InterDisplay-Italic.ttf new file mode 100644 index 00000000..c1140917 Binary files /dev/null and b/src/font/inter-display/InterDisplay-Italic.ttf differ diff --git a/src/font/inter-display/InterDisplay-Light.ttf b/src/font/inter-display/InterDisplay-Light.ttf new file mode 100644 index 00000000..d79a31c7 Binary files /dev/null and b/src/font/inter-display/InterDisplay-Light.ttf differ diff --git a/src/font/inter-display/InterDisplay-LightItalic.ttf b/src/font/inter-display/InterDisplay-LightItalic.ttf new file mode 100644 index 00000000..8eb829fb Binary files /dev/null and b/src/font/inter-display/InterDisplay-LightItalic.ttf differ diff --git a/src/font/inter-display/InterDisplay-Medium.ttf b/src/font/inter-display/InterDisplay-Medium.ttf new file mode 100644 index 00000000..64748bd9 Binary files /dev/null and b/src/font/inter-display/InterDisplay-Medium.ttf differ diff --git a/src/font/inter-display/InterDisplay-MediumItalic.ttf b/src/font/inter-display/InterDisplay-MediumItalic.ttf new file mode 100644 index 00000000..3e1428ad Binary files /dev/null and b/src/font/inter-display/InterDisplay-MediumItalic.ttf differ diff --git a/src/font/inter-display/InterDisplay-Regular.ttf b/src/font/inter-display/InterDisplay-Regular.ttf new file mode 100644 index 00000000..1d85af32 Binary files /dev/null and b/src/font/inter-display/InterDisplay-Regular.ttf differ diff --git a/src/font/inter-display/InterDisplay-SemiBold.ttf b/src/font/inter-display/InterDisplay-SemiBold.ttf new file mode 100644 index 00000000..14a5d449 Binary files /dev/null and b/src/font/inter-display/InterDisplay-SemiBold.ttf differ diff --git a/src/font/inter-display/InterDisplay-SemiBoldItalic.ttf b/src/font/inter-display/InterDisplay-SemiBoldItalic.ttf new file mode 100644 index 00000000..57546368 Binary files /dev/null and b/src/font/inter-display/InterDisplay-SemiBoldItalic.ttf differ diff --git a/src/font/inter-display/InterDisplay-Thin.ttf b/src/font/inter-display/InterDisplay-Thin.ttf new file mode 100644 index 00000000..12be6cc9 Binary files /dev/null and b/src/font/inter-display/InterDisplay-Thin.ttf differ diff --git a/src/font/inter-display/InterDisplay-ThinItalic.ttf b/src/font/inter-display/InterDisplay-ThinItalic.ttf new file mode 100644 index 00000000..03987bcf Binary files /dev/null and b/src/font/inter-display/InterDisplay-ThinItalic.ttf differ diff --git a/src/helpers/add-suggested-labs.js b/src/helpers/add-suggested-labs.js index b728f186..a48d05a0 100644 --- a/src/helpers/add-suggested-labs.js +++ b/src/helpers/add-suggested-labs.js @@ -2,7 +2,7 @@ module.exports = (attributes, content, { data: { root } }) => { const { contentCatalog } = root - if (attributes['component-name'] === 'redpanda-labs') return content + if (attributes['component-name'] === 'labs') return content if (attributes['exclude-related-labs'] === 'true') return content if (!contentCatalog) return content @@ -13,7 +13,8 @@ module.exports = (attributes, content, { data: { root } }) => { // Append "Suggested labs" heading if there are matching labs let contentString = content.toString('utf8') - contentString += '
\n

Suggested labs

\n
\n
\n
    ' + contentString += + '
    \n

    Suggested labs

    \n
    \n
    \n
      ' relatedLabs.forEach((lab, index) => { if (index > 10) return @@ -26,7 +27,7 @@ module.exports = (attributes, content, { data: { root } }) => { if (relatedLabs.length > 5) { contentString += '
      See more
      ' } - contentString += '' + contentString += '' contentString += `
    diff --git a/src/helpers/aggregate-whats-new.js b/src/helpers/aggregate-whats-new.js new file mode 100644 index 00000000..e3aa910d --- /dev/null +++ b/src/helpers/aggregate-whats-new.js @@ -0,0 +1,114 @@ +'use strict' + +/** + * Aggregates What's New items from multiple components + * + * Searches each component's home page for component-whats-new-N-* attributes + * and combines them into a single list for display on umbrella pages. + * + * Searches for home pages in this order: + * 1. modules/ROOT/pages/index.adoc + * 2. modules/home/pages/index.adoc + * 3. Any page with component-whats-new-1-title attribute + * + * Usage on Data Platform umbrella page: + * {{#with (aggregate-whats-new site "cloud-data-platform" "streaming" "connect")}} + * {{#if hasItems}} + * {{#each items}}...{{/each}} + * {{/if}} + * {{/with}} + * + * @param {object} site - Site object with content catalog + * @param {...string} componentNames - Component names to aggregate from + * @returns {object} { items: Array, hasItems: boolean } + */ +module.exports = function (site, ...args) { + // Last argument is Handlebars options object + const options = args[args.length - 1] + const componentNames = args.slice(0, -1) + + // Get contentCatalog from root context + const { contentCatalog } = options.data.root + if (!contentCatalog) return { items: [] } + if (!site || !site.components) return { items: [] } + + const items = [] + + // Helper to get component color + const getComponentColor = (componentName) => { + if (!site.components) return undefined + + let component + if (site.components.get) { + component = site.components.get(componentName) + } else if (site.components.find) { + component = site.components.find((c) => c.name === componentName) + } else if (typeof site.components === 'object') { + component = site.components[componentName] + if (!component) { + const components = Array.isArray(site.components) ? site.components : Object.values(site.components) + component = components.find((c) => c && c.name === componentName) + } + } + + if (!component) return undefined + + const version = component.latestVersion || (component.versions && component.versions[0]) + if (!version) return undefined + + const headerData = version.asciidoc && version.asciidoc.attributes && version.asciidoc.attributes['component-metadata'] + return headerData && headerData.color ? headerData.color : undefined + } + + // Collect items from each component + for (const componentName of componentNames) { + // Find the component's home/landing page + const pages = contentCatalog.findBy({ + component: componentName, + family: 'page', + }) + + if (!pages || pages.length === 0) continue + + // Look for home page or first page with component-whats-new attributes + // Check for ROOT/pages/index.adoc, home/pages/index.adoc, or any page with the attribute + const homePage = pages.find((p) => { + const path = p.src.relative + const module = p.src.module || '' + const isRootIndex = module === 'ROOT' && path === 'index.adoc' + const isHomeIndex = module === 'home' && path === 'index.adoc' + const hasAttr = !!p.asciidoc?.attributes?.['component-whats-new-1-title'] + return isRootIndex || isHomeIndex || hasAttr + }) + + if (!homePage) continue + + const attrs = homePage.asciidoc?.attributes + if (!attrs) continue + + // Extract component-whats-new items (up to 10) + for (let i = 1; i <= 10; i++) { + const title = attrs[`component-whats-new-${i}-title`] + if (!title) break + + const desc = attrs[`component-whats-new-${i}-desc`] + const link = attrs[`component-whats-new-${i}-link`] + const tag = attrs[`component-whats-new-${i}-tag`] + + items.push({ + title, + desc, + link, + tag, + componentName, + componentColor: getComponentColor(componentName), + index: i, + }) + } + } + + return { + items, + hasItems: items.length > 0, + } +} diff --git a/src/helpers/extract-description.js b/src/helpers/extract-description.js index 19b94927..caa0b272 100644 --- a/src/helpers/extract-description.js +++ b/src/helpers/extract-description.js @@ -46,7 +46,8 @@ module.exports = (content, maxLength = 160) => { for (const sentence of sentences) { const trimmed = sentence.trim() - if (trimmed.length > 20) { // Skip very short fragments + if (trimmed.length > 20) { + // Skip very short fragments description = trimmed break } diff --git a/src/helpers/find-component.js b/src/helpers/find-component.js new file mode 100644 index 00000000..e921e653 --- /dev/null +++ b/src/helpers/find-component.js @@ -0,0 +1,25 @@ +'use strict' + +/** + * Finds a component by name from site.components + * Usage: {{#with (find-component site 'component-name')}}...{{/with}} + * + * @param {object} site - The site object containing components array + * @param {string} componentName - The name of the component to find + * @returns {object|undefined} The component object or undefined if not found + */ +module.exports = function (site, componentName) { + if (!site || !site.components || !componentName) return undefined + + // site.components might be a Handlebars SafeString or similar, not a true array + // Convert to array if needed and iterate manually + const components = Array.isArray(site.components) ? site.components : Object.values(site.components || {}) + + for (let i = 0; i < components.length; i++) { + if (components[i] && components[i].name === componentName) { + return components[i] + } + } + + return undefined +} diff --git a/src/helpers/format-release-date.js b/src/helpers/format-release-date.js new file mode 100644 index 00000000..0900efc1 --- /dev/null +++ b/src/helpers/format-release-date.js @@ -0,0 +1,11 @@ +'use strict' + +// Format a YYYY-MM-DD date string as "Mon YYYY" (e.g., "Mar 2026") +// Usage: {{format-release-date page-release-date}} +module.exports = (dateStr) => { + if (!dateStr) return '' + const date = new Date(dateStr) + if (isNaN(date.getTime())) return '' + const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + return `${months[date.getUTCMonth()]} ${date.getUTCFullYear()}` +} diff --git a/src/helpers/get-ai-suggestions.js b/src/helpers/get-ai-suggestions.js new file mode 100644 index 00000000..be1686ba --- /dev/null +++ b/src/helpers/get-ai-suggestions.js @@ -0,0 +1,48 @@ +'use strict' + +/** + * Gets AI suggestion questions for the chat drawer + * + * Reads component-level asciidoc attributes: + * - ai-suggestion-1, ai-suggestion-2, ai-suggestion-3, ai-suggestion-4 + * + * Falls back to default suggestions if component doesn't define any. + * + * Usage in templates: + * {{#each (get-ai-suggestions)}} + * "{{this}}"{{#unless @last}},{{/unless}} + * {{/each}} + * + * @param {object} options - Handlebars options with data.root.page.component + * @returns {array} Array of suggestion strings (up to 4) + */ +module.exports = function (options) { + const { page } = options.data.root + + // Default suggestions if none are defined + const defaults = [ + 'How do I build my first agent?', + 'Set up MCP with Postgres', + 'Rotate an API key safely', + "What's a token budget?", + ] + + // Try to get component-specific suggestions + if (!page || !page.component || !page.component.asciidoc || !page.component.asciidoc.attributes) { + return defaults + } + + const attrs = page.component.asciidoc.attributes + const suggestions = [] + + // Collect up to 4 suggestions from component attributes + for (let i = 1; i <= 4; i++) { + const key = `ai-suggestion-${i}` + if (attrs[key]) { + suggestions.push(attrs[key]) + } + } + + // Return component suggestions if any were found, otherwise defaults + return suggestions.length > 0 ? suggestions : defaults +} diff --git a/src/helpers/get-component-color.js b/src/helpers/get-component-color.js new file mode 100644 index 00000000..0536da8b --- /dev/null +++ b/src/helpers/get-component-color.js @@ -0,0 +1,51 @@ +'use strict' + +/** + * Gets the color for a component from its component-metadata attributes + * Usage: {{get-component-color site "redpanda-adp"}} + * + * Looks up a component by name in site.components and returns its + * component-metadata color value. + * + * @param {object} site - The site object containing components + * @param {string} componentName - The component name to look up + * @returns {string|undefined} The color hex value or undefined + */ +module.exports = function (site, componentName) { + if (!site || !site.components || !componentName) return undefined + + // site.components in Antora might be various collection types + // Try to find the component by name using different approaches + let component + + // If it's a Map + if (site.components.get) { + component = site.components.get(componentName) + } else if (site.components.find) { + // If it has a find method (array-like) + component = site.components.find((c) => c.name === componentName) + } else if (typeof site.components === 'object') { + // If it's an object with entries - try direct access by name + component = site.components[componentName] + // Or iterate over values + if (!component) { + const components = Array.isArray(site.components) ? site.components : Object.values(site.components) + component = components.find((c) => c && c.name === componentName) + } + } + + if (!component) return undefined + + // Get the latestVersion (or first version if no latest) + const version = component.latestVersion || (component.versions && component.versions[0]) + if (!version) return undefined + + // Get component-metadata from version attributes + const headerData = version.asciidoc && version.asciidoc.attributes && version.asciidoc.attributes['component-metadata'] + + if (headerData && headerData.color) { + return headerData.color + } + + return undefined +} diff --git a/src/helpers/get-component-from-resource.js b/src/helpers/get-component-from-resource.js new file mode 100644 index 00000000..b46256f2 --- /dev/null +++ b/src/helpers/get-component-from-resource.js @@ -0,0 +1,18 @@ +'use strict' + +/** + * Extracts component name from a resource specifier + * Usage: {{get-component-from-resource "cloud-data-platform:sql:index.adoc"}} + * Returns: "cloud-data-platform" + * + * @param {string} resourceSpec - Resource specifier (e.g., "component:module:page.adoc") + * @returns {string|undefined} Component name or undefined + */ +module.exports = function (resourceSpec) { + if (!resourceSpec || typeof resourceSpec !== 'string') return undefined + + // Resource specifiers are in format: component:module:page.adoc + // Extract the first part (component name) + const parts = resourceSpec.split(':') + return parts.length > 0 ? parts[0] : undefined +} diff --git a/src/helpers/get-component-header-data.js b/src/helpers/get-component-header-data.js new file mode 100644 index 00000000..54953684 --- /dev/null +++ b/src/helpers/get-component-header-data.js @@ -0,0 +1,28 @@ +'use strict' + +/** + * Gets the component-metadata object from a component's latestVersion attributes + * Usage: {{get-component-header-data component}} + * + * This is used in product-switcher to iterate over site.components and get + * their metadata for display in the dropdown. + * + * @param {object} component - A component object from site.components + * @returns {object|undefined} The component-metadata object or undefined + */ +module.exports = function (component) { + if (!component) return undefined + + // Get the latestVersion (or first version if no latest) + const version = component.latestVersion || (component.versions && component.versions[0]) + if (!version) return undefined + + // Try to get from version.asciidoc.attributes['component-metadata'] + const headerData = version.asciidoc && version.asciidoc.attributes && version.asciidoc.attributes['component-metadata'] + + if (headerData) { + return headerData + } + + return undefined +} diff --git a/src/helpers/get-component-navigation.js b/src/helpers/get-component-navigation.js new file mode 100644 index 00000000..6a2800b8 --- /dev/null +++ b/src/helpers/get-component-navigation.js @@ -0,0 +1,33 @@ +'use strict' + +/** + * Gets navigation for a specific component by name + * + * @param {Object} site - The site object containing components + * @param {string} componentName - Name of the component to get navigation for + * @returns {Array|null} Navigation array or null if not found + */ +module.exports = (site, componentName) => { + if (!site || !site.components || !componentName) { + return null + } + + // Convert components to array if it's a Map + const components = Array.isArray(site.components) + ? site.components + : Array.from(site.components.values ? site.components.values() : []) + + // Find the component + const component = components.find((c) => c.name === componentName) + if (!component) { + return null + } + + // Get the latest version's navigation + const latestVersion = component.latestVersion || (component.versions && component.versions[0]) + if (latestVersion && latestVersion.navigation) { + return latestVersion.navigation + } + + return null +} diff --git a/src/helpers/get-header-color.js b/src/helpers/get-header-color.js new file mode 100644 index 00000000..bd526032 --- /dev/null +++ b/src/helpers/get-header-color.js @@ -0,0 +1,24 @@ +'use strict' + +/** + * Gets the header color from component-metadata attributes + * Usage: {{get-header-color page}} + * @param {object} page - The page object from Antora + * @returns {string|undefined} The hex color or undefined + */ +module.exports = function (page) { + if (!page) return undefined + + // Try to get from componentVersion.asciidoc.attributes['component-metadata'].color + const headerData = + page.componentVersion && + page.componentVersion.asciidoc && + page.componentVersion.asciidoc.attributes && + page.componentVersion.asciidoc.attributes['component-metadata'] + + if (headerData && headerData.color) { + return headerData.color + } + + return undefined +} diff --git a/src/helpers/get-header-data.js b/src/helpers/get-header-data.js new file mode 100644 index 00000000..50ea7e08 --- /dev/null +++ b/src/helpers/get-header-data.js @@ -0,0 +1,36 @@ +'use strict' + +/** + * Gets the full component-metadata object from component attributes + * Usage: {{get-header-data page}} + * + * Expected component-metadata structure in antora.yml: + * asciidoc: + * attributes: + * component-metadata: + * title: "Self-Managed" + * description: "Run Redpanda on your own infrastructure." + * color: "#0F8B66" + * order: 1 + * eyebrow: "REDPANDA SELF-MANAGED" # Full product name for hero badge + * heroGradient: "linear-gradient(180deg, #0B2A23 0%, #134638 100%)" # Hero background + * + * @param {object} page - The page object from Antora + * @returns {object|undefined} The component-metadata object or undefined + */ +module.exports = function (page) { + if (!page) return undefined + + // Try to get from componentVersion.asciidoc.attributes['component-metadata'] + const headerData = + page.componentVersion && + page.componentVersion.asciidoc && + page.componentVersion.asciidoc.attributes && + page.componentVersion.asciidoc.attributes['component-metadata'] + + if (headerData) { + return headerData + } + + return undefined +} diff --git a/src/helpers/get-home-navigation.js b/src/helpers/get-home-navigation.js new file mode 100644 index 00000000..edb83ca9 --- /dev/null +++ b/src/helpers/get-home-navigation.js @@ -0,0 +1,42 @@ +'use strict' + +/** + * Gets navigation for the home page. + * Tries ADP component first, then falls back to self-managed (redpanda). + * + * @param {Object} site - The site object containing components + * @param {Object} page - The current page object + * @returns {Array|null} Navigation array or null if not found + */ +module.exports = (site, page) => { + if (!site || !site.components) { + return page ? page.navigation : null + } + + // Convert components to array if it's a Map + const components = Array.isArray(site.components) + ? site.components + : Array.from(site.components.values ? site.components.values() : []) + + // Try ADP component first (redpanda-adp) + const adpComponent = components.find((c) => c.name === 'redpanda-adp') + if (adpComponent) { + // Get the latest version's navigation (Antora uses latestVersion) + const latestVersion = adpComponent.latestVersion || (adpComponent.versions && adpComponent.versions[0]) + if (latestVersion && latestVersion.navigation) { + return latestVersion.navigation + } + } + + // Fallback to self-managed (redpanda) + const rootComponent = components.find((c) => c.name === 'redpanda') + if (rootComponent) { + const latestVersion = rootComponent.latestVersion || (rootComponent.versions && rootComponent.versions[0]) + if (latestVersion && latestVersion.navigation) { + return latestVersion.navigation + } + } + + // Last resort: use page navigation + return page ? page.navigation : null +} diff --git a/src/helpers/get-index-data.js b/src/helpers/get-index-data.js index def60172..e8cfdf72 100644 --- a/src/helpers/get-index-data.js +++ b/src/helpers/get-index-data.js @@ -19,9 +19,8 @@ module.exports = ({ data: { root } }) => { const isNotCurrentPage = page.url !== currentPageUrl // Optional filtering by component and version - const matchesComponentVersion = !matchComponentVersion || ( - item.component === currentComponent && item.version === currentVersion - ) + const matchesComponentVersion = + !matchComponentVersion || (item.component === currentComponent && item.version === currentVersion) return isNotCurrentPage && matchesComponentVersion }) diff --git a/src/helpers/get-page-info.js b/src/helpers/get-page-info.js index 8380906b..542b1dd0 100644 --- a/src/helpers/get-page-info.js +++ b/src/helpers/get-page-info.js @@ -49,8 +49,8 @@ module.exports = (url, { data: { root } }) => { return /v?\d+(\.\d+)?/.test(str) } - // If the page component name is ROOT, the first part of the URL will be a version: https://docs.antora.org/antora/latest/component-name-key/#root-component - if (urlParts[0] && page.component.name === 'ROOT' && containsVersionNumber(urlParts[0])) { + // When the page component name is 'streaming', the first URL part may be a version (e.g., ".../streaming//...") + if (urlParts[0] && page.component.name === 'streaming' && containsVersionNumber(urlParts[0])) { isCurrentComponent = true } else if (urlParts[0] && urlParts[0] === page.component.name) { isCurrentComponent = true diff --git a/src/helpers/get-whats-new-color.js b/src/helpers/get-whats-new-color.js new file mode 100644 index 00000000..6070c8aa --- /dev/null +++ b/src/helpers/get-whats-new-color.js @@ -0,0 +1,93 @@ +'use strict' + +/** + * Determines the color for the What's New section based on featured components + * - If all items are from the same component: use that component's color + * - If items are from different components: use green (#10b981) as neutral + * - If no component found: use green as fallback + * + * Returns RGB values (e.g., "31, 91, 214") for use in rgba() CSS functions + * + * Usage: {{get-whats-new-color site page.attributes}} + * + * @param {object} site - The site object with components + * @param {object} attributes - Page attributes containing whats-new-*-link + * @returns {string} RGB values (e.g., "31, 91, 214") + */ +module.exports = function (site, attributes) { + // Helper to convert hex to RGB string + const hexToRgb = (hex) => { + if (!hex) return '16, 185, 129' // Green fallback + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) + return result ? `${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)}` : '16, 185, 129' + } + + // Helper to extract component name from resource specifier + const getComponentFromResource = (resourceSpec) => { + if (!resourceSpec || typeof resourceSpec !== 'string') return undefined + const parts = resourceSpec.split(':') + return parts.length > 0 ? parts[0] : undefined + } + + // Helper to get component color + const getComponentColor = (site, componentName) => { + if (!site || !site.components || !componentName) return undefined + + let component + if (site.components.get) { + component = site.components.get(componentName) + } else if (site.components.find) { + component = site.components.find((c) => c.name === componentName) + } else if (typeof site.components === 'object') { + component = site.components[componentName] + if (!component) { + const components = Array.isArray(site.components) ? site.components : Object.values(site.components) + component = components.find((c) => c && c.name === componentName) + } + } + + if (!component) return undefined + + const version = component.latestVersion || (component.versions && component.versions[0]) + if (!version) return undefined + + const headerData = version.asciidoc && version.asciidoc.attributes && version.asciidoc.attributes['component-metadata'] + return headerData && headerData.color ? headerData.color : undefined + } + + if (!attributes) return hexToRgb('#10b981') // Green fallback + + // Extract component names from up to 3 what's-new items + const components = [] + + if (attributes['whats-new-1-link']) { + const comp = getComponentFromResource(attributes['whats-new-1-link']) + if (comp) components.push(comp) + } + + if (attributes['whats-new-2-link']) { + const comp = getComponentFromResource(attributes['whats-new-2-link']) + if (comp) components.push(comp) + } + + if (attributes['whats-new-3-link']) { + const comp = getComponentFromResource(attributes['whats-new-3-link']) + if (comp) components.push(comp) + } + + // If no components found, use green + if (components.length === 0) return hexToRgb('#10b981') + + // Check if all components are the same + const uniqueComponents = [...new Set(components)] + + // If multiple different components, use green as neutral + if (uniqueComponents.length > 1) return hexToRgb('#10b981') + + // Single component (or all same) - use its color + const componentName = uniqueComponents[0] + const componentColor = getComponentColor(site, componentName) + + // Return component color or green as fallback + return hexToRgb(componentColor || '#10b981') +} diff --git a/src/helpers/get-whats-new-items.js b/src/helpers/get-whats-new-items.js new file mode 100644 index 00000000..aab4bfee --- /dev/null +++ b/src/helpers/get-whats-new-items.js @@ -0,0 +1,58 @@ +'use strict' + +/** + * Gets What's New items from the current page attributes + * + * Reads component-whats-new-N-* attributes where N = 1, 2, 3... up to 10 + * + * Required attributes per item: + * - component-whats-new-N-title: Feature title + * - component-whats-new-N-desc: Feature description + * - component-whats-new-N-link: Link to feature docs (Antora xref format) + * + * Optional attributes: + * - component-whats-new-N-tag: Badge text (e.g., "Cloud BYOC", "Enterprise") + * + * Usage in component landing pages: + * {{#with (get-whats-new-items)}} + * {{#if hasItems}} + * {{#each items}}...{{/each}} + * {{/if}} + * {{/with}} + * + * @param {object} options - Handlebars options with data.root + * @returns {object} { items: Array, componentName: string, hasItems: boolean } + */ +module.exports = function (options) { + const { page } = options.data.root + if (!page || !page.attributes) { + return { items: [] } + } + + const items = [] + const maxItems = 10 // Support up to 10 items + + for (let i = 1; i <= maxItems; i++) { + // Antora strips page- and component- prefixes, so we look for whats-new-* directly + const title = page.attributes[`whats-new-${i}-title`] + if (!title) continue // No more items + + const desc = page.attributes[`whats-new-${i}-desc`] + const link = page.attributes[`whats-new-${i}-link`] + const tag = page.attributes[`whats-new-${i}-tag`] + + items.push({ + title, + desc, + link, + tag, + index: i, + }) + } + + return { + items, + componentName: page.component.name, + hasItems: items.length > 0, + } +} diff --git a/src/helpers/gte.js b/src/helpers/gte.js new file mode 100644 index 00000000..726217b8 --- /dev/null +++ b/src/helpers/gte.js @@ -0,0 +1 @@ +module.exports = (a, b) => a >= b diff --git a/src/helpers/has-component.js b/src/helpers/has-component.js new file mode 100644 index 00000000..6114cbb5 --- /dev/null +++ b/src/helpers/has-component.js @@ -0,0 +1,34 @@ +'use strict' + +/** + * Checks if a component exists in the site with actual content (versions) + * Usage: {{#if (has-component site 'agentic-data-plane')}}...{{/if}} + * + * @param {object} site - The site object containing components + * @param {string} componentName - The name of the component to check + * @returns {boolean} True if component exists and has versions/content + */ +module.exports = function (site, componentName) { + if (!site || !site.components || !componentName) return false + + let component + + // Handle different collection types (Map, Array, Object) + if (site.components.get) { + component = site.components.get(componentName) + } else if (site.components.find) { + component = site.components.find((c) => c.name === componentName) + } else if (typeof site.components === 'object') { + component = site.components[componentName] + if (!component) { + const components = Array.isArray(site.components) ? site.components : Object.values(site.components) + component = components.find((c) => c && c.name === componentName) + } + } + + if (!component) return false + + // Check if component has versions (actual content) + const version = component.latestVersion || (component.versions && component.versions[0]) + return !!version +} diff --git a/src/helpers/has-markdown.js b/src/helpers/has-markdown.js index ae8bba6e..ff8cb710 100644 --- a/src/helpers/has-markdown.js +++ b/src/helpers/has-markdown.js @@ -5,19 +5,28 @@ * custom attributes added by extensions. */ +// Page roles that should not show the markdown dropdown +const excludedRoles = ['bloblang-playground', 'component-home-v2', 'home'] + module.exports = ({ data: { root } }) => { const { contentCatalog, page } = root + // In preview mode (no contentCatalog), show dropdown for testing + if (!contentCatalog) { + // Only show on pages that would normally have it + if (page?.attributes?.role && excludedRoles.includes(page.attributes.role)) return false + return true + } + // Safety checks for 404 pages and pages without components // Note: page.version can be null for unversioned components (cloud, connect, labs) - if (!contentCatalog || !page || !page.component || page.version === undefined) return false + if (!page || !page.component || page.version === undefined) return false // Only show dropdown on specific page layouts const allowedLayouts = ['default', 'index', 'lab'] if (!allowedLayouts.includes(page.layout)) return false // Exclude specific page roles - const excludedRoles = ['bloblang-playground', 'component-home-v2', 'home'] if (page.attributes?.role && excludedRoles.includes(page.attributes.role)) return false // Query contentCatalog for full page object diff --git a/src/helpers/is-byoc-feature.js b/src/helpers/is-byoc-feature.js new file mode 100644 index 00000000..d1890444 --- /dev/null +++ b/src/helpers/is-byoc-feature.js @@ -0,0 +1,26 @@ +'use strict' + +// Cache: Map> +let urlCache = null +let cachedComponent = null + +module.exports = (navUrl, { data: { root } }) => { + const { contentCatalog, page } = root + if (page.layout === '404') return false + if (!contentCatalog) return false + + // Build URL map once per component (O(n) once, then O(1) lookups) + if (cachedComponent !== page.component.name) { + urlCache = new Map() + cachedComponent = page.component.name + + const pages = contentCatalog.findBy({ component: page.component.name, family: 'page' }) + for (const p of pages) { + if (p.pub?.url) { + urlCache.set(p.pub.url, !!p.asciidoc?.attributes?.['page-byoc-only']) + } + } + } + + return urlCache.get(navUrl) || false +} diff --git a/src/helpers/is-cloud-feature.js b/src/helpers/is-cloud-feature.js new file mode 100644 index 00000000..75865336 --- /dev/null +++ b/src/helpers/is-cloud-feature.js @@ -0,0 +1,26 @@ +'use strict' + +// Cache: Map> +let urlCache = null +let cachedComponent = null + +module.exports = (navUrl, { data: { root } }) => { + const { contentCatalog, page } = root + if (page.layout === '404') return false + if (!contentCatalog) return false + + // Build URL map once per component (O(n) once, then O(1) lookups) + if (cachedComponent !== page.component.name) { + urlCache = new Map() + cachedComponent = page.component.name + + const pages = contentCatalog.findBy({ component: page.component.name, family: 'page' }) + for (const p of pages) { + if (p.pub?.url) { + urlCache.set(p.pub.url, !!p.asciidoc?.attributes?.['page-cloud-only']) + } + } + } + + return urlCache.get(navUrl) || false +} diff --git a/src/helpers/is-eol.js b/src/helpers/is-eol.js index ba86f323..42b46780 100644 --- a/src/helpers/is-eol.js +++ b/src/helpers/is-eol.js @@ -1,12 +1,25 @@ 'use strict' // Usage: {{#if (is-eol releaseDate)}} ... {{/if}} +// Usage: {{#if (is-eol attributes)}} ... {{/if}} - checks page-is-past-eol, page-eol, or page-release-date +// Usage: {{#if (is-eol attributes 12)}} ... {{/if}} - with custom support months // releaseDate should be a string in YYYY-MM-DD format // Accepts either an attributes object or a date string -module.exports = (input) => { - // If input is an object, check for explicit page-eol attribute +module.exports = (input, supportedMonths) => { + // If input is an object, check for explicit EOL attributes from compute-end-of-life extension if (input && typeof input === 'object') { + // First check page-is-past-eol set by the extension + if (input['page-is-past-eol'] === true || input['page-is-past-eol'] === 'true') return true + // Legacy support for page-eol attribute if (input['page-eol'] === true || input['page-eol'] === 'true') return true + // Use support months from extension if available + const extensionMonths = input['page-support-months'] + if ( + typeof extensionMonths === 'number' || + (typeof extensionMonths === 'string' && !isNaN(parseInt(extensionMonths, 10))) + ) { + supportedMonths = parseInt(extensionMonths, 10) + } // Fallback to release date if available input = input['page-release-date'] } @@ -14,7 +27,10 @@ module.exports = (input) => { const release = new Date(input) if (isNaN(release.getTime())) return false const now = new Date() - // EOL if one year (365 days) or more has passed - const msInYear = 365 * 24 * 60 * 60 * 1000 - return (now - release) >= msInYear + // Support duration - default to 12 months if not specified + const months = typeof supportedMonths === 'number' ? supportedMonths : 12 + // Calculate EOL date (release + supported months) + const eolDate = new Date(release) + eolDate.setMonth(eolDate.getMonth() + months) + return now >= eolDate } diff --git a/src/helpers/is-external-url.js b/src/helpers/is-external-url.js new file mode 100644 index 00000000..36b1ae16 --- /dev/null +++ b/src/helpers/is-external-url.js @@ -0,0 +1,12 @@ +'use strict' + +/** + * Check if a URL is external (starts with http:// or https://) + * + * @param {String} url - The URL to check + * @returns {Boolean} - True if URL is external, false otherwise + */ +module.exports = (url) => { + if (!url || typeof url !== 'string') return false + return url.startsWith('http://') || url.startsWith('https://') +} diff --git a/src/helpers/is-limited-availability-feature.js b/src/helpers/is-limited-availability-feature.js index fcb78a98..deaa7c5c 100644 --- a/src/helpers/is-limited-availability-feature.js +++ b/src/helpers/is-limited-availability-feature.js @@ -11,8 +11,8 @@ module.exports = (navUrl, { data: { root } }) => { // Preview mode: contentCatalog doesn't contain preview pages if (!contentCatalog) { const currentPageUrl = page.url - const isCurrentPage = navUrl === currentPageUrl || - (navUrl && page.src && navUrl.endsWith(page.src.basename.replace('.adoc', '.html'))) + const isCurrentPage = + navUrl === currentPageUrl || (navUrl && page.src && navUrl.endsWith(page.src.basename.replace('.adoc', '.html'))) return isCurrentPage && page.attributes && page.attributes['limited-availability'] } diff --git a/src/helpers/is-new-resource.js b/src/helpers/is-new-resource.js new file mode 100644 index 00000000..b2ee63c5 --- /dev/null +++ b/src/helpers/is-new-resource.js @@ -0,0 +1,40 @@ +'use strict' + +// Cache: Map +let urlCache = null + +/** + * Checks if a resource URL points to a page with page-new attribute + * Usage: {{#if (is-new-resource url)}}...{{/if}} + * + * @param {string} resourceUrl - The resolved URL to check + * @param {object} options - Handlebars context + * @returns {boolean} True if the page has page-new attribute + */ +module.exports = (resourceUrl, { data: { root } }) => { + const { contentCatalog, page } = root + if (page.layout === '404') return false + if (!contentCatalog) return false + if (!resourceUrl || typeof resourceUrl !== 'string') return false + + // Build URL map once for all pages (O(n) once, O(1) lookups) + if (!urlCache) { + urlCache = new Map() + + const pages = contentCatalog.findBy({ family: 'page' }) + for (const p of pages) { + if (p.pub?.url) { + urlCache.set(p.pub.url, !!p.asciidoc?.attributes?.['page-new']) + } + } + } + + // Normalize URL (handle both /path and path formats) + // Additional safety check before calling string methods + if (typeof resourceUrl !== 'string' || !resourceUrl) return false + + const normalizedUrl = resourceUrl.startsWith('/') ? resourceUrl.slice(1) : resourceUrl + const checkUrl = `/${normalizedUrl}` + + return urlCache.get(checkUrl) || urlCache.get(resourceUrl) || false +} diff --git a/src/helpers/json-safe.js b/src/helpers/json-safe.js index 4fc8730a..a24ba0fc 100644 --- a/src/helpers/json-safe.js +++ b/src/helpers/json-safe.js @@ -57,15 +57,17 @@ module.exports = (value) => { // First decode HTML entities to their actual characters const decoded = decodeHtmlEntities(value) - return decoded - // Escape backslashes first (must be done before escaping quotes) - .replace(/\\/g, '\\\\') - // Escape double quotes - .replace(/"/g, '\\"') - // Escape to prevent breaking out of script block - .replace(/<\/script>/gi, '<\\/script>') - // Escape other control characters that could break JSON - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') - .replace(/\t/g, '\\t') + return ( + decoded + // Escape backslashes first (must be done before escaping quotes) + .replace(/\\/g, '\\\\') + // Escape double quotes + .replace(/"/g, '\\"') + // Escape to prevent breaking out of script block + .replace(/<\/script>/gi, '<\\/script>') + // Escape other control characters that could break JSON + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + .replace(/\t/g, '\\t') + ) } diff --git a/src/helpers/list-related-labs.js b/src/helpers/list-related-labs.js index b23804ab..95d7c0ff 100644 --- a/src/helpers/list-related-labs.js +++ b/src/helpers/list-related-labs.js @@ -2,7 +2,7 @@ module.exports = (title, attributes, content, { data: { root } }) => { const { contentCatalog } = root - if (attributes['component-name'] === 'redpanda-labs') return content + if (attributes['component-name'] === 'labs') return content if (!contentCatalog) return content // Extract related labs from attributes diff --git a/src/helpers/log-missing.js b/src/helpers/log-missing.js index 93441c1a..6efd5c35 100644 --- a/src/helpers/log-missing.js +++ b/src/helpers/log-missing.js @@ -21,9 +21,11 @@ module.exports = (latest, missing, previousVersion, { data: { root } }) => { const intentionalRemovals = latest.asciidoc.attributes['removals-without-aliases'] // Check if the content was intentionally removed - const isIntentionallyRemoved = intentionalRemovals && intentionalRemovals.some((removal) => { - return previousVersionWithoutPrefix.includes(removal.page) - }) + const isIntentionallyRemoved = + intentionalRemovals && + intentionalRemovals.some((removal) => { + return previousVersionWithoutPrefix.includes(removal.page) + }) // Log a warning if the content was not intentionally removed if (!isIntentionallyRemoved) { diff --git a/src/helpers/lt.js b/src/helpers/lt.js new file mode 100644 index 00000000..4e28a07d --- /dev/null +++ b/src/helpers/lt.js @@ -0,0 +1 @@ +module.exports = (a, b) => a < b diff --git a/src/helpers/lte.js b/src/helpers/lte.js new file mode 100644 index 00000000..89e642ac --- /dev/null +++ b/src/helpers/lte.js @@ -0,0 +1 @@ +module.exports = (a, b) => a <= b diff --git a/src/helpers/markdown-url.js b/src/helpers/markdown-url.js index 30782d11..5fb89702 100644 --- a/src/helpers/markdown-url.js +++ b/src/helpers/markdown-url.js @@ -8,9 +8,18 @@ module.exports = ({ data: { root } }) => { const { contentCatalog, page } = root + // In preview mode (no contentCatalog), return placeholder URL for testing + if (!contentCatalog) { + // Return a test URL based on current page URL if available + if (page?.url) { + return page.url.replace(/\.html$/, '.md') + } + return '/preview-test.md' + } + // Safety checks for 404 pages and pages without components // Note: page.version can be null for unversioned components (cloud, connect, labs) - if (!contentCatalog || !page || !page.component || page.version === undefined) { + if (!page || !page.component || page.version === undefined) { return null } diff --git a/src/helpers/resolve-resource.js b/src/helpers/resolve-resource.js index ac01f621..47d50ad9 100644 --- a/src/helpers/resolve-resource.js +++ b/src/helpers/resolve-resource.js @@ -4,6 +4,11 @@ const cache = new Map() module.exports = (resource, { data, hash: context }) => { + // Return undefined if resource is not provided + if (!resource || typeof resource !== 'string') { + return undefined + } + if (resource.startsWith('http')) { return resource } @@ -11,7 +16,13 @@ module.exports = (resource, { data, hash: context }) => { // For preview builds where contentCatalog.resolveResource might not exist if (!contentCatalog || !contentCatalog.resolveResource) { - // Return the resource as-is for preview builds + // Convert Antora xref patterns to placeholder URLs for preview + // Pattern: ROOT:module:path/to/file.adoc or component:module:path/to/file.adoc + if (resource.includes(':') && resource.endsWith('.adoc')) { + // Use anchor for preview since these pages don't exist + return '#' + } + // Return the resource as-is for other cases return resource } @@ -28,7 +39,20 @@ module.exports = (resource, { data, hash: context }) => { } const file = contentCatalog.resolveResource(resource, context) - const result = file ? file.pub.url : resource + let result + + if (file) { + result = file.pub.url + } else { + // Log error for unresolved resource + console.error(`[resolve-resource] Unresolved resource: "${resource}" in context:`, { + component: context.component, + version: context.version, + module: context.module, + page: page.src?.relative || page.relativePath || 'unknown', + }) + result = resource + } cache.set(cacheKey, result) diff --git a/src/helpers/sort-components.js b/src/helpers/sort-components.js index 460b643f..55420938 100644 --- a/src/helpers/sort-components.js +++ b/src/helpers/sort-components.js @@ -13,7 +13,7 @@ module.exports = (collection) => { it.latest && it.latest.asciidoc && it.latest.asciidoc.attributes && - it.latest.asciidoc.attributes['page-header-data'] + it.latest.asciidoc.attributes['component-metadata'] if (headerAttributes && headerAttributes.order !== undefined) { accum.push({ title: it.latest.title, diff --git a/src/helpers/split.js b/src/helpers/split.js new file mode 100644 index 00000000..12284c4a --- /dev/null +++ b/src/helpers/split.js @@ -0,0 +1,18 @@ +'use strict' + +/** + * Splits a string by a delimiter and returns an array + * Usage: {{#each (split str ';;')}}...{{/each}} + * + * @param {string} str - The string to split + * @param {string} delimiter - The delimiter to split by + * @returns {Array} Array of strings + */ +module.exports = function (str, delimiter) { + if (!str || typeof str !== 'string') return [] + if (!delimiter || typeof delimiter !== 'string') return [str] + return str + .split(delimiter) + .map((s) => s.trim()) + .filter((s) => s.length > 0) +} diff --git a/src/helpers/strip-trailing-slash.js b/src/helpers/strip-trailing-slash.js index 35057a65..5790a4ee 100644 --- a/src/helpers/strip-trailing-slash.js +++ b/src/helpers/strip-trailing-slash.js @@ -3,7 +3,5 @@ module.exports = (url) => { if (typeof url !== 'string') return url // leave “/” alone, but drop any single trailing slash - return url.length > 1 && url.endsWith('/') - ? url.slice(0, -1) - : url + return url.length > 1 && url.endsWith('/') ? url.slice(0, -1) : url } diff --git a/src/helpers/subtract.js b/src/helpers/subtract.js new file mode 100644 index 00000000..bf2c29f0 --- /dev/null +++ b/src/helpers/subtract.js @@ -0,0 +1 @@ +module.exports = (a, b) => a - b diff --git a/src/helpers/support-end-date.js b/src/helpers/support-end-date.js new file mode 100644 index 00000000..22943c41 --- /dev/null +++ b/src/helpers/support-end-date.js @@ -0,0 +1,17 @@ +'use strict' + +// Calculate support end date (release date + supported months) and format as "Mon YYYY" +// Usage: {{support-end-date page-release-date}} - defaults to 12 months +// Usage: {{support-end-date page-release-date 12}} - explicit months +// Usage: {{support-end-date page-release-date page-support-months}} - from attribute +module.exports = (dateStr, supportedMonths) => { + if (!dateStr) return '' + const release = new Date(dateStr) + if (isNaN(release.getTime())) return '' + // Support duration - default to 12 months if not specified + const months = typeof supportedMonths === 'number' ? supportedMonths : 12 + const endDate = new Date(release) + endDate.setMonth(endDate.getMonth() + months) + const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + return `${monthNames[endDate.getMonth()]} ${endDate.getFullYear()}` +} diff --git a/src/helpers/test-home-component.js b/src/helpers/test-home-component.js new file mode 100644 index 00000000..12db38fe --- /dev/null +++ b/src/helpers/test-home-component.js @@ -0,0 +1,37 @@ +'use strict' + +/** + * Test helper to check if home component exists and has navigation + */ +module.exports = ({ data: { root } }) => { + const { site, contentCatalog } = root + + if (!site || !site.components) { + return 'No site or components' + } + + const components = Array.isArray(site.components) + ? site.components + : Array.from(site.components.values ? site.components.values() : []) + + const homeComponent = components.find((c) => c.name === 'home') + + if (!homeComponent) { + return `Home not found in site.components. Available: ${components.map((c) => c.name).join(', ')}` + } + + // Also check contentCatalog + const catalogHome = contentCatalog ? contentCatalog.getComponent('home') : null + + const latestVersion = homeComponent.latestVersion || (homeComponent.versions && homeComponent.versions[0]) + + if (!latestVersion) { + return 'Home has no versions' + } + + const metadata = latestVersion.asciidoc?.attributes?.['component-metadata'] + const hasNav = !!latestVersion.navigation + const navCount = latestVersion.navigation ? latestVersion.navigation.length : 0 + + return `Home: v${latestVersion.version}, metadata=${!!metadata}, nav=${hasNav} (${navCount} items), catalog=${!!catalogHome}` +} diff --git a/src/helpers/version-status.js b/src/helpers/version-status.js new file mode 100644 index 00000000..7775c52b --- /dev/null +++ b/src/helpers/version-status.js @@ -0,0 +1,20 @@ +'use strict' + +// Returns the status of a version: 'current', 'supported', or 'eol' +// Usage: {{version-status ver.asciidoc.attributes currentVersion}} +module.exports = (attributes, currentVersion, thisVersion) => { + // Check if explicitly marked as EOL or if release date indicates EOL + if (attributes && attributes['page-eol'] === true) return 'eol' + if (attributes && attributes['page-release-date']) { + const release = new Date(attributes['page-release-date']) + if (!isNaN(release.getTime())) { + const now = new Date() + const msInYear = 365 * 24 * 60 * 60 * 1000 + if (now - release >= msInYear) return 'eol' + } + } + // If this is the current/latest version + if (currentVersion === thisVersion) return 'current' + // Otherwise it's supported + return 'supported' +} diff --git a/src/img/redpanda-wordmark.svg b/src/img/redpanda-wordmark.svg new file mode 100644 index 00000000..82843bfe --- /dev/null +++ b/src/img/redpanda-wordmark.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/js/01-nav.js b/src/js/01-nav.js index 10f8c94c..7b38d91d 100644 --- a/src/js/01-nav.js +++ b/src/js/01-nav.js @@ -104,12 +104,18 @@ dropdownContainers.forEach((container) => { container.addEventListener('click', () => { - container.classList.toggle('is-active') + var isActive = container.classList.toggle('is-active') + // Update aria-expanded on the button trigger for accessibility + var trigger = container.querySelector('.version-selector-trigger') + if (trigger) trigger.setAttribute('aria-expanded', isActive ? 'true' : 'false') }) }) document.documentElement.addEventListener('click', function () { dropdownContainers.forEach((container) => { container.classList.remove('is-active') + // Reset aria-expanded when closing dropdowns + var trigger = container.querySelector('.version-selector-trigger') + if (trigger) trigger.setAttribute('aria-expanded', 'false') }) }) } @@ -181,7 +187,11 @@ var rect = this.getBoundingClientRect() var menuPanelRect = menuPanel.getBoundingClientRect() var overflowY = (rect.bottom - menuPanelRect.top - menuPanelRect.height + padding).toFixed() - if (event.target.classList.contains('nav-link') || event.target.classList.contains('nav-text') || (event.target.classList.contains('item') && !event.target.classList.contains('dropdown'))) { + if ( + event.target.classList.contains('nav-link') || + event.target.classList.contains('nav-text') || + (event.target.classList.contains('item') && !event.target.classList.contains('dropdown')) + ) { // Follow the link var a = event.target.closest('a') if (!a) { @@ -201,13 +211,20 @@ } function showNav (e, collapse) { - if (navToggle.classList.contains('is-active')) return hideNav(e) + if (navToggle && navToggle.classList.contains('is-active')) return hideNav(e) trapEvent(e) var html = document.documentElement + var body = document.querySelector('.body') if (!collapse) { html.classList.add('is-clipped--nav') - navToggle.classList.add('is-active') + if (navToggle) navToggle.classList.add('is-active') navContainer.classList.add('is-active') + // Fix: remove hidden class and reset styles if set by collapse + navContainer.classList.remove('hidden') + if (navExpand) navExpand.classList.add('hidden') + if (toolbar) toolbar.style.paddingLeft = '' + if (body) body.style.marginLeft = '' + if (main) main.style.width = '' // Note - Dan removed the height calculations - this should all be handled by css or we have overrides that work against us // var bounds = nav.getBoundingClientRect() // var expectedHeight = window.innerHeight - Math.round(bounds.top) @@ -217,6 +234,7 @@ navContainer.classList.remove('hidden') navExpand.classList.add('hidden') if (toolbar) toolbar.style.paddingLeft = 'unset' + if (body) body.style.marginLeft = '' main.style.width = 'unset' } } @@ -224,17 +242,23 @@ function hideNav (e, collapse) { trapEvent(e) var html = document.documentElement + var body = document.querySelector('.body') if (!collapse) { html.classList.remove('is-clipped--nav') - navToggle.classList.remove('is-active') + if (navToggle) navToggle.classList.remove('is-active') navContainer.classList.remove('is-active') nav.style.height = '' html.removeEventListener('click', hideNav) } else { navContainer.classList.add('hidden') + navContainer.classList.remove('is-active') + // Also reset navToggle so hamburger can reopen the nav + if (navToggle) navToggle.classList.remove('is-active') navExpand.classList.remove('hidden') if (toolbar) toolbar.style.paddingLeft = '10px' + if (body) body.style.marginLeft = '0' main.style.width = '100%' + html.classList.remove('is-clipped--nav') } } diff --git a/src/js/02-on-this-page.js b/src/js/02-on-this-page.js index d1d96ef2..90bdfd30 100644 --- a/src/js/02-on-this-page.js +++ b/src/js/02-on-this-page.js @@ -133,7 +133,7 @@ var containerHeight = scrollableContainer.offsetHeight var linkTop = activeLink.offsetTop - scrollableContainer.offsetTop var linkHeight = activeLink.offsetHeight - scrollableContainer.scrollTop = Math.max(0, linkTop - (containerHeight / 2) + (linkHeight / 2)) + scrollableContainer.scrollTop = Math.max(0, linkTop - containerHeight / 2 + linkHeight / 2) } } @@ -181,7 +181,7 @@ var containerHeight = scrollableContainer.offsetHeight var linkTop = activeLink.offsetTop - scrollableContainer.offsetTop var linkHeight = activeLink.offsetHeight - var targetScroll = linkTop - (containerHeight / 2) + (linkHeight / 2) + var targetScroll = linkTop - containerHeight / 2 + linkHeight / 2 scrollableContainer.scrollTop = Math.max(0, targetScroll) } lastActiveFragment = activeFragment diff --git a/src/js/06-copy-to-clipboard.js b/src/js/06-copy-to-clipboard.js index 73f92538..7a44ff90 100644 --- a/src/js/06-copy-to-clipboard.js +++ b/src/js/06-copy-to-clipboard.js @@ -101,8 +101,8 @@ copy.addEventListener('click', writeToClipboard.bind(copy, code)) } - // Create an "Ask AI" button (if Kapa is available) - if (window.Kapa && !pre.parentNode.parentNode.classList.contains('no-copy')) { + // Create an "Ask AI" button (if chat panel is available) + if (document.querySelector('[data-chat-panel]') && !pre.parentNode.parentNode.classList.contains('no-copy')) { ;(askAI = document.createElement('button')).className = 'ask-ai-button' // Only add tooltip on non-touch devices if (!isTouch) { @@ -121,7 +121,8 @@ sparklesPath.setAttribute('fill-rule', 'evenodd') sparklesPath.setAttribute('clip-rule', 'evenodd') // SVG path data for sparkles icon (broken into multiple lines for readability) - var pathData = 'M1.01942 4.14696C0.821273 4.07417 0.615365 4.0169 0.403168 3.97662C0.387588 3.97367 ' + + var pathData = + 'M1.01942 4.14696C0.821273 4.07417 0.615365 4.0169 0.403168 3.97662C0.387588 3.97367 ' + '0.371975 3.9708 0.356327 3.96802C0.214558 3.94289 0.214558 3.74081 0.356327 3.71568C0.371975 ' + '3.7129 0.387588 3.71003 0.403168 3.70709C0.615365 3.6668 0.821273 3.60953 1.01942 3.53675C1.138 ' + '3.49318 1.2538 3.44407 1.36651 3.38969C2.14702 3.01321 2.77911 2.38509 3.158 1.60949C3.2127 ' + @@ -213,9 +214,8 @@ // Build the URL with query params for the snippet sections // You can also wrap each in encodeURIComponent(...) if your environment needs extra safety. - var runUrl = '/redpanda-connect/guides/bloblang/playground/?map=' + encodedMap + - '&input=' + encodedIn + - '&meta=' + encodedMeta + var runUrl = + '/connect/guides/bloblang/playground/?map=' + encodedMap + '&input=' + encodedIn + '&meta=' + encodedMeta window.open(runUrl, '_blank') }) } @@ -253,25 +253,21 @@ ) } - // Handles opening Kapa AI with the code snippet + // Handles opening chat drawer with the code snippet function handleAskAI (code) { var text = code.innerText.replace(TRAILING_SPACE_RX, '') if (code.dataset.lang === 'console' && text.startsWith('$ ')) { text = extractCommands(text) } - var kapa = window.Kapa - if (kapa) { - // Create the prompt with the code snippet - var aiPromptText = 'Explain this code snippet:\n\n```\n' + text + '\n```' + // Create the prompt with the code snippet + var aiPromptText = 'Explain this code snippet:\n\n```\n' + text + '\n```' - kapa.open({ - mode: 'ai', - query: aiPromptText, - submit: true, - }) + // Use the chat drawer instead of modal + if (typeof window.openChatWithQuery === 'function') { + window.openChatWithQuery(aiPromptText, true) } else { - console.warn('Kapa AI is not available.') + console.warn('Chat panel is not available.') } } diff --git a/src/js/07-expand-images.js b/src/js/07-expand-images.js index adc7ec56..98c87948 100644 --- a/src/js/07-expand-images.js +++ b/src/js/07-expand-images.js @@ -1,4 +1,4 @@ -(function () { +;(function () { 'use strict' const modalOverlay = document.createElement('div') diff --git a/src/js/08-move-anchors.js b/src/js/08-move-anchors.js index 25264449..a725dbdd 100644 --- a/src/js/08-move-anchors.js +++ b/src/js/08-move-anchors.js @@ -1,10 +1,11 @@ ;(function () { 'use strict' const anchors = document.querySelectorAll('a.anchor') - anchors.length && anchors.forEach((a) => { - const heading = a.closest('h1, h2, h3, h4, h5, h6') - if (heading) { - heading.appendChild(a) - } - }) + anchors.length && + anchors.forEach((a) => { + const heading = a.closest('h1, h2, h3, h4, h5, h6') + if (heading) { + heading.appendChild(a) + } + }) })() diff --git a/src/js/09-linkable-line-numbers.js b/src/js/09-linkable-line-numbers.js index a3faa173..01cbc1f6 100644 --- a/src/js/09-linkable-line-numbers.js +++ b/src/js/09-linkable-line-numbers.js @@ -2,31 +2,33 @@ /** * This script assigns unique and consistent IDs to
     elements containing  blocks within the document.
    - * The IDs are generated based on a hash of the URL combined with an index. This ensures that the IDs are consistent 
    + * The IDs are generated based on a hash of the URL combined with an index. This ensures that the IDs are consistent
      * across page loads, which is useful for maintaining references and bookmarks to specific code blocks.
      * These IDs are required for the linkable line numbers feature in Prism.
      * https://prismjs.com/plugins/line-highlight/
      */
     
    -(function () {
    +;(function() {
       'use strict'
     
       // Event listener for when the DOM content is fully loaded
    -  window.addEventListener('DOMContentLoaded', function (event) {
    +  window.addEventListener('DOMContentLoaded', function(event) {
         /**
          * Generates a hash value for a given string.
          * @param {string} str - The input string to hash.
          * @returns {number} - The hash value of the input string.
          */
         function hashString(str) {
    -      let hash = 0, i, chr;
    -      if (str.length === 0) return hash;
    +      let hash = 0,
    +        i,
    +        chr
    +      if (str.length === 0) return hash
           for (i = 0; i < str.length; i++) {
    -        chr = str.charCodeAt(i);
    -        hash = ((hash << 5) - hash) + chr;
    -        hash |= 0; // Convert to 32bit integer
    +        chr = str.charCodeAt(i)
    +        hash = (hash << 5) - hash + chr
    +        hash |= 0 // Convert to 32bit integer
           }
    -      return hash;
    +      return hash
         }
     
         /**
    @@ -36,35 +38,35 @@
          * @returns {string} - The generated unique ID.
          */
         function generateUniqueId(index) {
    -      const urlHash = hashString(window.location.href);
    -      return `code-${urlHash}-${index}`;
    +      const urlHash = hashString(window.location.href)
    +      return `code-${urlHash}-${index}`
         }
     
         // Select all 
     elements that are direct children of two nested 
    elements - var preElements = document.querySelectorAll('div > div > pre'); + var preElements = document.querySelectorAll('div > div > pre') // Iterate over each
     element
    -    preElements.forEach(function (preElem, index) {
    +    preElements.forEach(function(preElem, index) {
           // If the first child of the 
     element is a  block, assign a unique ID
           if (preElem.firstElementChild && preElem.firstElementChild.tagName === 'CODE') {
    -        preElem.id = generateUniqueId(index);
    +        preElem.id = generateUniqueId(index)
           }
     
    -      var grandparent = preElem.parentElement.parentElement;
    +      var grandparent = preElem.parentElement.parentElement
     
           // Check if the grandparent element has a class that starts with 'lines'
    -      Array.from(grandparent.classList).forEach(function (className) {
    +      Array.from(grandparent.classList).forEach(function(className) {
             if (className.startsWith('lines')) {
    -          var matches = className.match(/(\d+(-\d+)?)/g);
    +          var matches = className.match(/(\d+(-\d+)?)/g)
               if (matches) {
    -            var attributeValue = matches.join(',');
    -            preElem.setAttribute('data-line', attributeValue);
    +            var attributeValue = matches.join(',')
    +            preElem.setAttribute('data-line', attributeValue)
               }
             }
             if (className.startsWith('line-numbers')) {
    -          preElem.classList.add('linkable-line-numbers');
    +          preElem.classList.add('linkable-line-numbers')
             }
    -      });
    -    });
    -  });
    -})();
    +      })
    +    })
    +  })
    +})()
    diff --git a/src/js/10-cloud-api-feedback.js b/src/js/10-cloud-api-feedback.js
    index 6a8fd885..51a3dc8d 100644
    --- a/src/js/10-cloud-api-feedback.js
    +++ b/src/js/10-cloud-api-feedback.js
    @@ -1,4 +1,4 @@
    -(function () {
    +;(function () {
       'use strict'
     
       document.addEventListener('DOMContentLoaded', function () {
    diff --git a/src/js/11-editable-placeholders.js b/src/js/11-editable-placeholders.js
    index 72288331..491fd18a 100644
    --- a/src/js/11-editable-placeholders.js
    +++ b/src/js/11-editable-placeholders.js
    @@ -1,279 +1,279 @@
     /* eslint-disable */
     
    -const REGEX_EDITABLE_SPAN = /<.[^&A-Z]+>/g;
    -const REGEX_ESCAPE = /[\\^$*+?.()|[\]{}]/g;
    -const REGEX_HTML_TAG = /<[^>]*>/g;
    -const REGEX_LT_GT = /<|>/g;
    -const REGEX_PREPROCESS_PUNCTUATION = /(\()<\/span>|(\))<\/span>/g;
    -const REGEX_CONUM_SPAN = /(\s\((\d+)<\/span>\)|(\s)\((\d+)\))$/gm;
    +const REGEX_EDITABLE_SPAN = /<.[^&A-Z]+>/g
    +const REGEX_ESCAPE = /[\\^$*+?.()|[\]{}]/g
    +const REGEX_HTML_TAG = /<[^>]*>/g
    +const REGEX_LT_GT = /<|>/g
    +const REGEX_PREPROCESS_PUNCTUATION = /(\()<\/span>|(\))<\/span>/g
    +const REGEX_CONUM_SPAN = /(\s\((\d+)<\/span>\)|(\s)\((\d+)\))$/gm
     
     function unnestPlaceholders() {
    -  const editables = document.querySelectorAll('[contenteditable="true"]');
    -
    -  editables.forEach(editable => {
    +  const editables = document.querySelectorAll('[contenteditable="true"]')
     
    +  editables.forEach((editable) => {
         // Remove empty siblings, but don't remove conum elements
    -    let nextSibling = editable.nextElementSibling;
    +    let nextSibling = editable.nextElementSibling
         while (nextSibling && nextSibling.innerHTML.trim() === '') {
           // Check if the sibling has a conum class, if so, skip removal
           if (!nextSibling.classList.contains('conum')) {
    -        const siblingToRemove = nextSibling;
    -        nextSibling = nextSibling.nextElementSibling;
    -        siblingToRemove.remove();
    +        const siblingToRemove = nextSibling
    +        nextSibling = nextSibling.nextElementSibling
    +        siblingToRemove.remove()
           } else {
             // If it's a conum, move to the next sibling without removing it
    -        nextSibling = nextSibling.nextElementSibling;
    +        nextSibling = nextSibling.nextElementSibling
           }
         }
     
    -
    -    let parent = editable.parentElement;
    +    let parent = editable.parentElement
     
         // If the parent is also contenteditable, move the child out of the nested structure
         while (parent && parent.getAttribute('contenteditable') === 'true') {
    -      const grandParent = parent.parentElement;
    +      const grandParent = parent.parentElement
     
           // Move the current editable element before the parent to "unnest" it
    -      grandParent.insertBefore(editable, parent);
    +      grandParent.insertBefore(editable, parent)
     
           // If the parent becomes empty, remove the parent element
           if (parent.childNodes.length === 0) {
    -        parent.remove();
    +        parent.remove()
           }
     
           // Continue checking up the chain if the parent is also contenteditable
    -      parent = grandParent;
    +      parent = grandParent
         }
    -  });
    +  })
     }
     
    -(function () {
    -  'use strict';
    +;(function() {
    +  'use strict'
     
       // Check if Prism is available, exit if not
    -  if (!Prism.highlightAll) {
    -    return;
    +  if (typeof Prism === 'undefined' || !Prism.highlightAll) {
    +    return
       }
     
       function observeCodeBlocksForConumRestoration() {
    -    const codeElems = document.querySelectorAll('code');
    +    const codeElems = document.querySelectorAll('code')
     
    -    codeElems.forEach(code => {
    -      let mutationInProgress = false;
    +    codeElems.forEach((code) => {
    +      let mutationInProgress = false
     
    -      const observer = new MutationObserver(mutations => {
    -        if (mutationInProgress) return; // Prevent recursion
    -        mutationInProgress = true;
    +      const observer = new MutationObserver((mutations) => {
    +        if (mutationInProgress) return // Prevent recursion
    +        mutationInProgress = true
     
    -        mutations.forEach(mutation => {
    +        mutations.forEach((mutation) => {
               // Check for removed nodes that are conum elements
    -          mutation.removedNodes.forEach(removedNode => {
    +          mutation.removedNodes.forEach((removedNode) => {
                 if (removedNode.nodeType === Node.ELEMENT_NODE && removedNode.classList.contains('conum')) {
                   // Only reinsert if it was actually removed and not reinserted elsewhere
                   if (!mutation.target.querySelector(`i.conum[data-value="${removedNode.getAttribute('data-value')}"]`)) {
    -                mutation.target.appendChild(removedNode);
    +                mutation.target.appendChild(removedNode)
                   }
                 }
    -          });
    +          })
               // Optionally, check for added nodes to ensure conum elements were correctly reinserted
    -          mutation.addedNodes.forEach(addedNode => {
    +          mutation.addedNodes.forEach((addedNode) => {
                 if (addedNode.nodeType === Node.ELEMENT_NODE && addedNode.classList.contains('conum')) {
    -              const dataValue = addedNode.getAttribute('data-value');
    -              const duplicates = mutation.target.querySelectorAll(`i.conum[data-value="${dataValue}"]`);
    +              const dataValue = addedNode.getAttribute('data-value')
    +              const duplicates = mutation.target.querySelectorAll(`i.conum[data-value="${dataValue}"]`)
                   if (duplicates.length > 1) {
                     // Remove duplicates, keeping the first one
                     duplicates.forEach((dup, index) => {
    -                  if (index > 0) dup.remove();
    -                });
    +                  if (index > 0) dup.remove()
    +                })
                   }
                 }
    -          });
    -        });
    -        mutationInProgress = false;
    -      });
    -      observer.observe(code, { childList: true, subtree: true });
    -    });
    +          })
    +        })
    +        mutationInProgress = false
    +      })
    +      observer.observe(code, { childList: true, subtree: true })
    +    })
       }
     
    -  window.addEventListener('DOMContentLoaded', function () {
    +  window.addEventListener('DOMContentLoaded', function() {
         try {
           observeCodeBlocksForConumRestoration()
    -      makePlaceholdersEditable();
    -      Prism && Prism.highlightAll();
    +      makePlaceholdersEditable()
    +      Prism && Prism.highlightAll()
         } catch (error) {
    -      console.error('An error occurred while making placeholders editable:', error);
    +      console.error('An error occurred while making placeholders editable:', error)
         }
    -  });
    +  })
     
       function makePlaceholdersEditable(element) {
    -    createEditablePlaceholders(element);
    -    unnestPlaceholders();
    -    addClasses(element);
    -    addEvents(element);
    +    createEditablePlaceholders(element)
    +    unnestPlaceholders()
    +    addClasses(element)
    +    addEvents(element)
       }
     
       function createEditablePlaceholders(parentElement) {
    -    const baseElement = parentElement || document;
    -    const codeElements = baseElement.querySelectorAll("pre > code");
    +    const baseElement = parentElement || document
    +    const codeElements = baseElement.querySelectorAll('pre > code')
     
    -    codeElements.forEach(codeElement => {
    -      const preElement = codeElement.parentElement;
    -      const contentDivElement = preElement.parentElement;
    -      const listingBlockElement = contentDivElement.parentElement;
    +    codeElements.forEach((codeElement) => {
    +      const preElement = codeElement.parentElement
    +      const contentDivElement = preElement.parentElement
    +      const listingBlockElement = contentDivElement.parentElement
     
           if (listingBlockElement.classList.contains('no-placeholders')) {
    -        return;
    +        return
           }
     
    -      codeElement.classList.add('keep-markup');
    -      preprocessParentheses(codeElement);
    -      addConumSpans(codeElement);
    +      codeElement.classList.add('keep-markup')
    +      preprocessParentheses(codeElement)
    +      addConumSpans(codeElement)
     
           if (!['xml', 'html', 'rust', 'coffeescript', 'text', 'bloblang', 'blobl'].includes(codeElement.dataset.lang)) {
    -        addEditableSpan(/<.[^&A-Z]+>/g, codeElement);
    +        addEditableSpan(/<.[^&A-Z]+>/g, codeElement)
           }
    -    });
    +    })
       }
     
       if (!RegExp.escape) {
         RegExp.escape = function(s) {
    -      return s.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
    -    };
    +      return s.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&')
    +    }
       }
     
       function addEditableSpan(regex, element) {
         if (!element || !element.textContent) {
    -      return;
    +      return
         }
     
    -    const text = element.innerHTML;
    -    const placeholders = text.match(regex) || [];
    -    const processed = new Set();
    -    let newHTML = text;
    +    const text = element.innerHTML
    +    const placeholders = text.match(regex) || []
    +    const processed = new Set()
    +    let newHTML = text
     
         placeholders
           .sort((a, b) => b.length - a.length)
    -      .forEach(placeholder => {
    -        const cleanedPlaceholder = placeholder.replace(/<[^>]*>/g, '').replace(/<|>/g, '');
    +      .forEach((placeholder) => {
    +        const cleanedPlaceholder = placeholder.replace(/<[^>]*>/g, '').replace(/<|>/g, '')
             if (processed.has(placeholder) || cleanedPlaceholder.trim() === 'none') {
    -          return;
    +          return
             }
    -        const regexString = RegExp.escape(placeholder);
    -        const globalRegex = new RegExp(regexString, 'g');
    -        newHTML = newHTML.replace(globalRegex, `<${cleanedPlaceholder}>`);
    -        processed.add(placeholder);
    -      });
    -
    -    element.innerHTML = newHTML;
    +        const regexString = RegExp.escape(placeholder)
    +        const globalRegex = new RegExp(regexString, 'g')
    +        newHTML = newHTML.replace(
    +          globalRegex,
    +          `<${cleanedPlaceholder}>`
    +        )
    +        processed.add(placeholder)
    +      })
    +
    +    element.innerHTML = newHTML
       }
     
       function preprocessParentheses(element) {
         if (!element || !element.textContent) {
    -      return;
    +      return
         }
     
    -    const pattern = /(\()<\/span>|(\))<\/span>/g;
    +    const pattern = /(\()<\/span>|(\))<\/span>/g
         element.innerHTML = element.innerHTML.replace(pattern, (match, openParen, closeParen) => {
    -      return openParen || closeParen || match;
    -    });
    +      return openParen || closeParen || match
    +    })
       }
     
       function addConumSpans(element) {
         if (!element || !element.textContent) {
    -      return;
    +      return
         }
         // Handle standalone numbers in parentheses, avoiding function-like patterns
    -    const standalonePattern = /(? {
    -      return ``;
    -    });
    -    const complexPattern = /(\s\((\d+)<\/span>\)|(\s)\((\d+)\))$/gm;
    +      return ``
    +    })
    +    const complexPattern = /(\s\((\d+)<\/span>\)|(\s)\((\d+)\))$/gm
         element.innerHTML = element.innerHTML.replace(complexPattern, (match, p1, p2, p3, p4) => {
    -      return p3 ? `${p3}` : ``;
    -    });
    +      return p3 ? `${p3}` : ``
    +    })
       }
     
       function addClasses(parentElement) {
    -    const baseElement = parentElement || document;
    -    const editablePlaceholders = baseElement.querySelectorAll('[contenteditable="true"]');
    +    const baseElement = parentElement || document
    +    const editablePlaceholders = baseElement.querySelectorAll('[contenteditable="true"]')
     
    -    editablePlaceholders.forEach(placeholder => {
    -      placeholder.classList.add('editable');
    -    });
    +    editablePlaceholders.forEach((placeholder) => {
    +      placeholder.classList.add('editable')
    +    })
       }
     
       function addEvents(parentElement) {
    -    const baseElement = parentElement || document;
    -    const editablePlaceholders = baseElement.querySelectorAll('[contenteditable="true"]');
    +    const baseElement = parentElement || document
    +    const editablePlaceholders = baseElement.querySelectorAll('[contenteditable="true"]')
     
    -    editablePlaceholders.forEach(placeholder => {
    -      const dataType = placeholder.getAttribute('data-type');
    +    editablePlaceholders.forEach((placeholder) => {
    +      const dataType = placeholder.getAttribute('data-type')
           if (!dataType) {
    -        console.info('Data type attribute is missing on the placeholder.');
    -        return;
    +        console.info('Data type attribute is missing on the placeholder.')
    +        return
           }
    -      placeholder.addEventListener('input', handleInputEvent);
    -      placeholder.addEventListener('keydown', handleEnterKey);
    -      placeholder.addEventListener('blur', handleBlurEvent);
    -      placeholder.addEventListener('focus', handleFocusEvent);
    -
    -      const savedText = sessionStorage.getItem(dataType);
    -      placeholder.textContent = savedText ? savedText : `<${dataType}>`;
    -    });
    +      placeholder.addEventListener('input', handleInputEvent)
    +      placeholder.addEventListener('keydown', handleEnterKey)
    +      placeholder.addEventListener('blur', handleBlurEvent)
    +      placeholder.addEventListener('focus', handleFocusEvent)
    +
    +      const savedText = sessionStorage.getItem(dataType)
    +      placeholder.textContent = savedText ? savedText : `<${dataType}>`
    +    })
       }
     
       function handleInputEvent(event) {
    -    const dataType = event.target.dataset.type;
    -    const newText = event.target.textContent;
    +    const dataType = event.target.dataset.type
    +    const newText = event.target.textContent
     
    -    document.querySelectorAll(`[data-type="${dataType}"][contenteditable="true"]`).forEach(span => {
    +    document.querySelectorAll(`[data-type="${dataType}"][contenteditable="true"]`).forEach((span) => {
           if (!isWithinHiddenTab(span) && span !== event.target) {
    -        span.textContent = newText;
    +        span.textContent = newText
           }
    -    });
    +    })
       }
     
       function handleEnterKey(event) {
         if (event.key === 'Enter') {
    -      event.preventDefault();
    -      event.target.blur();
    +      event.preventDefault()
    +      event.target.blur()
         }
       }
     
       function handleBlurEvent() {
    -
    -    const currentText = this.textContent.trim();
    -    const dataType = this.getAttribute('data-type');
    +    const currentText = this.textContent.trim()
    +    const dataType = this.getAttribute('data-type')
     
         if (!currentText) {
    -      const defaultText = `<${dataType}>`;
    -      this.textContent = defaultText;
    +      const defaultText = `<${dataType}>`
    +      this.textContent = defaultText
     
    -      document.querySelectorAll(`[data-type="${dataType}"][contenteditable="true"]`).forEach(span => {
    -        span.textContent = defaultText;
    -      });
    +      document.querySelectorAll(`[data-type="${dataType}"][contenteditable="true"]`).forEach((span) => {
    +        span.textContent = defaultText
    +      })
         } else {
    -      sessionStorage.setItem(dataType, currentText);
    +      sessionStorage.setItem(dataType, currentText)
         }
       }
     
       function handleFocusEvent() {
         // Select all text inside the placeholder when it receives focus
    -    const range = document.createRange();
    -    const selection = window.getSelection();
    -    range.selectNodeContents(this);
    -    selection.removeAllRanges();
    -    selection.addRange(range);
    +    const range = document.createRange()
    +    const selection = window.getSelection()
    +    range.selectNodeContents(this)
    +    selection.removeAllRanges()
    +    selection.addRange(range)
       }
     
       function isWithinHiddenTab(element) {
    -    let ancestor = element.parentElement;
    +    let ancestor = element.parentElement
         while (ancestor) {
           if (ancestor.classList.contains('tabpanel') && ancestor.classList.contains('is-hidden')) {
    -        return true;
    +        return true
           }
    -      ancestor = ancestor.parentElement;
    +      ancestor = ancestor.parentElement
         }
    -    return false;
    +    return false
       }
    -})();
    +})()
    diff --git a/src/js/12-activate-tooltips.js b/src/js/12-activate-tooltips.js
    index 4e49cc84..163727ed 100644
    --- a/src/js/12-activate-tooltips.js
    +++ b/src/js/12-activate-tooltips.js
    @@ -1,5 +1,5 @@
     /* global tippy */
    -(function () {
    +;(function () {
       'use strict'
     
       document.addEventListener('DOMContentLoaded', function () {
    diff --git a/src/js/13-open-nested-tabs.js b/src/js/13-open-nested-tabs.js
    index 3c9b25b5..8d34e357 100644
    --- a/src/js/13-open-nested-tabs.js
    +++ b/src/js/13-open-nested-tabs.js
    @@ -13,8 +13,8 @@
      * - Re-run Prism for syntax highlighting when tab content becomes visible.
      * - Scroll to the selected tab.
      */
    -(function () {
    -  'use strict';
    +;(function() {
    +  'use strict'
     
       /**
        * Debounce utility function to limit the rate at which a function can fire.
    @@ -23,11 +23,11 @@
        * @returns {Function} - The debounced function.
        */
       function debounce(func, wait) {
    -    let timeout;
    -    return function (...args) {
    -      clearTimeout(timeout);
    -      timeout = setTimeout(() => func.apply(this, args), wait);
    -    };
    +    let timeout
    +    return function(...args) {
    +      clearTimeout(timeout)
    +      timeout = setTimeout(() => func.apply(this, args), wait)
    +    }
       }
     
       /**
    @@ -38,19 +38,19 @@
       const debouncedHighlight = debounce((codeElements) => {
         if (typeof Prism !== 'undefined' && Prism.highlightElement) {
           requestAnimationFrame(() => {
    -        codeElements.forEach(pre => {
    -          const code = pre.querySelector('code');
    +        codeElements.forEach((pre) => {
    +          const code = pre.querySelector('code')
               if (code) {
                 // https://prismjs.com/docs/Prism.html#.highlightElement
    -            Prism.highlightElement(code, true);
    +            Prism.highlightElement(code, true)
                 Prism.plugins.lineNumbers.resize(code)
               }
    -        });
    +        })
           })
         } else {
    -      console.warn('Prism.highlightElement() is not available. Ensure Prism.js is correctly loaded.');
    +      console.warn('Prism.highlightElement() is not available. Ensure Prism.js is correctly loaded.')
         }
    -  }, 100);
    +  }, 100)
     
       /**
        * Simulates a click on the specified tab element.
    @@ -58,7 +58,7 @@
        */
       function simulateTabClick(tabElement) {
         if (tabElement) {
    -      tabElement.click();
    +      tabElement.click()
         }
       }
     
    @@ -69,8 +69,8 @@
        */
       function stripTabParamIfHashPresent(url) {
         if (url.hash && url.searchParams.has('tab')) {
    -      url.searchParams.delete('tab');
    -      window.history.replaceState(null, '', url);
    +      url.searchParams.delete('tab')
    +      window.history.replaceState(null, '', url)
         }
       }
     
    @@ -78,35 +78,35 @@
        * Handles deep linking by activating the appropriate tab based on the URL's query parameter or hash fragment.
        */
       function handleDeepLinking() {
    -    const url = new URL(window.location.href);
    -    stripTabParamIfHashPresent(url);
    +    const url = new URL(window.location.href)
    +    stripTabParamIfHashPresent(url)
     
         // Re-parse the URL after potential modification
    -    const updatedUrl = new URL(window.location.href);
    -    const updatedTabParam = updatedUrl.searchParams.get('tab');
    -    const hash = updatedUrl.hash.substring(1); // Remove the '#' character
    +    const updatedUrl = new URL(window.location.href)
    +    const updatedTabParam = updatedUrl.searchParams.get('tab')
    +    const hash = updatedUrl.hash.substring(1) // Remove the '#' character
     
         // Define a valid hash pattern (adjust as needed)
    -    const validHashPattern = /^[a-zA-Z0-9-_]+$/;
    +    const validHashPattern = /^[a-zA-Z0-9-_]+$/
     
         // Prioritize hash fragment over query parameter
         if (hash && validHashPattern.test(hash)) {
    -      const targetTab = document.getElementById(hash);
    +      const targetTab = document.getElementById(hash)
           if (targetTab) {
    -        simulateTabClick(targetTab);
    -        return;
    +        simulateTabClick(targetTab)
    +        return
           } else {
    -        console.warn(`No tab found for hash "${hash}".`);
    +        console.warn(`No tab found for hash "${hash}".`)
           }
         }
     
         if (updatedTabParam && validHashPattern.test(updatedTabParam)) {
    -      const targetTab = document.getElementById(updatedTabParam);
    +      const targetTab = document.getElementById(updatedTabParam)
           if (targetTab) {
    -        simulateTabClick(targetTab);
    -        return;
    +        simulateTabClick(targetTab)
    +        return
           } else {
    -        console.warn(`No tab found for query parameter "${updatedTabParam}".`);
    +        console.warn(`No tab found for query parameter "${updatedTabParam}".`)
           }
         }
       }
    @@ -116,41 +116,42 @@
        * Utilizes an external library to manage synchronized tab activation.
        */
       function setupTabListeners() {
    -    const tabs = document.querySelectorAll('li.tab');
    +    const tabs = document.querySelectorAll('li.tab')
     
    -    tabs.forEach(function (tab) {
    -      tab.addEventListener('click', function (event) {
    -        event.preventDefault();
    -        const clickedTab = event.currentTarget;
    -        const tabId = clickedTab.id;
    +    tabs.forEach(function(tab) {
    +      tab.addEventListener('click', function(event) {
    +        event.preventDefault()
    +        const clickedTab = event.currentTarget
    +        const tabId = clickedTab.id
     
             // Let the external library handle synchronization
             // After synchronization, highlight code blocks within active tabs
             // Use a short timeout to allow the external library to activate tabs
             setTimeout(() => {
    -          const activePanels = document.querySelectorAll('.tabpanel:not(.is-hidden)');
    -          const codeBlocks = Array.from(activePanels).flatMap(panel => Array.from(panel.querySelectorAll('pre.highlight, pre.line-numbers.highlight')));
    +          const activePanels = document.querySelectorAll('.tabpanel:not(.is-hidden)')
    +          const codeBlocks = Array.from(activePanels).flatMap((panel) =>
    +            Array.from(panel.querySelectorAll('pre.highlight, pre.line-numbers.highlight'))
    +          )
               if (codeBlocks.length > 0) {
    -            debouncedHighlight(codeBlocks);
    +            debouncedHighlight(codeBlocks)
               }
    -        }, 100); // Adjust delay as needed based on external library's behavior
    -      });
    -    });
    +        }, 100) // Adjust delay as needed based on external library's behavior
    +      })
    +    })
       }
     
       /**
        * Initializes the tab synchronization and deep linking on page load.
        */
       function initializeTabs() {
    -    setupTabListeners();
    -    handleDeepLinking();
    +    setupTabListeners()
    +    handleDeepLinking()
       }
     
    -  window.addEventListener('DOMContentLoaded', initializeTabs);
    +  window.addEventListener('DOMContentLoaded', initializeTabs)
     
       /**
        * Handle browser navigation (back/forward buttons) to maintain tab state.
        */
    -  window.addEventListener('popstate', handleDeepLinking);
    -
    -})();
    +  window.addEventListener('popstate', handleDeepLinking)
    +})()
    diff --git a/src/js/14-markdown-dropdown.js b/src/js/14-markdown-dropdown.js
    index 5eb1727e..b9728e86 100644
    --- a/src/js/14-markdown-dropdown.js
    +++ b/src/js/14-markdown-dropdown.js
    @@ -12,7 +12,15 @@
     ;(function () {
       'use strict'
     
    -  document.addEventListener('DOMContentLoaded', init)
    +  // Run init when DOM is ready - handle both cases:
    +  // 1. If DOM is still loading, wait for DOMContentLoaded
    +  // 2. If DOM is already ready (interactive or complete), run immediately
    +  if (document.readyState === 'loading') {
    +    document.addEventListener('DOMContentLoaded', init)
    +  } else {
    +    // DOM already ready, run immediately
    +    setTimeout(init, 0)
    +  }
     
       function init () {
         const dropdowns = document.querySelectorAll('.markdown-dropdown')
    @@ -126,7 +134,8 @@
        */
       function handleCopy (markdownUrl, button) {
         // Fetch markdown content and copy to clipboard
    -    window.fetch(markdownUrl)
    +    window
    +      .fetch(markdownUrl)
           .then(function (response) {
             if (!response.ok) throw new Error('Failed to fetch')
             return response.text()
    @@ -157,20 +166,25 @@
        * Handle Ask AI about this doc
        */
       function handleAskAI () {
    -    var kapa = window.Kapa
    +    // Find and click the "Ask AI" button in the top nav to open the chat drawer
    +    var askAiBtn = document.querySelector('[data-action="open-chat"]')
     
    -    if (kapa) {
    -      // Get page title for context
    -      var pageTitle = document.querySelector('h1.page')?.textContent || 'this page'
    -      var aiPromptText = 'I have a question about the documentation page: ' + pageTitle
    +    if (askAiBtn) {
    +      askAiBtn.click()
     
    -      kapa.open({
    -        mode: 'ai',
    -        query: aiPromptText,
    -        submit: false,
    -      })
    +      // Optional: Pre-fill the chat input with context about the page
    +      // Wait a moment for the drawer to open, then set the input value
    +      setTimeout(function () {
    +        var pageTitle = document.querySelector('h1.page')?.textContent || 'this page'
    +        var chatInput = document.querySelector('#chat-panel-input')
    +
    +        if (chatInput) {
    +          chatInput.value = 'I have a question about the documentation page: ' + pageTitle
    +          chatInput.focus()
    +        }
    +      }, 100)
         } else {
    -      console.warn('Kapa AI is not available.')
    +      console.warn('Ask AI drawer is not available.')
         }
       }
     
    diff --git a/src/js/15-optimize-images.js b/src/js/15-optimize-images.js
    index 2fbcd8e0..a68e4b4c 100644
    --- a/src/js/15-optimize-images.js
    +++ b/src/js/15-optimize-images.js
    @@ -4,7 +4,7 @@
      * - Add async decoding for better rendering performance
      * - Add explicit dimensions to prevent layout shifts
      */
    -(function () {
    +;(function () {
       'use strict'
     
       // Wait for DOM to be ready
    @@ -40,9 +40,13 @@
               setImageDimensions(img)
             } else {
               // Otherwise wait for load event
    -          img.addEventListener('load', function () {
    -            setImageDimensions(this)
    -          }, { once: true })
    +          img.addEventListener(
    +            'load',
    +            function () {
    +              setImageDimensions(this)
    +            },
    +            { once: true }
    +          )
             }
           }
         })
    @@ -79,14 +83,18 @@
           img.setAttribute('height', height)
     
           // Log warning if image is significantly oversized (developer tool)
    -      if (naturalWidth > 0 && displayedWidth > 0 &&
    -          (naturalWidth > displayedWidth * 2 || naturalHeight > displayedHeight * 2)) {
    -        const savings = Math.round(((naturalWidth * naturalHeight) - (displayedWidth * displayedHeight)) /
    -          (naturalWidth * naturalHeight) * 100)
    +      if (
    +        naturalWidth > 0 &&
    +        displayedWidth > 0 &&
    +        (naturalWidth > displayedWidth * 2 || naturalHeight > displayedHeight * 2)
    +      ) {
    +        const savings = Math.round(
    +          ((naturalWidth * naturalHeight - displayedWidth * displayedHeight) / (naturalWidth * naturalHeight)) * 100
    +        )
             console.info(
               `Image oversized: ${img.src.split('/').pop()} ` +
    -          `(${naturalWidth}×${naturalHeight} displayed as ${displayedWidth}×${displayedHeight}, ` +
    -          `~${savings}% potential savings)`
    +            `(${naturalWidth}×${naturalHeight} displayed as ${displayedWidth}×${displayedHeight}, ` +
    +            `~${savings}% potential savings)`
             )
           }
         }
    diff --git a/src/js/16-bloblang-interactive.js b/src/js/16-bloblang-interactive.js
    index 12e3976c..7cc84246 100644
    --- a/src/js/16-bloblang-interactive.js
    +++ b/src/js/16-bloblang-interactive.js
    @@ -8,13 +8,13 @@
      * - Quick actions (copy, share, format)
      */
     
    -(function() {
    -  'use strict';
    +;(function() {
    +  'use strict'
     
       // State
    -  let bloblangDocs = null;
    -  let docsLoading = false;
    -  let docsLoadQueue = [];
    +  let bloblangDocs = null
    +  let docsLoading = false
    +  let docsLoadQueue = []
     
       /**
        * Parse a Bloblang snippet into mapping, input, and metadata sections.
    @@ -22,94 +22,97 @@
        * # Out: lines are ignored.
        */
       function parseBloblangSnippet(rawSnippet) {
    -    const mappingLines = [];
    -    const inputLines = [];
    -    const metaLines = [];
    +    const mappingLines = []
    +    const inputLines = []
    +    const metaLines = []
     
    -    let inSeen = false;
    -    let metaSeen = false;
    -    let ignoreAll = false;
    -    let skip = false;
    -    let currentSection = 'mapping';
    +    let inSeen = false
    +    let metaSeen = false
    +    let ignoreAll = false
    +    let skip = false
    +    let currentSection = 'mapping'
     
    -    const lines = rawSnippet.split('\n');
    +    const lines = rawSnippet.split('\n')
         for (let i = 0; i < lines.length; i++) {
    -      const line = lines[i];
    -      const trimmed = line.trim();
    +      const line = lines[i]
    +      const trimmed = line.trim()
     
    -      if (ignoreAll) continue;
    +      if (ignoreAll) continue
     
           // Check for # Skip: directive (disables Try It button)
           if (trimmed.startsWith('# Skip:')) {
    -        const value = trimmed.slice('# Skip:'.length).trim().toLowerCase();
    +        const value = trimmed
    +          .slice('# Skip:'.length)
    +          .trim()
    +          .toLowerCase()
             if (value === 'true' || value === '1' || value === 'yes') {
    -          skip = true;
    +          skip = true
             }
    -        continue;
    +        continue
           }
     
           // Ignore # Out: and # Output: lines
    -      if (trimmed.startsWith('# Out:') || trimmed.startsWith('# Output:')) continue;
    +      if (trimmed.startsWith('# Out:') || trimmed.startsWith('# Output:')) continue
     
           // Check for # In: or # Input: directive
           if (trimmed.startsWith('# In:') || trimmed.startsWith('# Input:')) {
             if (!inSeen) {
    -          inSeen = true;
    -          currentSection = 'in';
    +          inSeen = true
    +          currentSection = 'in'
               // Extract content after the directive (handle both # In: and # Input:)
    -          const colonIndex = trimmed.indexOf(':');
    -          const afterDirective = trimmed.slice(colonIndex + 1).trim();
    -          if (afterDirective) inputLines.push(afterDirective);
    +          const colonIndex = trimmed.indexOf(':')
    +          const afterDirective = trimmed.slice(colonIndex + 1).trim()
    +          if (afterDirective) inputLines.push(afterDirective)
             } else {
    -          ignoreAll = true;
    +          ignoreAll = true
             }
    -        continue;
    +        continue
           }
     
           // Check for # Meta: directive
           if (trimmed.startsWith('# Meta:')) {
             if (!metaSeen) {
    -          metaSeen = true;
    -          currentSection = 'meta';
    -          const afterMeta = trimmed.slice('# Meta:'.length).trim();
    -          if (afterMeta) metaLines.push(afterMeta);
    +          metaSeen = true
    +          currentSection = 'meta'
    +          const afterMeta = trimmed.slice('# Meta:'.length).trim()
    +          if (afterMeta) metaLines.push(afterMeta)
             } else {
    -          ignoreAll = true;
    +          ignoreAll = true
             }
    -        continue;
    +        continue
           }
     
           switch (currentSection) {
             case 'mapping':
    -          mappingLines.push(line);
    -          break;
    +          mappingLines.push(line)
    +          break
             case 'in':
               // Support multi-line commented input (# prefix on each line)
               if (trimmed.startsWith('#')) {
                 // Strip the # and any leading whitespace
    -            const content = trimmed.slice(1).trim();
    -            if (content) inputLines.push(content);
    +            const content = trimmed.slice(1).trim()
    +            if (content) inputLines.push(content)
               } else if (trimmed === '') {
                 // Allow empty lines within the block
    -            continue;
    +            continue
               } else {
                 // Non-comment line - we've exited the input section
    -            currentSection = 'mapping';
    -            mappingLines.push(line);
    +            currentSection = 'mapping'
    +            mappingLines.push(line)
               }
    -          break;
    +          break
             case 'meta':
               // Support multi-line commented metadata (# prefix on each line)
               if (trimmed.startsWith('#')) {
    -            const content = trimmed.slice(1).trim();
    -            if (content) metaLines.push(content);
    +            const content = trimmed.slice(1).trim()
    +            if (content) metaLines.push(content)
               } else if (trimmed === '') {
    -            continue;
    +            continue
               } else {
    -            currentSection = 'mapping';
    -            mappingLines.push(line);
    +            currentSection = 'mapping'
    +            mappingLines.push(line)
               }
    -          break;
    +          break
           }
         }
     
    @@ -117,8 +120,8 @@
           mapping: mappingLines.join('\n').trim(),
           input: inputLines.join('\n').trim(),
           meta: metaLines.join('\n').trim(),
    -      skip: skip
    -    };
    +      skip: skip,
    +    }
       }
     
       /**
    @@ -126,18 +129,18 @@
        */
       async function tryFetchConnectJSON(version) {
         try {
    -      const url = `/redpanda-connect/components/_attachments/connect-${version}.json`;
    -      const response = await fetch(url);
    +      const url = `/connect/components/_attachments/connect-${version}.json`
    +      const response = await fetch(url)
     
           if (!response.ok) {
    -        return null;
    +        return null
           }
     
    -      const data = await response.json();
    -      return data;
    +      const data = await response.json()
    +      return data
         } catch (e) {
           // Silent fail - expected when trying fallback versions
    -      return null;
    +      return null
         }
       }
     
    @@ -147,21 +150,22 @@
       function transformConnectData(data) {
         const docs = {
           functions: {},
    -      methods: {}
    -    };
    +      methods: {},
    +    }
     
         // Transform Bloblang functions
         if (Array.isArray(data['bloblang-functions'])) {
    -      data['bloblang-functions'].forEach(fn => {
    -        const params = fn.params && fn.params.named ? fn.params.named.map(p => ({
    -          name: p.name,
    -          type: p.type || 'any',
    -          description: p.description || ''
    -        })) : [];
    -
    -        const paramSignature = params.length > 0
    -          ? params.map(p => p.name).join(', ')
    -          : '';
    +      data['bloblang-functions'].forEach((fn) => {
    +        const params =
    +          fn.params && fn.params.named
    +            ? fn.params.named.map((p) => ({
    +                name: p.name,
    +                type: p.type || 'any',
    +                description: p.description || '',
    +              }))
    +            : []
    +
    +        const paramSignature = params.length > 0 ? params.map((p) => p.name).join(', ') : ''
     
             docs.functions[fn.name] = {
               signature: `${fn.name}(${paramSignature})`,
    @@ -169,31 +173,34 @@
               parameters: params,
               returns: 'any',
               category: fn.category || 'general',
    -          url: `https://docs.redpanda.com/redpanda-connect/guides/bloblang/functions/#${fn.name.toLowerCase().replace(/_/g, '-')}`
    -        };
    +          url: `https://docs.redpanda.com/connect/guides/bloblang/functions/#${fn.name
    +            .toLowerCase()
    +            .replace(/_/g, '-')}`,
    +        }
     
             // Add example if available
             if (fn.examples && fn.examples.length > 0) {
    -          const example = fn.examples[0];
    +          const example = fn.examples[0]
               if (example.mapping) {
    -            docs.functions[fn.name].example = example.mapping;
    +            docs.functions[fn.name].example = example.mapping
               }
             }
    -      });
    +      })
         }
     
         // Transform Bloblang methods
         if (Array.isArray(data['bloblang-methods'])) {
    -      data['bloblang-methods'].forEach(method => {
    -        const params = method.params && method.params.named ? method.params.named.map(p => ({
    -          name: p.name,
    -          type: p.type || 'any',
    -          description: p.description || ''
    -        })) : [];
    -
    -        const paramSignature = params.length > 0
    -          ? params.map(p => p.name).join(', ')
    -          : '';
    +      data['bloblang-methods'].forEach((method) => {
    +        const params =
    +          method.params && method.params.named
    +            ? method.params.named.map((p) => ({
    +                name: p.name,
    +                type: p.type || 'any',
    +                description: p.description || '',
    +              }))
    +            : []
    +
    +        const paramSignature = params.length > 0 ? params.map((p) => p.name).join(', ') : ''
     
             docs.methods[method.name] = {
               signature: `${method.name}(${paramSignature})`,
    @@ -201,20 +208,22 @@
               parameters: params,
               returns: 'any',
               category: method.categories && method.categories.length > 0 ? method.categories[0].Category : 'general',
    -          url: `https://docs.redpanda.com/redpanda-connect/guides/bloblang/methods/#${method.name.toLowerCase().replace(/_/g, '-')}`
    -        };
    +          url: `https://docs.redpanda.com/connect/guides/bloblang/methods/#${method.name
    +            .toLowerCase()
    +            .replace(/_/g, '-')}`,
    +        }
     
             // Add example if available
             if (method.examples && method.examples.length > 0) {
    -          const example = method.examples[0];
    +          const example = method.examples[0]
               if (example.mapping) {
    -            docs.methods[method.name].example = example.mapping;
    +            docs.methods[method.name].example = example.mapping
               }
             }
    -      });
    +      })
         }
     
    -    return docs;
    +    return docs
       }
     
       /**
    @@ -222,16 +231,16 @@
        * Caches in localStorage for 1 hour to avoid repeated fetches
        */
       async function getConnectVersion() {
    -    var CACHE_KEY = 'bloblang-connect-version';
    -    var CACHE_TTL = 60 * 60 * 1000; // 1 hour
    +    var CACHE_KEY = 'bloblang-connect-version'
    +    var CACHE_TTL = 60 * 60 * 1000 // 1 hour
     
         // Check cache first
         try {
    -      var cached = localStorage.getItem(CACHE_KEY);
    +      var cached = localStorage.getItem(CACHE_KEY)
           if (cached) {
    -        var parsed = JSON.parse(cached);
    +        var parsed = JSON.parse(cached)
             if (Date.now() - parsed.timestamp < CACHE_TTL) {
    -          return parsed.version;
    +          return parsed.version
             }
           }
         } catch (e) {
    @@ -240,29 +249,32 @@
     
         // Fetch from antora.yml (no rate limits, CDN-served)
         try {
    -      var resp = await fetch('https://raw.githubusercontent.com/redpanda-data/rp-connect-docs/main/antora.yml');
    +      var resp = await fetch('https://raw.githubusercontent.com/redpanda-data/rp-connect-docs/main/antora.yml')
           if (resp.ok) {
    -        var yaml = await resp.text();
    -        var match = yaml.match(/latest-connect-version:\s*['"]?(\d+\.\d+\.\d+)/);
    +        var yaml = await resp.text()
    +        var match = yaml.match(/latest-connect-version:\s*['"]?(\d+\.\d+\.\d+)/)
             if (match) {
    -          var version = match[1];
    +          var version = match[1]
               // Cache the result
               try {
    -            localStorage.setItem(CACHE_KEY, JSON.stringify({
    -              version: version,
    -              timestamp: Date.now()
    -            }));
    +            localStorage.setItem(
    +              CACHE_KEY,
    +              JSON.stringify({
    +                version: version,
    +                timestamp: Date.now(),
    +              })
    +            )
               } catch (e) {
                 // localStorage not available
               }
    -          return version;
    +          return version
             }
           }
         } catch (e) {
           // Silent fail - will use fallback versions
         }
     
    -    return null;
    +    return null
       }
     
       /**
    @@ -270,74 +282,74 @@
        */
       async function loadBloblangDocs() {
         if (bloblangDocs) {
    -      return bloblangDocs;
    +      return bloblangDocs
         }
     
         if (docsLoading) {
           return new Promise((resolve) => {
    -        docsLoadQueue.push(resolve);
    -      });
    +        docsLoadQueue.push(resolve)
    +      })
         }
     
    -    docsLoading = true;
    +    docsLoading = true
     
         try {
    -      var data = null;
    -      var isDocsUiPreview = window.location.hostname.includes('docs-ui.netlify.app');
    +      var data = null
    +      var isDocsUiPreview = window.location.hostname.includes('docs-ui.netlify.app')
     
           // Skip remote fetches on docs-ui preview site - JSON files don't exist there
           if (!isDocsUiPreview) {
             // Try to get latest version from cached antora.yml
    -        var latestVersion = await getConnectVersion();
    +        var latestVersion = await getConnectVersion()
             if (latestVersion) {
    -          data = await tryFetchConnectJSON(latestVersion);
    +          data = await tryFetchConnectJSON(latestVersion)
             }
     
             // Fallback: try known recent versions
             if (!data) {
    -          var fallbackVersions = ['4.79.0', '4.78.0', '4.77.0', '4.76.0', '4.75.0'];
    +          var fallbackVersions = ['4.79.0', '4.78.0', '4.77.0', '4.76.0', '4.75.0']
               for (var i = 0; i < fallbackVersions.length; i++) {
    -            data = await tryFetchConnectJSON(fallbackVersions[i]);
    -            if (data) break;
    +            data = await tryFetchConnectJSON(fallbackVersions[i])
    +            if (data) break
               }
             }
           }
     
           // Transform data to our format
           if (data) {
    -        bloblangDocs = transformConnectData(data);
    +        bloblangDocs = transformConnectData(data)
           } else {
             // Fallback to static file if available (or primary source on localhost)
             try {
    -          var response = await fetch(uiRootPath + '/bloblang-docs.json');
    -          bloblangDocs = await response.json();
    +          var response = await fetch(uiRootPath + '/bloblang-docs.json')
    +          bloblangDocs = await response.json()
             } catch (err) {
               // No documentation available - tooltips will be disabled
    -          bloblangDocs = { functions: {}, methods: {} };
    +          bloblangDocs = { functions: {}, methods: {} }
             }
           }
     
    -      docsLoading = false;
    +      docsLoading = false
     
           // Resolve all queued promises
           for (const resolve of docsLoadQueue) {
    -        resolve(bloblangDocs);
    +        resolve(bloblangDocs)
           }
    -      docsLoadQueue = [];
    +      docsLoadQueue = []
     
    -      return bloblangDocs;
    +      return bloblangDocs
         } catch (error) {
           // Unexpected error - tooltips will be disabled
    -      docsLoading = false;
    -      bloblangDocs = { functions: {}, methods: {} };
    +      docsLoading = false
    +      bloblangDocs = { functions: {}, methods: {} }
     
           // Resolve all queued promises with fallback
           for (const resolve of docsLoadQueue) {
    -        resolve(bloblangDocs);
    +        resolve(bloblangDocs)
           }
    -      docsLoadQueue = [];
    +      docsLoadQueue = []
     
    -      return bloblangDocs;
    +      return bloblangDocs
         }
       }
     
    @@ -349,72 +361,76 @@
           
    ${escapeHtml(doc.signature)}
    ${formatDescription(doc.description)}
    - `; + ` if (doc.parameters && doc.parameters.length > 0) { - html += '
    Parameters:
      '; - doc.parameters.forEach(param => { - html += `
    • ${escapeHtml(param.name)} (${escapeHtml(param.type)}): ${formatDescription(param.description)}
    • `; - }); - html += '
    '; + html += '
    Parameters:
      ' + doc.parameters.forEach((param) => { + html += `
    • ${escapeHtml(param.name)} (${escapeHtml(param.type)}): ${formatDescription( + param.description + )}
    • ` + }) + html += '
    ' } if (doc.returns) { - html += `
    Returns: ${escapeHtml(doc.returns)}
    `; + html += `
    Returns: ${escapeHtml(doc.returns)}
    ` } if (doc.example) { - html += `
    ${escapeHtml(doc.example)}
    `; + html += `
    ${escapeHtml(doc.example)}
    ` } if (doc.url) { - html += `View full documentation →`; + html += `View full documentation →` } - html += '
    '; - return html; + html += '
    ' + return html } /** * Escape HTML to prevent XSS */ function escapeHtml(text) { - const div = document.createElement('div'); - div.textContent = text; - return div.innerHTML; + const div = document.createElement('div') + div.textContent = text + return div.innerHTML } /** * Format description text - escape HTML but convert backticks to tags */ function formatDescription(text) { - if (!text) return ''; + if (!text) return '' // First escape HTML - const escaped = escapeHtml(text); + const escaped = escapeHtml(text) // Then convert backtick-wrapped text to tags - return escaped.replace(/`([^`]+)`/g, '$1'); + return escaped.replace(/`([^`]+)`/g, '$1') } /** * Check if device is touch-based */ function isTouchDevice() { - return 'ontouchstart' in window || navigator.maxTouchPoints > 0; + return 'ontouchstart' in window || navigator.maxTouchPoints > 0 } /** * Add tooltips to Bloblang tokens */ function addDocumentationTooltips(codeBlock) { - const isTouch = isTouchDevice(); + const isTouch = isTouchDevice() if (!window.tippy) { - console.warn('Tippy.js not loaded, skipping Bloblang tooltips'); - return; + console.warn('Tippy.js not loaded, skipping Bloblang tooltips') + return } - loadBloblangDocs().then(docs => { - if (!docs) return; + loadBloblangDocs().then((docs) => { + if (!docs) return // Tippy configuration - different trigger for touch vs mouse const getTippyConfig = (doc) => ({ @@ -431,129 +447,131 @@ hideOnClick: isTouch ? 'toggle' : true, onShow(instance) { // Hide other tooltips - document.querySelectorAll('.tippy-box').forEach(box => { + document.querySelectorAll('.tippy-box').forEach((box) => { if (box !== instance.popper) { - box._tippy && box._tippy.hide(); + box._tippy && box._tippy.hide() } - }); - } - }); + }) + }, + }) // Add tooltips to functions - codeBlock.querySelectorAll('.token.function').forEach(el => { - const functionName = el.textContent.trim(); - const doc = docs.functions[functionName]; + codeBlock.querySelectorAll('.token.function').forEach((el) => { + const functionName = el.textContent.trim() + const doc = docs.functions[functionName] if (doc) { - el.classList.add('has-documentation'); - el.style.cursor = 'help'; - el.setAttribute('tabindex', '0'); - el.setAttribute('role', 'button'); - el.setAttribute('aria-label', `${functionName} function documentation`); + el.classList.add('has-documentation') + el.style.cursor = 'help' + el.setAttribute('tabindex', '0') + el.setAttribute('role', 'button') + el.setAttribute('aria-label', `${functionName} function documentation`) if (isTouch) { - el.setAttribute('aria-haspopup', 'dialog'); + el.setAttribute('aria-haspopup', 'dialog') } - tippy(el, getTippyConfig(doc)); + tippy(el, getTippyConfig(doc)) } - }); + }) // Add tooltips to methods - codeBlock.querySelectorAll('.token.method').forEach(el => { - const methodText = el.textContent.trim(); - const methodName = methodText.replace(/^\./, '').replace(/\(\)$/, ''); - const doc = docs.methods[methodName]; + codeBlock.querySelectorAll('.token.method').forEach((el) => { + const methodText = el.textContent.trim() + const methodName = methodText.replace(/^\./, '').replace(/\(\)$/, '') + const doc = docs.methods[methodName] if (doc) { - el.classList.add('has-documentation'); - el.style.cursor = 'help'; - el.setAttribute('tabindex', '0'); - el.setAttribute('role', 'button'); - el.setAttribute('aria-label', `${methodName} method documentation`); + el.classList.add('has-documentation') + el.style.cursor = 'help' + el.setAttribute('tabindex', '0') + el.setAttribute('role', 'button') + el.setAttribute('aria-label', `${methodName} method documentation`) if (isTouch) { - el.setAttribute('aria-haspopup', 'dialog'); + el.setAttribute('aria-haspopup', 'dialog') } - tippy(el, getTippyConfig(doc)); + tippy(el, getTippyConfig(doc)) } - }); + }) // Add keyboard accessibility - codeBlock.querySelectorAll('.has-documentation').forEach(el => { + codeBlock.querySelectorAll('.has-documentation').forEach((el) => { el.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { - e.preventDefault(); - el._tippy && el._tippy.show(); + e.preventDefault() + el._tippy && el._tippy.show() } else if (e.key === 'Escape') { - el._tippy && el._tippy.hide(); + el._tippy && el._tippy.hide() } - }); - }); - }); + }) + }) + }) } /** * Add "Try It" button to code block */ function addTryItButton(listingBlock, code) { - const toolbox = listingBlock.querySelector('.source-toolbox'); - if (!toolbox) return; + const toolbox = listingBlock.querySelector('.source-toolbox') + if (!toolbox) return // Check if already has button - if (toolbox.querySelector('.try-bloblang-button')) return; + if (toolbox.querySelector('.try-bloblang-button')) return // Parse the code block to extract mapping, input, and metadata from comments - const parsed = parseBloblangSnippet(code); + const parsed = parseBloblangSnippet(code) // Skip if # Skip: true directive is present - if (parsed.skip) return; + if (parsed.skip) return // Helper to get attribute from listingblock, pre, or code element const getDataAttr = (name) => { - const pre = listingBlock.querySelector('pre'); - const codeEl = listingBlock.querySelector('code'); - return listingBlock.getAttribute(name) || - (pre && pre.getAttribute(name)) || - (codeEl && codeEl.getAttribute(name)); - }; + const pre = listingBlock.querySelector('pre') + const codeEl = listingBlock.querySelector('code') + return listingBlock.getAttribute(name) || (pre && pre.getAttribute(name)) || (codeEl && codeEl.getAttribute(name)) + } // Use parsed values, with fallbacks from data attributes or defaults - const mapping = parsed.mapping || code; - const inputData = parsed.input || getDataAttr('data-bloblang-input') || '{}'; - const metadata = parsed.meta || getDataAttr('data-bloblang-metadata') || '{}'; + const mapping = parsed.mapping || code + const inputData = parsed.input || getDataAttr('data-bloblang-input') || '{}' + const metadata = parsed.meta || getDataAttr('data-bloblang-metadata') || '{}' - const button = document.createElement('button'); - button.className = 'try-bloblang-button'; - button.textContent = 'Try It'; - button.setAttribute('aria-label', 'Try this Bloblang mapping'); + const button = document.createElement('button') + button.className = 'try-bloblang-button' + button.textContent = 'Try It' + button.setAttribute('aria-label', 'Try this Bloblang mapping') button.addEventListener('click', () => { - openBloblangPlayground(mapping, inputData, metadata); - }); + openBloblangPlayground(mapping, inputData, metadata) + }) // Preload WASM and scripts on hover for faster "Try It" experience - button.addEventListener('mouseenter', () => { - loadRequiredScripts().then(() => loadBloblangWasm()); - }, { once: true }); + button.addEventListener( + 'mouseenter', + () => { + loadRequiredScripts().then(() => loadBloblangWasm()) + }, + { once: true } + ) // Add to toolbox - toolbox.appendChild(button); + toolbox.appendChild(button) // Initialize tooltip if tippy is available (skip on touch devices) if (window.tippy && !isTouchDevice()) { - button.setAttribute('data-tippy-content', 'Execute this mapping in a mini-playground'); + button.setAttribute('data-tippy-content', 'Execute this mapping in a mini-playground') tippy(button, { - delay: [200, 0] - }); + delay: [200, 0], + }) } } // WASM and script loading state - let wasmLoading = false; - let wasmLoaded = false; - let wasmLoadPromise = null; - let scriptsLoaded = false; - let scriptsLoadPromise = null; + let wasmLoading = false + let wasmLoaded = false + let wasmLoadPromise = null + let scriptsLoaded = false + let scriptsLoadPromise = null /** * Dynamically load a script @@ -562,16 +580,16 @@ return new Promise((resolve, reject) => { // Check if already loaded if (document.querySelector(`script[src="${src}"]`)) { - resolve(); - return; + resolve() + return } - const script = document.createElement('script'); - script.src = src; - script.onload = resolve; - script.onerror = () => reject(new Error(`Failed to load ${src}`)); - document.head.appendChild(script); - }); + const script = document.createElement('script') + script.src = src + script.onload = resolve + script.onerror = () => reject(new Error(`Failed to load ${src}`)) + document.head.appendChild(script) + }) } /** @@ -579,36 +597,38 @@ */ function loadRequiredScripts() { if (scriptsLoaded) { - return Promise.resolve(); + return Promise.resolve() } if (scriptsLoadPromise) { - return scriptsLoadPromise; + return scriptsLoadPromise } - const rootPath = typeof uiRootPath !== 'undefined' ? uiRootPath : '/_'; + const rootPath = typeof uiRootPath !== 'undefined' ? uiRootPath : '/_' scriptsLoadPromise = Promise.all([ // Load wasm_exec.js if Go is not defined typeof Go === 'undefined' ? loadScript(rootPath + '/js/vendor/wasm_exec.js') : Promise.resolve(), // Load Ace if not defined - typeof ace === 'undefined' ? loadScript(rootPath + '/js/vendor/ace/ace.js') : Promise.resolve() - ]).then(() => { - // Load Ace dependencies after ace.js - const acePromises = []; - if (typeof ace !== 'undefined') { - acePromises.push( - loadScript(rootPath + '/js/vendor/ace/theme-github.js'), - loadScript(rootPath + '/js/vendor/ace/mode-json.js'), - loadScript(rootPath + '/js/vendor/ace/mode-bloblang.js') - ); - } - return Promise.all(acePromises); - }).then(() => { - scriptsLoaded = true; - }); + typeof ace === 'undefined' ? loadScript(rootPath + '/js/vendor/ace/ace.js') : Promise.resolve(), + ]) + .then(() => { + // Load Ace dependencies after ace.js + const acePromises = [] + if (typeof ace !== 'undefined') { + acePromises.push( + loadScript(rootPath + '/js/vendor/ace/theme-github.js'), + loadScript(rootPath + '/js/vendor/ace/mode-json.js'), + loadScript(rootPath + '/js/vendor/ace/mode-bloblang.js') + ) + } + return Promise.all(acePromises) + }) + .then(() => { + scriptsLoaded = true + }) - return scriptsLoadPromise; + return scriptsLoadPromise } /** @@ -616,59 +636,74 @@ */ function loadBloblangWasm() { if (wasmLoaded && window.blobl) { - return Promise.resolve(); + return Promise.resolve() } if (wasmLoading && wasmLoadPromise) { - return wasmLoadPromise; + return wasmLoadPromise } - wasmLoading = true; + wasmLoading = true // WASM path varies by build type: // - Production/Netlify: /blobl.wasm (site root) // - UI Preview (local dev): /_/blobl.wasm // Use isUiPreview variable set in head-scripts.hbs to determine correct path - const rootPath = typeof uiRootPath !== 'undefined' ? uiRootPath : '/_'; - const siteRoot = typeof siteRootPath !== 'undefined' ? siteRootPath : ''; - const isPreview = typeof isUiPreview !== 'undefined' ? isUiPreview : false; + const rootPath = typeof uiRootPath !== 'undefined' ? uiRootPath : '/_' + const siteRoot = typeof siteRootPath !== 'undefined' ? siteRootPath : '' + const isPreview = typeof isUiPreview !== 'undefined' ? isUiPreview : false // Select the correct path based on environment - no fallback to avoid 404s - const wasmPath = isPreview ? rootPath + '/blobl.wasm' : siteRoot + '/blobl.wasm'; + const wasmPath = isPreview ? rootPath + '/blobl.wasm' : siteRoot + '/blobl.wasm' wasmLoadPromise = new Promise((resolve, reject) => { loadRequiredScripts() .then(() => { if (typeof Go === 'undefined') { - reject(new Error('Go WASM runtime not available')); - return; + // Reset state before rejecting to allow retry + wasmLoading = false + wasmLoadPromise = null + wasmLoaded = false + reject(new Error('Go WASM runtime not available')) + return } - const go = new Go(); + const go = new Go() fetch(wasmPath) .then((response) => { if (!response.ok) { - throw new Error('WASM file not found at ' + wasmPath); + throw new Error('WASM file not found at ' + wasmPath) } - const responseClone = response.clone(); - return WebAssembly.instantiateStreaming(response, go.importObject) - .catch(async () => { - const bytes = await responseClone.arrayBuffer(); - return WebAssembly.instantiate(bytes, go.importObject); - }); + const responseClone = response.clone() + return WebAssembly.instantiateStreaming(response, go.importObject).catch(async () => { + const bytes = await responseClone.arrayBuffer() + return WebAssembly.instantiate(bytes, go.importObject) + }) }) .then((result) => { - go.run(result.instance); - wasmLoaded = true; - wasmLoading = false; - resolve(); + go.run(result.instance) + wasmLoaded = true + wasmLoading = false + resolve() + }) + .catch((error) => { + // Reset state before rejecting to allow retry + wasmLoading = false + wasmLoadPromise = null + wasmLoaded = false + reject(error) }) - .catch(reject); }) - .catch(reject); - }); + .catch((error) => { + // Reset state before rejecting to allow retry + wasmLoading = false + wasmLoadPromise = null + wasmLoaded = false + reject(error) + }) + }) - return wasmLoadPromise; + return wasmLoadPromise } /** @@ -676,22 +711,22 @@ */ function initAceEditor(elementId, mode, readOnly, initialValue, options = {}) { if (typeof ace === 'undefined') { - return null; + return null } - const editor = ace.edit(elementId); + const editor = ace.edit(elementId) // Set theme - use github if available, otherwise use a built-in light theme try { - editor.setTheme('ace/theme/github'); + editor.setTheme('ace/theme/github') } catch (e) { // Fallback - textmate is a built-in light theme - console.warn('GitHub theme not available, using default'); + console.warn('GitHub theme not available, using default') } - editor.session.setMode(mode); - editor.setReadOnly(readOnly); - editor.setValue(initialValue || '', -1); + editor.session.setMode(mode) + editor.setReadOnly(readOnly) + editor.setValue(initialValue || '', -1) // Build editor options - if maxLines is null, don't set it (use CSS height instead) const editorOptions = { @@ -702,24 +737,24 @@ tabSize: 2, useSoftTabs: true, wrap: true, - minLines: options.minLines || 4, - useWorker: false // Disable workers to avoid 404s for missing worker files - }; + minLines: options.minLines || 5, + useWorker: false, // Disable workers to avoid 404s for missing worker files + } // Only set maxLines if not explicitly null (null = use CSS height with scrollbar) if (options.maxLines !== null) { - editorOptions.maxLines = options.maxLines !== undefined ? options.maxLines : 15; + editorOptions.maxLines = options.maxLines !== undefined ? options.maxLines : 15 } - editor.setOptions(editorOptions); + editor.setOptions(editorOptions) // Force light background via CSS as fallback - const container = document.getElementById(elementId); + const container = document.getElementById(elementId) if (container) { - container.style.backgroundColor = '#fff'; + container.style.backgroundColor = '#fff' } - return editor; + return editor } /** @@ -727,32 +762,32 @@ * Matches the encoding used by the main playground. */ function encodeBase64(str) { - const utf8Bytes = new TextEncoder().encode(str); - let binaryStr = ''; + const utf8Bytes = new TextEncoder().encode(str) + let binaryStr = '' for (let i = 0; i < utf8Bytes.length; i++) { - binaryStr += String.fromCharCode(utf8Bytes[i]); + binaryStr += String.fromCharCode(utf8Bytes[i]) } - return window.btoa(binaryStr); + return window.btoa(binaryStr) } /** * Build the full playground URL with encoded parameters */ function buildPlaygroundUrl(input, mapping, meta) { - const baseUrl = '/redpanda-connect/guides/bloblang/playground/'; - const params = new URLSearchParams(); + const baseUrl = '/connect/guides/bloblang/playground/' + const params = new URLSearchParams() if (input) { - params.set('input', encodeBase64(input)); + params.set('input', encodeBase64(input)) } if (mapping) { - params.set('map', encodeBase64(mapping)); + params.set('map', encodeBase64(mapping)) } // Always include meta to prevent main playground from showing "Loading..." - params.set('meta', encodeBase64(meta || '{}')); + params.set('meta', encodeBase64(meta || '{}')) - const queryString = params.toString(); - return queryString ? `${baseUrl}?${queryString}` : baseUrl; + const queryString = params.toString() + return queryString ? `${baseUrl}?${queryString}` : baseUrl } /** @@ -760,14 +795,14 @@ */ function openBloblangPlayground(mapping, inputData, metadata) { // Create modal overlay - const overlay = document.createElement('div'); - overlay.className = 'bloblang-playground-overlay'; - overlay.setAttribute('role', 'dialog'); - overlay.setAttribute('aria-modal', 'true'); - overlay.setAttribute('aria-labelledby', 'playground-title'); + const overlay = document.createElement('div') + overlay.className = 'bloblang-playground-overlay' + overlay.setAttribute('role', 'dialog') + overlay.setAttribute('aria-modal', 'true') + overlay.setAttribute('aria-labelledby', 'playground-title') // Build initial playground URL with current data - const initialPlaygroundUrl = buildPlaygroundUrl(inputData || '{}', mapping, metadata || '{}'); + const initialPlaygroundUrl = buildPlaygroundUrl(inputData || '{}', mapping, metadata || '{}') overlay.innerHTML = `
- `; + ` - document.body.appendChild(overlay); + document.body.appendChild(overlay) // Get elements - const modal = overlay.querySelector('.bloblang-mini-playground'); - const closeBtn = overlay.querySelector('.mini-playground-close'); - const runBtn = overlay.querySelector('.mini-playground-run'); - const copyBtn = overlay.querySelector('.mini-playground-copy-output'); - const statusEl = overlay.querySelector('.mini-playground-status'); + const modal = overlay.querySelector('.bloblang-mini-playground') + const closeBtn = overlay.querySelector('.mini-playground-close') + const runBtn = overlay.querySelector('.mini-playground-run') + const copyBtn = overlay.querySelector('.mini-playground-copy-output') + const statusEl = overlay.querySelector('.mini-playground-status') // Focus trap for accessibility function setupFocusTrap() { - const focusableSelector = 'button:not([disabled]), [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'; + const focusableSelector = + 'button:not([disabled]), [href], input, select, textarea, [tabindex]:not([tabindex="-1"])' modal.addEventListener('keydown', (e) => { - if (e.key !== 'Tab') return; + if (e.key !== 'Tab') return - const focusableElements = Array.from(modal.querySelectorAll(focusableSelector)); - if (focusableElements.length === 0) return; + const focusableElements = Array.from(modal.querySelectorAll(focusableSelector)) + if (focusableElements.length === 0) return - const firstEl = focusableElements[0]; - const lastEl = focusableElements[focusableElements.length - 1]; + const firstEl = focusableElements[0] + const lastEl = focusableElements[focusableElements.length - 1] if (e.shiftKey && document.activeElement === firstEl) { - e.preventDefault(); - lastEl.focus(); + e.preventDefault() + lastEl.focus() } else if (!e.shiftKey && document.activeElement === lastEl) { - e.preventDefault(); - firstEl.focus(); + e.preventDefault() + firstEl.focus() } - }); + }) // Focus first focusable element (close button) - closeBtn.focus(); + closeBtn.focus() } - setupFocusTrap(); + setupFocusTrap() // Editor references (will be set after scripts load) - let inputEditor = null; - let mappingEditor = null; - let outputEditor = null; + let inputEditor = null + let mappingEditor = null + let outputEditor = null + + // Store metadata for reuse in runMapping and full playground link + const playgroundMetadata = metadata || '{}' // Show loading status - showStatus('Loading editor...', 'info'); + showStatus('Loading editor...', 'info') // Load required scripts first, then initialize editors and WASM loadRequiredScripts() .then(() => { // Initialize Ace editors after scripts are loaded // Disable maxLines auto-sizing so CSS controls height and Ace scrollbar works - inputEditor = initAceEditor('mini-playground-input', 'ace/mode/json', false, inputData || '{}', { maxLines: null }); - mappingEditor = initAceEditor('mini-playground-mapping', 'ace/mode/bloblang', false, mapping, { maxLines: null }); - outputEditor = initAceEditor('mini-playground-output', 'ace/mode/json', true, '', { maxLines: null }); + inputEditor = initAceEditor('mini-playground-input', 'ace/mode/json', false, inputData || '{}', { + maxLines: null, + }) + mappingEditor = initAceEditor('mini-playground-mapping', 'ace/mode/bloblang', false, mapping, { + maxLines: null, + }) + outputEditor = initAceEditor('mini-playground-output', 'ace/mode/json', true, '', { maxLines: null }) // Force resize after initialization to ensure scrollbars work - if (inputEditor) inputEditor.resize(true); - if (mappingEditor) mappingEditor.resize(true); - if (outputEditor) outputEditor.resize(true); + if (inputEditor) inputEditor.resize(true) + if (mappingEditor) mappingEditor.resize(true) + if (outputEditor) outputEditor.resize(true) // Add keyboard shortcut for running if (mappingEditor) { mappingEditor.commands.addCommand({ name: 'runMapping', bindKey: { win: 'Ctrl-Enter', mac: 'Cmd-Enter' }, - exec: runMapping - }); + exec: runMapping, + }) } if (inputEditor) { inputEditor.commands.addCommand({ name: 'runMapping', bindKey: { win: 'Ctrl-Enter', mac: 'Cmd-Enter' }, - exec: runMapping - }); - inputEditor.focus(); + exec: runMapping, + }) + inputEditor.focus() } - showStatus('Loading...', 'info'); + showStatus('Loading...', 'info') // Now load WASM - return loadBloblangWasm(); + return loadBloblangWasm() }) .then(() => { - showStatus('Ready', 'ready'); - runBtn.disabled = false; + showStatus('Ready', 'ready') + runBtn.disabled = false // Focus mapping editor if (mappingEditor) { - mappingEditor.focus(); + mappingEditor.focus() } }) .catch((err) => { - showStatus('Failed to load: ' + err.message, 'error'); - console.error('Mini-playground load error:', err); - }); + showStatus('Failed to load: ' + err.message, 'error') + console.error('Mini-playground load error:', err) + }) // Close handlers function closePlayground() { - document.removeEventListener('keydown', handleEscape); + document.removeEventListener('keydown', handleEscape) // Destroy Ace editors - if (inputEditor) inputEditor.destroy(); - if (mappingEditor) mappingEditor.destroy(); - if (outputEditor) outputEditor.destroy(); - overlay.remove(); + if (inputEditor) inputEditor.destroy() + if (mappingEditor) mappingEditor.destroy() + if (outputEditor) outputEditor.destroy() + overlay.remove() } function handleEscape(e) { if (e.key === 'Escape') { - closePlayground(); + closePlayground() } } overlay.addEventListener('click', (e) => { - if (e.target === overlay) closePlayground(); - }); - closeBtn.addEventListener('click', closePlayground); - document.addEventListener('keydown', handleEscape); + if (e.target === overlay) closePlayground() + }) + closeBtn.addEventListener('click', closePlayground) + document.addEventListener('keydown', handleEscape) // Run mapping function runMapping() { - const currentMapping = mappingEditor ? mappingEditor.getValue() : ''; - const currentInput = inputEditor ? inputEditor.getValue() : '{}'; + const currentMapping = mappingEditor ? mappingEditor.getValue() : '' + const currentInput = inputEditor ? inputEditor.getValue() : '{}' if (!currentMapping.trim()) { - showStatus('Please enter a mapping', 'error'); - return; + showStatus('Please enter a mapping', 'error') + return } if (!window.blobl) { - showStatus('WASM not loaded yet', 'error'); - return; + showStatus('WASM not loaded yet', 'error') + return } try { - showStatus('Running...', 'info'); - const result = window.blobl(currentMapping, currentInput, '{}'); + showStatus('Running...', 'info') + const result = window.blobl(currentMapping, currentInput, playgroundMetadata) if (typeof result === 'string' && result.startsWith('Error:')) { - showStatus(result, 'error'); + showStatus(result, 'error') if (outputEditor) { - outputEditor.setValue('', -1); - outputEditor.scrollToRow(0); + outputEditor.setValue('', -1) + outputEditor.scrollToRow(0) } } else { // Format JSON if possible - let formattedResult = result; + let formattedResult = result try { - const parsed = JSON.parse(result); + const parsed = JSON.parse(result) // Extract .msg field like main playground does - const message = parsed.msg !== undefined ? parsed.msg : parsed; - formattedResult = JSON.stringify(message, null, 2); + const message = parsed.msg !== undefined ? parsed.msg : parsed + formattedResult = JSON.stringify(message, null, 2) } catch { // Not JSON, use as-is } if (outputEditor) { - outputEditor.setValue(formattedResult, -1); + outputEditor.setValue(formattedResult, -1) // Resize to recalculate scrollbar after content change - outputEditor.resize(true); + outputEditor.resize(true) // Explicitly scroll to top to fix Firefox rendering issue - outputEditor.scrollToRow(0); + outputEditor.scrollToRow(0) } - showStatus('Success!', 'success'); + showStatus('Success!', 'success') } } catch (error) { - showStatus('Error: ' + error.message, 'error'); + showStatus('Error: ' + error.message, 'error') if (outputEditor) { - outputEditor.setValue('', -1); - outputEditor.scrollToRow(0); + outputEditor.setValue('', -1) + outputEditor.scrollToRow(0) } } } function showStatus(message, type) { - statusEl.textContent = message; - statusEl.className = 'mini-playground-status mini-playground-status-' + type; + statusEl.textContent = message + statusEl.className = 'mini-playground-status mini-playground-status-' + type // Use assertive announcements for errors, polite for other messages if (type === 'error') { - statusEl.setAttribute('role', 'alert'); - statusEl.setAttribute('aria-live', 'assertive'); + statusEl.setAttribute('role', 'alert') + statusEl.setAttribute('aria-live', 'assertive') } else { - statusEl.setAttribute('role', 'status'); - statusEl.setAttribute('aria-live', 'polite'); + statusEl.setAttribute('role', 'status') + statusEl.setAttribute('aria-live', 'polite') } if (type === 'success') { setTimeout(() => { if (statusEl.textContent === message) { - statusEl.textContent = 'Ready'; - statusEl.className = 'mini-playground-status mini-playground-status-ready'; + statusEl.textContent = 'Ready' + statusEl.className = 'mini-playground-status mini-playground-status-ready' } - }, 2000); + }, 2000) } } // Copy output function copyOutput() { - const output = outputEditor ? outputEditor.getValue() : ''; + const output = outputEditor ? outputEditor.getValue() : '' if (!output) { - showStatus('No output to copy', 'error'); - return; + showStatus('No output to copy', 'error') + return } // Try modern clipboard API first, fall back to execCommand if (navigator.clipboard && navigator.clipboard.writeText) { - navigator.clipboard.writeText(output).then(() => { - showStatus('Copied!', 'success'); - }).catch(() => { - fallbackCopy(output); - }); + navigator.clipboard + .writeText(output) + .then(() => { + showStatus('Copied!', 'success') + }) + .catch(() => { + fallbackCopy(output) + }) } else { - fallbackCopy(output); + fallbackCopy(output) } } // Fallback copy method for older browsers or non-HTTPS function fallbackCopy(text) { - const textarea = document.createElement('textarea'); - textarea.value = text; - textarea.style.position = 'fixed'; - textarea.style.opacity = '0'; - document.body.appendChild(textarea); - textarea.select(); + const textarea = document.createElement('textarea') + textarea.value = text + textarea.style.position = 'fixed' + textarea.style.opacity = '0' + document.body.appendChild(textarea) + textarea.select() try { - document.execCommand('copy'); - showStatus('Copied!', 'success'); + document.execCommand('copy') + showStatus('Copied!', 'success') } catch (e) { - showStatus('Failed to copy', 'error'); + showStatus('Failed to copy', 'error') } - document.body.removeChild(textarea); + document.body.removeChild(textarea) } // Event listeners - runBtn.addEventListener('click', runMapping); - copyBtn.addEventListener('click', copyOutput); + runBtn.addEventListener('click', runMapping) + copyBtn.addEventListener('click', copyOutput) // Update playground link with current editor state when clicked - const playgroundLink = overlay.querySelector('.mini-playground-link'); + const playgroundLink = overlay.querySelector('.mini-playground-link') if (playgroundLink) { playgroundLink.addEventListener('click', (e) => { // Get current editor values - const currentInput = inputEditor ? inputEditor.getValue() : '{}'; - const currentMapping = mappingEditor ? mappingEditor.getValue() : ''; - // Build URL with encoded parameters - const url = buildPlaygroundUrl(currentInput, currentMapping, '{}'); - playgroundLink.href = url; - }); + const currentInput = inputEditor ? inputEditor.getValue() : '{}' + const currentMapping = mappingEditor ? mappingEditor.getValue() : '' + // Build URL with encoded parameters (use stored metadata) + const url = buildPlaygroundUrl(currentInput, currentMapping, playgroundMetadata) + playgroundLink.href = url + }) } } @@ -1054,28 +1100,26 @@ */ function initializeBloblang() { // Find all Bloblang code blocks - const bloblangBlocks = document.querySelectorAll( - 'pre > code.language-bloblang, pre > code.language-blobl' - ); + const bloblangBlocks = document.querySelectorAll('pre > code.language-bloblang, pre > code.language-blobl') - bloblangBlocks.forEach(codeBlock => { - const listingBlock = codeBlock.closest('.listingblock'); - if (!listingBlock) return; + bloblangBlocks.forEach((codeBlock) => { + const listingBlock = codeBlock.closest('.listingblock') + if (!listingBlock) return // Add documentation tooltips - addDocumentationTooltips(codeBlock); + addDocumentationTooltips(codeBlock) // Add Try It button - const code = codeBlock.textContent; - addTryItButton(listingBlock, code); - }); + const code = codeBlock.textContent + addTryItButton(listingBlock, code) + }) } // Initialize when DOM is ready if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', initializeBloblang); + document.addEventListener('DOMContentLoaded', initializeBloblang) } else { - initializeBloblang(); + initializeBloblang() } // Also initialize after Prism highlighting completes @@ -1083,18 +1127,18 @@ Prism.hooks.add('complete', (env) => { if (env.language === 'bloblang' || env.language === 'blobl') { setTimeout(() => { - const codeBlock = env.element; - const listingBlock = codeBlock.closest('.listingblock'); + const codeBlock = env.element + const listingBlock = codeBlock.closest('.listingblock') if (listingBlock) { - addDocumentationTooltips(codeBlock); - const code = codeBlock.textContent; - addTryItButton(listingBlock, code); + addDocumentationTooltips(codeBlock) + const code = codeBlock.textContent + addTryItButton(listingBlock, code) } - }, 100); + }, 100) } - }); + }) } // Export for use by other modules (e.g., 17-bloblang-yaml.js) - window.addBloblangTooltips = addDocumentationTooltips; -})(); + window.addBloblangTooltips = addDocumentationTooltips +})() diff --git a/src/js/17-bloblang-yaml.js b/src/js/17-bloblang-yaml.js index ca8261fb..538b21d3 100644 --- a/src/js/17-bloblang-yaml.js +++ b/src/js/17-bloblang-yaml.js @@ -12,8 +12,8 @@ * 4. Attaching hover documentation tooltips */ -(function() { - 'use strict'; +;(function() { + 'use strict' // YAML keys that contain full Bloblang mappings (multi-line) var BLOBLANG_MAPPING_KEYS = [ @@ -26,96 +26,98 @@ // Hyphenated variants 'request-map', 'result-map', - 'fields-mapping' - ]; + 'fields-mapping', + ] // YAML keys that contain Bloblang boolean expressions (single-line) var BLOBLANG_CHECK_KEYS = [ 'check', 'skip_on', - 'skip-on' // Hyphenated variant - ]; + 'skip-on', // Hyphenated variant + ] // Pattern for Bloblang interpolation functions: ${! ... } - var INTERPOLATION_PATTERN = /\$\{!\s*([^}]+)\s*\}/g; + var INTERPOLATION_PATTERN = /\$\{!\s*([^}]+)\s*\}/g // Connect-specific patterns to detect if YAML is a Connect config + // Accept both underscore and hyphenated variants (e.g., request_map and request-map) var CONNECT_INDICATORS = [ /\bmapping\s*:/, /\bprocessors\s*:/, - /\brequest_map\s*:/, - /\bresult_map\s*:/, + /\brequest[-_]map\s*:/, + /\bresult[-_]map\s*:/, /\bcheck\s*:/, /\binput\s*:/, /\boutput\s*:/, /\bpipeline\s*:/, - /\$\{!\s*/ - ]; + /\bskip[-_]on\s*:/, + /\$\{!\s*/, + ] /** * Check if YAML text contains Connect pipeline patterns */ function hasConnectPatterns(text) { return CONNECT_INDICATORS.some(function(pattern) { - return pattern.test(text); - }); + return pattern.test(text) + }) } /** * Check if a string likely contains Bloblang code */ function isLikelyBloblang(str) { - if (!str || str.length < 3) return false; + if (!str || str.length < 3) return false var bloblangPatterns = [ - /\broot\s*[.=]/, // root assignment or access - /\bthis\s*\./, // this context access - /=>/, // lambda arrow - /@[\w(]/, // metadata access - /\$\w+/, // variable reference - /\.(map_each|filter|fold|flatten|catch|or)\s*\(/, // common methods - /\b(if|match|let)\s+/, // control flow keywords - /\|\s*$/m, // pipe operator at end of line - /\.parse_json\s*\(/, // common parsing methods + /\broot\s*[.=]/, // root assignment or access + /\bthis\s*\./, // this context access + /=>/, // lambda arrow + /@[\w(]/, // metadata access + /\$\w+/, // variable reference + /\.(map_each|filter|fold|flatten|catch|or)\s*\(/, // common methods + /\b(if|match|let)\s+/, // control flow keywords + /\|\s*$/m, // pipe operator at end of line + /\.parse_json\s*\(/, // common parsing methods /\.format_json\s*\(/, - /\buuid_v4\s*\(/, // common functions + /\buuid_v4\s*\(/, // common functions /\bnow\s*\(/, /\bjson\s*\(/, - /\bcontent\s*\(/ - ]; + /\bcontent\s*\(/, + ] return bloblangPatterns.some(function(pattern) { - return pattern.test(str); - }); + return pattern.test(str) + }) } /** * Find the YAML key that precedes a token by walking backwards through siblings */ function findPrecedingKey(token) { - var node = token.previousSibling; - var textAccum = ''; - var maxSteps = 20; - var steps = 0; + var node = token.previousSibling + var textAccum = '' + var maxSteps = 20 + var steps = 0 while (node && steps < maxSteps) { if (node.nodeType === Node.TEXT_NODE) { - textAccum = node.textContent + textAccum; + textAccum = node.textContent + textAccum } else if (node.nodeType === Node.ELEMENT_NODE) { - textAccum = node.textContent + textAccum; + textAccum = node.textContent + textAccum } // Check for key pattern (supports hyphenated keys like request-map) - var keyMatch = textAccum.match(/([\w-]+)\s*:\s*[\|>]?\s*$/); + var keyMatch = textAccum.match(/([\w-]+)\s*:\s*[\|>]?\s*$/) if (keyMatch) { - return keyMatch[1]; + return keyMatch[1] } - node = node.previousSibling; - steps++; + node = node.previousSibling + steps++ } - return null; + return null } /** @@ -124,20 +126,20 @@ */ function extractBloblangFromBlock(tokenText) { // Remove leading/trailing quotes if present - var text = tokenText.trim(); - if ((text.startsWith('"') && text.endsWith('"')) || - (text.startsWith("'") && text.endsWith("'"))) { - text = text.slice(1, -1); + var text = tokenText.trim() + if ((text.startsWith('"') && text.endsWith('"')) || (text.startsWith("'") && text.endsWith("'"))) { + text = text.slice(1, -1) } // Handle escape sequences - text = text.replace(/\\n/g, '\n') - .replace(/\\t/g, '\t') - .replace(/\\"/g, '"') - .replace(/\\'/g, "'") - .replace(/\\\\/g, '\\'); - - return text; + text = text + .replace(/\\n/g, '\n') + .replace(/\\t/g, '\t') + .replace(/\\"/g, '"') + .replace(/\\'/g, "'") + .replace(/\\\\/g, '\\') + + return text } /** @@ -145,20 +147,20 @@ */ function tokenizeBloblang(code) { if (!window.Prism || !Prism.languages.bloblang) { - return escapeHtml(code); + return escapeHtml(code) } - var tokens = Prism.tokenize(code, Prism.languages.bloblang); - return Prism.Token.stringify(Prism.util.encode(tokens), 'bloblang'); + var tokens = Prism.tokenize(code, Prism.languages.bloblang) + return Prism.Token.stringify(Prism.util.encode(tokens), 'bloblang') } /** * Escape HTML special characters */ function escapeHtml(text) { - var div = document.createElement('div'); - div.textContent = text; - return div.innerHTML; + var div = document.createElement('div') + div.textContent = text + return div.innerHTML } /** @@ -166,68 +168,72 @@ * (a new YAML key or list item at the same or lower indent level) */ function isEndOfLiteralBlock(node, baseIndent) { - if (!node) return true; + if (!node) return true // Text node: check if it ends with a newline and indent that's lower/equal to baseIndent // This handles cases where the next token will be at a lower indent if (node.nodeType === Node.TEXT_NODE) { - var text = node.textContent; + var text = node.textContent // Check for text node that's just whitespace ending with lower indent // Pattern: newlines followed by spaces, where the last line's indent is <= baseIndent - var lines = text.split('\n'); + var lines = text.split('\n') if (lines.length > 1) { - var lastLine = lines[lines.length - 1]; + var lastLine = lines[lines.length - 1] // If last line is just spaces (waiting for next token), check indent if (/^\s*$/.test(lastLine)) { - var lastIndent = lastLine.length; + var lastIndent = lastLine.length // If this indent is lower than base, block has ended if (lastIndent < baseIndent) { - return true; + return true } } } // Also check for inline content that starts at lower indent - var match = text.match(/\n( *)\S/); + var match = text.match(/\n( *)\S/) if (match) { - var indent = match[1].length; + var indent = match[1].length if (indent < baseIndent) { - return true; + return true } } } // Element node that is a YAML punctuation "-" (list item marker) at lower indent - if (node.nodeType === Node.ELEMENT_NODE && - node.classList.contains('token') && - node.classList.contains('punctuation') && - node.textContent === '-') { + if ( + node.nodeType === Node.ELEMENT_NODE && + node.classList.contains('token') && + node.classList.contains('punctuation') && + node.textContent === '-' + ) { // Check previous text node for indent - var prev = node.previousSibling; + var prev = node.previousSibling if (prev && prev.nodeType === Node.TEXT_NODE) { - var indentMatch = prev.textContent.match(/\n( *)$/); + var indentMatch = prev.textContent.match(/\n( *)$/) if (indentMatch && indentMatch[1].length < baseIndent) { - return true; + return true } } } // Element node that is a YAML key at lower indent - if (node.nodeType === Node.ELEMENT_NODE && - node.classList.contains('token') && - (node.classList.contains('key') || node.classList.contains('atrule'))) { + if ( + node.nodeType === Node.ELEMENT_NODE && + node.classList.contains('token') && + (node.classList.contains('key') || node.classList.contains('atrule')) + ) { // Check previous text node for indent - var prev = node.previousSibling; + var prev = node.previousSibling if (prev && prev.nodeType === Node.TEXT_NODE) { - var indentMatch = prev.textContent.match(/\n( *)$/); + var indentMatch = prev.textContent.match(/\n( *)$/) if (indentMatch && indentMatch[1].length < baseIndent) { - return true; + return true } } } - return false; + return false } /** @@ -236,31 +242,31 @@ */ function getBaseIndent(token) { // First, check the token content itself for indentation of the first real line - var content = token.textContent; - var contentMatch = content.match(/\n( +)\S/); + var content = token.textContent + var contentMatch = content.match(/\n( +)\S/) if (contentMatch) { - return contentMatch[1].length; + return contentMatch[1].length } // Fall back to checking preceding siblings - var prev = token.previousSibling; - var attempts = 0; + var prev = token.previousSibling + var attempts = 0 while (prev && attempts < 10) { if (prev.nodeType === Node.TEXT_NODE) { - var match = prev.textContent.match(/\n( +)$/); + var match = prev.textContent.match(/\n( +)$/) if (match) { - return match[1].length; + return match[1].length } // Also check for newline within the text - var innerMatch = prev.textContent.match(/\n( +)\S/); + var innerMatch = prev.textContent.match(/\n( +)\S/) if (innerMatch) { - return innerMatch[1].length; + return innerMatch[1].length } } - prev = prev.previousSibling; - attempts++; + prev = prev.previousSibling + attempts++ } - return 2; // Default minimum indent for YAML block content + return 2 // Default minimum indent for YAML block content } /** @@ -269,25 +275,27 @@ * the continuation content becomes separate siblings */ function collectLiteralBlockContinuation(startToken) { - var nodes = []; - var baseIndent = getBaseIndent(startToken); - var node = startToken.nextSibling; + var nodes = [] + var baseIndent = getBaseIndent(startToken) + var node = startToken.nextSibling while (node && !isEndOfLiteralBlock(node, baseIndent)) { - nodes.push(node); - node = node.nextSibling; + nodes.push(node) + node = node.nextSibling } - return nodes; + return nodes } /** * Extract text content from a list of nodes */ function extractTextFromNodes(nodes) { - return nodes.map(function(node) { - return node.textContent || ''; - }).join(''); + return nodes + .map(function(node) { + return node.textContent || '' + }) + .join('') } /** @@ -295,103 +303,112 @@ * Also handles continuation content after blank lines */ function processMultilineMapping(token) { - var bloblangCode = extractBloblangFromBlock(token.textContent); + var bloblangCode = extractBloblangFromBlock(token.textContent) // Check for continuation content after this token - var continuationNodes = collectLiteralBlockContinuation(token); - var continuationText = extractTextFromNodes(continuationNodes); + var continuationNodes = collectLiteralBlockContinuation(token) + var continuationText = extractTextFromNodes(continuationNodes) // Combine the token content with continuation - var fullCode = bloblangCode + continuationText; + var fullCode = bloblangCode + continuationText - if (!fullCode.trim()) return false; + if (!fullCode.trim()) return false // Check if the combined content looks like Bloblang if (!isLikelyBloblang(fullCode) && !isLikelyBloblang(bloblangCode)) { - return false; + return false } - var highlighted = tokenizeBloblang(fullCode); + var highlighted = tokenizeBloblang(fullCode) - var wrapper = document.createElement('span'); - wrapper.className = 'bloblang-embedded'; - wrapper.innerHTML = highlighted; + var wrapper = document.createElement('span') + wrapper.className = 'bloblang-embedded' + wrapper.innerHTML = highlighted - token.innerHTML = ''; - token.appendChild(wrapper); + token.innerHTML = '' + token.appendChild(wrapper) // Remove continuation nodes (they're now inside the wrapper) continuationNodes.forEach(function(node) { if (node.parentNode) { - node.parentNode.removeChild(node); + node.parentNode.removeChild(node) } - }); + }) - return true; + return true } /** * Process a single-line check expression (like check: "this.type == 'foo'") */ function processSingleLineCheck(token) { - var text = token.textContent.trim(); + var text = token.textContent.trim() // Remove surrounding quotes - if ((text.startsWith('"') && text.endsWith('"')) || - (text.startsWith("'") && text.endsWith("'"))) { - var quote = text[0]; - var inner = text.slice(1, -1); - var highlighted = tokenizeBloblang(inner); - - token.innerHTML = '' + quote + '' + - '' + highlighted + '' + - '' + quote + ''; - return true; + if ((text.startsWith('"') && text.endsWith('"')) || (text.startsWith("'") && text.endsWith("'"))) { + var quote = text[0] + var inner = text.slice(1, -1) + var highlighted = tokenizeBloblang(inner) + + token.innerHTML = + '' + + quote + + '' + + '' + + highlighted + + '' + + '' + + quote + + '' + return true } - return false; + return false } /** * Process interpolation functions within a string: ${! ... } */ function processInterpolation(token) { - var text = token.textContent; - if (!INTERPOLATION_PATTERN.test(text)) return false; + var text = token.textContent + if (!INTERPOLATION_PATTERN.test(text)) return false // Reset regex - INTERPOLATION_PATTERN.lastIndex = 0; + INTERPOLATION_PATTERN.lastIndex = 0 - var result = ''; - var lastIndex = 0; - var match; + var result = '' + var lastIndex = 0 + var match while ((match = INTERPOLATION_PATTERN.exec(text)) !== null) { // Add text before the match - result += escapeHtml(text.slice(lastIndex, match.index)); + result += escapeHtml(text.slice(lastIndex, match.index)) // Tokenize the Bloblang expression inside ${! } - var bloblangExpr = match[1]; - var highlighted = tokenizeBloblang(bloblangExpr); - - result += '' + - '${!' + - '' + highlighted + '' + - '}' + - ''; - - lastIndex = match.index + match[0].length; + var bloblangExpr = match[1] + var highlighted = tokenizeBloblang(bloblangExpr) + + result += + '' + + '${!' + + '' + + highlighted + + '' + + '}' + + '' + + lastIndex = match.index + match[0].length } // Add remaining text - result += escapeHtml(text.slice(lastIndex)); + result += escapeHtml(text.slice(lastIndex)) if (lastIndex > 0) { - token.innerHTML = result; - return true; + token.innerHTML = result + return true } - return false; + return false } /** @@ -399,12 +416,12 @@ */ function processYamlBlock(codeElement) { // Early exit if not Connect config - var fullText = codeElement.textContent; + var fullText = codeElement.textContent if (!hasConnectPatterns(fullText)) { - return; + return } - var processed = false; + var processed = false // Find all potential Bloblang regions // In YAML, Bloblang appears in: @@ -413,23 +430,20 @@ // 3. Interpolation within any string // Strategy: Walk through text nodes and token spans - var walker = document.createTreeWalker( - codeElement, - NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, - null, - false - ); + var walker = document.createTreeWalker(codeElement, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, null, false) - var nodesToProcess = []; - var node; + var nodesToProcess = [] + var node while ((node = walker.nextNode())) { - if (node.nodeType === Node.ELEMENT_NODE && - node.classList.contains('token') && - (node.classList.contains('string') || - node.classList.contains('scalar') || - node.classList.contains('punctuation'))) { - nodesToProcess.push(node); + if ( + node.nodeType === Node.ELEMENT_NODE && + node.classList.contains('token') && + (node.classList.contains('string') || + node.classList.contains('scalar') || + node.classList.contains('punctuation')) + ) { + nodesToProcess.push(node) } } @@ -437,46 +451,46 @@ nodesToProcess.forEach(function(token) { // Skip already processed if (token.querySelector('.bloblang-embedded, .bloblang-inline')) { - return; + return } - var text = token.textContent; + var text = token.textContent // Check for interpolation first (can appear anywhere) if (INTERPOLATION_PATTERN.test(text)) { - INTERPOLATION_PATTERN.lastIndex = 0; + INTERPOLATION_PATTERN.lastIndex = 0 if (processInterpolation(token)) { - processed = true; - return; + processed = true + return } } // Find preceding key - var key = findPrecedingKey(token); + var key = findPrecedingKey(token) if (key && BLOBLANG_MAPPING_KEYS.indexOf(key) !== -1) { // This is a mapping value - check if it looks like Bloblang if (isLikelyBloblang(text)) { if (processMultilineMapping(token)) { - processed = true; + processed = true } } } else if (key && BLOBLANG_CHECK_KEYS.indexOf(key) !== -1) { // This is a check expression if (processSingleLineCheck(token)) { - processed = true; + processed = true } } else if (isLikelyBloblang(text) && text.length > 20) { // Heuristic: long strings that look like Bloblang if (processMultilineMapping(token)) { - processed = true; + processed = true } } - }); + }) // Attach tooltips to newly created Bloblang tokens if (processed && window.addBloblangTooltips) { - window.addBloblangTooltips(codeElement); + window.addBloblangTooltips(codeElement) } } @@ -485,42 +499,49 @@ */ function init() { if (!window.Prism) { - return; + return } // Process YAML blocks after Prism highlights them Prism.hooks.add('complete', function(env) { if (env.language === 'yaml' || env.language === 'yml') { // Use requestIdleCallback for better performance, fallback to setTimeout - var schedule = window.requestIdleCallback || function(cb) { setTimeout(cb, 10); }; + var schedule = + window.requestIdleCallback || + function(cb) { + setTimeout(cb, 10) + } schedule(function() { - processYamlBlock(env.element); - }); + processYamlBlock(env.element) + }) } - }); + }) // Also process existing YAML blocks on page load document.addEventListener('DOMContentLoaded', function() { - var yamlBlocks = document.querySelectorAll('pre > code.language-yaml, pre > code.language-yml'); + var yamlBlocks = document.querySelectorAll('pre > code.language-yaml, pre > code.language-yml') yamlBlocks.forEach(function(block) { - var schedule = window.requestIdleCallback || function(cb) { setTimeout(cb, 10); }; + var schedule = + window.requestIdleCallback || + function(cb) { + setTimeout(cb, 10) + } schedule(function() { - processYamlBlock(block); - }); - }); - }); + processYamlBlock(block) + }) + }) + }) } // Initialize when Prism is ready if (window.Prism) { - init(); + init() } else { // Wait for Prism to load document.addEventListener('DOMContentLoaded', function() { if (window.Prism) { - init(); + init() } - }); + }) } - -})(); +})() diff --git a/src/js/19-chat-panel.js b/src/js/19-chat-panel.js new file mode 100644 index 00000000..2cdd3fe8 --- /dev/null +++ b/src/js/19-chat-panel.js @@ -0,0 +1,115 @@ +/* global localStorage */ +;(function () { + 'use strict' + + // DOM elements + var chatPanel = document.querySelector('[data-chat-panel]') + var main = document.querySelector('main.article') + + if (!chatPanel) return + + // Storage key for persisting panel state + var STORAGE_KEY = 'redpanda-chat-panel-open' + + // State + var isOpen = false + + // Event listeners + chatPanel.querySelectorAll('[data-chat-action="close"]').forEach(function (btn) { + btn.addEventListener('click', function () { + closePanel() + }) + }) + + // Ask AI button in header (opens chat panel) + document.querySelectorAll('[data-action="open-chat"]').forEach(function (btn) { + btn.addEventListener('click', function () { + openPanel() + }) + }) + + // Keyboard shortcut: Cmd/Ctrl + K + document.addEventListener('keydown', function (e) { + if ((e.metaKey || e.ctrlKey) && e.key === 'k') { + e.preventDefault() + if (isOpen) { + closePanel() + } else { + openPanel() + } + } + }) + + // Global trigger for opening chat from other components + window.openChatPanel = function () { + openPanel() + } + + // Global trigger for opening chat with a pre-filled query + // Used by playground error buttons and code block Ask AI buttons + window.openChatWithQuery = function (query, autoSubmit) { + openPanel() + // Wait for panel animation and React to be ready, then submit query + setTimeout(function () { + if (typeof window.submitChatQuery === 'function') { + window.submitChatQuery(query, autoSubmit !== false) + } + }, 100) + } + + // Functions + function openPanel () { + isOpen = true + chatPanel.classList.add('is-open') + chatPanel.setAttribute('aria-hidden', 'false') + if (main) main.classList.add('chat-push') + + // Hide all Ask AI buttons if they exist + var askAiBtns = document.querySelectorAll('[data-action="open-chat"]') + askAiBtns.forEach(function (btn) { + btn.style.display = 'none' + }) + + // Persist state to localStorage + try { + localStorage.setItem(STORAGE_KEY, 'true') + } catch (e) { + // localStorage not available, ignore + } + } + + function closePanel () { + isOpen = false + chatPanel.classList.remove('is-open') + chatPanel.setAttribute('aria-hidden', 'true') + if (main) main.classList.remove('chat-push') + + // Show all Ask AI buttons if they exist + var askAiBtns = document.querySelectorAll('[data-action="open-chat"]') + askAiBtns.forEach(function (btn) { + btn.style.display = '' + }) + + // Remove from localStorage (panel explicitly closed) + try { + localStorage.removeItem(STORAGE_KEY) + } catch (e) { + // localStorage not available, ignore + } + } + + // Restore panel state from localStorage on page load + function restoreState () { + try { + var savedState = localStorage.getItem(STORAGE_KEY) + if (savedState === 'true') { + openPanel() + } + } catch (e) { + // localStorage not available, ignore + } + } + + // Restore state on page load + restoreState() +})() diff --git a/src/js/20-mermaid-zoom.js b/src/js/20-mermaid-zoom.js index 179cf0c8..fc1de6b9 100644 --- a/src/js/20-mermaid-zoom.js +++ b/src/js/20-mermaid-zoom.js @@ -91,8 +91,9 @@ // Check if scrolling is needed and show hint setTimeout(function () { - var needsScroll = modalContainer.scrollWidth > modalContainer.clientWidth || - modalContainer.scrollHeight > modalContainer.clientHeight + var needsScroll = + modalContainer.scrollWidth > modalContainer.clientWidth || + modalContainer.scrollHeight > modalContainer.clientHeight if (needsScroll) { modalHint.classList.remove('hidden') // Auto-hide hint after 3 seconds diff --git a/src/js/20-product-switcher.js b/src/js/20-product-switcher.js new file mode 100644 index 00000000..548e237b --- /dev/null +++ b/src/js/20-product-switcher.js @@ -0,0 +1,70 @@ +/** + * Product Switcher + * Dropdown menu for switching between Redpanda products (ADP, Data Platform, etc.) + */ +;(function () { + 'use strict' + + var switcher = document.querySelector('[data-product-switcher]') + if (!switcher) return + + var toggle = switcher.querySelector('[data-product-toggle]') + var menu = switcher.querySelector('[data-product-menu]') + var caret = switcher.querySelector('.sb-product-caret') + var isOpen = false + + // Toggle menu open/close + function openMenu () { + isOpen = true + menu.style.display = 'block' + toggle.classList.add('is-open') + toggle.setAttribute('aria-expanded', 'true') + if (caret) caret.classList.add('rot') + } + + function closeMenu () { + isOpen = false + menu.style.display = 'none' + toggle.classList.remove('is-open') + toggle.setAttribute('aria-expanded', 'false') + if (caret) caret.classList.remove('rot') + } + + function toggleMenu () { + if (isOpen) { + closeMenu() + } else { + openMenu() + } + } + + // Toggle on button click + toggle.addEventListener('click', function (e) { + e.stopPropagation() + toggleMenu() + }) + + // Close on click outside + document.addEventListener('mousedown', function (e) { + if (!switcher.contains(e.target) && isOpen) { + closeMenu() + } + }) + + // Close on Escape key + document.addEventListener('keydown', function (e) { + if (e.key === 'Escape' && isOpen) { + closeMenu() + } + }) + + // Navigate to selected product + menu.querySelectorAll('.sb-product-opt').forEach(function (opt) { + opt.addEventListener('click', function () { + var url = this.getAttribute('data-product-url') + if (url) { + window.location.href = url + } + }) + }) +})() diff --git a/src/js/21-breadcrumb-collapse.js b/src/js/21-breadcrumb-collapse.js new file mode 100644 index 00000000..6a1a4472 --- /dev/null +++ b/src/js/21-breadcrumb-collapse.js @@ -0,0 +1,183 @@ +;(function () { + 'use strict' + + var container = document.querySelector('.topbar-crumbs') + if (!container) return + + var breadcrumbsNav = container.querySelector('.breadcrumbs') + if (!breadcrumbsNav) return + + var ul = breadcrumbsNav.querySelector('ul') + if (!ul) return + + var items = Array.from(ul.querySelectorAll('li')) + if (items.length <= 3) return // No need to collapse if 3 or fewer items + + // Create ellipsis button and dropdown container + var ellipsisLi = document.createElement('li') + ellipsisLi.className = 'bc-ellipsis-li' + + var ellipsisBtn = document.createElement('button') + ellipsisBtn.className = 'bc-ellipsis' + ellipsisBtn.type = 'button' + ellipsisBtn.setAttribute('aria-label', 'Show all breadcrumbs') + ellipsisBtn.setAttribute('aria-expanded', 'false') + ellipsisBtn.innerHTML = '…' + ellipsisLi.appendChild(ellipsisBtn) + + // Insert ellipsis after first item + if (items.length > 1) { + items[0].after(ellipsisLi) + } + + // Track which items are hidden + var hiddenItems = [] + var dropdown = null + var isDropdownOpen = false + + // Measure true width of all items by temporarily removing constraints + function measureTrueWidth () { + // Save original styles + var originalFlexShrink = [] + var originalMinWidth = [] + var originalOverflow = [] + + items.forEach(function (item, i) { + originalFlexShrink[i] = item.style.flexShrink + originalMinWidth[i] = item.style.minWidth + originalOverflow[i] = item.style.overflow + // Remove constraints to get natural width + item.style.flexShrink = '0' + item.style.minWidth = 'auto' + item.style.overflow = 'visible' + }) + + // Force reflow to get accurate measurements + ul.offsetWidth // eslint-disable-line no-unused-expressions + + // Calculate total width of all visible items + var totalWidth = 0 + items.forEach(function (item) { + if (!item.classList.contains('bc-hidden')) { + totalWidth += item.offsetWidth + } + }) + + // Restore original styles + items.forEach(function (item, i) { + item.style.flexShrink = originalFlexShrink[i] + item.style.minWidth = originalMinWidth[i] + item.style.overflow = originalOverflow[i] + }) + + return totalWidth + } + + // Check if breadcrumbs overflow and collapse if needed + function checkOverflow () { + // Close dropdown if open + closeDropdown() + + // Reset to expanded state first + container.classList.remove('is-collapsed') + items.forEach(function (item) { + item.classList.remove('bc-hidden') + }) + hiddenItems = [] + + // Get available width (container width) + var availableWidth = container.clientWidth + + // Measure true total width of all items + var totalWidth = measureTrueWidth() + + // If overflowing, collapse middle items + if (totalWidth > availableWidth && items.length > 3) { + container.classList.add('is-collapsed') + // Hide middle items (keep first, ellipsis, and last two) + for (var i = 1; i < items.length - 2; i++) { + items[i].classList.add('bc-hidden') + hiddenItems.push(items[i]) + } + } + } + + // Create and show dropdown with hidden items + function showDropdown () { + if (hiddenItems.length === 0) return + + isDropdownOpen = true + ellipsisBtn.classList.add('is-open') + ellipsisBtn.setAttribute('aria-expanded', 'true') + + dropdown = document.createElement('div') + dropdown.className = 'bc-dropdown' + + hiddenItems.forEach(function (item) { + var link = item.querySelector('a') + if (link) { + var dropdownLink = document.createElement('a') + dropdownLink.href = link.href + dropdownLink.textContent = link.textContent + dropdown.appendChild(dropdownLink) + } else { + var span = item.querySelector('span') + if (span) { + var dropdownSpan = document.createElement('span') + dropdownSpan.textContent = span.textContent + dropdown.appendChild(dropdownSpan) + } + } + }) + + ellipsisLi.appendChild(dropdown) + } + + // Close dropdown + function closeDropdown () { + if (dropdown) { + dropdown.remove() + dropdown = null + } + isDropdownOpen = false + ellipsisBtn.classList.remove('is-open') + ellipsisBtn.setAttribute('aria-expanded', 'false') + } + + // Toggle dropdown on ellipsis click + ellipsisBtn.addEventListener('click', function (e) { + e.preventDefault() + e.stopPropagation() + + if (isDropdownOpen) { + closeDropdown() + } else { + showDropdown() + } + }) + + // Close dropdown when clicking outside + document.addEventListener('click', function (e) { + if (isDropdownOpen && !ellipsisLi.contains(e.target)) { + closeDropdown() + } + }) + + // Close dropdown on escape key + document.addEventListener('keydown', function (e) { + if (e.key === 'Escape' && isDropdownOpen) { + closeDropdown() + ellipsisBtn.focus() + } + }) + + // Initial check after a brief delay to ensure layout is complete + setTimeout(checkOverflow, 50) + + // Re-check on resize + var resizeTimeout + window.addEventListener('resize', function () { + clearTimeout(resizeTimeout) + resizeTimeout = setTimeout(checkOverflow, 100) + }) +})() diff --git a/src/js/22-version-selector.js b/src/js/22-version-selector.js new file mode 100644 index 00000000..e483d7cb --- /dev/null +++ b/src/js/22-version-selector.js @@ -0,0 +1,94 @@ +/* Version Selector Dropdown */ +;(function () { + 'use strict' + + // Find all version selectors on the page + var selectors = document.querySelectorAll('[data-version-selector]') + if (!selectors.length) return + + selectors.forEach(function (smVer) { + var btn = smVer.querySelector('.sm-ver-pill') + var tabs = smVer.querySelectorAll('.sm-ver-tab') + var groups = smVer.querySelectorAll('.sm-ver-group') + + if (!btn) return + + // Update group counts + function updateCounts () { + groups.forEach(function (group) { + var rows = group.querySelectorAll('.sm-ver-row') + var countEl = group.querySelector('.sm-ver-group-count') + if (countEl) countEl.textContent = rows.length + // Hide empty groups + group.classList.toggle('is-hidden', rows.length === 0) + }) + } + updateCounts() + + // Tab filtering + tabs.forEach(function (tab) { + tab.addEventListener('click', function (e) { + e.preventDefault() + var filter = tab.dataset.filter + + // Update active tab + tabs.forEach(function (t) { + t.classList.remove('is-active') + t.setAttribute('aria-selected', 'false') + }) + tab.classList.add('is-active') + tab.setAttribute('aria-selected', 'true') + + // Filter groups + groups.forEach(function (group) { + var groupStatus = group.dataset.group + var rows = group.querySelectorAll('.sm-ver-row') + if (filter === 'all') { + group.classList.toggle('is-hidden', rows.length === 0) + } else { + group.classList.toggle('is-hidden', groupStatus !== filter) + } + }) + }) + }) + + // Toggle dropdown + btn.addEventListener('click', function (e) { + e.stopPropagation() + smVer.classList.toggle('is-open') + btn.classList.toggle('is-open') + btn.setAttribute('aria-expanded', smVer.classList.contains('is-open')) + }) + }) + + // Global handlers for closing dropdowns (outside the loop to avoid duplicates) + // Close on outside click + document.addEventListener('mousedown', function (e) { + selectors.forEach(function (smVer) { + var btn = smVer.querySelector('.sm-ver-pill') + if (!smVer.contains(e.target) && smVer.classList.contains('is-open')) { + smVer.classList.remove('is-open') + if (btn) { + btn.classList.remove('is-open') + btn.setAttribute('aria-expanded', 'false') + } + } + }) + }) + + // Close on Escape + document.addEventListener('keydown', function (e) { + if (e.key === 'Escape') { + selectors.forEach(function (smVer) { + var btn = smVer.querySelector('.sm-ver-pill') + if (smVer.classList.contains('is-open')) { + smVer.classList.remove('is-open') + if (btn) { + btn.classList.remove('is-open') + btn.setAttribute('aria-expanded', 'false') + } + } + }) + } + }) +})() diff --git a/src/js/23-nav-bucket.js b/src/js/23-nav-bucket.js new file mode 100644 index 00000000..0862eab3 --- /dev/null +++ b/src/js/23-nav-bucket.js @@ -0,0 +1,162 @@ +/** + * Nav Bucket interactions for unified navigation + * Handles bucket expand/collapse and per-bucket version selectors + */ +;(function () { + 'use strict' + + // Initialize when DOM is ready + document.addEventListener('DOMContentLoaded', init) + + function init () { + // Initialize bucket toggles + initBucketToggles() + + // Initialize per-bucket version selectors + initBucketVersionSelectors() + + // Initialize version toggle buttons + initVersionToggles() + + // Global escape handler + document.addEventListener('keydown', function (e) { + if (e.key === 'Escape') { + closeAllVersionMenus() + } + }) + + // Click outside to close version menus + document.addEventListener('click', function (e) { + if (!e.target.closest('[data-bucket-version]')) { + closeAllVersionMenus() + } + }) + } + + /** + * Initialize bucket expand/collapse toggles + */ + function initBucketToggles () { + // Handle clicks on the caret button to toggle bucket + var caretBtns = document.querySelectorAll('.nav-bucket-caret-btn') + caretBtns.forEach(function (caretBtn) { + caretBtn.addEventListener('click', function (e) { + e.preventDefault() + toggleBucket(caretBtn) + }) + }) + } + + /** + * Toggle a bucket's expanded/collapsed state + */ + function toggleBucket (caretBtn) { + var bucket = caretBtn.closest('.nav-bucket') + // Use direct child selector to avoid selecting nested bucket content + var content = bucket.querySelector(':scope > .nav-bucket-content') + var isExpanded = !content.classList.contains('is-collapsed') + + // Toggle expanded state + if (content) { + content.classList.toggle('is-collapsed', isExpanded) + } + } + + /** + * Initialize per-bucket version selector dropdowns + */ + function initBucketVersionSelectors () { + var versionSelectors = document.querySelectorAll('[data-bucket-version]') + + versionSelectors.forEach(function (selector) { + var btn = selector.querySelector('.nav-bucket-version-btn') + var menu = selector.querySelector('.nav-bucket-version-menu') + + if (!btn || !menu) return + + btn.addEventListener('click', function (e) { + e.preventDefault() + e.stopPropagation() + + var isOpen = btn.getAttribute('aria-expanded') === 'true' + var bucket = selector.closest('.nav-bucket') + + // Close all other menus first + closeAllVersionMenus() + + if (!isOpen) { + btn.setAttribute('aria-expanded', 'true') + menu.style.display = 'block' + // Add class to bucket for z-index elevation (fallback for :has()) + if (bucket) bucket.classList.add('is-dropdown-open') + } + }) + + // Close on option click (navigation will happen via href) + var options = menu.querySelectorAll('.nav-bucket-version-opt') + options.forEach(function (opt) { + opt.addEventListener('click', function () { + closeAllVersionMenus() + }) + }) + }) + } + + /** + * Close all version selector menus + */ + function closeAllVersionMenus () { + var versionSelectors = document.querySelectorAll('[data-bucket-version]') + + versionSelectors.forEach(function (selector) { + var btn = selector.querySelector('.nav-bucket-version-btn') + var menu = selector.querySelector('.nav-bucket-version-menu') + var bucket = selector.closest('.nav-bucket') + + if (btn) btn.setAttribute('aria-expanded', 'false') + if (menu) menu.style.display = 'none' + // Remove z-index elevation class + if (bucket) bucket.classList.remove('is-dropdown-open') + }) + } + + /** + * Initialize version toggle buttons (show/hide older versions) + */ + function initVersionToggles () { + var toggleButtons = document.querySelectorAll('[data-version-toggle]') + + toggleButtons.forEach(function (toggleBtn) { + toggleBtn.addEventListener('click', function (e) { + e.preventDefault() + e.stopPropagation() + + var menu = toggleBtn.closest('.nav-bucket-version-menu') + if (!menu) return + + var olderVersions = menu.querySelector('.nav-bucket-version-older') + var showText = toggleBtn.querySelector('.version-toggle-show') + var hideText = toggleBtn.querySelector('.version-toggle-hide') + var chevron = toggleBtn.querySelector('svg') + + if (!olderVersions) return + + var isExpanded = olderVersions.style.display !== 'none' + + if (isExpanded) { + // Collapse + olderVersions.style.display = 'none' + showText.style.display = '' + hideText.style.display = 'none' + if (chevron) chevron.style.transform = '' + } else { + // Expand + olderVersions.style.display = 'block' + showText.style.display = 'none' + hideText.style.display = '' + if (chevron) chevron.style.transform = 'rotate(180deg)' + } + }) + }) + } +})() diff --git a/src/js/24-move-connector-metadata.js b/src/js/24-move-connector-metadata.js new file mode 100644 index 00000000..31ac01f3 --- /dev/null +++ b/src/js/24-move-connector-metadata.js @@ -0,0 +1,297 @@ +/** + * Move connector metadata (Type dropdown, availability info) to sticky bar + */ +;(function () { + 'use strict' + + function moveConnectorMetadataToSticky () { + const stickyBar = document.querySelector('.component-indicator-sticky') + const metadataBlock = document.querySelector('.metadata-block') + const metadataContent = metadataBlock?.querySelector('.metadata-content') + + if (!stickyBar || !metadataBlock || !metadataContent) return + + // Check if we already moved it + if (stickyBar.querySelector('.metadata-inline')) return + + // Create metadata-inline container + const metadataInline = document.createElement('div') + metadataInline.className = 'metadata-inline' + + // Move the Type dropdown if it exists + const typeDropdownWrapper = metadataContent.querySelector('.dropdown-wrapper') + if (typeDropdownWrapper) { + // Create context-switcher wrapper + const contextSwitcher = document.createElement('div') + contextSwitcher.className = 'context-switcher' + + const contextDropdown = document.createElement('div') + contextDropdown.className = 'context-dropdown' + + // Get the original toggle and menu + const originalToggle = typeDropdownWrapper.querySelector('.dropdown-toggle') + const originalMenu = typeDropdownWrapper.querySelector('.dropdown-menu') + + if (originalToggle && originalMenu) { + // Create compact toggle with "Type:" prefix (CSS adds this via ::before) + const compactToggle = document.createElement('button') + compactToggle.type = 'button' + compactToggle.className = 'context-dropdown-toggle' + compactToggle.setAttribute('aria-expanded', 'false') + compactToggle.setAttribute('aria-haspopup', 'true') + + const dropdownText = originalToggle.querySelector('.dropdown-text') + if (dropdownText) { + compactToggle.textContent = dropdownText.textContent + } + + // Add arrow + const arrow = document.createElementNS('http://www.w3.org/2000/svg', 'svg') + arrow.setAttribute('class', 'context-dropdown-arrow') + arrow.setAttribute('viewBox', '0 0 24 24') + arrow.setAttribute('width', '16') + arrow.setAttribute('height', '16') + const path = document.createElementNS('http://www.w3.org/2000/svg', 'path') + path.setAttribute('fill', 'currentColor') + path.setAttribute('d', 'M7 10l5 5 5-5z') + arrow.appendChild(path) + compactToggle.appendChild(arrow) + + // Create compact menu + const compactMenu = document.createElement('div') + compactMenu.className = 'context-dropdown-menu' + compactMenu.setAttribute('role', 'menu') + + // Copy menu items + const originalItems = originalMenu.querySelectorAll('.dropdown-option') + originalItems.forEach((item) => { + const compactItem = document.createElement('a') + compactItem.href = item.href + compactItem.className = 'context-dropdown-item' + compactItem.setAttribute('role', 'menuitem') + compactItem.textContent = item.textContent + + // Mark current page as active + if (window.location.pathname.includes(new URL(item.href).pathname)) { + compactItem.classList.add('active') + } + + compactMenu.appendChild(compactItem) + }) + + // Set up toggle functionality + compactToggle.addEventListener('click', function (e) { + e.preventDefault() + e.stopPropagation() + + const isOpen = compactToggle.getAttribute('aria-expanded') === 'true' + + if (isOpen) { + compactToggle.setAttribute('aria-expanded', 'false') + compactMenu.classList.remove('show') + } else { + compactToggle.setAttribute('aria-expanded', 'true') + compactMenu.classList.add('show') + } + }) + + // Close on outside click + document.addEventListener('click', function (e) { + if (!contextDropdown.contains(e.target)) { + compactToggle.setAttribute('aria-expanded', 'false') + compactMenu.classList.remove('show') + } + }) + + // Close on Escape + document.addEventListener('keydown', function (e) { + if ( + e.key === 'Escape' && + compactToggle.getAttribute('aria-expanded') === 'true' + ) { + compactToggle.setAttribute('aria-expanded', 'false') + compactMenu.classList.remove('show') + compactToggle.focus() + } + }) + + contextDropdown.appendChild(compactToggle) + contextDropdown.appendChild(compactMenu) + contextSwitcher.appendChild(contextDropdown) + metadataInline.appendChild(contextSwitcher) + } + } + + // Create availability dropdown (check "Available in:" text) + const availabilityPara = Array.from(metadataContent.querySelectorAll('p')).find( + (p) => p.textContent.includes('Available in:') + ) + + if (availabilityPara) { + const links = availabilityPara.querySelectorAll('a') + const currentVersionSpan = availabilityPara.querySelector('.current-version') + + if (currentVersionSpan) { + const currentText = currentVersionSpan.textContent.trim() + + // Extract version from URL (e.g., /connect/... or /streaming/26.1/...) + const versionMatch = window.location.pathname.match(/\/(streaming|connect)\/(\d+\.\d+)/) + const currentVersion = versionMatch ? versionMatch[2] : null + + // Create availability dropdown container + const availabilityDropdown = document.createElement('div') + availabilityDropdown.className = 'availability-selector' + + // Create dropdown button + const dropdownButton = document.createElement('button') + dropdownButton.className = 'availability-selector-toggle' + dropdownButton.setAttribute('aria-expanded', 'false') + dropdownButton.setAttribute('aria-haspopup', 'true') + + // Button text based on context - Cloud doesn't show version + if (currentText === 'Cloud') { + dropdownButton.innerHTML = ` + Availability: + Cloud + + + + ` + } else { + // Self-Managed shows version + dropdownButton.innerHTML = ` + Availability: + Self-Managed${currentVersion ? ' v' + currentVersion : ''} + + + + ` + } + + // Create dropdown menu + const dropdownMenu = document.createElement('div') + dropdownMenu.className = 'availability-selector-menu' + dropdownMenu.setAttribute('role', 'menu') + + // Add menu items based on availability + let hasAlternatives = false + links.forEach((link) => { + const linkText = link.textContent.trim() + + if (linkText === 'Cloud' && currentText !== 'Cloud') { + // Viewing Self-Managed, link to Cloud (no version) + const menuItem = document.createElement('a') + menuItem.href = link.href + menuItem.className = 'availability-selector-item' + menuItem.setAttribute('role', 'menuitem') + menuItem.innerHTML = ` + + + + Also in Cloud + ` + dropdownMenu.appendChild(menuItem) + hasAlternatives = true + } else if (linkText === 'Self-Managed' && currentText !== 'Self-Managed') { + // Viewing Cloud, link to Self-Managed (with version) + // Extract version from the link URL + const linkVersionMatch = link.href.match(/\/(streaming|connect)\/(\d+\.\d+)/) + const linkVersion = linkVersionMatch ? linkVersionMatch[2] : null + + const menuItem = document.createElement('a') + menuItem.href = link.href + menuItem.className = 'availability-selector-item' + menuItem.setAttribute('role', 'menuitem') + menuItem.innerHTML = ` + + + + Also in Self-Managed${linkVersion ? ' v' + linkVersion : ''} + ` + dropdownMenu.appendChild(menuItem) + hasAlternatives = true + } + }) + + // If no alternatives, show "only available" message + if (!hasAlternatives) { + const menuItem = document.createElement('div') + menuItem.className = 'availability-selector-item availability-selector-item--disabled' + menuItem.innerHTML = ` + + + + Only available in ${currentText} + ` + dropdownMenu.appendChild(menuItem) + dropdownButton.classList.add('availability-selector-toggle--disabled') + } + + // Set up toggle functionality + dropdownButton.addEventListener('click', function (e) { + e.preventDefault() + e.stopPropagation() + + if (dropdownButton.classList.contains('availability-selector-toggle--disabled')) { + return + } + + const isOpen = dropdownButton.getAttribute('aria-expanded') === 'true' + + if (isOpen) { + dropdownButton.setAttribute('aria-expanded', 'false') + dropdownMenu.classList.remove('show') + } else { + dropdownButton.setAttribute('aria-expanded', 'true') + dropdownMenu.classList.add('show') + } + }) + + // Close on outside click + document.addEventListener('click', function (e) { + if (!availabilityDropdown.contains(e.target)) { + dropdownButton.setAttribute('aria-expanded', 'false') + dropdownMenu.classList.remove('show') + } + }) + + // Close on Escape + document.addEventListener('keydown', function (e) { + if ( + e.key === 'Escape' && + dropdownButton.getAttribute('aria-expanded') === 'true' + ) { + dropdownButton.setAttribute('aria-expanded', 'false') + dropdownMenu.classList.remove('show') + dropdownButton.focus() + } + }) + + availabilityDropdown.appendChild(dropdownButton) + availabilityDropdown.appendChild(dropdownMenu) + metadataInline.appendChild(availabilityDropdown) + } + } + + // Only add metadata-inline if it has content + if (metadataInline.children.length > 0) { + // Insert before the page options dropdown (markdown-dropdown) + const pageOptions = stickyBar.querySelector('.markdown-dropdown') + if (pageOptions) { + stickyBar.insertBefore(metadataInline, pageOptions) + } else { + stickyBar.appendChild(metadataInline) + } + + // Hide the original metadata block + metadataBlock.style.display = 'none' + } + } + + // Run when DOM is ready + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', moveConnectorMetadataToSticky) + } else { + moveConnectorMetadataToSticky() + } +})() diff --git a/src/js/25-topbar-dropdown.js b/src/js/25-topbar-dropdown.js new file mode 100644 index 00000000..85aa9293 --- /dev/null +++ b/src/js/25-topbar-dropdown.js @@ -0,0 +1,45 @@ +/** + * Topbar dropdown toggle + * Handles click/tap interactions for dropdown menus in the topbar + */ +;(function () { + 'use strict' + + // Handle dropdown toggle on click (for mobile/touch) + document.addEventListener('click', function (e) { + const trigger = e.target.closest('.tb-dropdown-trigger') + + if (trigger) { + e.preventDefault() + const isExpanded = trigger.getAttribute('aria-expanded') === 'true' + + // Close all other dropdowns + document.querySelectorAll('.tb-dropdown-trigger[aria-expanded="true"]').forEach(function (otherTrigger) { + if (otherTrigger !== trigger) { + otherTrigger.setAttribute('aria-expanded', 'false') + } + }) + + // Toggle this dropdown + trigger.setAttribute('aria-expanded', isExpanded ? 'false' : 'true') + } else { + // Click outside - close all dropdowns + const clickedInsideDropdown = e.target.closest('.tb-dropdown') + if (!clickedInsideDropdown) { + document.querySelectorAll('.tb-dropdown-trigger[aria-expanded="true"]').forEach(function (trigger) { + trigger.setAttribute('aria-expanded', 'false') + }) + } + } + }) + + // Close dropdown on escape key + document.addEventListener('keydown', function (e) { + if (e.key === 'Escape') { + document.querySelectorAll('.tb-dropdown-trigger[aria-expanded="true"]').forEach(function (trigger) { + trigger.setAttribute('aria-expanded', 'false') + trigger.focus() + }) + } + }) +})() diff --git a/src/js/react/AskAI.jsx b/src/js/react/AskAI.jsx index f36c97ed..d1bcaac1 100644 --- a/src/js/react/AskAI.jsx +++ b/src/js/react/AskAI.jsx @@ -2,6 +2,8 @@ import React from 'react' import { createRoot } from 'react-dom/client' import { KapaProvider } from '@kapaai/react-sdk' import ChatInterface from './components/ChatInterface.jsx' +import { saveConversation } from './chatPersistence.js' +import { createPersistentApiService } from './persistentApiService.js' const safeHeap = (eventName, eventParams) => { if (typeof window.heap === 'object' && typeof window.heap.track === 'function') { @@ -9,6 +11,9 @@ const safeHeap = (eventName, eventParams) => { } }; +// Create singleton API service instance for conversation persistence +const persistentApiService = createPersistentApiService() + function App() { const integrationId = window.UI_INTEGRATION_ID @@ -16,6 +21,7 @@ function App() { <> { @@ -25,6 +31,11 @@ function App() { }); }, onAnswerGenerationCompleted: (data) => { + // Save conversation state for cross-page persistence + // Save after answer is complete so we have the full exchange + if (data.threadId && data.conversation) { + saveConversation(data.threadId, data.conversation) + } safeHeap("answer_generated_docs_home", { question_id: data.questionAnswerId, answer_length: data.answer.length, @@ -46,7 +57,11 @@ function App() { } document.addEventListener('DOMContentLoaded', () => { - const el = document.getElementById('kapa-chat-root') - if (!el) return - createRoot(el).render() + // Mount to exactly one root to prevent duplicate App instances + const homeEl = document.getElementById('kapa-chat-root') + const panelEl = document.getElementById('chat-panel-kapa-root') + const mountEl = homeEl || panelEl + if (mountEl) { + createRoot(mountEl).render() + } }) diff --git a/src/js/react/chatPersistence.js b/src/js/react/chatPersistence.js new file mode 100644 index 00000000..7898010d --- /dev/null +++ b/src/js/react/chatPersistence.js @@ -0,0 +1,78 @@ +/* globals localStorage */ +/** + * Chat Persistence Module + * Saves and restores conversation state to localStorage for cross-page continuity + */ + +const STORAGE_KEY = 'redpanda-chat-thread' +const EXPIRY_MS = 24 * 60 * 60 * 1000 // 24 hours + +/** + * Save conversation state to localStorage + * @param {string} threadId - The Kapa thread ID + * @param {Array} conversation - Array of {id, question, answer} objects + */ +export function saveConversation (threadId, conversation) { + if (!threadId || !conversation) return + + try { + localStorage.setItem( + STORAGE_KEY, + JSON.stringify({ + threadId, + conversation: conversation.map((qa) => ({ + id: qa.id || qa.questionAnswerId, + question: qa.question, + answer: qa.answer, + })), + timestamp: Date.now(), + }) + ) + } catch (err) { + console.warn('Failed to save chat conversation:', err) + } +} + +/** + * Load saved conversation from localStorage + * @returns {Object|null} - {threadId, conversation, timestamp} or null if not found/expired + */ +export function loadConversation () { + try { + const data = localStorage.getItem(STORAGE_KEY) + if (!data) return null + + const parsed = JSON.parse(data) + + // Check expiry + if (Date.now() - parsed.timestamp > EXPIRY_MS) { + clearConversation() + return null + } + + return parsed + } catch (err) { + console.warn('Failed to load chat conversation:', err) + return null + } +} + +/** + * Clear saved conversation from localStorage + */ +export function clearConversation () { + try { + localStorage.removeItem(STORAGE_KEY) + } catch (err) { + console.warn('Failed to clear chat conversation:', err) + } +} + +/** + * Get saved thread ID if available and not expired + * @returns {string|null} - The saved thread ID or null + */ +export function getSavedThreadId () { + const data = loadConversation() + return data?.threadId || null +} diff --git a/src/js/react/components/ChatInterface.jsx b/src/js/react/components/ChatInterface.jsx index 25c1be7d..acfd5d85 100644 --- a/src/js/react/components/ChatInterface.jsx +++ b/src/js/react/components/ChatInterface.jsx @@ -1,7 +1,7 @@ import React, { useState, useEffect, useRef, Component } from 'react' import { useChat, useDeepThinking } from '@kapaai/react-sdk' import { - ArrowUp, + ArrowRight, ArrowDown, ThumbsUp, ThumbsDown, @@ -9,11 +9,15 @@ import { ClipboardCopy, CircleStop, FileSearch, + Check, + AlertCircle, + Sparkles, } from 'lucide-react' import DOMPurify from 'dompurify' import { Marked } from 'marked' import { markedHighlight } from 'marked-highlight' import hljs from 'highlight.js' +import { loadConversation, clearConversation } from '../chatPersistence.js' // ——— ErrorBoundary —————————————————————————————————————————————————— class ErrorBoundary extends Component { @@ -54,6 +58,27 @@ const marked = new Marked( ) +// ——— Toast component ———————————————————————————————————————————————————— +function Toast({ message, type = 'success', onDismiss }) { + useEffect(() => { + const timer = setTimeout(() => { + if (onDismiss) onDismiss() + }, 3000) + return () => clearTimeout(timer) + }, [onDismiss]) + + const isError = type === 'error' + + return ( +
+ + {isError ? : } + + {message} +
+ ) +} + // ——— Answer component ——————————————————————————————————————————————————— function Answer({ md }) { const containerRef = useRef(null) @@ -77,22 +102,22 @@ function Answer({ md }) { } // ——— FeedbackButtons ————————————————————————————————————————————————————— -function FeedbackButtons({ questionAnswerId, setFeedbackToast }) { +function FeedbackButtons({ questionAnswerId, showToast }) { const { addFeedback } = useChat() const handleFeedback = async (reaction) => { try { await addFeedback(questionAnswerId, reaction) - setFeedbackToast( + showToast( reaction === 'upvote' - ? "Thanks! Glad you found that helpful." - : "We've got your feedback." + ? 'Thanks for the feedback!' + : 'Feedback received', + 'success' ) } catch (err) { console.error('Feedback error', err) - setFeedbackToast('⚠️ Could not send your feedback. Try again.') + showToast('Could not send feedback', 'error') } - setTimeout(() => setFeedbackToast(null), 3000) } return ( @@ -102,6 +127,7 @@ function FeedbackButtons({ questionAnswerId, setFeedbackToast }) { className="feedback-button" type="button" onClick={() => handleFeedback('upvote')} + title="This was helpful" > @@ -109,6 +135,7 @@ function FeedbackButtons({ questionAnswerId, setFeedbackToast }) { className="feedback-button" type="button" onClick={() => handleFeedback('downvote')} + title="This wasn't helpful" > @@ -118,16 +145,15 @@ function FeedbackButtons({ questionAnswerId, setFeedbackToast }) { } // ——— ActionButtons ——————————————————————————————————————————————————————— -function ActionButtons({ onReset, onCopy, setCopyToast }) { - const safeCopy = () => { +function ActionButtons({ onReset, onCopy, showToast }) { + const safeCopy = async () => { try { - onCopy() - setCopyToast('Copied to clipboard!') + await onCopy() + showToast('Copied to clipboard', 'success') } catch (e) { console.error('Copy error:', e) - setCopyToast('⚠️ Copy failed.') + showToast('Failed to copy', 'error') } - setTimeout(() => setCopyToast(null), 2000) } return ( @@ -154,10 +180,18 @@ export default function ChatInterface() { const [stoppedIds, setStoppedIds] = useState(new Set()) const [suggestions, setSuggestions] = useState([]) const [hasInteracted, setHasInteracted] = useState(false) - const [copyToast, setCopyToast] = useState(null) - const [feedbackToast, setFeedbackToast] = useState(null) + const [toast, setToast] = useState(null) + const [restoredConversation, setRestoredConversation] = useState(null) const textareaRef = useRef(null) + const showToast = (message, type = 'success') => { + setToast({ message, type }) + } + + const dismissToast = () => { + setToast(null) + } + const resetTextareaHeight = () => { if (!textareaRef.current) return textareaRef.current.style.height = 'unset' @@ -185,6 +219,15 @@ export default function ChatInterface() { } }, []); + // Restore conversation from localStorage on mount (cross-page persistence) + useEffect(() => { + const saved = loadConversation() + if (saved?.conversation?.length > 0) { + setRestoredConversation(saved.conversation) + setHasInteracted(true) + } + }, []) + // Update isMobile on resize. Close dropdown if switching breakpoints. useEffect(() => { const handleResize = () => { @@ -211,19 +254,41 @@ export default function ChatInterface() { const deepThinking = useDeepThinking() - const latestQA = conversation.getLatest() + // Merge restored conversation with live conversation for display + // Show restored conversation when live is empty, otherwise show live + // (live conversation will include new queries that continue the thread) + const displayConversation = restoredConversation && conversation.length === 0 + ? restoredConversation + : conversation - // Show/hide “scroll down” button + const latestQA = conversation.length > 0 ? conversation.getLatest() : null + + // Show/hide "scroll down" button useEffect(() => { if (!hasInteracted || isPreparingAnswer) return const THRESHOLD = 300 + // Check if we're in chat panel drawer + const chatScroll = document.querySelector('.chat-scroll') + const isInPanel = chatScroll && chatScroll.contains(document.getElementById('chat-panel-kapa-root')) + const handleScroll = () => { - const scrollTop = window.scrollY - const innerH = window.innerHeight - const scrollH = document.documentElement.scrollHeight + let scrollTop, innerH, scrollH + + if (isInPanel && chatScroll) { + // Use chat panel scroll container + scrollTop = chatScroll.scrollTop + innerH = chatScroll.clientHeight + scrollH = chatScroll.scrollHeight + } else { + // Use window scroll (home page) + scrollTop = window.scrollY + innerH = window.innerHeight + scrollH = document.documentElement.scrollHeight + } + const canScroll = scrollH > innerH - const atBottom = scrollTop + innerH >= scrollH - THRESHOLD + const atBottom = scrollTop + innerH >= scrollH - THRESHOLD if (!canScroll) { setShowScrollDown(false) @@ -232,20 +297,32 @@ export default function ChatInterface() { setShowScrollDown(!atBottom) } - window.addEventListener('scroll', handleScroll, { passive: true }) + const scrollTarget = isInPanel ? chatScroll : window + scrollTarget.addEventListener('scroll', handleScroll, { passive: true }) window.addEventListener('resize', handleScroll, { passive: true }) handleScroll() return () => { - window.removeEventListener('scroll', handleScroll) + scrollTarget.removeEventListener('scroll', handleScroll) window.removeEventListener('resize', handleScroll) } }, [hasInteracted, isPreparingAnswer, isGeneratingAnswer]) const scrollToBottom = () => { - window.scrollTo({ - top: document.documentElement.scrollHeight, - behavior: 'smooth', - }) + // Check if we're in the chat panel drawer + const chatScroll = document.querySelector('.chat-scroll') + if (chatScroll && chatScroll.contains(document.getElementById('chat-panel-kapa-root'))) { + // Scroll within the chat panel + chatScroll.scrollTo({ + top: chatScroll.scrollHeight, + behavior: 'smooth', + }) + } else { + // Scroll the window (home page behavior) + window.scrollTo({ + top: document.documentElement.scrollHeight, + behavior: 'smooth', + }) + } } // “Preparing answer…” dots animation @@ -290,6 +367,25 @@ export default function ChatInterface() { setDropdownOpen(false) // close dropdown when you tap anything } + // Expose submitChatQuery globally for external components (playground, code blocks) + useEffect(() => { + window.submitChatQuery = (query, autoSubmit = true) => { + if (!query || !query.trim()) return + if (autoSubmit) { + doQuery(query) + } else { + setMessage(query) + // Focus the textarea + if (textareaRef.current) { + textareaRef.current.focus() + } + } + } + return () => { + delete window.submitChatQuery + } + }, [submitQuery, hasInteracted]) + const handleSubmit = (e) => { e.preventDefault() doQuery(message) @@ -297,9 +393,11 @@ export default function ChatInterface() { } const handleReset = () => { + clearConversation() // Clear localStorage persistence resetConversation() setMessage('') setStoppedIds(new Set()) + setRestoredConversation(null) setHasInteracted(false) setShowScrollDown(false) window.scrollTo({ top: 0, behavior: 'smooth' }) @@ -310,7 +408,7 @@ export default function ChatInterface() { const handleCopy = async () => { try { await navigator.clipboard.writeText( - conversation + displayConversation .map((q) => `Question: ${q.question}\nAnswer: ${q.answer}`) .join('\n---\n') ) @@ -415,15 +513,54 @@ export default function ChatInterface() { return (
+ {/* Toast notification */} + {toast && ( + + )} + + {/* Welcome screen - shown before interaction */} + {!hasInteracted && ( +
+
+ +
+

How can I help?

+

+ I can answer questions about Redpanda docs, write quickstarts, and help you troubleshoot. +

+ {suggestions.length > 0 && ( +
+ {suggestions.map((s, i) => ( + + ))} +
+ )} +
+ )} +
- {conversation.map((qa, idx) => { + {displayConversation.map((qa, idx) => { const key = qa.id ?? `temp-${idx}` const wasStopped = stoppedIds.has(key) - const isLast = latestQA?.id === qa.id + // For restored conversations, show action buttons on the last item + const isLast = idx === displayConversation.length - 1 + // Feedback only available for live conversation items (not restored) + const canFeedback = conversation.length > 0 && latestQA?.id === qa.id return (

@@ -434,21 +571,16 @@ export default function ChatInterface() { - {!wasStopped && ( + {!wasStopped && canFeedback && ( )}
)} - {(copyToast || feedbackToast) && ( -
- {copyToast || feedbackToast} -
- )}
) })} @@ -475,86 +607,46 @@ export default function ChatInterface() { )} -
-
-
+ +
-