diff --git a/.cursorrules b/.cursorrules index b0636760a..8443da929 100644 --- a/.cursorrules +++ b/.cursorrules @@ -8,7 +8,6 @@ - **Never run jq command** - it crashes you. - **Never run sleep** from command line - it hibernates pc. - **Do not generate .md files** unless explicity told to do so. -- **Comments** should always be made in all lowercase and simple english - **Error messages**, any error being shown in the ui should be user friendly and easy to understand, and any error being logged in consoles and sentry should be descriptive for developers to help with debugging - **Never add AI co-author to commits** - do not add "Co-Authored-By" lines for AI assistants in git commits diff --git a/.env.example b/.env.example index c2a4fe59d..8e6080723 100644 --- a/.env.example +++ b/.env.example @@ -4,7 +4,7 @@ export NEXT_PUBLIC_PEANUT_WS_URL="wss://api.staging.peanut.me" # export PEANUT_API_URL="http://127.0.0.1:5000/" # If running api locally # export NEXT_PUBLIC_PEANUT_API_URL="http://127.0.0.1:5000/" # If running api locally -export PEANUT_API_KEY="" # See in docs.peanut.to +export PEANUT_API_KEY="" # See in docs.peanut.me export NODE_ENV="development" @@ -53,7 +53,7 @@ export PROMO_LIST={} #generate these with scripts/generate.mjs export NEXT_PUBLIC_VAPID_PUBLIC_KEY= export VAPID_PRIVATE_KEY= -export NEXT_PUBLIC_VAPID_SUBJECT="mailto:hello@peanut.to" +export NEXT_PUBLIC_VAPID_SUBJECT="mailto:hello@peanut.me" export NEXT_PUBLIC_FETCH_TIMEOUT_MS=10000 # one signal diff --git a/.github/workflows/preview.yaml b/.github/workflows/preview.yaml index 13be38b27..635054d4d 100644 --- a/.github/workflows/preview.yaml +++ b/.github/workflows/preview.yaml @@ -2,8 +2,8 @@ name: Preview deploy on: pull_request: branches: - - peanut-wallet - - peanut-wallet-dev + - main + - dev jobs: Deploy-Preview: @@ -12,6 +12,7 @@ jobs: - uses: actions/checkout@v4 with: submodules: true + token: ${{ secrets.SUBMODULE_TOKEN }} - uses: pnpm/action-setup@v4 with: version: 9 @@ -24,4 +25,4 @@ jobs: - name: Build Project Artifacts run: vercel build --target=preview --token=${{ secrets.VERCEL_TOKEN }} - name: Deploy Project Artifacts to Vercel - run: vercel deploy --prebuilt --target=preview --token=${{ secrets.VERCEL_TOKEN }} + run: vercel deploy --prebuilt --archive=tgz --target=preview --token=${{ secrets.VERCEL_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 18aad0ce8..181cb4a07 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,6 +11,7 @@ jobs: - uses: actions/checkout@v4 with: submodules: true + token: ${{ secrets.SUBMODULE_TOKEN }} - uses: actions/setup-node@v4 with: @@ -26,6 +27,9 @@ jobs: - name: Check formatting run: pnpm prettier --check . + - name: Validate internal links + run: pnpm validate-links + - name: Run Unit Tests run: pnpm test diff --git a/.github/workflows/update-content.yml b/.github/workflows/update-content.yml new file mode 100644 index 000000000..3b0f63aa9 --- /dev/null +++ b/.github/workflows/update-content.yml @@ -0,0 +1,60 @@ +name: Update content submodule + +on: + repository_dispatch: + types: [content-updated] + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + update: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Init and update submodule + env: + SUBMODULE_TOKEN: ${{ secrets.SUBMODULE_TOKEN }} + run: | + git config submodule.src/content.url "https://x-access-token:${SUBMODULE_TOKEN}@github.com/peanutprotocol/peanut-content.git" + git submodule update --init src/content + cd src/content + git fetch origin main + git checkout origin/main + + - name: Check for changes + id: check + run: | + if git diff --quiet src/content; then + echo "changed=false" >> "$GITHUB_OUTPUT" + else + echo "changed=true" >> "$GITHUB_OUTPUT" + fi + + - name: Create PR + if: steps.check.outputs.changed == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + BRANCH="auto/update-content-$(date -u +%Y%m%d-%H%M%S)" + TREE=$(git write-tree) + PARENT=$(git rev-parse HEAD) + # create signed commit via GitHub API (verified signature) + COMMIT_SHA=$(gh api repos/${{ github.repository }}/git/commits \ + --method POST \ + -f message="Update content submodule to latest main" \ + -f "tree=$TREE" \ + -f "parents[]=$PARENT" \ + --jq '.sha') + # create branch pointing to signed commit + gh api repos/${{ github.repository }}/git/refs \ + --method POST \ + -f "ref=refs/heads/$BRANCH" \ + -f "sha=$COMMIT_SHA" + gh pr create \ + --head "$BRANCH" \ + --title "Update content submodule" \ + --body "Auto-generated: updates content submodule to latest peanut-content main." diff --git a/.gitignore b/.gitignore index 148c7fb2e..afb8d3eaf 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,4 @@ public/swe-worker* # mobile POC android/ +.claude/ diff --git a/.gitmodules b/.gitmodules index 38ee7fcbe..2a901695e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,7 @@ [submodule "src/assets/animations"] path = src/assets/animations url = https://github.com/peanutprotocol/peanut-animations.git +[submodule "src/content"] + path = src/content + url = https://github.com/peanutprotocol/peanut-content.git + branch = main diff --git a/README.md b/README.md index ee2299790..26415abda 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,14 @@ +# Peanut UI + +[![Tests](https://github.com/peanutprotocol/peanut-ui/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/peanutprotocol/peanut-ui/actions/workflows/tests.yml) +[![CodeQL](https://github.com/peanutprotocol/peanut-ui/actions/workflows/github-code-scanning/codeql/badge.svg?branch=main)](https://github.com/peanutprotocol/peanut-ui/security/code-scanning) +[![Next.js](https://img.shields.io/badge/Next.js-16-black?logo=next.js)](https://nextjs.org/) +[![React](https://img.shields.io/badge/React-19-61DAFB?logo=react)](https://react.dev/) +[![TypeScript](https://img.shields.io/badge/TypeScript-5.6-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/) +[![Tailwind CSS](https://img.shields.io/badge/Tailwind-4-06B6D4?logo=tailwindcss&logoColor=white)](https://tailwindcss.com/) +[![i18n](https://img.shields.io/badge/i18n-5_locales-blue)](https://peanut.me) +[![PWA Ready](https://img.shields.io/badge/PWA-ready-5A0FC8?logo=pwa)](https://peanut.me) + Live at: [peanut.me](https://peanut.me) | [staging.peanut.me](https://staging.peanut.me) ## Getting Started @@ -68,3 +79,14 @@ describe('Bank Account Formatting', () => { ``` The CI pipeline runs tests on all PRs. Failed tests will block merging. + +## Archived Branches + +This repo previously hosted two other apps under the `peanut.to` domain. Both are now deprecated in favor of `peanut.me` (this branch). Their final states are preserved as tags: + +| Tag | Was | Last commit | Notes | +|-----|-----|-------------|-------| +| `archive/peanut-to` | `main` → `peanut.to` | Nov 2025 | Link-based send/claim app, cashout, SDK pages | +| `archive/legacy-peanut-to` | `legacy` → `legacy.peanut.to` | Mar 2025 | Batch send, raffles, leaderboard | + +To browse the old code: `git checkout archive/peanut-to` diff --git a/next.config.js b/next.config.js index b41d343c5..d37743d58 100644 --- a/next.config.js +++ b/next.config.js @@ -1,9 +1,7 @@ const os = require('os') const { execSync } = require('child_process') -const withBundleAnalyzer = require('@next/bundle-analyzer')({ - // Only enable in production builds when explicitly requested - enabled: process.env.ANALYZE === 'true' && process.env.NODE_ENV !== 'development', -}) +const withBundleAnalyzer = + process.env.ANALYZE === 'true' ? require('@next/bundle-analyzer')({ enabled: true }) : (config) => config const redirectsConfig = require('./redirects.json') diff --git a/package.json b/package.json index 4bfe240f7..bb974423c 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,9 @@ "test:e2e": "playwright test", "test:e2e:ui": "playwright test --ui", "test:e2e:headed": "playwright test --headed", - "script": "NODE_OPTIONS=\"--experimental-json-modules\" tsx" + "script": "NODE_OPTIONS=\"--experimental-json-modules\" tsx", + "validate-content": "tsx scripts/validate-content.ts", + "validate-links": "tsx scripts/validate-links.ts" }, "dependencies": { "@dicebear/collection": "^9.2.2", @@ -52,7 +54,7 @@ "@vercel/analytics": "^1.4.1", "@wagmi/core": "2.19.0", "@zerodev/passkey-validator": "^5.6.0", - "@zerodev/sdk": "5.5.0", + "@zerodev/sdk": "5.5.7", "autoprefixer": "^10.4.20", "canvas-confetti": "^1.9.3", "classnames": "^2.5.1", @@ -60,11 +62,14 @@ "embla-carousel-react": "^8.6.0", "ethers": "5.7.2", "framer-motion": "^11.11.17", + "gray-matter": "^4.0.3", "i18n-iso-countries": "^7.13.0", "iban-to-bic": "^1.4.0", "js-cookie": "^3.0.5", "jsqr": "^1.4.0", + "marked": "^17.0.2", "next": "16.0.10", + "next-mdx-remote": "^6.0.0", "nuqs": "^2.8.6", "pix-utils": "^2.8.2", "pulltorefreshjs": "^0.1.22", @@ -79,6 +84,8 @@ "react-redux": "^9.2.0", "react-tooltip": "^5.28.0", "redux": "^5.0.1", + "remark-gfm": "^4.0.1", + "shiki": "^3.22.0", "siwe": "^2.3.2", "tailwind-merge": "^1.14.0", "tailwind-scrollbar": "^3.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0df89f257..192bc6dff 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,7 +30,7 @@ importers: version: 2.2.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@headlessui/tailwindcss': specifier: ^0.2.1 - version: 0.2.2(tailwindcss@3.4.19(tsx@4.21.0)) + version: 0.2.2(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2)) '@justaname.id/react': specifier: 0.3.180 version: 0.3.180(@tanstack/react-query@5.8.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(ethers@5.7.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(react@19.2.4)(siwe@2.3.2(ethers@5.7.2(bufferutil@4.1.0)(utf-8-validate@5.0.10)))(typescript@5.9.3)(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6))(wagmi@2.16.3(@tanstack/query-core@5.8.3)(@tanstack/react-query@5.8.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@18.3.27)(bufferutil@4.1.0)(immer@11.1.3)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6))(zod@4.3.6))(zod@4.3.6) @@ -93,10 +93,10 @@ importers: version: 2.19.0(@tanstack/query-core@5.8.3)(@types/react@18.3.27)(immer@11.1.3)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)) '@zerodev/passkey-validator': specifier: ^5.6.0 - version: 5.6.0(@zerodev/sdk@5.5.0(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)))(@zerodev/webauthn-key@5.5.0(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)))(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)) + version: 5.6.0(@zerodev/sdk@5.5.7(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)))(@zerodev/webauthn-key@5.5.0(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)))(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)) '@zerodev/sdk': - specifier: 5.5.0 - version: 5.5.0(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)) + specifier: 5.5.7 + version: 5.5.7(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)) autoprefixer: specifier: ^10.4.20 version: 10.4.23(postcss@8.5.6) @@ -118,6 +118,9 @@ importers: framer-motion: specifier: ^11.11.17 version: 11.18.2(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + gray-matter: + specifier: ^4.0.3 + version: 4.0.3 i18n-iso-countries: specifier: ^7.13.0 version: 7.14.0 @@ -130,9 +133,15 @@ importers: jsqr: specifier: ^1.4.0 version: 1.4.0 + marked: + specifier: ^17.0.2 + version: 17.0.2 next: specifier: 16.0.10 version: 16.0.10(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + next-mdx-remote: + specifier: ^6.0.0 + version: 6.0.0(@types/react@18.3.27)(react@19.2.4) nuqs: specifier: ^2.8.6 version: 2.8.6(next@16.0.10(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) @@ -175,6 +184,12 @@ importers: redux: specifier: ^5.0.1 version: 5.0.1 + remark-gfm: + specifier: ^4.0.1 + version: 4.0.1 + shiki: + specifier: ^3.22.0 + version: 3.22.0 siwe: specifier: ^2.3.2 version: 2.3.2(ethers@5.7.2(bufferutil@4.1.0)(utf-8-validate@5.0.10)) @@ -183,7 +198,7 @@ importers: version: 1.14.0 tailwind-scrollbar: specifier: ^3.1.0 - version: 3.1.0(tailwindcss@3.4.19(tsx@4.21.0)) + version: 3.1.0(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2)) use-haptic: specifier: ^1.1.11 version: 1.1.13 @@ -274,7 +289,7 @@ importers: version: 11.2.0 tailwindcss: specifier: ^3.4.15 - version: 3.4.19(tsx@4.21.0) + version: 3.4.19(tsx@4.21.0)(yaml@2.8.2) ts-jest: specifier: ^29.1.2 version: 29.4.6(@babel/core@7.28.6)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.6))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.4.2)(babel-plugin-macros@3.1.0))(typescript@5.9.3) @@ -1336,6 +1351,15 @@ packages: '@lit/reactive-element@2.1.2': resolution: {integrity: sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==} + '@mdx-js/mdx@3.1.1': + resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==} + + '@mdx-js/react@3.1.1': + resolution: {integrity: sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==} + peerDependencies: + '@types/react': '>=16' + react: '>=16' + '@metamask/eth-json-rpc-provider@1.0.1': resolution: {integrity: sha512-whiUMPlAOrVGmX8aKYVPvlKyG4CpQXiNNyt74vE1xb5sPvmx5oA7B/kOi/JdBvhGQq97U1/AVdXEdk2zkP8qyA==} engines: {node: '>=14.0.0'} @@ -2627,6 +2651,27 @@ packages: typescript: optional: true + '@shikijs/core@3.22.0': + resolution: {integrity: sha512-iAlTtSDDbJiRpvgL5ugKEATDtHdUVkqgHDm/gbD2ZS9c88mx7G1zSYjjOxp5Qa0eaW0MAQosFRmJSk354PRoQA==} + + '@shikijs/engine-javascript@3.22.0': + resolution: {integrity: sha512-jdKhfgW9CRtj3Tor0L7+yPwdG3CgP7W+ZEqSsojrMzCjD1e0IxIbwUMDDpYlVBlC08TACg4puwFGkZfLS+56Tw==} + + '@shikijs/engine-oniguruma@3.22.0': + resolution: {integrity: sha512-DyXsOG0vGtNtl7ygvabHd7Mt5EY8gCNqR9Y7Lpbbd/PbJvgWrqaKzH1JW6H6qFkuUa8aCxoiYVv8/YfFljiQxA==} + + '@shikijs/langs@3.22.0': + resolution: {integrity: sha512-x/42TfhWmp6H00T6uwVrdTJGKgNdFbrEdhaDwSR5fd5zhQ1Q46bHq9EO61SCEWJR0HY7z2HNDMaBZp8JRmKiIA==} + + '@shikijs/themes@3.22.0': + resolution: {integrity: sha512-o+tlOKqsr6FE4+mYJG08tfCFDS+3CG20HbldXeVoyP+cYSUxDhrFf3GPjE60U55iOkkjbpY2uC3It/eeja35/g==} + + '@shikijs/types@3.22.0': + resolution: {integrity: sha512-491iAekgKDBFE67z70Ok5a8KBMsQ2IJwOWw3us/7ffQkIBCyOQfm/aNwVMBUriP02QshIfgHCBSIYAl3u2eWjg==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@simplewebauthn/browser@8.3.7': resolution: {integrity: sha512-ZtRf+pUEgOCvjrYsbMsJfiHOdKcrSZt2zrAnIIpfmA06r0FxBovFYq0rJ171soZbe13KmWzAoLKjSxVW7KxCdQ==} @@ -2804,12 +2849,18 @@ packages: '@types/eslint@9.6.1': resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} '@types/graceful-fs@4.1.9': resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -2834,6 +2885,12 @@ packages: '@types/lodash@4.17.23': resolution: {integrity: sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==} + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/mdx@2.0.13': + resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==} + '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} @@ -2889,6 +2946,12 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/use-sync-external-store@0.0.6': resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} @@ -2904,6 +2967,9 @@ packages: '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@vercel/analytics@1.6.1': resolution: {integrity: sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==} peerDependencies: @@ -3155,8 +3221,8 @@ packages: '@zerodev/webauthn-key': ^5.4.2 viem: ^2.22.0 - '@zerodev/sdk@5.5.0': - resolution: {integrity: sha512-S8m7u6QiSbhKpxv/mpxRODZFLtz35+PFY7FG5DSPsToTPH05BfWEgy9nSgrsgdAv6ZDhDfwCG3qiVmBQF0vt6Q==} + '@zerodev/sdk@5.5.7': + resolution: {integrity: sha512-Sf4G13yi131H8ujun64obvXIpk1UWn64GiGJjfvGx8aIKg+OWTRz9AZHgGKK+bE/evAmqIg4nchuSvKPhOau1w==} peerDependencies: viem: ^2.22.0 @@ -3198,6 +3264,11 @@ packages: peerDependencies: acorn: ^8.14.0 + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn-walk@8.3.4: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} @@ -3292,6 +3363,10 @@ packages: resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} engines: {node: '>=4'} + astring@1.9.0: + resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} + hasBin: true + async-mutex@0.2.6: resolution: {integrity: sha512-Hs4R+4SPgamu6rSGW8C7cV9gaWUKEHykfzCCvIRuaVv636Ju10ZdeUbvb4TBEW0INuq2DHZqXbK4Nd3yG4RaRw==} @@ -3353,6 +3428,9 @@ packages: peerDependencies: '@babel/core': ^7.0.0 + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -3513,6 +3591,9 @@ packages: canvas-confetti@1.9.4: resolution: {integrity: sha512-yxQbJkAVrFXWNbTUjPqjF7G+g6pDotOUHGbkZq2NELZUMDpiJ85rIEazVb8GTaAptNW2miJAXbs1BtioA251Pw==} + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chalk@3.0.0: resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} engines: {node: '>=8'} @@ -3525,6 +3606,18 @@ packages: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -3578,6 +3671,9 @@ packages: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + collapse-white-space@2.1.0: + resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} + collect-v8-coverage@1.0.3: resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==} @@ -3592,6 +3688,9 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + commander@12.0.0: resolution: {integrity: sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==} engines: {node: '>=18'} @@ -3794,6 +3893,9 @@ packages: decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + decode-uri-component@0.2.2: resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} engines: {node: '>=0.10'} @@ -3851,6 +3953,9 @@ packages: detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + devtools-protocol@0.0.1495869: resolution: {integrity: sha512-i+bkd9UYFis40RcnkW7XrOprCujXRAHg62IVh/Ah3G8MmNXpCGt1m0dTFhSdx/AVs8XEMbdOGRwdkR1Bcta8AA==} @@ -3990,6 +4095,12 @@ packages: es-toolkit@1.33.0: resolution: {integrity: sha512-X13Q/ZSc+vsO1q600bvNK4bxgXMkHcf//RxCmYDaRY5DAcT+eoXjY5hoAPGMdRnWQjvyLEcyauG3b6hz76LNqg==} + esast-util-from-estree@2.0.0: + resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} + + esast-util-from-js@2.0.1: + resolution: {integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==} + esbuild@0.27.2: resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} engines: {node: '>=18'} @@ -4007,6 +4118,10 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + escodegen@2.1.0: resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} engines: {node: '>=6.0'} @@ -4038,9 +4153,30 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + estree-util-attach-comments@3.0.0: + resolution: {integrity: sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==} + + estree-util-build-jsx@3.0.1: + resolution: {integrity: sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==} + + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + estree-util-scope@1.0.0: + resolution: {integrity: sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==} + + estree-util-to-js@2.0.0: + resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==} + + estree-util-visit@2.0.0: + resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} + estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -4093,6 +4229,13 @@ packages: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + extension-port-stream@3.0.0: resolution: {integrity: sha512-an2S5quJMiy5bnZKEf6AkfH/7r8CzHvhchU40gxN+OM6HPhe7Z9T1FUychcf2M9PpPOO0Hf7BAEfJkw2TDIBDw==} engines: {node: '>=12.0.0'} @@ -4324,6 +4467,10 @@ packages: resolution: {integrity: sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + gray-matter@4.0.3: + resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} + engines: {node: '>=6.0'} + gzip-size@6.0.0: resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} engines: {node: '>=10'} @@ -4358,6 +4505,18 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hast-util-to-estree@3.1.3: + resolution: {integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + hmac-drbg@1.0.1: resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} @@ -4371,6 +4530,9 @@ packages: html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + http-proxy-agent@5.0.0: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} @@ -4451,6 +4613,9 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + internmap@2.0.3: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} engines: {node: '>=12'} @@ -4462,6 +4627,12 @@ packages: iron-webcrypto@1.2.1: resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + is-arguments@1.2.0: resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} engines: {node: '>= 0.4'} @@ -4481,6 +4652,13 @@ packages: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -4501,10 +4679,17 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + is-plain-object@5.0.0: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} @@ -4789,6 +4974,10 @@ packages: keyvaluestorage-interface@1.0.0: resolution: {integrity: sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==} + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} @@ -4858,6 +5047,9 @@ packages: lodash@4.17.23: resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -4897,10 +5089,70 @@ packages: makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + markdown-extensions@2.0.0: + resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} + engines: {node: '>=16'} + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + marked@17.0.2: + resolution: {integrity: sha512-s5HZGFQea7Huv5zZcAGhJLT3qLpAfnY7v7GWkICUr0+Wd5TFEtdlRR2XUL5Gg+RH7u2Df595ifrxR03mBaw7gA==} + engines: {node: '>= 20'} + hasBin: true + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.2: + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdx@3.0.0: + resolution: {integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -4911,6 +5163,111 @@ packages: micro-ftch@0.3.1: resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-extension-mdx-expression@3.0.1: + resolution: {integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==} + + micromark-extension-mdx-jsx@3.0.2: + resolution: {integrity: sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==} + + micromark-extension-mdx-md@2.0.0: + resolution: {integrity: sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==} + + micromark-extension-mdxjs-esm@3.0.0: + resolution: {integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==} + + micromark-extension-mdxjs@3.0.0: + resolution: {integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-mdx-expression@2.0.3: + resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-events-to-acorn@2.0.3: + resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -5015,6 +5372,12 @@ packages: resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} engines: {node: '>= 0.4.0'} + next-mdx-remote@6.0.0: + resolution: {integrity: sha512-cJEpEZlgD6xGjB4jL8BnI8FaYdN9BzZM4NwadPe1YQr7pqoWjg9EBCMv3nXBkuHqMRfv2y33SzUsuyNh9LFAQQ==} + engines: {node: '>=14', npm: '>=7'} + peerDependencies: + react: '>=16' + next@16.0.10: resolution: {integrity: sha512-RtWh5PUgI+vxlV3HdR+IfWA1UUHu0+Ram/JBO4vWB54cVPentCD0e+lxyAYEsDTqGGMg7qpjhKh6dc6aW7W/sA==} engines: {node: '>=20.9.0'} @@ -5124,6 +5487,12 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} + oniguruma-parser@0.12.1: + resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} + + oniguruma-to-es@4.3.4: + resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==} + opener@1.5.2: resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} hasBin: true @@ -5185,6 +5554,9 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -5461,6 +5833,9 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + proxy-agent@6.5.0: resolution: {integrity: sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==} engines: {node: '>= 14'} @@ -5664,6 +6039,20 @@ packages: resolution: {integrity: sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==} engines: {node: '>= 12.13.0'} + recma-build-jsx@1.0.0: + resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==} + + recma-jsx@1.0.1: + resolution: {integrity: sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + recma-parse@1.0.0: + resolution: {integrity: sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==} + + recma-stringify@1.0.0: + resolution: {integrity: sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==} + redent@3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} @@ -5676,6 +6065,33 @@ packages: redux@5.0.1: resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + + rehype-recma@1.0.0: + resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-mdx@3.1.1: + resolution: {integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -5768,6 +6184,10 @@ packages: scrypt-js@3.0.1: resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} + section-matter@1.0.0: + resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} + engines: {node: '>=4'} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -5812,6 +6232,9 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + shiki@3.22.0: + resolution: {integrity: sha512-LBnhsoYEe0Eou4e1VgJACes+O6S6QC0w71fCSp5Oya79inkwkm15gQ1UF6VtQ8j/taMDh79hAB49WUk8ALQW3g==} + shimmer@1.2.1: resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==} @@ -5908,11 +6331,18 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} deprecated: The work that was done in this beta branch won't be included in future versions + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + split-on-first@1.1.0: resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} engines: {node: '>=6'} @@ -5975,6 +6405,9 @@ packages: string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -5983,6 +6416,10 @@ packages: resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} engines: {node: '>=12'} + strip-bom-string@1.0.0: + resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} + engines: {node: '>=0.10.0'} + strip-bom@4.0.0: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} engines: {node: '>=8'} @@ -6003,6 +6440,12 @@ packages: resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} engines: {node: '>=14.16'} + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + styled-jsx@5.1.6: resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} engines: {node: '>= 12.0.0'} @@ -6144,6 +6587,12 @@ packages: resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==} engines: {node: '>=12'} + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} @@ -6233,6 +6682,30 @@ packages: uncrypto@0.1.3: resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position-from-estree@2.0.0: + resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-remove@4.0.0: + resolution: {integrity: sha512-b4gokeGId57UVRX/eVKej5gXqGlc9+trkORhFJpu9raqZkZhU0zm8Doi05+HaiBsMEIJowL+2WtQ5ItjsngPXg==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + universalify@0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} @@ -6399,6 +6872,15 @@ packages: react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + vfile-matter@5.0.1: + resolution: {integrity: sha512-o6roP82AiX0XfkyTHyRCMXgHfltUNlXSEqCIS80f+mbAyiQBE2fxtDVMtseyytGx75sihiJFo/zR6r/4LTs2Cw==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + viem@2.45.0: resolution: {integrity: sha512-iVA9qrAgRdtpWa80lCZ6Jri6XzmLOwwA1wagX2HnKejKeliFLpON0KOdyfqvcy+gUpBVP59LBxP2aKiL3aj8fg==} peerDependencies: @@ -6601,6 +7083,11 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} + yaml@2.8.2: + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + engines: {node: '>= 14.6'} + hasBin: true + yargs-parser@18.1.3: resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} engines: {node: '>=6'} @@ -6672,6 +7159,9 @@ packages: use-sync-external-store: optional: true + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + snapshots: '@adobe/css-tools@4.4.4': {} @@ -7637,9 +8127,9 @@ snapshots: react-dom: 19.2.4(react@19.2.4) use-sync-external-store: 1.6.0(react@19.2.4) - '@headlessui/tailwindcss@0.2.2(tailwindcss@3.4.19(tsx@4.21.0))': + '@headlessui/tailwindcss@0.2.2(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2))': dependencies: - tailwindcss: 3.4.19(tsx@4.21.0) + tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.8.2) '@img/colour@1.0.0': optional: true @@ -7985,6 +8475,42 @@ snapshots: dependencies: '@lit-labs/ssr-dom-shim': 1.5.1 + '@mdx-js/mdx@3.1.1': + dependencies: + '@types/estree': 1.0.8 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdx': 2.0.13 + acorn: 8.15.0 + collapse-white-space: 2.1.0 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-util-scope: 1.0.0 + estree-walker: 3.0.3 + hast-util-to-jsx-runtime: 2.3.6 + markdown-extensions: 2.0.0 + recma-build-jsx: 1.0.0 + recma-jsx: 1.0.1(acorn@8.15.0) + recma-stringify: 1.0.0 + rehype-recma: 1.0.0 + remark-mdx: 3.1.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + source-map: 0.7.6 + unified: 11.0.5 + unist-util-position-from-estree: 2.0.0 + unist-util-stringify-position: 4.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@mdx-js/react@3.1.1(@types/react@18.3.27)(react@19.2.4)': + dependencies: + '@types/mdx': 2.0.13 + '@types/react': 18.3.27 + react: 19.2.4 + '@metamask/eth-json-rpc-provider@1.0.1': dependencies: '@metamask/json-rpc-engine': 7.3.3 @@ -9932,6 +10458,39 @@ snapshots: optionalDependencies: typescript: 5.9.3 + '@shikijs/core@3.22.0': + dependencies: + '@shikijs/types': 3.22.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@3.22.0': + dependencies: + '@shikijs/types': 3.22.0 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.4 + + '@shikijs/engine-oniguruma@3.22.0': + dependencies: + '@shikijs/types': 3.22.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@3.22.0': + dependencies: + '@shikijs/types': 3.22.0 + + '@shikijs/themes@3.22.0': + dependencies: + '@shikijs/types': 3.22.0 + + '@shikijs/types@3.22.0': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + '@simplewebauthn/browser@8.3.7': dependencies: '@simplewebauthn/typescript-types': 8.3.4 @@ -10137,12 +10696,20 @@ snapshots: '@types/estree': 1.0.8 '@types/json-schema': 7.0.15 + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.8 + '@types/estree@1.0.8': {} '@types/graceful-fs@4.1.9': dependencies: '@types/node': 20.4.2 + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + '@types/istanbul-lib-coverage@2.0.6': {} '@types/istanbul-lib-report@3.0.3': @@ -10170,6 +10737,12 @@ snapshots: '@types/lodash@4.17.23': {} + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdx@2.0.13': {} + '@types/ms@2.1.0': {} '@types/mysql@2.15.26': @@ -10221,6 +10794,10 @@ snapshots: '@types/trusted-types@2.0.7': {} + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + '@types/use-sync-external-store@0.0.6': {} '@types/validator@13.15.10': {} @@ -10236,6 +10813,8 @@ snapshots: '@types/node': 20.4.2 optional: true + '@ungap/structured-clone@1.3.0': {} + '@vercel/analytics@1.6.1(next@16.0.10(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)': optionalDependencies: next: 16.0.10(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -11112,15 +11691,15 @@ snapshots: '@xtuc/long@4.2.2': {} - '@zerodev/passkey-validator@5.6.0(@zerodev/sdk@5.5.0(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)))(@zerodev/webauthn-key@5.5.0(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)))(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6))': + '@zerodev/passkey-validator@5.6.0(@zerodev/sdk@5.5.7(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)))(@zerodev/webauthn-key@5.5.0(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)))(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6))': dependencies: '@noble/curves': 1.9.7 '@simplewebauthn/browser': 8.3.7 - '@zerodev/sdk': 5.5.0(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)) + '@zerodev/sdk': 5.5.7(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)) '@zerodev/webauthn-key': 5.5.0(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)) viem: 2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6) - '@zerodev/sdk@5.5.0(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6))': + '@zerodev/sdk@5.5.7(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6))': dependencies: semver: 7.7.3 viem: 2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6) @@ -11159,6 +11738,10 @@ snapshots: dependencies: acorn: 8.15.0 + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + acorn-walk@8.3.4: dependencies: acorn: 8.15.0 @@ -11238,6 +11821,8 @@ snapshots: dependencies: tslib: 2.8.1 + astring@1.9.0: {} + async-mutex@0.2.6: dependencies: tslib: 2.8.1 @@ -11330,6 +11915,8 @@ snapshots: babel-plugin-jest-hoist: 29.6.3 babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.6) + bail@2.0.2: {} + balanced-match@1.0.2: {} bare-events@2.8.2: {} @@ -11474,6 +12061,8 @@ snapshots: canvas-confetti@1.9.4: {} + ccount@2.0.1: {} + chalk@3.0.0: dependencies: ansi-styles: 4.3.0 @@ -11486,6 +12075,14 @@ snapshots: char-regex@1.0.2: {} + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -11540,6 +12137,8 @@ snapshots: co@4.6.0: {} + collapse-white-space@2.1.0: {} + collect-v8-coverage@1.0.3: {} color-convert@2.0.1: @@ -11552,6 +12151,8 @@ snapshots: dependencies: delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} + commander@12.0.0: {} commander@2.20.3: {} @@ -11744,6 +12345,10 @@ snapshots: decimal.js@10.6.0: {} + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + decode-uri-component@0.2.2: {} dedent@1.7.1(babel-plugin-macros@3.1.0): @@ -11785,6 +12390,10 @@ snapshots: detect-node-es@1.1.0: {} + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + devtools-protocol@0.0.1495869: {} diacritics@1.3.0: {} @@ -11934,6 +12543,20 @@ snapshots: es-toolkit@1.33.0: {} + esast-util-from-estree@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + unist-util-position-from-estree: 2.0.0 + + esast-util-from-js@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + acorn: 8.15.0 + esast-util-from-estree: 2.0.0 + vfile-message: 4.0.3 + esbuild@0.27.2: optionalDependencies: '@esbuild/aix-ppc64': 0.27.2 @@ -11969,6 +12592,8 @@ snapshots: escape-string-regexp@4.0.0: {} + escape-string-regexp@5.0.0: {} + escodegen@2.1.0: dependencies: esprima: 4.0.1 @@ -12007,8 +12632,41 @@ snapshots: estraverse@5.3.0: {} + estree-util-attach-comments@3.0.0: + dependencies: + '@types/estree': 1.0.8 + + estree-util-build-jsx@3.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-walker: 3.0.3 + + estree-util-is-identifier-name@3.0.0: {} + + estree-util-scope@1.0.0: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + + estree-util-to-js@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + astring: 1.9.0 + source-map: 0.7.6 + + estree-util-visit@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/unist': 3.0.3 + estree-walker@2.0.2: {} + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + esutils@2.0.3: {} eth-block-tracker@7.1.0: @@ -12117,6 +12775,12 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 + extend-shallow@2.0.1: + dependencies: + is-extendable: 0.1.1 + + extend@3.0.2: {} + extension-port-stream@3.0.0: dependencies: readable-stream: 3.6.2 @@ -12367,6 +13031,13 @@ snapshots: graphql@16.12.0: {} + gray-matter@4.0.3: + dependencies: + js-yaml: 3.14.2 + kind-of: 6.0.3 + section-matter: 1.0.0 + strip-bom-string: 1.0.0 + gzip-size@6.0.0: dependencies: duplexer: 0.1.2 @@ -12413,6 +13084,65 @@ snapshots: dependencies: function-bind: 1.1.2 + hast-util-to-estree@3.1.3: + dependencies: + '@types/estree': 1.0.8 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-attach-comments: 3.0.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + zwitch: 2.0.4 + transitivePeerDependencies: + - supports-color + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-to-jsx-runtime@2.3.6: + dependencies: + '@types/estree': 1.0.8 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + hmac-drbg@1.0.1: dependencies: hash.js: 1.1.7 @@ -12429,6 +13159,8 @@ snapshots: html-escaper@2.0.2: {} + html-void-elements@3.0.0: {} + http-proxy-agent@5.0.0: dependencies: '@tootallnate/once': 2.0.0 @@ -12514,12 +13246,21 @@ snapshots: inherits@2.0.4: {} + inline-style-parser@0.2.7: {} + internmap@2.0.3: {} ip-address@10.1.0: {} iron-webcrypto@1.2.1: {} + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + is-arguments@1.2.0: dependencies: call-bound: 1.0.4 @@ -12537,6 +13278,10 @@ snapshots: dependencies: hasown: 2.0.2 + is-decimal@2.0.1: {} + + is-extendable@0.1.1: {} + is-extglob@2.1.1: {} is-fullwidth-code-point@3.0.0: {} @@ -12555,8 +13300,12 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-hexadecimal@2.0.1: {} + is-number@7.0.0: {} + is-plain-obj@4.1.0: {} + is-plain-object@5.0.0: {} is-potential-custom-element-name@1.0.1: {} @@ -13049,6 +13798,8 @@ snapshots: keyvaluestorage-interface@1.0.0: {} + kind-of@6.0.3: {} + kleur@3.0.3: {} knip@5.82.1(@types/node@20.4.2)(typescript@5.9.3): @@ -13120,6 +13871,8 @@ snapshots: lodash@4.17.23: {} + longest-streak@3.1.0: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -13154,14 +13907,447 @@ snapshots: dependencies: tmpl: 1.0.5 + markdown-extensions@2.0.0: {} + + markdown-table@3.0.4: {} + + marked@17.0.2: {} + math-intrinsics@1.1.0: {} + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.2 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx@3.0.0: + dependencies: + mdast-util-from-markdown: 2.0.2 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + merge-stream@2.0.0: {} merge2@1.4.1: {} micro-ftch@0.3.1: {} + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-expression@3.0.1: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-jsx@3.0.2: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-extension-mdx-md@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-mdxjs-esm@3.0.0: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-extension-mdxjs@3.0.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + micromark-extension-mdx-expression: 3.0.1 + micromark-extension-mdx-jsx: 3.0.2 + micromark-extension-mdx-md: 2.0.0 + micromark-extension-mdxjs-esm: 3.0.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-mdx-expression@2.0.3: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-events-to-acorn@2.0.3: + dependencies: + '@types/estree': 1.0.8 + '@types/unist': 3.0.3 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -13239,6 +14425,20 @@ snapshots: netmask@2.0.2: {} + next-mdx-remote@6.0.0(@types/react@18.3.27)(react@19.2.4): + dependencies: + '@babel/code-frame': 7.28.6 + '@mdx-js/mdx': 3.1.1 + '@mdx-js/react': 3.1.1(@types/react@18.3.27)(react@19.2.4) + react: 19.2.4 + unist-util-remove: 4.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + vfile-matter: 5.0.1 + transitivePeerDependencies: + - '@types/react' + - supports-color + next@16.0.10(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: '@next/env': 16.0.10 @@ -13323,6 +14523,14 @@ snapshots: dependencies: mimic-fn: 2.1.0 + oniguruma-parser@0.12.1: {} + + oniguruma-to-es@4.3.4: + dependencies: + oniguruma-parser: 0.12.1 + regex: 6.1.0 + regex-recursion: 6.0.2 + opener@1.5.2: {} ox@0.11.3(typescript@5.9.3)(zod@3.22.4): @@ -13436,6 +14644,16 @@ snapshots: dependencies: callsites: 3.1.0 + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.3.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + parse-json@5.2.0: dependencies: '@babel/code-frame': 7.28.6 @@ -13556,13 +14774,14 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.5.6 - postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0): + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 1.21.7 postcss: 8.5.6 tsx: 4.21.0 + yaml: 2.8.2 postcss-nested@6.2.0(postcss@8.5.6): dependencies: @@ -13639,6 +14858,8 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + property-information@7.1.0: {} + proxy-agent@6.5.0: dependencies: agent-base: 7.1.4 @@ -13856,6 +15077,35 @@ snapshots: real-require@0.1.0: {} + recma-build-jsx@1.0.0: + dependencies: + '@types/estree': 1.0.8 + estree-util-build-jsx: 3.0.1 + vfile: 6.0.3 + + recma-jsx@1.0.1(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + estree-util-to-js: 2.0.0 + recma-parse: 1.0.0 + recma-stringify: 1.0.0 + unified: 11.0.5 + + recma-parse@1.0.0: + dependencies: + '@types/estree': 1.0.8 + esast-util-from-js: 2.0.1 + unified: 11.0.5 + vfile: 6.0.3 + + recma-stringify@1.0.0: + dependencies: + '@types/estree': 1.0.8 + estree-util-to-js: 2.0.0 + unified: 11.0.5 + vfile: 6.0.3 + redent@3.0.0: dependencies: indent-string: 4.0.0 @@ -13867,6 +15117,65 @@ snapshots: redux@5.0.1: {} + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 + + rehype-recma@1.0.0: + dependencies: + '@types/estree': 1.0.8 + '@types/hast': 3.0.4 + hast-util-to-estree: 3.1.3 + transitivePeerDependencies: + - supports-color + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-mdx@3.1.1: + dependencies: + mdast-util-mdx: 3.0.0 + micromark-extension-mdxjs: 3.0.0 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -13948,6 +15257,11 @@ snapshots: scrypt-js@3.0.1: {} + section-matter@1.0.0: + dependencies: + extend-shallow: 2.0.1 + kind-of: 6.0.3 + semver@6.3.1: {} semver@7.7.3: {} @@ -14018,6 +15332,17 @@ snapshots: shebang-regex@3.0.0: {} + shiki@3.22.0: + dependencies: + '@shikijs/core': 3.22.0 + '@shikijs/engine-javascript': 3.22.0 + '@shikijs/engine-oniguruma': 3.22.0 + '@shikijs/langs': 3.22.0 + '@shikijs/themes': 3.22.0 + '@shikijs/types': 3.22.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + shimmer@1.2.1: {} side-channel-list@1.0.0: @@ -14137,10 +15462,14 @@ snapshots: source-map@0.6.1: {} + source-map@0.7.6: {} + source-map@0.8.0-beta.0: dependencies: whatwg-url: 7.1.0 + space-separated-tokens@2.0.2: {} + split-on-first@1.1.0: {} split2@4.2.0: {} @@ -14212,6 +15541,11 @@ snapshots: dependencies: safe-buffer: 5.2.1 + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -14220,6 +15554,8 @@ snapshots: dependencies: ansi-regex: 6.2.2 + strip-bom-string@1.0.0: {} + strip-bom@4.0.0: {} strip-final-newline@2.0.0: {} @@ -14232,6 +15568,14 @@ snapshots: strip-json-comments@5.0.3: {} + style-to-js@1.1.21: + dependencies: + style-to-object: 1.0.14 + + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + styled-jsx@5.1.6(@babel/core@7.28.6)(babel-plugin-macros@3.1.0)(react@19.2.4): dependencies: client-only: 0.0.1 @@ -14270,11 +15614,11 @@ snapshots: tailwind-merge@1.14.0: {} - tailwind-scrollbar@3.1.0(tailwindcss@3.4.19(tsx@4.21.0)): + tailwind-scrollbar@3.1.0(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2)): dependencies: - tailwindcss: 3.4.19(tsx@4.21.0) + tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.8.2) - tailwindcss@3.4.19(tsx@4.21.0): + tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -14293,7 +15637,7 @@ snapshots: postcss: 8.5.6 postcss-import: 15.1.0(postcss@8.5.6) postcss-js: 4.1.0(postcss@8.5.6) - postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2) postcss-nested: 6.2.0(postcss@8.5.6) postcss-selector-parser: 6.1.2 resolve: 1.22.11 @@ -14403,6 +15747,10 @@ snapshots: dependencies: punycode: 2.3.1 + trim-lines@3.0.1: {} + + trough@2.2.0: {} + ts-interface-checker@0.1.13: {} ts-jest@29.4.6(@babel/core@7.28.6)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.6))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.4.2)(babel-plugin-macros@3.1.0))(typescript@5.9.3): @@ -14471,6 +15819,49 @@ snapshots: uncrypto@0.1.3: {} + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position-from-estree@2.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-remove@4.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + universalify@0.2.0: {} unplugin@1.0.1: @@ -14586,6 +15977,21 @@ snapshots: - '@types/react' - '@types/react-dom' + vfile-matter@5.0.1: + dependencies: + vfile: 6.0.3 + yaml: 2.8.2 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.22.4): dependencies: '@noble/curves': 1.9.1 @@ -14840,6 +16246,8 @@ snapshots: yaml@1.10.2: {} + yaml@2.8.2: {} + yargs-parser@18.1.3: dependencies: camelcase: 5.3.1 @@ -14899,3 +16307,5 @@ snapshots: immer: 11.1.3 react: 19.2.4 use-sync-external-store: 1.4.0(react@19.2.4) + + zwitch@2.0.4: {} diff --git a/public/.well-known/did.json b/public/.well-known/did.json index 39b8d4811..a8d50e049 100644 --- a/public/.well-known/did.json +++ b/public/.well-known/did.json @@ -1,20 +1,20 @@ { "@context": ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/jws-2020/v1"], - "id": "did:web:peanut.to", + "id": "did:web:peanut.me", "verificationMethod": [ { - "id": "did:web:peanut.to#wc-notify-subscribe-key", + "id": "did:web:peanut.me#wc-notify-subscribe-key", "type": "JsonWebKey2020", - "controller": "did:web:peanut.to", + "controller": "did:web:peanut.me", "publicKeyJwk": { "kty": "OKP", "crv": "X25519", "x": "ZfGDEKhduDxgC0xZ4rOghj8rXpMZAGbxZVyW9C72yis" } }, { - "id": "did:web:peanut.to#wc-notify-authentication-key", + "id": "did:web:peanut.me#wc-notify-authentication-key", "type": "JsonWebKey2020", - "controller": "did:web:peanut.to", + "controller": "did:web:peanut.me", "publicKeyJwk": { "kty": "OKP", "crv": "Ed25519", "x": "DSrCX0IC6NodVVlDylY09dwXDWwR5tVLOqxw7aPR-HU" } } ], - "keyAgreement": ["did:web:peanut.to#wc-notify-subscribe-key"], - "authentication": ["did:web:peanut.to#wc-notify-authentication-key"] + "keyAgreement": ["did:web:peanut.me#wc-notify-subscribe-key"], + "authentication": ["did:web:peanut.me#wc-notify-authentication-key"] } diff --git a/public/llms-full.txt b/public/llms-full.txt new file mode 100644 index 000000000..906b896de --- /dev/null +++ b/public/llms-full.txt @@ -0,0 +1,77 @@ +# Peanut — Full Product Description + +> Instant global peer-to-peer payments in digital dollars. + +## Overview + +Peanut is a peer-to-peer payments app that lets users send and receive money globally using digital dollars (USDC stablecoins). It provides a consumer-grade UX on top of blockchain infrastructure — users never need to understand crypto, manage wallets, or handle gas fees. + +## Key Features + +### Instant P2P Transfers +Send digital dollars to any Peanut user instantly. No waiting for bank processing, no wire fees. + +### Payment Links +Generate a shareable link containing funds. The recipient clicks the link to claim the money — no account needed. Links work across messaging apps, email, and social media. + +### Bank Cash-Out +Connect a local bank account and convert digital dollars to local currency. Supported rails: +- **Argentina**: Bank transfer, MercadoPago +- **Brazil**: PIX, bank transfer +- **Mexico**: SPEI, bank transfer +- **Colombia**: Bank transfer +- **Peru**: Bank transfer +- **Bolivia**: Bank transfer (via Meru) + +### Crypto Deposit +Fund your account by depositing crypto from any exchange (Coinbase, Binance, Kraken, Bybit, OKX, etc.) or external wallet. + +### Card Payments +Physical and virtual debit cards for spending digital dollars at any merchant that accepts card payments. + +### QR Payments +Generate and scan QR codes for in-person payments. + +## Security Model + +- **Self-custodied smart accounts**: User funds sit in ERC-4337 smart accounts, not on Peanut servers +- **Biometric passkeys**: Account access is secured by the device's Secure Enclave (face/fingerprint). The private key never leaves the device +- **No server-side keys**: Peanut cannot access, freeze, or move user funds — even under regulatory pressure +- **Independent recovery**: If Peanut goes offline, users can recover access via any ERC-4337-compatible wallet + +## KYC / Compliance + +- Core features (send, receive, payment links) work without KYC +- Bank connections trigger a one-time identity check via Persona (SOC2 Type 2, GDPR, ISO 27001) +- Peanut only receives a pass/fail result — no documents stored on Peanut servers + +## Fee Structure + +- Peer-to-peer transfers: minimal fees +- Bank cash-out: small conversion spread +- No monthly subscription or account fees +- Merchant payments planned with fees lower than Visa/Mastercard + +## Target Markets + +Primary focus on Latin America: +- Argentina, Brazil, Mexico (largest markets) +- Colombia, Peru, Bolivia, Chile, Ecuador + +Use cases: remittances, freelancer payments, cross-border transfers, savings in stable currency, merchant payments. + +## Technical Stack + +- Next.js web application (progressive web app) +- ERC-4337 smart accounts on Base (Ethereum L2) +- Biometric passkeys via WebAuthn / Secure Enclave +- Licensed banking partners for fiat on/off ramps + +## Company + +- Founded by Konrad Kononenko and Hugo Montenegro +- Based in Europe, serving Latin America +- Website: https://peanut.me +- Twitter: https://twitter.com/PeanutProtocol +- GitHub: https://github.com/peanutprotocol +- LinkedIn: https://www.linkedin.com/company/peanut-trade/ diff --git a/public/llms.txt b/public/llms.txt new file mode 100644 index 000000000..eb344e2cc --- /dev/null +++ b/public/llms.txt @@ -0,0 +1,27 @@ +# Peanut + +> Instant global peer-to-peer payments in digital dollars. + +Peanut is the easiest way to send digital dollars to anyone, anywhere. No banks, no borders — just fast, cheap money transfers. + +## What Peanut Does + +- **Send & receive money instantly** — peer-to-peer transfers powered by digital dollars (USDC) +- **Cash out to local banks** — connect bank accounts in Argentina, Brazil, Mexico, and more +- **No KYC required for core features** — send and receive without identity verification +- **Self-custodied accounts** — your funds sit in your own smart account, secured by biometric passkeys +- **Payment links** — share a link to send money to anyone, even without an account + +## Supported Corridors + +- Argentina (bank transfer, MercadoPago) +- Brazil (PIX, bank transfer) +- Mexico (SPEI, bank transfer) +- Colombia, Peru, Bolivia, and more + +## Links + +- Website: https://peanut.me +- Careers: https://peanut.me/careers +- Support: https://peanut.me/support +- Full description: https://peanut.me/llms-full.txt diff --git a/redirects.json b/redirects.json index fc8a5cd9e..e771b321d 100644 --- a/redirects.json +++ b/redirects.json @@ -1,33 +1,42 @@ [ + { + "source": "/support", + "destination": "/en/help", + "permanent": true + }, + { + "source": "/help", + "destination": "/en/help", + "permanent": false + }, { "source": "/docs", - "destination": "https://docs.peanut.me", - "permanent": false, - "basePath": false + "destination": "/en/help", + "permanent": true }, { - "source": "/packet", - "destination": "/raffle/claim", + "source": "/docs/:path*", + "destination": "/en/help", "permanent": true }, { - "source": "/create-packet", - "destination": "/raffle/create", + "source": "/packet", + "destination": "https://github.com/peanutprotocol/peanut-ui/tree/archive/legacy-peanut-to", "permanent": true }, { - "source": "/batch/create", - "destination": "https://legacy.peanut.to/batch/create", + "source": "/create-packet", + "destination": "https://github.com/peanutprotocol/peanut-ui/tree/archive/legacy-peanut-to", "permanent": true }, { - "source": "/raffle/create", - "destination": "https://legacy.peanut.to/raffle/create", + "source": "/batch/:path*", + "destination": "https://github.com/peanutprotocol/peanut-ui/tree/archive/legacy-peanut-to", "permanent": true }, { - "source": "/raffle/claim", - "destination": "https://legacy.peanut.to/raffle/claim", + "source": "/raffle/:path*", + "destination": "https://github.com/peanutprotocol/peanut-ui/tree/archive/legacy-peanut-to", "permanent": true }, { diff --git a/scripts/README-qr-generator.md b/scripts/README-qr-generator.md index d746b5181..453ac4fae 100644 --- a/scripts/README-qr-generator.md +++ b/scripts/README-qr-generator.md @@ -17,7 +17,7 @@ This script generates an HTML page containing multiple Peanut-branded QR codes t You can run the script directly with individual links: ```bash -pnpm run script scripts/generate-qr-sheet.ts output.html "https://peanut.to/claim/link1" "https://peanut.to/claim/link2" +pnpm run script scripts/generate-qr-sheet.ts output.html "https://peanut.me/claim/link1" "https://peanut.me/claim/link2" ``` ### Using a File with Links @@ -25,10 +25,10 @@ pnpm run script scripts/generate-qr-sheet.ts output.html "https://peanut.to/clai For multiple links, create a text file with one link per line: ``` -https://peanut.to/claim/link1 -https://peanut.to/claim/link2 -https://peanut.to/claim/link3 -https://peanut.to/claim/link4 +https://peanut.me/claim/link1 +https://peanut.me/claim/link2 +https://peanut.me/claim/link3 +https://peanut.me/claim/link4 ``` Then run: diff --git a/scripts/generate-valid-links.ts b/scripts/generate-valid-links.ts new file mode 100644 index 000000000..82911450c --- /dev/null +++ b/scripts/generate-valid-links.ts @@ -0,0 +1,185 @@ +#!/usr/bin/env tsx +/** + * Generates input/context/valid-links.md for the content submodule. + * This file is loaded by LLMs during content generation so they know + * exactly which internal URLs exist. + * + * Run: pnpm script scripts/generate-valid-links.ts + * Run after adding new pages/countries/corridors/etc. + */ + +import fs from 'fs' +import path from 'path' + +const ROOT = path.join(process.cwd(), 'src/content') +const CONTENT_DIR = path.join(ROOT, 'content') +const OUTPUT = path.join(ROOT, 'input/context/valid-links.md') + +const LOCALES = ['en', 'es-419', 'es-ar', 'es-es', 'pt-br'] + +function listDirs(dir: string): string[] { + if (!fs.existsSync(dir)) return [] + return fs + .readdirSync(dir, { withFileTypes: true }) + .filter((d) => d.isDirectory()) + .map((d) => d.name) + .sort() +} + +function main() { + const countrySlugs = listDirs(path.join(CONTENT_DIR, 'countries')) + const competitorSlugs = listDirs(path.join(CONTENT_DIR, 'compare')) + const payWithSlugs = listDirs(path.join(CONTENT_DIR, 'pay-with')) + const depositSlugs = listDirs(path.join(CONTENT_DIR, 'deposit')) + const helpSlugs = listDirs(path.join(CONTENT_DIR, 'help')) + const useCaseSlugs = listDirs(path.join(CONTENT_DIR, 'use-cases')) + const withdrawSlugs = listDirs(path.join(CONTENT_DIR, 'withdraw')) + + // Build corridors from file structure + const corridors: Array<{ to: string; from: string }> = [] + for (const dest of listDirs(path.join(CONTENT_DIR, 'send-to'))) { + const fromDir = path.join(CONTENT_DIR, 'send-to', dest, 'from') + for (const origin of listDirs(fromDir)) { + corridors.push({ to: dest, from: origin }) + } + } + const receiveSources = [...new Set(corridors.map((c) => c.from))].sort() + + const lines: string[] = [] + lines.push('# Valid Internal Links') + lines.push('') + lines.push('> Auto-generated by `scripts/generate-valid-links.ts`. Do not edit manually.') + lines.push('> Regenerate after adding new pages: `pnpm script scripts/generate-valid-links.ts`') + lines.push('') + lines.push( + 'When writing content, **only link to URLs listed below**. Replace `{locale}` with the target locale (`en`, `es-419`, `es-ar`, `es-es`, `pt-br`).' + ) + lines.push('') + + // Static pages + lines.push('## Static Pages') + lines.push('') + for (const p of ['/', '/careers', '/exchange', '/privacy', '/terms', '/lp/card']) { + lines.push(`- \`${p}\``) + } + lines.push('') + + // Pricing + lines.push('## Pricing') + lines.push('') + lines.push('- `/{locale}/pricing`') + lines.push('') + + // Help + lines.push('## Help Pages') + lines.push('') + lines.push('- `/{locale}/help`') + for (const slug of helpSlugs) { + lines.push(`- \`/{locale}/help/${slug}\``) + } + lines.push('') + + // Country hubs + lines.push('## Country Hub Pages') + lines.push('') + lines.push('Pattern: `/{locale}/{country}`') + lines.push('') + for (const slug of countrySlugs) { + lines.push(`- \`/{locale}/${slug}\``) + } + lines.push('') + + // Send money to + lines.push('## Send Money To Pages') + lines.push('') + lines.push('Pattern: `/{locale}/send-money-to/{country}`') + lines.push('') + for (const slug of countrySlugs) { + lines.push(`- \`/{locale}/send-money-to/${slug}\``) + } + lines.push('') + + // Corridors + lines.push('## Corridor Pages (Send Money From)') + lines.push('') + lines.push('Pattern: `/{locale}/send-money-from/{origin}/to/{destination}`') + lines.push('') + for (const c of corridors) { + lines.push(`- \`/{locale}/send-money-from/${c.from}/to/${c.to}\``) + } + lines.push('') + + // Receive money + lines.push('## Receive Money Pages') + lines.push('') + lines.push('Pattern: `/{locale}/receive-money-from/{source}`') + lines.push('') + for (const source of receiveSources) { + lines.push(`- \`/{locale}/receive-money-from/${source}\``) + } + lines.push('') + + // Compare + lines.push('## Comparison Pages') + lines.push('') + lines.push('Pattern: `/{locale}/compare/peanut-vs-{competitor}`') + lines.push('') + for (const slug of competitorSlugs) { + lines.push(`- \`/{locale}/compare/peanut-vs-${slug}\``) + } + lines.push('') + + // Pay-with + lines.push('## Pay With Pages') + lines.push('') + lines.push('Pattern: `/{locale}/pay-with/{method}`') + lines.push('') + for (const slug of payWithSlugs) { + lines.push(`- \`/{locale}/pay-with/${slug}\``) + } + lines.push('') + + // Deposit + lines.push('## Deposit Pages') + lines.push('') + lines.push('Pattern: `/{locale}/deposit/from-{source}`') + lines.push('') + for (const slug of depositSlugs) { + lines.push(`- \`/{locale}/deposit/from-${slug}\``) + } + lines.push('') + + // Withdraw + lines.push('## Withdraw Pages') + lines.push('') + lines.push('Pattern: `/{locale}/withdraw/to-{destination}`') + lines.push('') + for (const slug of withdrawSlugs) { + lines.push(`- \`/{locale}/withdraw/to-${slug}\``) + } + lines.push('') + + // Use cases + lines.push('## Use Case Pages') + lines.push('') + lines.push('Pattern: `/{locale}/use-cases/{slug}`') + lines.push('') + for (const slug of useCaseSlugs) { + lines.push(`- \`/{locale}/use-cases/${slug}\``) + } + lines.push('') + + fs.mkdirSync(path.dirname(OUTPUT), { recursive: true }) + fs.writeFileSync(OUTPUT, lines.join('\n')) + console.log(`Generated ${OUTPUT} with valid links for:`) + console.log(` ${countrySlugs.length} countries`) + console.log(` ${corridors.length} corridors`) + console.log(` ${competitorSlugs.length} competitors`) + console.log(` ${payWithSlugs.length} payment methods`) + console.log(` ${depositSlugs.length} deposit sources`) + console.log(` ${withdrawSlugs.length} withdraw destinations`) + console.log(` ${helpSlugs.length} help articles`) + console.log(` ${useCaseSlugs.length} use cases`) +} + +main() diff --git a/scripts/ping-sitemap.sh b/scripts/ping-sitemap.sh new file mode 100755 index 000000000..35c68c849 --- /dev/null +++ b/scripts/ping-sitemap.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# Notify search engines of sitemap update after deploy. +# Usage: Run as a post-deploy step or manually after content changes. + +SITEMAP_URL="https://peanut.me/sitemap.xml" + +echo "Pinging Google..." +curl -s -o /dev/null -w " HTTP %{http_code}\n" "https://www.google.com/ping?sitemap=${SITEMAP_URL}" + +echo "Pinging Bing..." +curl -s -o /dev/null -w " HTTP %{http_code}\n" "https://www.bing.com/ping?sitemap=${SITEMAP_URL}" + +echo "Done." diff --git a/scripts/validate-content.ts b/scripts/validate-content.ts new file mode 100644 index 000000000..716ebc104 --- /dev/null +++ b/scripts/validate-content.ts @@ -0,0 +1,272 @@ +#!/usr/bin/env tsx +/** + * Content validation for peanut-ui. + * Run: npx tsx scripts/validate-content.ts + * + * Validates that content consumed by SEO loaders (src/data/seo/*.ts) has: + * 1. Valid YAML frontmatter with required fields per content type + * 2. Slugs matching expected URL patterns + * 3. Published flag set correctly + * 4. en.md files present for all published content + * 5. Entity data files present for all content pages + */ + +import fs from 'fs' +import path from 'path' +import matter from 'gray-matter' + +const ROOT = path.join(process.cwd(), 'src/content') +const errors: string[] = [] +const warnings: string[] = [] + +function error(msg: string) { + errors.push(`ERROR: ${msg}`) +} + +function warn(msg: string) { + warnings.push(`WARN: ${msg}`) +} + +function rel(filePath: string): string { + return path.relative(ROOT, filePath) +} + +function readFrontmatter(filePath: string): Record | null { + try { + const raw = fs.readFileSync(filePath, 'utf8') + const { data } = matter(raw) + return data + } catch (e) { + error(`Invalid frontmatter: ${rel(filePath)} — ${(e as Error).message}`) + return null + } +} + +function listDirs(dir: string): string[] { + try { + return fs + .readdirSync(dir, { withFileTypes: true }) + .filter((d) => d.isDirectory()) + .map((d) => d.name) + } catch { + return [] + } +} + +function listMdFiles(dir: string): string[] { + try { + return fs.readdirSync(dir).filter((f) => f.endsWith('.md') && f !== 'README.md') + } catch { + return [] + } +} + +// --- Content type validators --- + +interface ContentTypeConfig { + /** Directory under content/ */ + contentDir: string + /** Directory under input/data/ for entity data (null if no entity data expected) */ + entityDir: string | null + /** Required frontmatter fields */ + requiredFields: string[] + /** Slug pattern regex (validates the directory name) */ + slugPattern?: RegExp + /** Optional: additional entity data required fields */ + entityRequiredFields?: string[] +} + +const CONTENT_TYPES: ContentTypeConfig[] = [ + { + contentDir: 'countries', + entityDir: 'countries', + requiredFields: ['title', 'description', 'slug', 'lang', 'published'], + slugPattern: /^[a-z]+(-[a-z]+)*$/, + entityRequiredFields: ['name', 'currency'], + }, + { + contentDir: 'compare', + entityDir: 'competitors', + requiredFields: ['title', 'description', 'slug', 'lang', 'published', 'competitor'], + slugPattern: /^[a-z0-9]+(-[a-z0-9]+)*$/, + entityRequiredFields: ['name', 'type'], + }, + { + contentDir: 'deposit', + entityDir: null, // deposit content doesn't map 1:1 to exchange entities + requiredFields: ['title', 'description', 'slug', 'lang', 'published'], + slugPattern: /^[a-z0-9]+(-[a-z0-9]+)*$/, + }, + { + contentDir: 'pay-with', + entityDir: 'spending-methods', + requiredFields: ['title', 'description', 'slug', 'lang', 'published'], + slugPattern: /^[a-z]+(-[a-z]+)*$/, + entityRequiredFields: ['name', 'type'], + }, +] + +interface TypeCounts { + total: number + published: number + draft: number + missingEn: number +} + +function validateContentType(config: ContentTypeConfig): TypeCounts { + const contentPath = path.join(ROOT, 'content', config.contentDir) + const slugs = listDirs(contentPath) + const counts: TypeCounts = { total: slugs.length, published: 0, draft: 0, missingEn: 0 } + + for (const slug of slugs) { + const slugDir = path.join(contentPath, slug) + + // Validate slug format + if (config.slugPattern && !config.slugPattern.test(slug)) { + error(`${config.contentDir}/${slug}: slug doesn't match pattern ${config.slugPattern}`) + } + + // Check en.md exists + const enPath = path.join(slugDir, 'en.md') + if (!fs.existsSync(enPath)) { + error(`${config.contentDir}/${slug}: missing en.md`) + counts.missingEn++ + continue + } + + // Validate frontmatter + const fm = readFrontmatter(enPath) + if (!fm) continue + + // Check required fields + for (const field of config.requiredFields) { + if (fm[field] === undefined || fm[field] === null || fm[field] === '') { + error(`${config.contentDir}/${slug}/en.md: missing required field '${field}'`) + } + } + + // Check slug consistency + if (fm.slug && fm.slug !== slug) { + warn( + `${config.contentDir}/${slug}/en.md: frontmatter slug '${fm.slug}' doesn't match directory name '${slug}'` + ) + } + + // Check published status + if (fm.published === true) { + counts.published++ + } else { + counts.draft++ + } + + // Validate locale files have matching slugs + const mdFiles = listMdFiles(slugDir) + for (const mdFile of mdFiles) { + if (mdFile === 'en.md') continue + const localeFm = readFrontmatter(path.join(slugDir, mdFile)) + if (localeFm && localeFm.slug && localeFm.slug !== slug) { + warn( + `${config.contentDir}/${slug}/${mdFile}: frontmatter slug '${localeFm.slug}' doesn't match directory '${slug}'` + ) + } + if (localeFm && localeFm.lang) { + const expectedLang = mdFile.replace('.md', '') + if (localeFm.lang !== expectedLang) { + warn( + `${config.contentDir}/${slug}/${mdFile}: frontmatter lang '${localeFm.lang}' doesn't match filename '${expectedLang}'` + ) + } + } + } + + // Cross-reference entity data + if (config.entityDir) { + const entityPath = path.join(ROOT, 'input/data', config.entityDir, `${slug}.md`) + if (!fs.existsSync(entityPath)) { + warn( + `${config.contentDir}/${slug}: no matching entity data at input/data/${config.entityDir}/${slug}.md` + ) + } else if (config.entityRequiredFields) { + const entityFm = readFrontmatter(entityPath) + if (entityFm) { + for (const field of config.entityRequiredFields) { + if (entityFm[field] === undefined || entityFm[field] === null) { + error(`input/data/${config.entityDir}/${slug}.md: missing required field '${field}'`) + } + } + } + } + } + } + + return counts +} + +// --- Validate entity data without content pages --- + +function validateEntityData() { + // Check exchanges entity data (consumed directly by exchanges.ts loader) + const exchangeDir = path.join(ROOT, 'input/data/exchanges') + const exchangeFiles = listMdFiles(exchangeDir) + + for (const file of exchangeFiles) { + const slug = file.replace('.md', '') + const fm = readFrontmatter(path.join(exchangeDir, file)) + if (!fm) continue + + if (!fm.name) error(`input/data/exchanges/${file}: missing required field 'name'`) + if (!fm.supported_networks) warn(`input/data/exchanges/${file}: missing 'supported_networks'`) + } + + console.log(` Exchange entities: ${exchangeFiles.length}`) +} + +// --- Validate convert pairs --- + +function validateConvertPairs() { + const pairsPath = path.join(ROOT, 'content/convert/pairs.yaml') + if (!fs.existsSync(pairsPath)) { + // Try alternate location + const altPath = path.join(ROOT, 'input/data/currencies/pairs.yaml') + if (!fs.existsSync(altPath)) { + warn('No convert pairs file found') + return + } + } +} + +// --- Run --- + +console.log('\nValidating peanut-ui content...\n') + +for (const config of CONTENT_TYPES) { + const counts = validateContentType(config) + const parts = [`${counts.total} entries`] + if (counts.published > 0 || counts.draft > 0) { + parts.push(`${counts.published} published, ${counts.draft} draft`) + } + if (counts.missingEn > 0) { + parts.push(`${counts.missingEn} missing en.md`) + } + console.log(` ${config.contentDir}: ${parts.join(' — ')}`) +} + +validateEntityData() +validateConvertPairs() + +console.log('') + +if (warnings.length > 0) { + console.log(`${warnings.length} warning(s):`) + for (const w of warnings) console.log(` ${w}`) + console.log('') +} + +if (errors.length > 0) { + console.log(`${errors.length} error(s):`) + for (const e of errors) console.log(` ${e}`) + console.log('') + process.exit(1) +} else { + console.log('All content valid!\n') +} diff --git a/scripts/validate-links.ts b/scripts/validate-links.ts new file mode 100644 index 000000000..f7880f371 --- /dev/null +++ b/scripts/validate-links.ts @@ -0,0 +1,275 @@ +#!/usr/bin/env tsx +/** + * Internal link validation for peanut-ui content. + * Run: pnpm validate-links + * + * Scans all .md files in src/content/content/ and validates that every + * internal link points to a route that exists in the app. + */ + +import fs from 'fs' +import path from 'path' + +const ROOT = path.join(process.cwd(), 'src/content') +const CONTENT_DIR = path.join(ROOT, 'content') + +// --- Build valid URL index --- + +const SUPPORTED_LOCALES = ['en', 'es-419', 'es-ar', 'es-es', 'pt-br'] + +function listDirs(dir: string): string[] { + if (!fs.existsSync(dir)) return [] + return fs + .readdirSync(dir, { withFileTypes: true }) + .filter((d) => d.isDirectory()) + .map((d) => d.name) +} + +function listEntitySlugs(category: string): string[] { + const dir = path.join(ROOT, 'input/data', category) + if (!fs.existsSync(dir)) return [] + return fs + .readdirSync(dir) + .filter((f) => f.endsWith('.md')) + .map((f) => f.replace('.md', '')) +} + +function buildValidPaths(): Set { + const paths = new Set() + + // Static pages (no locale prefix) + for (const p of ['/', '/careers', '/exchange', '/privacy', '/terms', '/lp/card']) { + paths.add(p) + } + + const countrySlugs = listDirs(path.join(CONTENT_DIR, 'countries')) + const competitorSlugs = listDirs(path.join(CONTENT_DIR, 'compare')) + const payWithSlugs = listDirs(path.join(CONTENT_DIR, 'pay-with')) + const depositSlugs = listDirs(path.join(CONTENT_DIR, 'deposit')) + const helpSlugs = listDirs(path.join(CONTENT_DIR, 'help')) + const useCaseSlugs = listDirs(path.join(CONTENT_DIR, 'use-cases')) + const withdrawSlugs = listDirs(path.join(CONTENT_DIR, 'withdraw')) + const exchangeSlugs = listEntitySlugs('exchanges') + + // Also check for corridor pages: send-to/{country}/from/{origin}/ + const corridors: Array<{ to: string; from: string }> = [] + for (const dest of listDirs(path.join(CONTENT_DIR, 'send-to'))) { + const fromDir = path.join(CONTENT_DIR, 'send-to', dest, 'from') + for (const origin of listDirs(fromDir)) { + corridors.push({ to: dest, from: origin }) + } + } + + // Receive-money sources (unique "from" values in corridors) + const receiveSources = [...new Set(corridors.map((c) => c.from))] + + for (const locale of SUPPORTED_LOCALES) { + // Country hub pages: /{locale}/{country} + for (const slug of countrySlugs) { + paths.add(`/${locale}/${slug}`) + } + + // Send-money-to: /{locale}/send-money-to/{country} + for (const slug of countrySlugs) { + paths.add(`/${locale}/send-money-to/${slug}`) + } + + // Corridors: /{locale}/send-money-from/{from}/to/{to} + for (const c of corridors) { + paths.add(`/${locale}/send-money-from/${c.from}/to/${c.to}`) + } + + // Receive money: /{locale}/receive-money-from/{source} + for (const source of receiveSources) { + paths.add(`/${locale}/receive-money-from/${source}`) + } + + // Compare: /{locale}/compare/peanut-vs-{slug} + for (const slug of competitorSlugs) { + paths.add(`/${locale}/compare/peanut-vs-${slug}`) + } + + // Pay-with: /{locale}/pay-with/{method} + for (const slug of payWithSlugs) { + paths.add(`/${locale}/pay-with/${slug}`) + } + + // Deposit: /{locale}/deposit/from-{exchange} + for (const slug of depositSlugs) { + paths.add(`/${locale}/deposit/from-${slug}`) + } + // Also add exchange entity slugs (may differ from content dirs) + for (const slug of exchangeSlugs) { + paths.add(`/${locale}/deposit/from-${slug}`) + } + + // Help: /{locale}/help and /{locale}/help/{slug} + paths.add(`/${locale}/help`) + for (const slug of helpSlugs) { + paths.add(`/${locale}/help/${slug}`) + } + + // Use-cases: /{locale}/use-cases/{slug} + for (const slug of useCaseSlugs) { + paths.add(`/${locale}/use-cases/${slug}`) + } + + // Withdraw: /{locale}/withdraw/{slug} + for (const slug of withdrawSlugs) { + paths.add(`/${locale}/withdraw/to-${slug}`) + // Also allow without prefix in case route doesn't use one + paths.add(`/${locale}/withdraw/${slug}`) + } + + // Pricing + paths.add(`/${locale}/pricing`) + } + + return paths +} + +// --- Extract links from markdown --- + +interface BrokenLink { + file: string + line: number + url: string + text: string +} + +const MARKDOWN_LINK_RE = /\[([^\]]*)\]\((\/?[^)]+)\)/g +const JSX_HREF_RE = /href=["'](\/[^"']+)["']/g + +function extractLinks(content: string): Array<{ line: number; url: string; text: string }> { + const links: Array<{ line: number; url: string; text: string }> = [] + const lines = content.split('\n') + + for (let i = 0; i < lines.length; i++) { + const lineContent = lines[i] + + // Skip frontmatter alternates (they're file paths, not URLs) + if (lineContent.trim().startsWith('content/')) continue + + // Markdown links: [text](/path) + let match + MARKDOWN_LINK_RE.lastIndex = 0 + while ((match = MARKDOWN_LINK_RE.exec(lineContent)) !== null) { + const url = match[2] + if (isInternalLink(url)) { + links.push({ line: i + 1, url, text: match[1] }) + } + } + + // JSX href="/path" + JSX_HREF_RE.lastIndex = 0 + while ((match = JSX_HREF_RE.exec(lineContent)) !== null) { + const url = match[1] + if (isInternalLink(url)) { + links.push({ line: i + 1, url, text: '' }) + } + } + } + + return links +} + +function isInternalLink(url: string): boolean { + if (!url.startsWith('/')) return false + if (url.startsWith('//')) return false // protocol-relative + if (url === '/') return true + // Skip anchor links, API routes, images + if (url.startsWith('/api/')) return false + if (url.startsWith('/#')) return false + if (url.match(/\.(png|jpg|jpeg|gif|svg|webp|ico)$/i)) return false + return true +} + +// --- Scan content files --- + +function getAllMdFiles(dir: string): string[] { + const results: string[] = [] + if (!fs.existsSync(dir)) return results + + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const full = path.join(dir, entry.name) + if (entry.isDirectory()) { + // Skip deprecated content + if (entry.name === 'deprecated') continue + results.push(...getAllMdFiles(full)) + } else if (entry.name.endsWith('.md')) { + results.push(full) + } + } + + return results +} + +function rel(filePath: string): string { + return path.relative(process.cwd(), filePath) +} + +// --- Main --- + +function main() { + console.log('Building valid URL index...') + const validPaths = buildValidPaths() + console.log(` ${validPaths.size} valid paths indexed\n`) + + console.log('Scanning content files...') + const files = getAllMdFiles(CONTENT_DIR) + console.log(` ${files.length} markdown files found\n`) + + const broken: BrokenLink[] = [] + let totalLinks = 0 + + for (const file of files) { + const content = fs.readFileSync(file, 'utf-8') + const links = extractLinks(content) + totalLinks += links.length + + for (const link of links) { + // Strip query string and hash for validation + const cleanUrl = link.url.split('?')[0].split('#')[0].replace(/\/$/, '') + + if (!validPaths.has(cleanUrl)) { + broken.push({ + file: rel(file), + line: link.line, + url: link.url, + text: link.text, + }) + } + } + } + + // --- Report --- + console.log(`Checked ${totalLinks} internal links across ${files.length} files\n`) + + if (broken.length === 0) { + console.log('✓ No broken internal links found!') + process.exit(0) + } + + console.log(`✗ ${broken.length} broken internal links found:\n`) + + // Group by file + const byFile = new Map() + for (const b of broken) { + const existing = byFile.get(b.file) || [] + existing.push(b) + byFile.set(b.file, existing) + } + + for (const [file, links] of byFile) { + console.log(` ${file}`) + for (const link of links) { + const textInfo = link.text ? ` "${link.text}"` : '' + console.log(` L${link.line}: ${link.url}${textInfo}`) + } + console.log() + } + + process.exit(1) +} + +main() diff --git a/src/app/(mobile-ui)/dev/components/page.tsx b/src/app/(mobile-ui)/dev/components/page.tsx index 930ab1957..edac175e3 100644 --- a/src/app/(mobile-ui)/dev/components/page.tsx +++ b/src/app/(mobile-ui)/dev/components/page.tsx @@ -275,7 +275,7 @@ export default function ComponentsPage() { rows={[ [ 'variant', - 'purple | stroke | primary-soft | transparent | dark | transparent-dark | transparent-light | green | yellow', + 'purple | stroke | primary-soft | transparent | dark | transparent-dark | transparent-light', 'purple', ], ['size', 'small | medium | large', '(none = h-13)'], @@ -327,22 +327,10 @@ export default function ComponentsPage() { Label`} /> - - {(['green', 'yellow'] as const).map((variant) => ( -
-
- {variant} - 0 production usages - -
- -
- ))}
-

xl and xl-fixed exist in code but have 0 usages anywhere

diff --git a/src/app/(mobile-ui)/dev/ds/_components/CatalogCard.tsx b/src/app/(mobile-ui)/dev/ds/_components/CatalogCard.tsx new file mode 100644 index 000000000..17d29d2bc --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/_components/CatalogCard.tsx @@ -0,0 +1,55 @@ +'use client' + +import Link from 'next/link' +import { Icon, type IconName } from '@/components/Global/Icons/Icon' +import { Card } from '@/components/0_Bruddle/Card' +import { StatusTag } from './StatusTag' + +interface CatalogCardProps { + title: string + description: string + href: string + icon?: IconName + status?: 'production' | 'limited' | 'unused' | 'needs-refactor' + quality?: 1 | 2 | 3 | 4 | 5 + usages?: number +} + +export function CatalogCard({ title, description, href, icon, status, quality, usages }: CatalogCardProps) { + return ( + + +
+ {icon && ( +
+ +
+ )} +
+

{title}

+

{description}

+
+ {status && } + {quality && ( + + {'★'.repeat(quality)} + {'☆'.repeat(5 - quality)} + + )} + {usages !== undefined && ( + + {usages} usage{usages !== 1 ? 's' : ''} + + )} +
+
+ +
+
+ + ) +} + +export function CatalogGrid({ children }: { children: React.ReactNode }) { + return
{children}
+} diff --git a/src/app/(mobile-ui)/dev/ds/_components/CodeBlock.tsx b/src/app/(mobile-ui)/dev/ds/_components/CodeBlock.tsx new file mode 100644 index 000000000..be340465e --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/_components/CodeBlock.tsx @@ -0,0 +1,37 @@ +'use client' + +import { useState } from 'react' +import { Icon } from '@/components/Global/Icons/Icon' +import { useHighlightedCode } from '../_hooks/useHighlightedCode' + +interface CodeBlockProps { + code: string + label?: string + language?: string +} + +export function CodeBlock({ code, label, language = 'tsx' }: CodeBlockProps) { + const html = useHighlightedCode(code, language) + const [copied, setCopied] = useState(false) + + const handleCopy = () => { + navigator.clipboard.writeText(code) + setCopied(true) + setTimeout(() => setCopied(false), 1500) + } + + return ( +
+
+ {label && {label}} + +
+
+
+ ) +} diff --git a/src/app/(mobile-ui)/dev/ds/_components/DesignNote.tsx b/src/app/(mobile-ui)/dev/ds/_components/DesignNote.tsx new file mode 100644 index 000000000..e82a33622 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/_components/DesignNote.tsx @@ -0,0 +1,24 @@ +import { Icon } from '@/components/Global/Icons/Icon' + +const styles = { + warning: { + container: 'border-yellow-1/40 bg-yellow-1/20', + icon: 'text-n-1', + iconName: 'alert' as const, + }, + info: { + container: 'border-primary-3 bg-primary-3/20', + icon: 'text-n-1', + iconName: 'info' as const, + }, +} + +export function DesignNote({ type, children }: { type: 'warning' | 'info'; children: React.ReactNode }) { + const s = styles[type] + return ( +
+ +
{children}
+
+ ) +} diff --git a/src/app/(mobile-ui)/dev/ds/_components/DoDont.tsx b/src/app/(mobile-ui)/dev/ds/_components/DoDont.tsx new file mode 100644 index 000000000..8de7cb3f9 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/_components/DoDont.tsx @@ -0,0 +1,33 @@ +import { Icon } from '@/components/Global/Icons/Icon' + +interface DoDontProps { + doExample: React.ReactNode + doLabel?: string + dontExample: React.ReactNode + dontLabel?: string +} + +export function DoDont({ doExample, doLabel = 'Do', dontExample, dontLabel = "Don't" }: DoDontProps) { + return ( +
+
+
{doExample}
+
+
+ +
+ {doLabel} +
+
+
+
{dontExample}
+
+
+ +
+ {dontLabel} +
+
+
+ ) +} diff --git a/src/app/(mobile-ui)/dev/ds/_components/DocHeader.tsx b/src/app/(mobile-ui)/dev/ds/_components/DocHeader.tsx new file mode 100644 index 000000000..55cf98bc0 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/_components/DocHeader.tsx @@ -0,0 +1,21 @@ +import { StatusTag } from './StatusTag' + +interface DocHeaderProps { + title: string + description: string + status?: 'production' | 'limited' | 'unused' | 'needs-refactor' + usages?: string +} + +export function DocHeader({ title, description, status, usages }: DocHeaderProps) { + return ( +
+
+

{title}

+ {status && } + {usages && {usages}} +
+

{description}

+
+ ) +} diff --git a/src/app/(mobile-ui)/dev/ds/_components/DocPage.tsx b/src/app/(mobile-ui)/dev/ds/_components/DocPage.tsx new file mode 100644 index 000000000..3183b66fc --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/_components/DocPage.tsx @@ -0,0 +1,33 @@ +import React from 'react' + +function DocPageRoot({ children }: { children: React.ReactNode }) { + // Extract Design/Code children for backward compat, or render directly + const extracted: React.ReactNode[] = [] + + React.Children.forEach(children, (child) => { + if (!React.isValidElement(child)) { + extracted.push(child) + return + } + if (child.type === Design) { + // Unwrap Design children directly + extracted.push(child.props.children) + } else if (child.type === Code) { + // Skip Code — code now lives inside DocSection.Code + } else { + extracted.push(child) + } + }) + + return
{extracted}
+} + +function Design({ children }: { children: React.ReactNode }) { + return <>{children} +} + +function Code({ children }: { children: React.ReactNode }) { + return <>{children} +} + +export const DocPage = Object.assign(DocPageRoot, { Design, Code }) diff --git a/src/app/(mobile-ui)/dev/ds/_components/DocSection.tsx b/src/app/(mobile-ui)/dev/ds/_components/DocSection.tsx new file mode 100644 index 000000000..acaad3762 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/_components/DocSection.tsx @@ -0,0 +1,75 @@ +'use client' + +import React, { useState } from 'react' + +interface DocSectionProps { + title: string + description?: string + children: React.ReactNode +} + +function DocSectionRoot({ title, description, children }: DocSectionProps) { + const [codeVisible, setCodeVisible] = useState(false) + + let contentNode: React.ReactNode = null + let codeNode: React.ReactNode = null + let hasCompoundChildren = false + + React.Children.forEach(children, (child) => { + if (!React.isValidElement(child)) return + if (child.type === Content) { + contentNode = child.props.children + hasCompoundChildren = true + } + if (child.type === Code) { + codeNode = child.props.children + hasCompoundChildren = true + } + }) + + // Backward compat: if no Content/Code wrappers, treat all children as content + if (!hasCompoundChildren) { + contentNode = children + } + + const hasCode = codeNode !== null + + return ( +
+ {/* Left: title + description + content */} +
+
+

{title}

+ {hasCode && ( + + )} +
+ {description &&

{description}

} +
{contentNode}
+
+ + {/* Right: code */} + {hasCode && ( +
+
{codeNode}
+
+ )} +
+ ) +} + +function Content({ children }: { children: React.ReactNode }) { + return <>{children} +} + +function Code({ children }: { children: React.ReactNode }) { + return <>{children} +} + +export const DocSection = Object.assign(DocSectionRoot, { Content, Code }) diff --git a/src/app/(mobile-ui)/dev/ds/_components/DocSidebar.tsx b/src/app/(mobile-ui)/dev/ds/_components/DocSidebar.tsx new file mode 100644 index 000000000..937c63b61 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/_components/DocSidebar.tsx @@ -0,0 +1,95 @@ +'use client' + +import { useState } from 'react' +import Link from 'next/link' +import { usePathname } from 'next/navigation' +import { Icon } from '@/components/Global/Icons/Icon' +import { SIDEBAR_CONFIG } from './nav-config' + +export function DocSidebar() { + const pathname = usePathname() + const [isOpen, setIsOpen] = useState(false) + + // Determine which tier we're in + const tier = pathname?.includes('/foundations') + ? 'foundations' + : pathname?.includes('/primitives') + ? 'primitives' + : pathname?.includes('/patterns') + ? 'patterns' + : pathname?.includes('/playground') + ? 'playground' + : null + + const items = tier ? SIDEBAR_CONFIG[tier] : [] + + if (!tier || items.length === 0) return null + + return ( + <> + {/* Mobile hamburger */} + + + {/* Mobile overlay */} + {isOpen && ( +
setIsOpen(false)}> +
+ +
+ )} + + {/* Desktop sidebar */} + + + ) +} + +function SidebarLinks({ + items, + pathname, + onNavigate, +}: { + items: typeof SIDEBAR_CONFIG.foundations + pathname: string | null + onNavigate?: () => void +}) { + return ( +
+ {items.map((item) => { + const isActive = pathname === item.href + return ( + + + {item.label} + + ) + })} +
+ ) +} diff --git a/src/app/(mobile-ui)/dev/ds/_components/Playground.tsx b/src/app/(mobile-ui)/dev/ds/_components/Playground.tsx new file mode 100644 index 000000000..1b4a15eb4 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/_components/Playground.tsx @@ -0,0 +1,111 @@ +'use client' + +import { useState } from 'react' +import { CodeBlock } from './CodeBlock' + +export type PlaygroundControl = + | { type: 'select'; prop: string; label: string; options: string[] } + | { type: 'boolean'; prop: string; label: string } + | { type: 'text'; prop: string; label: string; placeholder?: string } + +interface PlaygroundProps { + name: string + importPath: string + defaults: Record + controls: PlaygroundControl[] + render: (props: Record) => React.ReactNode + codeTemplate: (props: Record) => string +} + +export function Playground({ name, importPath, defaults, controls, render, codeTemplate }: PlaygroundProps) { + const [props, setProps] = useState>(defaults) + + const updateProp = (key: string, value: any) => { + setProps((prev) => ({ ...prev, [key]: value })) + } + + return ( +
+ {/* Preview */} +
+
Preview
+
{render(props)}
+
+ + {/* Controls */} +
+
Controls
+
+ {controls.map((control) => ( + updateProp(control.prop, v)} + /> + ))} +
+
+ + {/* Generated code */} + + +
+ ) +} + +function ControlField({ + control, + value, + onChange, +}: { + control: PlaygroundControl + value: any + onChange: (v: any) => void +}) { + switch (control.type) { + case 'select': + return ( +
+ + +
+ ) + case 'boolean': + return ( +
+ onChange(e.target.checked)} + className="size-4 rounded-sm border border-n-1" + /> + +
+ ) + case 'text': + return ( +
+ + onChange(e.target.value || undefined)} + placeholder={control.placeholder} + className="w-full rounded-sm border border-n-1/30 bg-white px-2 py-1.5 text-xs" + /> +
+ ) + } +} diff --git a/src/app/(mobile-ui)/dev/ds/_components/PropsTable.tsx b/src/app/(mobile-ui)/dev/ds/_components/PropsTable.tsx new file mode 100644 index 000000000..217a0ca37 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/_components/PropsTable.tsx @@ -0,0 +1,47 @@ +interface PropsTableRow { + name: string + type: string + default: string + required?: boolean + description?: string +} + +export function PropsTable({ rows }: { rows: PropsTableRow[] }) { + return ( +
+ + + + + + + + + + + {rows.map((row) => ( + + + + + {row.description && ( + + )} + + ))} + +
+ prop + + type + + default + + description +
+ {row.name} + {row.required && *} + {row.type}{row.default}{row.description}
+
+ ) +} diff --git a/src/app/(mobile-ui)/dev/ds/_components/SectionDivider.tsx b/src/app/(mobile-ui)/dev/ds/_components/SectionDivider.tsx new file mode 100644 index 000000000..255fca580 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/_components/SectionDivider.tsx @@ -0,0 +1,3 @@ +export function SectionDivider() { + return
+} diff --git a/src/app/(mobile-ui)/dev/ds/_components/StatusTag.tsx b/src/app/(mobile-ui)/dev/ds/_components/StatusTag.tsx new file mode 100644 index 000000000..1013f4282 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/_components/StatusTag.tsx @@ -0,0 +1,21 @@ +const styles = { + production: 'bg-green-1/30 text-n-1', + limited: 'bg-yellow-1/30 text-n-1', + unused: 'bg-n-1/10 text-grey-1', + 'needs-refactor': 'bg-error-1/30 text-n-1', +} + +const labels = { + production: 'production', + limited: 'limited use', + unused: 'unused', + 'needs-refactor': 'needs refactor', +} + +export function StatusTag({ status }: { status: 'production' | 'limited' | 'unused' | 'needs-refactor' }) { + return ( + + {labels[status]} + + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/_components/TierNav.tsx b/src/app/(mobile-ui)/dev/ds/_components/TierNav.tsx new file mode 100644 index 000000000..1efe60467 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/_components/TierNav.tsx @@ -0,0 +1,32 @@ +'use client' + +import Link from 'next/link' +import { usePathname } from 'next/navigation' +import { Icon } from '@/components/Global/Icons/Icon' +import { TIERS } from './nav-config' + +export function TierNav() { + const pathname = usePathname() + + return ( +
+ {TIERS.map((tier) => { + const isActive = pathname?.startsWith(tier.href) + return ( + + + {tier.label} + + ) + })} +
+ ) +} diff --git a/src/app/(mobile-ui)/dev/ds/_components/WhenToUse.tsx b/src/app/(mobile-ui)/dev/ds/_components/WhenToUse.tsx new file mode 100644 index 000000000..cb8d605c1 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/_components/WhenToUse.tsx @@ -0,0 +1,37 @@ +import { Icon } from '@/components/Global/Icons/Icon' + +interface WhenToUseProps { + use: string[] + dontUse?: string[] +} + +export function WhenToUse({ use, dontUse }: WhenToUseProps) { + return ( +
+
+

When to use

+
    + {use.map((item, i) => ( +
  • + + {item} +
  • + ))} +
+
+ {dontUse && ( +
+

When not to use

+
    + {dontUse.map((item, i) => ( +
  • + + {item} +
  • + ))} +
+
+ )} +
+ ) +} diff --git a/src/app/(mobile-ui)/dev/ds/_components/nav-config.ts b/src/app/(mobile-ui)/dev/ds/_components/nav-config.ts new file mode 100644 index 000000000..fa64e72cb --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/_components/nav-config.ts @@ -0,0 +1,51 @@ +import type { IconName } from '@/components/Global/Icons/Icon' + +export interface NavItem { + label: string + href: string + icon: IconName +} + +export const TIERS = [ + { label: 'Foundations', href: '/dev/ds/foundations', icon: 'bulb' as IconName }, + { label: 'Primitives', href: '/dev/ds/primitives', icon: 'switch' as IconName }, + { label: 'Patterns', href: '/dev/ds/patterns', icon: 'docs' as IconName }, + { label: 'Playground', href: '/dev/ds/playground', icon: 'bulb' as IconName }, +] + +export const SIDEBAR_CONFIG: Record = { + foundations: [ + { label: 'Colors', icon: 'bulb', href: '/dev/ds/foundations/colors' }, + { label: 'Typography', icon: 'docs', href: '/dev/ds/foundations/typography' }, + { label: 'Spacing', icon: 'switch', href: '/dev/ds/foundations/spacing' }, + { label: 'Shadows', icon: 'docs', href: '/dev/ds/foundations/shadows' }, + { label: 'Icons', icon: 'search', href: '/dev/ds/foundations/icons' }, + { label: 'Borders', icon: 'docs', href: '/dev/ds/foundations/borders' }, + ], + primitives: [ + { label: 'Button', icon: 'switch', href: '/dev/ds/primitives/button' }, + { label: 'Card', icon: 'docs', href: '/dev/ds/primitives/card' }, + { label: 'BaseInput', icon: 'clip', href: '/dev/ds/primitives/base-input' }, + { label: 'BaseSelect', icon: 'clip', href: '/dev/ds/primitives/base-select' }, + { label: 'Checkbox', icon: 'check', href: '/dev/ds/primitives/checkbox' }, + { label: 'Toast', icon: 'bell', href: '/dev/ds/primitives/toast' }, + { label: 'Divider', icon: 'minus-circle', href: '/dev/ds/primitives/divider' }, + { label: 'Title', icon: 'docs', href: '/dev/ds/primitives/title' }, + { label: 'PageContainer', icon: 'docs', href: '/dev/ds/primitives/page-container' }, + ], + patterns: [ + { label: 'Modal', icon: 'link', href: '/dev/ds/patterns/modal' }, + { label: 'Drawer', icon: 'link', href: '/dev/ds/patterns/drawer' }, + { label: 'Navigation', icon: 'link', href: '/dev/ds/patterns/navigation' }, + { label: 'Loading', icon: 'processing', href: '/dev/ds/patterns/loading' }, + { label: 'Feedback', icon: 'meter', href: '/dev/ds/patterns/feedback' }, + { label: 'Copy & Share', icon: 'copy', href: '/dev/ds/patterns/copy-share' }, + { label: 'Layouts', icon: 'switch', href: '/dev/ds/patterns/layouts' }, + { label: 'Cards (Global)', icon: 'docs', href: '/dev/ds/patterns/cards-global' }, + { label: 'AmountInput', icon: 'dollar', href: '/dev/ds/patterns/amount-input' }, + ], + playground: [ + { label: 'Shake & Confetti', icon: 'gift', href: '/dev/ds/playground/shake-test' }, + { label: 'Perk Success', icon: 'check-circle', href: '/dev/ds/playground/perk-success' }, + ], +} diff --git a/src/app/(mobile-ui)/dev/ds/_hooks/useHighlightedCode.ts b/src/app/(mobile-ui)/dev/ds/_hooks/useHighlightedCode.ts new file mode 100644 index 000000000..da80e8620 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/_hooks/useHighlightedCode.ts @@ -0,0 +1,39 @@ +'use client' + +import { useEffect, useState } from 'react' +import type { HighlighterCore } from 'shiki' + +let highlighterPromise: Promise | null = null + +function getHighlighter() { + if (!highlighterPromise) { + highlighterPromise = import('shiki/bundle/web').then((shiki) => + shiki.createHighlighter({ + themes: ['github-light'], + langs: ['tsx'], + }) + ) + } + return highlighterPromise +} + +function escapeHtml(str: string) { + return str.replace(/&/g, '&').replace(//g, '>') +} + +export function useHighlightedCode(code: string, lang = 'tsx') { + const [html, setHtml] = useState(() => `
${escapeHtml(code)}
`) + + useEffect(() => { + let cancelled = false + getHighlighter().then((h) => { + if (cancelled) return + setHtml(h.codeToHtml(code, { lang, theme: 'github-light' })) + }) + return () => { + cancelled = true + } + }, [code, lang]) + + return html +} diff --git a/src/app/(mobile-ui)/dev/ds/foundations/borders/page.tsx b/src/app/(mobile-ui)/dev/ds/foundations/borders/page.tsx new file mode 100644 index 000000000..de94424e1 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/foundations/borders/page.tsx @@ -0,0 +1,87 @@ +'use client' + +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function BordersPage() { + return ( + + + + {/* Border radius */} + +

+ Always use rounded-sm. This is the standard + across all components. +

+
+
+
+ rounded-sm + standard +
+
+
+ rounded-full + badges, avatars +
+
+ + + {/* Border styles */} + + +
+
+
border border-n-1
+

Standard 1px black border. Most common.

+
+
+
brutal-border
+

2px solid black. For emphasis.

+
+
+
+ border border-n-1/20 +
+

+ Subtle border. For code snippets, secondary containers. +

+
+
+
+ border-dashed border-n-1/30 +
+

Dashed border. For drop zones, placeholders.

+
+
+
+ + + + +
+ + {/* Labels */} + + +
+ {['label-stroke', 'label-purple', 'label-yellow', 'label-black', 'label-teal'].map((cls) => ( + + {cls.replace('label-', '')} + + ))} +
+
+ + + +
+ + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/foundations/colors/page.tsx b/src/app/(mobile-ui)/dev/ds/foundations/colors/page.tsx new file mode 100644 index 000000000..3452e1d5d --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/foundations/colors/page.tsx @@ -0,0 +1,124 @@ +'use client' + +import { useState } from 'react' +import { Icon } from '@/components/Global/Icons/Icon' +import { DesignNote } from '../../_components/DesignNote' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { DocPage } from '../../_components/DocPage' + +const COLORS = [ + { name: 'purple-1', bg: 'bg-purple-1', text: 'text-purple-1', hex: '#FF90E8', note: 'PINK not purple!' }, + { name: 'primary-3', bg: 'bg-primary-3', text: 'text-primary-3', hex: '#EFE4FF', note: 'lavender' }, + { name: 'primary-4', bg: 'bg-primary-4', text: 'text-primary-4', hex: '#D8C4F6', note: 'deeper lavender' }, + { name: 'yellow-1', bg: 'bg-yellow-1', text: 'text-yellow-1', hex: '#FFC900', note: 'peanut yellow' }, + { name: 'green-1', bg: 'bg-green-1', text: 'text-green-1', hex: '#98E9AB', note: 'success green' }, + { name: 'n-1', bg: 'bg-n-1', text: 'text-n-1', hex: '#000000', note: 'black / primary text' }, + { name: 'grey-1', bg: 'bg-grey-1', text: 'text-grey-1', hex: '#6B6B6B', note: 'secondary text' }, + { name: 'teal-1', bg: 'bg-teal-1', text: 'text-teal-1', hex: '#C3F5E4', note: 'teal accent' }, + { name: 'violet-1', bg: 'bg-violet-1', text: 'text-violet-1', hex: '#A78BFA', note: 'violet' }, + { name: 'error-1', bg: 'bg-error-1', text: 'text-error-1', hex: '#FF6B6B', note: 'error red' }, + { name: 'success-3', bg: 'bg-success-3', text: 'text-success-3', hex: '#4ADE80', note: 'success bg' }, + { name: 'secondary-1', bg: 'bg-secondary-1', text: 'text-secondary-1', hex: '#FFC900', note: 'same as yellow-1' }, +] + +const BACKGROUNDS = [ + { name: 'bg-peanut-repeat-normal', description: 'Normal peanut repeat pattern' }, + { name: 'bg-peanut-repeat-large', description: 'Large peanut repeat pattern' }, + { name: 'bg-peanut-repeat-small', description: 'Small peanut repeat pattern' }, +] + +export default function ColorsPage() { + const [copiedColor, setCopiedColor] = useState(null) + + const copyClass = (cls: string) => { + navigator.clipboard.writeText(cls) + setCopiedColor(cls) + setTimeout(() => setCopiedColor(null), 1500) + } + + return ( + + + + + purple-1 / primary-1 = #FF90E8 — this is PINK, not purple. The naming is misleading but too widely used + to rename. + + + {/* Color grid */} + +
+ {COLORS.map((color) => ( + + ))} +
+
+ + {/* Text / BG pairs */} + +
+
+ text-n-1 + Primary text — headings, labels, body (134 usages) +
+
+ text-grey-1 + Secondary text — descriptions, hints, metadata +
+
+ text-error-1 + Error text — validation messages, alerts +
+
+ text-success-3 + Success text — confirmations +
+
+ + + Inline links: always use{' '} + text-black underline — never + text-purple-1. + +
+ + {/* Background patterns */} + +
+ {BACKGROUNDS.map((bg) => ( + + ))} +
+
+
+ ) +} diff --git a/src/app/(mobile-ui)/dev/ds/foundations/icons/page.tsx b/src/app/(mobile-ui)/dev/ds/foundations/icons/page.tsx new file mode 100644 index 000000000..0bf1f13e2 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/foundations/icons/page.tsx @@ -0,0 +1,148 @@ +'use client' + +import { useState } from 'react' +import { Icon, type IconName } from '@/components/Global/Icons/Icon' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +const ALL_ICONS: IconName[] = [ + 'alert', + 'alert-filled', + 'arrow-down', + 'arrow-down-left', + 'arrow-up', + 'arrow-up-right', + 'arrow-exchange', + 'badge', + 'bank', + 'bell', + 'bulb', + 'camera', + 'camera-flip', + 'cancel', + 'check', + 'check-circle', + 'chevron-up', + 'chevron-down', + 'clip', + 'clock', + 'copy', + 'currency', + 'docs', + 'dollar', + 'double-check', + 'download', + 'error', + 'exchange', + 'external-link', + 'eye', + 'eye-slash', + 'failed', + 'fees', + 'gift', + 'globe-lock', + 'history', + 'home', + 'info', + 'info-filled', + 'invite-heart', + 'link', + 'link-slash', + 'lock', + 'logout', + 'meter', + 'minus-circle', + 'mobile-install', + 'paperclip', + 'paste', + 'peanut-support', + 'pending', + 'plus', + 'plus-circle', + 'processing', + 'qr-code', + 'question-mark', + 'retry', + 'search', + 'share', + 'shield', + 'smile', + 'split', + 'star', + 'success', + 'switch', + 'trophy', + 'txn-off', + 'upload-cloud', + 'user', + 'user-id', + 'user-plus', + 'wallet', + 'wallet-cancel', + 'wallet-outline', + 'achievements', +] + +export default function IconsPage() { + const [search, setSearch] = useState('') + const [copiedIcon, setCopiedIcon] = useState(null) + + const filtered = search ? ALL_ICONS.filter((name) => name.includes(search.toLowerCase())) : ALL_ICONS + + const copyIcon = (name: string) => { + navigator.clipboard.writeText(name) + setCopiedIcon(name) + setTimeout(() => setCopiedIcon(null), 1500) + } + + return ( + + + + {/* Search */} + setSearch(e.target.value)} + placeholder="Search icons..." + className="w-full rounded-sm border border-n-1 px-3 py-2 text-sm" + /> + + {/* Grid */} +
+ {filtered.map((name) => ( + + ))} +
+ + {filtered.length === 0 && ( +

No icons match "{search}"

+ )} + + + + `} + /> + + +
+ ) +} diff --git a/src/app/(mobile-ui)/dev/ds/foundations/page.tsx b/src/app/(mobile-ui)/dev/ds/foundations/page.tsx new file mode 100644 index 000000000..1bcc89a44 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/foundations/page.tsx @@ -0,0 +1,61 @@ +import { CatalogCard, CatalogGrid } from '../_components/CatalogCard' +import { DocPage } from '../_components/DocPage' + +export default function FoundationsPage() { + return ( + +
+

Foundations

+

+ Design tokens, visual primitives, and systemic building blocks. +

+
+ + + + + + + + + +
+ ) +} diff --git a/src/app/(mobile-ui)/dev/ds/foundations/shadows/page.tsx b/src/app/(mobile-ui)/dev/ds/foundations/shadows/page.tsx new file mode 100644 index 000000000..bda11777a --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/foundations/shadows/page.tsx @@ -0,0 +1,78 @@ +'use client' + +import { Button } from '@/components/0_Bruddle/Button' +import { Card } from '@/components/0_Bruddle/Card' +import { DesignNote } from '../../_components/DesignNote' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function ShadowsPage() { + return ( + + + + + shadowSize="4" has 160+ usages. It is the standard. All others are negligible. + + + {/* Button shadows */} + + +
+ {(['3', '4', '6', '8'] as const).map((s) => ( +
+ +

+ {s === '4' + ? '160 usages' + : s === '3' + ? '2 usages' + : s === '6' + ? '1 usage' + : '1 usage'} +

+
+ ))} +
+
+ + Label`} /> + +
+ + {/* Card shadows */} + + +
+ {(['4', '6', '8'] as const).map((s) => ( + +

shadowSize="{s}"

+
+ ))} +
+
+ + content`} /> + +
+ + {/* Tailwind shadow classes */} + +
+ {['shadow-2', 'shadow-4', 'shadow-sm', 'shadow-lg'].map((cls) => ( +
+ .{cls} +
+ ))} +
+
+
+ ) +} diff --git a/src/app/(mobile-ui)/dev/ds/foundations/spacing/page.tsx b/src/app/(mobile-ui)/dev/ds/foundations/spacing/page.tsx new file mode 100644 index 000000000..167aba3d0 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/foundations/spacing/page.tsx @@ -0,0 +1,87 @@ +'use client' + +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function SpacingPage() { + return ( + + + + {/* Custom layout classes */} + + +
+
+ .row + flex items-center gap-2 +
+
+ .col + flex flex-col gap-2 +
+
+ +
+

Example: .row

+
+
+
+
+
+ +

Example: .col

+
+
+
+
+
+
+ + + ...
`} /> + ...
`} /> + + + + {/* Common gap patterns */} + +
+ {[ + ['gap-1', '4px', 'Tight grouping (icon + label)'], + ['gap-2', '8px', 'Default row/col spacing'], + ['gap-3', '12px', 'Card list spacing'], + ['gap-4', '16px', 'Section spacing within a card'], + ['gap-6', '24px', 'Content block spacing'], + ['gap-8', '32px', 'Major section spacing'], + ].map(([cls, px, note]) => ( +
+ {cls} + {px} + {note} +
+ ))} +
+
+ + {/* Page padding */} + +
+

+ Standard page content padding: px-4 (16px) +

+

+ Card internal padding: p-4 (16px) or{' '} + p-6 (24px) +

+

+ Section spacing: space-y-6 or{' '} + gap-6 +

+
+
+ + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/foundations/typography/page.tsx b/src/app/(mobile-ui)/dev/ds/foundations/typography/page.tsx new file mode 100644 index 000000000..b16cbf5ae --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/foundations/typography/page.tsx @@ -0,0 +1,99 @@ +'use client' + +import Title from '@/components/0_Bruddle/Title' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +const WEIGHTS = [ + { class: 'font-light', label: 'Light', usages: 5 }, + { class: 'font-normal', label: 'Normal', usages: 50 }, + { class: 'font-medium', label: 'Medium', usages: 104 }, + { class: 'font-semibold', label: 'Semibold', usages: 66 }, + { class: 'font-bold', label: 'Bold', usages: 304 }, + { class: 'font-extrabold', label: 'Extrabold', usages: 55 }, + { class: 'font-black', label: 'Black', usages: 16 }, +] + +const SIZES = [ + { class: 'text-xs', example: 'Extra small (12px)', note: 'metadata, badges, hints' }, + { class: 'text-sm', example: 'Small (14px)', note: 'body text, descriptions' }, + { class: 'text-base', example: 'Base (16px)', note: 'default' }, + { class: 'text-lg', example: 'Large (18px)', note: 'section headings' }, + { class: 'text-xl', example: 'Extra large (20px)', note: 'page titles' }, + { class: 'text-2xl', example: '2XL (24px)', note: 'hero text' }, +] + +export default function TypographyPage() { + return ( + + + + {/* Font families */} + + +
+
+

System Default

+

Primary body font. Used everywhere by default.

+
+
+

font-mono

+

Monospace for code, addresses, amounts. 21 usages.

+
+
+

font-roboto-flex

+

Roboto Flex for specific UI elements. 16 usages.

+
+
+ + <p className="mt-1 text-sm text-n-1"> + Display font with filled+outline double-render effect. + </p> + </div> + </div> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Font Mono" code='className="font-mono"' /> + <CodeBlock + label="Title Component" + code={`import Title from '@/components/0_Bruddle/Title'\n<Title text="PEANUT" />`} + /> + </DocSection.Code> + </DocSection> + + {/* Font weights */} + <DocSection title="Font Weights"> + <div className="space-y-1 rounded-sm border border-n-1 p-3"> + {WEIGHTS.map((w) => ( + <div key={w.class} className="flex items-baseline justify-between"> + <p className={`text-sm ${w.class}`}> + {w.label} <span className="font-mono text-[10px] text-grey-1">.{w.class}</span> + </p> + <span className="text-xs text-grey-1">{w.usages}</span> + </div> + ))} + </div> + <p className="text-sm text-grey-1"> + font-bold dominates (304 usages). Use font-bold for labels and headings, font-medium for secondary + text. + </p> + </DocSection> + + {/* Text sizes */} + <DocSection title="Text Sizes"> + <div className="space-y-2 rounded-sm border border-n-1 p-3"> + {SIZES.map((s) => ( + <div key={s.class}> + <p className={`${s.class} font-bold`}>{s.example}</p> + <p className="text-xs text-grey-1"> + .{s.class} — {s.note} + </p> + </div> + ))} + </div> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/layout.tsx b/src/app/(mobile-ui)/dev/ds/layout.tsx new file mode 100644 index 000000000..fa87ff7bd --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/layout.tsx @@ -0,0 +1,37 @@ +'use client' + +import NavHeader from '@/components/Global/NavHeader' +import { TierNav } from './_components/TierNav' +import { DocSidebar } from './_components/DocSidebar' + +export default function DesignSystemLayout({ children }: { children: React.ReactNode }) { + return ( + <div className="flex w-full flex-col"> + {/* Header */} + <div className="px-4 pt-4"> + <NavHeader title="Design System" href="/dev" /> + </div> + + {/* Tier tabs */} + <div className="sticky top-0 z-10 border-b border-gray-3 bg-white px-6 py-3"> + <div className="flex items-center gap-2"> + <TierNav /> + <div className="ml-auto md:hidden"> + <DocSidebar /> + </div> + </div> + </div> + + {/* Content area */} + <div className="flex flex-1 px-6 py-10 lg:px-10"> + {/* Desktop sidebar */} + <div className="hidden md:block"> + <DocSidebar /> + </div> + + {/* Main content */} + <div className="min-w-0 flex-1 md:pl-10">{children}</div> + </div> + </div> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/page.tsx b/src/app/(mobile-ui)/dev/ds/page.tsx new file mode 100644 index 000000000..b9e5f57ff --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/page.tsx @@ -0,0 +1,115 @@ +'use client' + +import Link from 'next/link' +import { Icon } from '@/components/Global/Icons/Icon' +import { Card } from '@/components/0_Bruddle/Card' +import Title from '@/components/0_Bruddle/Title' +import { DocPage } from './_components/DocPage' + +const sections = [ + { + title: 'Foundations', + description: 'Color tokens, typography, spacing, shadows, icons, and borders', + href: '/dev/ds/foundations', + icon: 'bulb' as const, + count: 6, + }, + { + title: 'Primitives', + description: 'Bruddle base components: Button, Card, Input, Select, Checkbox, Toast', + href: '/dev/ds/primitives', + icon: 'switch' as const, + count: 9, + }, + { + title: 'Patterns', + description: 'Composed components: Modal, Drawer, Navigation, Loading, Feedback, Layouts', + href: '/dev/ds/patterns', + icon: 'docs' as const, + count: 9, + }, + { + title: 'Playground', + description: 'Interactive test harnesses: shake animations, haptics, confetti, perk flows', + href: '/dev/ds/playground', + icon: 'bulb' as const, + count: 2, + }, +] + +export default function DesignSystemPage() { + return ( + <DocPage> + {/* Hero */} + <div className="rounded-sm border border-n-1 bg-purple-1 p-6"> + <Title text="PEANUT" /> + <p className="mt-2 text-base font-bold text-n-1">Design System</p> + <p className="mt-1 text-sm text-n-1/70">Foundations → Primitives → Patterns → Playground</p> + </div> + + {/* Quick stats */} + <div className="grid grid-cols-3 gap-2"> + {[ + { label: 'Primitives', value: '9' }, + { label: 'Global', value: '70+' }, + { label: 'Icons', value: '85+' }, + ].map((stat) => ( + <div key={stat.label} className="rounded-sm border border-n-1 p-3 text-center"> + <p className="text-2xl font-bold">{stat.value}</p> + <p className="text-xs text-grey-1">{stat.label}</p> + </div> + ))} + </div> + + {/* Section cards */} + <div className="space-y-4"> + {sections.map((section) => ( + <Link key={section.href} href={section.href}> + <Card + shadowSize="4" + className="cursor-pointer p-4 transition-all hover:translate-x-[2px] hover:translate-y-[2px] hover:shadow-none" + > + <div className="flex items-center gap-3"> + <div className="flex size-10 items-center justify-center rounded-sm border border-n-1 bg-primary-3"> + <Icon name={section.icon} size={20} /> + </div> + <div className="flex-1"> + <div className="flex items-center gap-2"> + <h3 className="text-base font-bold">{section.title}</h3> + <span className="rounded-full bg-n-1/10 px-2 py-0.5 text-xs font-bold text-grey-1"> + {section.count} + </span> + </div> + <p className="mt-0.5 text-sm text-grey-1">{section.description}</p> + </div> + <Icon name="arrow-up-right" size={16} className="text-grey-1" /> + </div> + </Card> + </Link> + ))} + </div> + + {/* Design rules quick reference */} + <div className="space-y-4 rounded-sm border border-n-1 bg-primary-3/20 p-3"> + <p className="text-sm font-bold">Quick Rules</p> + <ul className="space-y-1 text-sm text-grey-1"> + <li> + Primary CTA:{' '} + <code className="rounded bg-white px-1 font-mono text-[10px]"> + variant="purple" shadowSize="4" w-full + </code> + </li> + <li> + Links: <code className="rounded bg-white px-1 font-mono text-[10px]">text-black underline</code>{' '} + — never text-purple-1 + </li> + <li> + purple-1 is <span className="inline-block size-3 rounded-sm bg-purple-1 align-middle" /> pink + (#FF90E8), not purple + </li> + <li>size="large" is h-10 (shorter than default h-13)</li> + </ul> + </div> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/patterns/amount-input/page.tsx b/src/app/(mobile-ui)/dev/ds/patterns/amount-input/page.tsx new file mode 100644 index 000000000..3b4727980 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/patterns/amount-input/page.tsx @@ -0,0 +1,223 @@ +import { PropsTable } from '../../_components/PropsTable' +import { DesignNote } from '../../_components/DesignNote' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { SectionDivider } from '../../_components/SectionDivider' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function AmountInputPage() { + return ( + <DocPage> + <DocHeader + title="AmountInput" + description="Large currency input with denomination switching, conversion display, balance indicator, and optional slider. Reference page only -- no live demo due to complex context dependencies." + status="needs-refactor" + /> + + {/* Refactor Note */} + <DocSection title="Refactor Note"> + <DesignNote type="warning"> + This component needs refactoring. It has 20+ props, mixes display logic with currency conversion + math, and requires multiple setter callbacks. Consider splitting into AmountDisplay (visual) and + useAmountConversion (hook) in a future pass. + </DesignNote> + </DocSection> + + {/* Visual Description */} + <DocSection title="Visual Structure"> + <DocSection.Content> + <div className="rounded-sm border border-n-1 p-4"> + <div className="flex flex-col items-center gap-2 py-4"> + <div className="flex items-center gap-1"> + <span className="text-xl font-bold text-grey-1">$</span> + <span className="text-6xl font-black">0.00</span> + </div> + <span className="text-lg font-bold text-grey-1">≈ ETH 0.00</span> + <span className="text-sm text-grey-1">Balance: $ 42.50</span> + </div> + <div className="absolute right-4 top-1/2 -translate-y-1/2 text-grey-1"></div> + </div> + <p className="text-xs text-grey-1"> + The input uses a transparent background with auto-sizing width. A fake blinking caret (primary-1 + color) shows when the input is empty and not focused. + </p> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import AmountInput from '@/components/Global/AmountInput'`} /> + + <CodeBlock + label="Basic (USD only)" + code={`<AmountInput + setPrimaryAmount={setAmount} + primaryDenomination={{ symbol: '$', price: 1, decimals: 2 }} +/>`} + /> + + <CodeBlock + label="With conversion" + code={`<AmountInput + setPrimaryAmount={setUsdAmount} + setSecondaryAmount={setTokenAmount} + primaryDenomination={{ symbol: '$', price: 1, decimals: 2 }} + secondaryDenomination={{ symbol: 'ETH', price: ethPrice, decimals: 8 }} + walletBalance={formattedBalance} +/>`} + /> + + <CodeBlock + label="With slider (Pot contributions)" + code={`<AmountInput + setPrimaryAmount={setAmount} + primaryDenomination={{ symbol: '$', price: 1, decimals: 2 }} + showSlider + maxAmount={potMax} + amountCollected={potCollected} + defaultSliderValue={33} +/>`} + /> + </DocSection.Code> + </DocSection> + + <SectionDivider /> + + {/* Props */} + <DocSection title="Props"> + <PropsTable + rows={[ + { + name: 'setPrimaryAmount', + type: '(value: string) => void', + default: '-', + required: true, + description: 'Callback for the primary denomination amount', + }, + { + name: 'primaryDenomination', + type: '{ symbol, price, decimals }', + default: "{ symbol: '$', price: 1, decimals: 2 }", + description: 'Primary currency config', + }, + { + name: 'secondaryDenomination', + type: '{ symbol, price, decimals }', + default: '(none)', + description: 'Enables currency toggle when provided', + }, + { + name: 'setSecondaryAmount', + type: '(value: string) => void', + default: '(none)', + description: 'Callback for converted amount', + }, + { + name: 'setDisplayedAmount', + type: '(value: string) => void', + default: '(none)', + description: 'Callback for the currently displayed value', + }, + { + name: 'setCurrentDenomination', + type: '(denomination: string) => void', + default: '(none)', + description: 'Reports which denomination is active', + }, + { name: 'initialAmount', type: 'string', default: "''", description: 'Pre-fill amount' }, + { + name: 'initialDenomination', + type: 'string', + default: '(none)', + description: 'Pre-select denomination', + }, + { + name: 'walletBalance', + type: 'string', + default: '(none)', + description: 'Formatted balance to display', + }, + { + name: 'hideBalance', + type: 'boolean', + default: 'false', + description: 'Hide the balance line', + }, + { + name: 'hideCurrencyToggle', + type: 'boolean', + default: 'false', + description: 'Hide the swap icon even with secondary denomination', + }, + { name: 'disabled', type: 'boolean', default: 'false', description: 'Disable input' }, + { name: 'onSubmit', type: '() => void', default: '(none)', description: 'Enter key handler' }, + { name: 'onBlur', type: '() => void', default: '(none)', description: 'Blur handler' }, + { + name: 'showSlider', + type: 'boolean', + default: 'false', + description: 'Show percentage slider below input', + }, + { name: 'maxAmount', type: 'number', default: '(none)', description: 'Slider max value' }, + { + name: 'amountCollected', + type: 'number', + default: '0', + description: 'Already collected (for pot snap logic)', + }, + { + name: 'defaultSliderValue', + type: 'number', + default: '(none)', + description: 'Initial slider percentage', + }, + { + name: 'defaultSliderSuggestedAmount', + type: 'number', + default: '(none)', + description: 'Suggested amount to pre-fill', + }, + { + name: 'infoContent', + type: 'ReactNode', + default: '(none)', + description: 'Content below the input area', + }, + { + name: 'className', + type: 'string', + default: "''", + description: 'Override form container styles', + }, + ]} + /> + </DocSection> + + {/* Architecture Notes */} + <DocSection title="Architecture Notes"> + <DesignNote type="info"> + Internally uses exactValue (scaled by 10^18) for precise integer arithmetic during currency + conversion. Display values are formatted separately from calculation values to avoid precision loss. + </DesignNote> + <DesignNote type="info"> + The component auto-focuses on desktop (DeviceType.WEB) but not on mobile to avoid keyboard popup. + Input width auto-sizes based on character count (ch units). + </DesignNote> + <DesignNote type="warning"> + The slider has a 33.33% "magnetic snap point" that snaps to the remaining pot amount. This + is specific to the pot/group-pay use case and ideally should not be baked into the generic + component. + </DesignNote> + </DocSection> + + {/* Refactoring Ideas */} + <DocSection title="Refactoring Ideas"> + <div className="space-y-1 text-sm text-grey-1"> + <p>1. Extract conversion logic into a useAmountConversion hook</p> + <p>2. Split slider into a separate SliderAmountInput wrapper component</p> + <p>3. Remove pot-specific snap logic from the base component</p> + <p>4. Simplify the 7 callback props into a single onChange object</p> + <p>5. Consider using a controlled-only pattern (value + onChange) instead of internal state</p> + </div> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/patterns/cards-global/page.tsx b/src/app/(mobile-ui)/dev/ds/patterns/cards-global/page.tsx new file mode 100644 index 000000000..99be830d4 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/patterns/cards-global/page.tsx @@ -0,0 +1,201 @@ +'use client' + +import Card from '@/components/Global/Card' +import { PropsTable } from '../../_components/PropsTable' +import { DesignNote } from '../../_components/DesignNote' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { SectionDivider } from '../../_components/SectionDivider' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function CardsGlobalPage() { + return ( + <DocPage> + <DocHeader + title="Card (Global)" + description="Global shared Card component for stacked lists with position-aware border radius. Different from the Bruddle Card primitive (named export from 0_Bruddle)." + status="production" + /> + + {/* Import */} + <DocSection title="Import"> + <DesignNote type="warning"> + This is the default export from Global/Card. The Bruddle Card is a named export: import {'{ Card }'}{' '} + from '@/components/0_Bruddle/Card'. They are different components. + </DesignNote> + </DocSection> + + {/* Single Card */} + <DocSection title="Single Card"> + <DocSection.Content> + <Card position="single"> + <div className="flex items-center justify-between py-1"> + <span className="text-sm font-bold">Single Card</span> + <span className="text-xs text-grey-1">position="single"</span> + </div> + </Card> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import Card from '@/components/Global/Card'`} /> + + <CodeBlock + label="Usage" + code={`<Card position="single"> + <div>Content</div> +</Card>`} + /> + </DocSection.Code> + </DocSection> + + {/* Stacked List */} + <DocSection title="Stacked List"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Cards stack seamlessly by using position props: first, middle, last. Only the first card has top + border-radius, only the last has bottom, and middle cards have no border-radius. Border-top is + removed on middle and last to avoid double borders. + </p> + + <div> + {(['first', 'middle', 'middle', 'middle', 'last'] as const).map((pos, i) => ( + <Card key={i} position={pos}> + <div className="flex items-center justify-between py-1"> + <span className="text-sm">Item {i + 1}</span> + <span className="text-xs text-grey-1">position="{pos}"</span> + </div> + </Card> + ))} + </div> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="Usage" + code={`{items.map((item, index) => { + const position = + items.length === 1 ? 'single' : + index === 0 ? 'first' : + index === items.length - 1 ? 'last' : + 'middle' + + return ( + <Card key={item.id} position={position}> + {/* Item content */} + </Card> + ) +})}`} + /> + </DocSection.Code> + </DocSection> + + {/* Clickable */} + <DocSection title="Clickable Cards"> + <DocSection.Content> + <div> + <Card position="first" onClick={() => {}}> + <div className="flex items-center justify-between py-1"> + <span className="text-sm">Clickable item 1</span> + <span className="text-xs text-grey-1">→</span> + </div> + </Card> + <Card position="last" onClick={() => {}}> + <div className="flex items-center justify-between py-1"> + <span className="text-sm">Clickable item 2</span> + <span className="text-xs text-grey-1">→</span> + </div> + </Card> + </div> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="Usage" + code={`<Card position="single" onClick={() => router.push('/detail')}> + <div>Clickable card content</div> +</Card>`} + /> + </DocSection.Code> + </DocSection> + + {/* No Border */} + <DocSection title="Without Border"> + <DocSection.Content> + <Card position="single" border={false}> + <div className="py-1"> + <span className="text-sm">No border card</span> + </div> + </Card> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Usage" code={`<Card border={false}>Content</Card>`} /> + </DocSection.Code> + </DocSection> + + <SectionDivider /> + + {/* Props */} + <DocSection title="Props"> + <PropsTable + rows={[ + { + name: 'position', + type: "'single' | 'first' | 'middle' | 'last'", + default: "'single'", + description: 'Controls border-radius for stacking', + }, + { name: 'border', type: 'boolean', default: 'true', description: 'Show/hide border' }, + { name: 'onClick', type: '() => void', default: '(none)', description: 'Makes card clickable' }, + { + name: 'className', + type: 'string', + default: "''", + description: 'Override styles (base: w-full bg-white px-4 py-2)', + }, + { name: 'children', type: 'ReactNode', default: '-', required: true }, + { name: 'ref', type: 'Ref<HTMLDivElement>', default: '(none)' }, + ]} + /> + </DocSection> + + {/* Position behavior table */} + <DocSection title="Position Behavior"> + <div className="overflow-x-auto rounded-sm border border-n-1 text-xs"> + <table className="w-full"> + <thead> + <tr className="border-b border-n-1 bg-primary-3/20"> + <th className="px-3 py-1.5 text-left font-bold">Position</th> + <th className="px-3 py-1.5 text-left font-bold">Border Radius</th> + <th className="px-3 py-1.5 text-left font-bold">Border</th> + </tr> + </thead> + <tbody> + {[ + ['single', 'rounded-sm (all)', 'border border-black'], + ['first', 'rounded-t-sm (top only)', 'border border-black'], + ['middle', 'none', 'border border-black border-t-0'], + ['last', 'rounded-b-sm (bottom only)', 'border border-black border-t-0'], + ].map(([pos, radius, border]) => ( + <tr key={pos} className="border-b border-n-1 last:border-0"> + <td className="px-3 py-1.5 font-mono font-bold">{pos}</td> + <td className="px-3 py-1.5 font-mono">{radius}</td> + <td className="px-3 py-1.5 font-mono">{border}</td> + </tr> + ))} + </tbody> + </table> + </div> + </DocSection> + + {/* Design Notes */} + <DocSection title="Design Rules"> + <DesignNote type="info"> + Use Global Card for stacked lists (transaction history, settings, token lists). Use Bruddle Card for + standalone content cards with shadows and variants. + </DesignNote> + <DesignNote type="info"> + The base styles are: w-full bg-white px-4 py-2. Override with className for custom padding or + background. + </DesignNote> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/patterns/copy-share/page.tsx b/src/app/(mobile-ui)/dev/ds/patterns/copy-share/page.tsx new file mode 100644 index 000000000..9ae5e5562 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/patterns/copy-share/page.tsx @@ -0,0 +1,286 @@ +'use client' + +import CopyField from '@/components/Global/CopyField' +import CopyToClipboard from '@/components/Global/CopyToClipboard' +import MoreInfo from '@/components/Global/MoreInfo' +import { PropsTable } from '../../_components/PropsTable' +import { DesignNote } from '../../_components/DesignNote' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { SectionDivider } from '../../_components/SectionDivider' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function CopySharePage() { + return ( + <DocPage> + <DocHeader + title="Copy & Share" + description="Components for copying text to clipboard, sharing links, displaying addresses, and showing tooltips." + status="production" + /> + + {/* CopyField */} + <DocSection title="CopyField"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Input field + Copy button combo. The input is disabled (read-only display). Button shows + "Copied" feedback for 3 seconds. + </p> + + <div className="space-y-3"> + <CopyField text="https://peanut.me/claim/abc123" /> + <CopyField text="0x1234...abcd" variant="purple" shadowSize="4" /> + </div> + + <PropsTable + rows={[ + { + name: 'text', + type: 'string', + default: '-', + required: true, + description: 'Text to display and copy', + }, + { + name: 'variant', + type: 'ButtonVariant', + default: "'stroke'", + description: 'Copy button variant', + }, + { + name: 'shadowSize', + type: "'4' | '6' | '8'", + default: '(none)', + description: 'Copy button shadow', + }, + { name: 'disabled', type: 'boolean', default: 'false', description: 'Disables copying' }, + { + name: 'onDisabledClick', + type: '() => void', + default: '(none)', + description: 'Handler when clicking disabled button', + }, + ]} + /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import CopyField from '@/components/Global/CopyField'`} /> + + <CodeBlock + label="Usage" + code={`<CopyField text="https://peanut.me/claim/abc123" /> +<CopyField text={linkUrl} variant="purple" shadowSize="4" />`} + /> + </DocSection.Code> + </DocSection> + + {/* CopyToClipboard */} + <DocSection title="CopyToClipboard"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Icon-only or button-style copy trigger. Shows check icon for 2 seconds after copying. Supports + imperative copy via ref. + </p> + + <div className="space-y-4"> + <div className="flex items-center gap-4"> + <div className="flex items-center gap-2"> + <span className="text-xs">Icon mode:</span> + <CopyToClipboard textToCopy="Hello from Peanut!" /> + </div> + <div className="flex items-center gap-2"> + <span className="text-xs">Different sizes:</span> + <CopyToClipboard textToCopy="small" iconSize="3" /> + <CopyToClipboard textToCopy="medium" iconSize="4" /> + <CopyToClipboard textToCopy="large" iconSize="6" /> + </div> + </div> + <div> + <CopyToClipboard textToCopy="Button mode text" type="button" /> + </div> + </div> + + <PropsTable + rows={[ + { + name: 'textToCopy', + type: 'string', + default: '-', + required: true, + description: 'Text to copy to clipboard', + }, + { + name: 'type', + type: "'icon' | 'button'", + default: "'icon'", + description: 'Render as icon or Button component', + }, + { + name: 'iconSize', + type: "'2' | '3' | '4' | '6' | '8'", + default: "'6'", + description: 'Icon size (Tailwind scale)', + }, + { name: 'fill', type: 'string', default: "'black'", description: 'Icon fill color' }, + { + name: 'buttonSize', + type: 'ButtonSize', + default: '(none)', + description: 'Button size when type="button"', + }, + { name: 'className', type: 'string', default: "''", description: 'Override styles' }, + ]} + /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="Import" + code={`import CopyToClipboard from '@/components/Global/CopyToClipboard'`} + /> + + <CodeBlock + label="Usage" + code={`{/* Icon (default) */} +<CopyToClipboard textToCopy={address} /> + +{/* Button */} +<CopyToClipboard textToCopy={code} type="button" /> + +{/* Imperative */} +const copyRef = useRef<CopyToClipboardRef>(null) +<CopyToClipboard ref={copyRef} textToCopy={text} /> +copyRef.current?.copy()`} + /> + </DocSection.Code> + </DocSection> + + {/* ShareButton */} + <DocSection title="ShareButton"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Reference only. Uses the Web Share API (navigator.share) with clipboard fallback. Typically + composed inline rather than imported as a standalone component. + </p> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="Pattern" + code={`<Button + variant="purple" + icon="share" + onClick={() => { + if (navigator.share) { + navigator.share({ url, title }) + } else { + navigator.clipboard.writeText(url) + } + }} +> + Share +</Button>`} + /> + </DocSection.Code> + </DocSection> + + {/* AddressLink */} + <DocSection title="AddressLink"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Displays a shortened crypto address as a link. Resolves ENS names for Ethereum addresses. Links + to the user profile page. + </p> + + <DesignNote type="warning"> + AddressLink uses usePrimaryName hook (ENS resolution) which requires JustAName provider context. + Cannot demo in isolation. Showing code example only. + </DesignNote> + + <PropsTable + rows={[ + { + name: 'address', + type: 'string', + default: '-', + required: true, + description: 'Crypto address or ENS name', + }, + { + name: 'isLink', + type: 'boolean', + default: 'true', + description: 'Render as link or plain text', + }, + { name: 'className', type: 'string', default: "''", description: 'Override styles' }, + ]} + /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import AddressLink from '@/components/Global/AddressLink'`} /> + + <CodeBlock + label="Usage" + code={`<AddressLink address="0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18" /> +<AddressLink address={senderAddress} isLink={false} />`} + /> + </DocSection.Code> + </DocSection> + + {/* MoreInfo */} + <DocSection title="MoreInfo"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Info icon that toggles a positioned tooltip on click. Uses HeadlessUI Menu and createPortal for + correct z-indexing. + </p> + + <div className="flex items-center gap-2 rounded-sm border border-n-1 p-3"> + <span className="text-sm">Network fee</span> + <MoreInfo text="This is the gas fee required to process your transaction on the blockchain. It varies based on network congestion." /> + </div> + + <PropsTable + rows={[ + { + name: 'text', + type: 'string | ReactNode', + default: '-', + required: true, + description: 'Tooltip content', + }, + { + name: 'html', + type: 'boolean', + default: 'false', + description: 'Render text as HTML (dangerouslySetInnerHTML)', + }, + ]} + /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import MoreInfo from '@/components/Global/MoreInfo'`} /> + + <CodeBlock + label="Usage" + code={`<span>Network fee</span> +<MoreInfo text="Gas fee for processing the transaction." />`} + /> + </DocSection.Code> + </DocSection> + + <SectionDivider /> + + {/* Design Notes */} + <DocSection title="Design Rules"> + <DesignNote type="info"> + CopyField for displaying + copying full strings (links, codes). CopyToClipboard for inline copy + icons next to existing text. + </DesignNote> + <DesignNote type="info"> + MoreInfo tooltip is portaled to document.body and auto-positions to avoid viewport edges. Preferred + over native title attributes. + </DesignNote> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/patterns/drawer/page.tsx b/src/app/(mobile-ui)/dev/ds/patterns/drawer/page.tsx new file mode 100644 index 000000000..b2eeb3a1d --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/patterns/drawer/page.tsx @@ -0,0 +1,178 @@ +'use client' + +import { Button } from '@/components/0_Bruddle/Button' +import { + Drawer, + DrawerContent, + DrawerTitle, + DrawerTrigger, + DrawerHeader, + DrawerFooter, + DrawerDescription, + DrawerClose, +} from '@/components/Global/Drawer' +import { PropsTable } from '../../_components/PropsTable' +import { DesignNote } from '../../_components/DesignNote' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { SectionDivider } from '../../_components/SectionDivider' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function DrawerPage() { + return ( + <DocPage> + <DocHeader + title="Drawer" + description="Vaul-based bottom sheet with compound component API. Swipe-to-dismiss, snap points, and overlay." + status="production" + /> + + {/* Live Demo + Usage */} + <DocSection title="Live Example"> + <DocSection.Content> + <Drawer> + <DrawerTrigger asChild> + <Button variant="stroke">Open Drawer</Button> + </DrawerTrigger> + <DrawerContent> + <DrawerHeader> + <DrawerTitle>Example Drawer</DrawerTitle> + <DrawerDescription> + This is a vaul-based bottom sheet. Swipe down to dismiss. + </DrawerDescription> + </DrawerHeader> + <div className="px-4 pb-4"> + <p className="text-sm text-grey-1"> + The Drawer component wraps vaul and provides a consistent bottom-sheet experience. + It includes an overlay, drag handle, and max-height constraint (80vh). + </p> + <div className="mt-4"> + <DrawerClose asChild> + <Button variant="purple" shadowSize="4" className="w-full"> + Close Drawer + </Button> + </DrawerClose> + </div> + </div> + </DrawerContent> + </Drawer> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="Import" + code={`import { + Drawer, + DrawerContent, + DrawerTitle, + DrawerTrigger, + DrawerHeader, + DrawerFooter, + DrawerDescription, + DrawerClose, +} from '@/components/Global/Drawer'`} + /> + + <CodeBlock + label="Basic Usage" + code={`<Drawer> + <DrawerTrigger asChild> + <Button variant="stroke">Open</Button> + </DrawerTrigger> + <DrawerContent> + <DrawerHeader> + <DrawerTitle>Title</DrawerTitle> + <DrawerDescription>Description</DrawerDescription> + </DrawerHeader> + <div className="px-4 pb-4"> + {/* Content */} + </div> + <DrawerFooter> + <DrawerClose asChild> + <Button variant="purple" shadowSize="4" className="w-full"> + Done + </Button> + </DrawerClose> + </DrawerFooter> + </DrawerContent> +</Drawer>`} + /> + + <CodeBlock + label="Controlled" + code={`const [open, setOpen] = useState(false) + +<Drawer open={open} onOpenChange={setOpen}> + <DrawerContent> + {/* Content */} + </DrawerContent> +</Drawer>`} + /> + </DocSection.Code> + </DocSection> + + <SectionDivider /> + + {/* Compound Components */} + <DocSection title="Compound Components"> + <PropsTable + rows={[ + { + name: 'Drawer', + type: 'Root', + default: '-', + description: 'Vaul root. Accepts open, onOpenChange, snapPoints, etc.', + }, + { + name: 'DrawerTrigger', + type: 'Trigger', + default: '-', + description: 'Element that opens the drawer. Use asChild.', + }, + { + name: 'DrawerContent', + type: 'Content', + default: '-', + description: 'Panel with overlay, drag handle, max-h-[80vh]', + }, + { + name: 'DrawerHeader', + type: 'Header', + default: '-', + description: 'Grid layout for title area', + }, + { + name: 'DrawerTitle', + type: 'Title', + default: '-', + description: 'Accessible title (required for a11y)', + }, + { name: 'DrawerDescription', type: 'Description', default: '-', description: 'Subtitle text' }, + { name: 'DrawerFooter', type: 'Footer', default: '-', description: 'Bottom area for CTAs' }, + { + name: 'DrawerClose', + type: 'Close', + default: '-', + description: 'Closes the drawer. Use asChild.', + }, + ]} + /> + </DocSection> + + {/* Design Notes */} + <DocSection title="Design Rules"> + <DesignNote type="info"> + Always include a DrawerTitle inside DrawerContent for accessibility (screen readers). + </DesignNote> + <DesignNote type="info"> + Drawer scales the background by default (shouldScaleBackground=true). The drag handle is a 40px wide + rounded bar at the top. + </DesignNote> + <DesignNote type="warning"> + Content is capped at max-h-[80vh] with overflow-auto. For long lists, scrolling works inside the + drawer. + </DesignNote> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/patterns/feedback/page.tsx b/src/app/(mobile-ui)/dev/ds/patterns/feedback/page.tsx new file mode 100644 index 000000000..2a1f73973 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/patterns/feedback/page.tsx @@ -0,0 +1,312 @@ +'use client' + +import StatusBadge, { type StatusType } from '@/components/Global/Badges/StatusBadge' +import StatusPill, { type StatusPillType } from '@/components/Global/StatusPill' +import ErrorAlert from '@/components/Global/ErrorAlert' +import EmptyState from '@/components/Global/EmptyStates/EmptyState' +import NoDataEmptyState from '@/components/Global/EmptyStates/NoDataEmptyState' +import { Button } from '@/components/0_Bruddle/Button' +import { PropsTable } from '../../_components/PropsTable' +import { DesignNote } from '../../_components/DesignNote' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { SectionDivider } from '../../_components/SectionDivider' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +const allStatuses: StatusType[] = [ + 'completed', + 'pending', + 'processing', + 'failed', + 'cancelled', + 'refunded', + 'soon', + 'closed', +] + +export default function FeedbackPage() { + return ( + <DocPage> + <DocHeader + title="Feedback" + description="Status indicators (StatusBadge, StatusPill), error messaging (ErrorAlert), and empty states (EmptyState, NoDataEmptyState)." + status="production" + /> + + {/* StatusBadge */} + <DocSection title="StatusBadge"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Rounded pill badge with text label. Three size variants. Shared StatusType across the codebase. + </p> + + {/* All statuses */} + <div className="space-y-4"> + <p className="text-xs font-bold uppercase tracking-wider text-grey-1">All Status Types</p> + <div className="flex flex-wrap gap-2"> + {allStatuses.map((status) => ( + <StatusBadge key={status} status={status} /> + ))} + </div> + </div> + + {/* Sizes */} + <div className="space-y-4"> + <p className="text-xs font-bold uppercase tracking-wider text-grey-1">Sizes</p> + <div className="flex items-center gap-3"> + {(['small', 'medium', 'large'] as const).map((size) => ( + <div key={size} className="text-center"> + <StatusBadge status="completed" size={size} /> + <p className="mt-1 text-xs text-grey-1">{size}</p> + </div> + ))} + </div> + </div> + + <PropsTable + rows={[ + { + name: 'status', + type: 'StatusType', + default: '-', + required: true, + description: + 'completed | pending | processing | failed | cancelled | refunded | soon | closed | custom', + }, + { name: 'size', type: "'small' | 'medium' | 'large'", default: "'small'" }, + { + name: 'customText', + type: 'string', + default: '(none)', + description: 'Text when status="custom"', + }, + { name: 'className', type: 'string', default: "''", description: 'Override styles' }, + ]} + /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="Import" + code={`import StatusBadge from '@/components/Global/Badges/StatusBadge'`} + /> + + <CodeBlock + label="Usage" + code={`<StatusBadge status="completed" /> +<StatusBadge status="pending" size="medium" /> +<StatusBadge status="custom" customText="Active" />`} + /> + </DocSection.Code> + </DocSection> + + {/* StatusPill */} + <DocSection title="StatusPill"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Tiny 14px circular icon indicator. Uses the same StatusType as StatusBadge (minus + "custom"). Pairs well with list items. + </p> + + <div className="space-y-4"> + <p className="text-xs font-bold uppercase tracking-wider text-grey-1">All Status Types</p> + <div className="flex flex-wrap items-center gap-4"> + {allStatuses + .filter((s): s is StatusPillType => s !== 'custom') + .map((status) => ( + <div key={status} className="flex items-center gap-1.5"> + <StatusPill status={status} /> + <span className="text-xs">{status}</span> + </div> + ))} + </div> + </div> + + <PropsTable + rows={[ + { + name: 'status', + type: 'StatusPillType', + default: '-', + required: true, + description: 'Same as StatusType but excludes "custom"', + }, + ]} + /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import StatusPill from '@/components/Global/StatusPill'`} /> + + <CodeBlock label="Usage" code={`<StatusPill status="completed" />`} /> + </DocSection.Code> + </DocSection> + + {/* ErrorAlert */} + <DocSection title="ErrorAlert"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Inline error message with icon. Red text, left-aligned icon + description. + </p> + + <div className="space-y-2 rounded-sm border border-n-1 p-3"> + <ErrorAlert description="Insufficient balance to complete this transaction." /> + </div> + + <PropsTable + rows={[ + { + name: 'description', + type: 'string', + default: '-', + required: true, + description: 'Error message text', + }, + { + name: 'className', + type: 'string', + default: "''", + description: 'Override container styles', + }, + { name: 'iconSize', type: 'number', default: '16' }, + { + name: 'iconClassName', + type: 'string', + default: "''", + description: 'Override icon styles', + }, + ]} + /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import ErrorAlert from '@/components/Global/ErrorAlert'`} /> + + <CodeBlock + label="Usage" + code={`<ErrorAlert description="Something went wrong. Please try again." />`} + /> + </DocSection.Code> + </DocSection> + + {/* EmptyState */} + <DocSection title="EmptyState"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Card-based empty state with icon, title, description, and optional CTA. Uses Global Card + internally. + </p> + + <div className="space-y-4"> + <EmptyState + icon="wallet" + title="No transactions yet" + description="Your transaction history will appear here." + cta={ + <Button variant="purple" shadowSize="4" size="small" className="mt-2"> + Send Money + </Button> + } + /> + + <EmptyState icon="search" title="No results found" description="Try a different search term." /> + </div> + + <PropsTable + rows={[ + { + name: 'icon', + type: 'IconName', + default: '-', + required: true, + description: 'Icon shown in pink circle', + }, + { name: 'title', type: 'string | ReactNode', default: '-', required: true }, + { name: 'description', type: 'string', default: '(none)' }, + { + name: 'cta', + type: 'ReactNode', + default: '(none)', + description: 'Action button below text', + }, + { + name: 'containerClassName', + type: 'string', + default: "''", + description: 'Override Card container', + }, + ]} + /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="Import" + code={`import EmptyState from '@/components/Global/EmptyStates/EmptyState'`} + /> + + <CodeBlock + label="Usage" + code={`<EmptyState + icon="wallet" + title="No transactions yet" + description="Your history will appear here." + cta={<Button variant="purple" size="small">Send Money</Button>} +/>`} + /> + </DocSection.Code> + </DocSection> + + {/* NoDataEmptyState */} + <DocSection title="NoDataEmptyState"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Branded empty state with crying Peanutman GIF animation. For "no data" scenarios. + </p> + + <div className="rounded-sm border border-n-1 p-4"> + <NoDataEmptyState message="Nothing to show here" /> + </div> + + <PropsTable + rows={[ + { + name: 'message', + type: 'string', + default: '-', + required: true, + description: 'Text below the animation', + }, + { name: 'cta', type: 'ReactNode', default: '(none)', description: 'Action below message' }, + { + name: 'animSize', + type: "'sm' | 'md' | 'lg' | 'xl'", + default: "'sm'", + description: '96 / 128 / 192 / 256 px', + }, + ]} + /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="Import" + code={`import NoDataEmptyState from '@/components/Global/EmptyStates/NoDataEmptyState'`} + /> + + <CodeBlock label="Usage" code={`<NoDataEmptyState message="No links found" animSize="md" />`} /> + </DocSection.Code> + </DocSection> + + <SectionDivider /> + + {/* Design Notes */} + <DocSection title="Design Rules"> + <DesignNote type="info"> + StatusBadge for text labels in tables/lists. StatusPill for compact icon-only indicators next to + items. + </DesignNote> + <DesignNote type="info"> + Use EmptyState (card-based, icon) for structured empty states inside content areas. Use + NoDataEmptyState (Peanutman GIF) for full-section "no data" states. + </DesignNote> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/patterns/layouts/page.tsx b/src/app/(mobile-ui)/dev/ds/patterns/layouts/page.tsx new file mode 100644 index 000000000..32e70b78b --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/patterns/layouts/page.tsx @@ -0,0 +1,289 @@ +'use client' + +import { Icon } from '@/components/Global/Icons/Icon' +import { DesignNote } from '../../_components/DesignNote' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { SectionDivider } from '../../_components/SectionDivider' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function LayoutsPage() { + return ( + <DocPage> + <DocHeader + title="Layouts" + description="Three page layout recipes used across the app. Every screen follows one of these patterns." + status="production" + /> + + {/* Recipe 1: Centered Content + CTA */} + <DocSection title="1. Centered Content + CTA (Most Common)"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Content vertically centered in viewport, CTA button pinned to the bottom. Used for: claim pages, + success states, amount input, confirmations. + </p> + + {/* Wireframe */} + <div className="rounded-sm border border-n-1"> + <div className="flex h-80 flex-col p-3"> + <div className="rounded-sm bg-grey-2/30 px-3 py-1.5"> + <div className="flex items-center gap-1"> + <Icon name="chevron-up" size={12} className="-rotate-90" /> + <span className="text-xs text-grey-1">FlowHeader</span> + </div> + </div> + <div className="flex flex-1 items-center justify-center"> + <div className="space-y-2 text-center"> + <div className="mx-auto h-8 w-8 rounded-full bg-primary-1/30" /> + <div className="text-xs font-bold">Main Content</div> + <div className="text-xs text-grey-1">flex-1 + items-center</div> + </div> + </div> + <div className="rounded-sm bg-purple-1/20 px-3 py-2 text-center"> + <span className="text-xs font-bold">CTA Button</span> + </div> + </div> + </div> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="Pattern 1: Centered Content + CTA" + code={`<div className="flex h-full flex-col"> + <FlowHeader onPrev={handleBack} /> + + {/* Centered content */} + <div className="flex flex-1 items-center justify-center"> + <div className="text-center"> + {/* Icon, title, description */} + </div> + </div> + + {/* Bottom CTA */} + <Button variant="purple" shadowSize="4" className="w-full"> + Continue + </Button> +</div>`} + /> + </DocSection.Code> + </DocSection> + + {/* Recipe 2: Pinned Footer CTA */} + <DocSection title="2. Pinned Footer CTA"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Content flows naturally from top, CTA stays at the very bottom regardless of content height. + Used for: forms, settings, token selection. + </p> + + {/* Wireframe */} + <div className="rounded-sm border border-n-1"> + <div className="flex h-80 flex-col p-3"> + <div className="rounded-sm bg-grey-2/30 px-3 py-1.5"> + <span className="text-xs text-grey-1">NavHeader</span> + </div> + <div className="mt-2 space-y-1.5"> + <div className="rounded-sm bg-primary-3/20 px-3 py-2"> + <span className="text-xs">Form Field 1</span> + </div> + <div className="rounded-sm bg-primary-3/20 px-3 py-2"> + <span className="text-xs">Form Field 2</span> + </div> + <div className="rounded-sm bg-primary-3/20 px-3 py-2"> + <span className="text-xs">Form Field 3</span> + </div> + </div> + <div className="flex-1" /> + <div className="rounded-sm bg-purple-1/20 px-3 py-2 text-center"> + <span className="text-xs font-bold">Submit Button</span> + </div> + </div> + </div> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="Pattern 2: Pinned Footer CTA" + code={`<div className="flex h-full flex-col"> + <NavHeader title="Settings" /> + + {/* Top-aligned content */} + <div className="space-y-3 py-4"> + <BaseInput label="Name" ... /> + <BaseInput label="Email" ... /> + </div> + + {/* Spacer pushes CTA to bottom */} + <div className="flex-1" /> + + {/* Pinned CTA */} + <Button variant="purple" shadowSize="4" className="w-full"> + Save Changes + </Button> +</div>`} + /> + </DocSection.Code> + </DocSection> + + {/* Recipe 3: Scrollable List */} + <DocSection title="3. Scrollable List"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Header + scrollable list area + optional footer. The list scrolls independently while header and + footer remain fixed. Used for: transaction history, token lists, contact lists. + </p> + + {/* Wireframe */} + <div className="rounded-sm border border-n-1"> + <div className="flex h-80 flex-col p-3"> + <div className="rounded-sm bg-grey-2/30 px-3 py-1.5"> + <span className="text-xs text-grey-1">NavHeader + Search/Filter</span> + </div> + <div className="mt-2 flex-1 space-y-1 overflow-hidden"> + {[1, 2, 3, 4, 5, 6].map((i) => ( + <div key={i} className="rounded-sm border border-n-1/20 bg-white px-3 py-2"> + <div className="flex items-center justify-between"> + <span className="text-xs">List Item {i}</span> + <span className="text-xs text-grey-1">detail</span> + </div> + </div> + ))} + <div className="text-center text-xs text-grey-1">overflow-y-auto</div> + </div> + </div> + </div> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="Pattern 3: Scrollable List" + code={`<div className="flex h-full flex-col"> + <NavHeader title="History" /> + + {/* Fixed search bar */} + <div className="py-2"> + <BaseInput placeholder="Search..." /> + </div> + + {/* Scrollable list */} + <div className="flex-1 overflow-y-auto"> + {items.map(item => ( + <Card key={item.id} position={getPosition(index, items.length)}> + {/* Item content */} + </Card> + ))} + </div> +</div>`} + /> + </DocSection.Code> + </DocSection> + + <SectionDivider /> + + {/* Common Mistakes */} + <DocSection title="Common Mistakes"> + <DocSection.Content> + {/* Error callout */} + <div className="space-y-2 rounded-sm border border-error-2 bg-error-1/10 p-3"> + <div className="flex items-center gap-1.5"> + <Icon name="cancel" size={14} className="text-error" /> + <span className="text-xs font-bold text-error">Wrong</span> + </div> + <p className="text-xs text-grey-1"> + Without h-full the flex container collapses to content height. The CTA sits right below + content instead of at the bottom. + </p> + </div> + + {/* Success callout */} + <div className="space-y-2 rounded-sm border border-success-5 bg-success-2/10 p-3"> + <div className="flex items-center gap-1.5"> + <Icon name="success" size={14} className="text-success-4" /> + <span className="text-xs font-bold text-success-4">Correct</span> + </div> + <p className="text-xs text-grey-1"> + h-full ensures the flex column fills the available height from PageContainer. flex-1 on the + content area pushes the CTA to the bottom. + </p> + </div> + + {/* Error callout 2 */} + <div className="space-y-2 rounded-sm border border-error-2 bg-error-1/10 p-3"> + <div className="flex items-center gap-1.5"> + <Icon name="cancel" size={14} className="text-error" /> + <span className="text-xs font-bold text-error">Wrong</span> + </div> + <p className="text-xs text-grey-1"> + overflow-y-auto alone does nothing unless the element has a bounded height. Use flex-1 + inside a flex-col container, or set an explicit max-height. + </p> + </div> + + {/* Success callout 2 */} + <div className="space-y-2 rounded-sm border border-success-5 bg-success-2/10 p-3"> + <div className="flex items-center gap-1.5"> + <Icon name="success" size={14} className="text-success-4" /> + <span className="text-xs font-bold text-success-4">Correct</span> + </div> + <p className="text-xs text-grey-1"> + Inside a flex column with h-full, flex-1 fills remaining space and provides the bounded + height that overflow-y-auto needs to actually scroll. + </p> + </div> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="Wrong: Missing h-full" + code={`{/* Missing h-full on container - CTA won't pin to bottom */} +<div className="flex flex-col"> + <div className="flex-1">Content</div> + <Button>Submit</Button> +</div>`} + /> + + <CodeBlock + label="Correct: With h-full" + code={`{/* h-full makes container fill PageContainer */} +<div className="flex h-full flex-col"> + <div className="flex-1">Content</div> + <Button>Submit</Button> +</div>`} + /> + + <CodeBlock + label="Wrong: Scrollable without bounded height" + code={`{/* Scrollable area without bounded height */} +<div className="overflow-y-auto"> + {items.map(...)} +</div>`} + /> + + <CodeBlock + label="Correct: flex-1 provides bounded height" + code={`{/* flex-1 gives the scroll area a bounded height */} +<div className="flex h-full flex-col"> + <div className="flex-1 overflow-y-auto"> + {items.map(...)} + </div> +</div>`} + /> + </DocSection.Code> + </DocSection> + + {/* Design Notes */} + <DocSection title="Design Rules"> + <DesignNote type="info"> + Every page is wrapped in PageContainer which provides padding and max-width. Your layout div needs + h-full to fill it. + </DesignNote> + <DesignNote type="info"> + The key pattern is always: flex flex-col h-full. Then use flex-1 on the expanding section and let + the CTA sit naturally at the bottom. + </DesignNote> + <DesignNote type="warning"> + Never use absolute/fixed positioning for bottom CTAs. The flex approach handles keyboard open, safe + areas, and content overflow correctly. + </DesignNote> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/patterns/loading/page.tsx b/src/app/(mobile-ui)/dev/ds/patterns/loading/page.tsx new file mode 100644 index 000000000..3929ad9ef --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/patterns/loading/page.tsx @@ -0,0 +1,145 @@ +'use client' + +import Loading from '@/components/Global/Loading' +import PeanutLoading from '@/components/Global/PeanutLoading' +import { PropsTable } from '../../_components/PropsTable' +import { DesignNote } from '../../_components/DesignNote' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { SectionDivider } from '../../_components/SectionDivider' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function LoadingPage() { + return ( + <DocPage> + <DocHeader + title="Loading" + description="CSS spinner (Loading) for inline/button use, and branded Peanut logo spinner (PeanutLoading) for full-page or section loading states." + status="production" + /> + + {/* Loading (CSS Spinner) */} + <DocSection title="Loading (CSS Spinner)"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Minimal CSS-only spinner. Uses border animation. Size controlled via className. + </p> + + <div className="space-y-4"> + <p className="text-xs font-bold uppercase tracking-wider text-grey-1">Sizes</p> + <div className="flex items-end gap-6"> + <div className="text-center"> + <Loading className="h-3 w-3" /> + <p className="mt-2 text-xs text-grey-1">h-3 w-3</p> + </div> + <div className="text-center"> + <Loading /> + <p className="mt-2 text-xs text-grey-1">h-4 w-4 (default)</p> + </div> + <div className="text-center"> + <Loading className="h-6 w-6" /> + <p className="mt-2 text-xs text-grey-1">h-6 w-6</p> + </div> + <div className="text-center"> + <Loading className="h-8 w-8" /> + <p className="mt-2 text-xs text-grey-1">h-8 w-8</p> + </div> + <div className="text-center"> + <Loading className="h-12 w-12" /> + <p className="mt-2 text-xs text-grey-1">h-12 w-12</p> + </div> + </div> + </div> + + <PropsTable + rows={[ + { + name: 'className', + type: 'string', + default: "'h-4 w-4'", + description: 'Controls size via Tailwind width/height', + }, + ]} + /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import Loading from '@/components/Global/Loading'`} /> + + <CodeBlock + label="Usage" + code={`<Loading /> {/* default 16px */} +<Loading className="h-8 w-8" /> {/* 32px */}`} + /> + </DocSection.Code> + </DocSection> + + {/* PeanutLoading */} + <DocSection title="PeanutLoading (Branded)"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Spinning Peanut logo with optional message. Can cover the full screen as an overlay. + </p> + + {/* Inline demo */} + <div className="space-y-4"> + <p className="text-xs font-bold uppercase tracking-wider text-grey-1">Inline</p> + <div className="rounded-sm border border-n-1 p-4"> + <PeanutLoading message="Processing your transaction..." /> + </div> + </div> + + <div className="space-y-4"> + <p className="text-xs font-bold uppercase tracking-wider text-grey-1">Without message</p> + <div className="rounded-sm border border-n-1 p-4"> + <PeanutLoading /> + </div> + </div> + + <PropsTable + rows={[ + { + name: 'coverFullScreen', + type: 'boolean', + default: 'false', + description: 'Fixed overlay covering entire viewport', + }, + { + name: 'message', + type: 'string', + default: '(none)', + description: 'Text shown below the spinner', + }, + ]} + /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import PeanutLoading from '@/components/Global/PeanutLoading'`} /> + + <CodeBlock + label="Usage" + code={`{/* Inline */} +<PeanutLoading message="Loading your wallet..." /> + +{/* Full screen overlay */} +<PeanutLoading coverFullScreen message="Please wait..." />`} + /> + </DocSection.Code> + </DocSection> + + <SectionDivider /> + + {/* Design Notes */} + <DocSection title="Design Rules"> + <DesignNote type="info"> + Use Loading (CSS spinner) inside buttons, inline indicators, and small containers. Use PeanutLoading + for page-level or section-level loading states where brand presence matters. + </DesignNote> + <DesignNote type="warning"> + PeanutLoading with coverFullScreen renders a fixed z-50 overlay. Make sure to conditionally render + it only when loading is active to avoid blocking the UI. + </DesignNote> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/patterns/modal/page.tsx b/src/app/(mobile-ui)/dev/ds/patterns/modal/page.tsx new file mode 100644 index 000000000..e16c79855 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/patterns/modal/page.tsx @@ -0,0 +1,327 @@ +'use client' + +import { useState } from 'react' +import { Button } from '@/components/0_Bruddle/Button' +import Modal from '@/components/Global/Modal' +import ActionModal from '@/components/Global/ActionModal' +import { PropsTable } from '../../_components/PropsTable' +import { DesignNote } from '../../_components/DesignNote' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { SectionDivider } from '../../_components/SectionDivider' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function ModalPage() { + const [showModal, setShowModal] = useState(false) + const [showActionModal, setShowActionModal] = useState(false) + const [actionCheckbox, setActionCheckbox] = useState(false) + + return ( + <DocPage> + <DocHeader + title="Modal" + description="Base Modal for custom dialog content, and ActionModal for standardized confirmation/action dialogs with icon, title, description, CTAs, and optional checkbox." + status="production" + /> + + {/* Base Modal */} + <DocSection title="Base Modal"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + HeadlessUI Dialog wrapper with animated overlay and panel. Use for custom modal content. + </p> + + <div> + <Button variant="stroke" onClick={() => setShowModal(true)}> + Open Base Modal + </Button> + <Modal visible={showModal} onClose={() => setShowModal(false)} title="Example Modal"> + <div className="p-5"> + <p className="text-sm text-grey-1"> + This is the base Modal. It provides the overlay, panel animation, close button, and + optional title bar. You supply the children. + </p> + <div className="mt-4"> + <Button + variant="purple" + shadowSize="4" + className="w-full" + onClick={() => setShowModal(false)} + > + Got it + </Button> + </div> + </div> + </Modal> + </div> + + <PropsTable + rows={[ + { + name: 'visible', + type: 'boolean', + default: '-', + required: true, + description: 'Controls modal visibility', + }, + { + name: 'onClose', + type: '() => void', + default: '-', + required: true, + description: 'Called when overlay or close button clicked', + }, + { + name: 'title', + type: 'string', + default: '(none)', + description: 'Renders title bar with border', + }, + { + name: 'className', + type: 'string', + default: "''", + description: 'Class for the Dialog root', + }, + { name: 'classWrap', type: 'string', default: "''", description: 'Class for Dialog.Panel' }, + { + name: 'classOverlay', + type: 'string', + default: "''", + description: 'Class for the backdrop overlay', + }, + { + name: 'classButtonClose', + type: 'string', + default: "''", + description: 'Class for the close button', + }, + { + name: 'preventClose', + type: 'boolean', + default: 'false', + description: 'Disables closing via overlay click', + }, + { + name: 'hideOverlay', + type: 'boolean', + default: 'false', + description: 'Hides close button and title, renders children directly', + }, + { + name: 'video', + type: 'boolean', + default: 'false', + description: 'Aspect-ratio video mode', + }, + { name: 'children', type: 'ReactNode', default: '-', required: true }, + ]} + /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import Modal from '@/components/Global/Modal'`} /> + + <CodeBlock + label="Usage" + code={`<Modal visible={visible} onClose={() => setVisible(false)} title="Example"> + <div className="p-5"> + {/* Your content */} + </div> +</Modal>`} + /> + </DocSection.Code> + </DocSection> + + {/* ActionModal */} + <DocSection title="ActionModal"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Pre-composed modal with icon, title, description, CTA buttons, and optional checkbox. Built on + top of Base Modal. + </p> + + <div> + <Button variant="stroke" onClick={() => setShowActionModal(true)}> + Open ActionModal + </Button> + <ActionModal + visible={showActionModal} + onClose={() => { + setShowActionModal(false) + setActionCheckbox(false) + }} + title="Confirm Action" + description="Are you sure you want to proceed? This action cannot be undone." + icon="alert" + checkbox={{ + text: 'I understand the consequences', + checked: actionCheckbox, + onChange: setActionCheckbox, + }} + ctas={[ + { + text: 'Cancel', + variant: 'stroke', + onClick: () => { + setShowActionModal(false) + setActionCheckbox(false) + }, + }, + { + text: 'Confirm', + variant: 'purple', + disabled: !actionCheckbox, + onClick: () => { + setShowActionModal(false) + setActionCheckbox(false) + }, + }, + ]} + /> + </div> + + <PropsTable + rows={[ + { name: 'visible', type: 'boolean', default: '-', required: true }, + { name: 'onClose', type: '() => void', default: '-', required: true }, + { name: 'title', type: 'string | ReactNode', default: '-', required: true }, + { + name: 'description', + type: 'string | ReactNode', + default: '(none)', + description: 'Subtitle text', + }, + { + name: 'icon', + type: 'IconName | ReactNode', + default: '(none)', + description: 'Displayed in pink circle above title', + }, + { + name: 'iconProps', + type: 'Partial<IconProps>', + default: '(none)', + description: 'Override icon size/color', + }, + { + name: 'isLoadingIcon', + type: 'boolean', + default: 'false', + description: 'Replace icon with spinner', + }, + { + name: 'ctas', + type: 'ActionModalButtonProps[]', + default: '[]', + description: 'Array of {text, variant, onClick, ...ButtonProps}', + }, + { + name: 'checkbox', + type: 'ActionModalCheckboxProps', + default: '(none)', + description: '{text, checked, onChange}', + }, + { + name: 'preventClose', + type: 'boolean', + default: 'false', + description: 'Block overlay-click dismiss', + }, + { + name: 'hideModalCloseButton', + type: 'boolean', + default: 'false', + description: 'Hides the X button', + }, + { + name: 'content', + type: 'ReactNode', + default: '(none)', + description: 'Custom content between description and CTAs', + }, + { name: 'footer', type: 'ReactNode', default: '(none)', description: 'Content below CTAs' }, + ]} + /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import ActionModal from '@/components/Global/ActionModal'`} /> + + <CodeBlock + label="Usage" + code={`<ActionModal + visible={visible} + onClose={() => setVisible(false)} + title="Confirm Action" + description="Are you sure?" + icon="alert" + checkbox={{ + text: 'I understand', + checked: checked, + onChange: setChecked, + }} + ctas={[ + { text: 'Cancel', variant: 'stroke', onClick: handleCancel }, + { text: 'Confirm', variant: 'purple', onClick: handleConfirm }, + ]} +/>`} + /> + </DocSection.Code> + </DocSection> + + <SectionDivider /> + + {/* Design Notes */} + <DocSection title="Design Rules"> + <DesignNote type="info"> + ActionModal is the preferred pattern for confirmations and simple actions. Use Base Modal only when + you need fully custom content. + </DesignNote> + <DesignNote type="warning"> + ActionModal icon renders in a pink (primary-1) circle by default. Override with + iconContainerClassName if needed. + </DesignNote> + </DocSection> + + {/* Specialized Modals Reference */} + <DocSection title="Specialized Modals (14)"> + <p className="text-sm text-grey-1"> + These are pre-built modals for specific flows. They compose ActionModal or Modal internally. + </p> + <div className="overflow-x-auto rounded-sm border border-n-1 text-xs"> + <table className="w-full"> + <thead> + <tr className="border-b border-n-1 bg-primary-3/20"> + <th className="px-3 py-1.5 text-left font-bold">Component</th> + <th className="px-3 py-1.5 text-left font-bold">Purpose</th> + </tr> + </thead> + <tbody> + {[ + ['InviteFriendsModal', 'Share referral link with copy + social buttons'], + ['ConfirmInviteModal', 'Confirm invitation before sending'], + ['GuestLoginModal', 'Prompt guest users to log in or register'], + ['KycVerifiedOrReviewModal', 'KYC verification status feedback'], + ['BalanceWarningModal', 'Warn about insufficient balance'], + ['TokenAndNetworkConfirmationModal', 'Confirm token + chain before transfer'], + ['TokenSelectorModal', 'Pick token from a list'], + ['ChainSelectorModal', 'Pick blockchain network'], + ['RecipientSelectorModal', 'Pick or enter recipient address'], + ['QRCodeModal', 'Display QR code for sharing'], + ['TransactionStatusModal', 'Show tx pending/success/failed state'], + ['WalletConnectModal', 'Wallet connection flow'], + ['ExportPrivateKeyModal', 'Reveal and copy private key'], + ['ConfirmTransactionModal', 'Final review before transaction submit'], + ].map(([name, purpose]) => ( + <tr key={name} className="border-b border-n-1 last:border-0"> + <td className="px-3 py-1.5 font-mono font-bold">{name}</td> + <td className="px-3 py-1.5">{purpose}</td> + </tr> + ))} + </tbody> + </table> + </div> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/patterns/navigation/page.tsx b/src/app/(mobile-ui)/dev/ds/patterns/navigation/page.tsx new file mode 100644 index 000000000..2905d1f34 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/patterns/navigation/page.tsx @@ -0,0 +1,188 @@ +'use client' + +import { useState } from 'react' +import FlowHeader from '@/components/Global/FlowHeader' +import { Button } from '@/components/0_Bruddle/Button' +import { PropsTable } from '../../_components/PropsTable' +import { DesignNote } from '../../_components/DesignNote' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { SectionDivider } from '../../_components/SectionDivider' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function NavigationPage() { + const [flowStep, setFlowStep] = useState(1) + + return ( + <DocPage> + <DocHeader + title="Navigation" + description="NavHeader for page-level navigation with title and back button. FlowHeader for multi-step flows with optional right element." + status="production" + /> + + {/* NavHeader */} + <DocSection title="NavHeader"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Top navigation bar with back button (link or callback), centered title, and optional logout + button. Uses authContext for logout. + </p> + + <DesignNote type="warning"> + NavHeader uses useAuth() internally for the logout button. It cannot be rendered in isolation + outside of the auth provider. Showing code examples only. + </DesignNote> + + <PropsTable + rows={[ + { name: 'title', type: 'string', default: '(none)', description: 'Centered title text' }, + { + name: 'href', + type: 'string', + default: "'/home'", + description: 'Link destination when no onPrev', + }, + { + name: 'onPrev', + type: '() => void', + default: '(none)', + description: 'Callback replaces Link with Button', + }, + { + name: 'icon', + type: 'IconName', + default: "'chevron-up'", + description: 'Back button icon (rotated -90deg)', + }, + { + name: 'disableBackBtn', + type: 'boolean', + default: 'false', + description: 'Disables the back button', + }, + { + name: 'showLogoutBtn', + type: 'boolean', + default: 'false', + description: 'Shows logout icon button on right', + }, + { + name: 'hideLabel', + type: 'boolean', + default: 'false', + description: 'Hides the title text', + }, + { + name: 'titleClassName', + type: 'string', + default: "''", + description: 'Override title styles', + }, + ]} + /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import NavHeader from '@/components/Global/NavHeader'`} /> + + <CodeBlock label="Link-based (default)" code={`<NavHeader title="Settings" href="/home" />`} /> + + <CodeBlock + label="Callback-based" + code={`<NavHeader title="Edit Profile" onPrev={() => router.back()} />`} + /> + + <CodeBlock label="With logout" code={`<NavHeader title="Account" showLogoutBtn />`} /> + </DocSection.Code> + </DocSection> + + {/* FlowHeader */} + <DocSection title="FlowHeader"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Minimal header for multi-step flows. Back button on the left, optional element on the right. No + title -- the screen content below provides context. + </p> + + {/* Live demo */} + <div className="space-y-2 rounded-sm border border-n-1 p-3"> + <p className="text-xs font-bold uppercase tracking-wider text-grey-1"> + Live Demo (step {flowStep}/3) + </p> + <FlowHeader + onPrev={flowStep > 1 ? () => setFlowStep((s) => s - 1) : undefined} + disableBackBtn={flowStep <= 1} + rightElement={<span className="text-xs text-grey-1">{flowStep}/3</span>} + /> + <div className="flex items-center justify-center rounded-sm bg-primary-3/20 py-8"> + <span className="text-sm font-bold">Step {flowStep} Content</span> + </div> + {flowStep < 3 ? ( + <Button + variant="purple" + shadowSize="4" + className="w-full" + onClick={() => setFlowStep((s) => s + 1)} + > + Next + </Button> + ) : ( + <Button variant="purple" shadowSize="4" className="w-full" onClick={() => setFlowStep(1)}> + Restart + </Button> + )} + </div> + + <PropsTable + rows={[ + { + name: 'onPrev', + type: '() => void', + default: '(none)', + description: 'Back button handler. If omitted, no back button shown.', + }, + { + name: 'disableBackBtn', + type: 'boolean', + default: 'false', + description: 'Grays out the back button', + }, + { + name: 'rightElement', + type: 'ReactNode', + default: '(none)', + description: 'Element rendered on the right (e.g. step indicator)', + }, + ]} + /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import FlowHeader from '@/components/Global/FlowHeader'`} /> + + <CodeBlock + label="Usage" + code={`<FlowHeader + onPrev={() => setStep(step - 1)} + rightElement={<span className="text-xs text-grey-1">2/3</span>} +/>`} + /> + </DocSection.Code> + </DocSection> + + <SectionDivider /> + + {/* Design Notes */} + <DocSection title="Design Rules"> + <DesignNote type="info"> + Use NavHeader for standalone pages (Settings, Profile, etc.). Use FlowHeader for multi-step wizards + (Send, Request, Claim, etc.). + </DesignNote> + <DesignNote type="info"> + Both use a 28px (h-7 w-7) stroke button for the back arrow. This is the standard navigation button + size. + </DesignNote> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/patterns/page.tsx b/src/app/(mobile-ui)/dev/ds/patterns/page.tsx new file mode 100644 index 000000000..023c23901 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/patterns/page.tsx @@ -0,0 +1,90 @@ +import { CatalogCard, CatalogGrid } from '../_components/CatalogCard' +import { DocPage } from '../_components/DocPage' + +export default function PatternsPage() { + return ( + <DocPage> + <div> + <h1 className="text-h3">Patterns</h1> + <p className="mt-1 text-sm text-grey-1"> + Composed components and layout patterns built from primitives and Global shared components. + </p> + </div> + + <CatalogGrid> + <CatalogCard + title="Modal" + description="Base Modal + ActionModal + specialized modals (14 total)" + href="/dev/ds/patterns/modal" + icon="link" + status="production" + quality={4} + /> + <CatalogCard + title="Drawer" + description="Vaul-based bottom sheet with compound component API" + href="/dev/ds/patterns/drawer" + icon="link" + status="production" + quality={5} + /> + <CatalogCard + title="Navigation" + description="NavHeader and FlowHeader for screen navigation" + href="/dev/ds/patterns/navigation" + icon="link" + status="production" + quality={4} + /> + <CatalogCard + title="Loading" + description="CSS spinner (Loading) and branded animation (PeanutLoading)" + href="/dev/ds/patterns/loading" + icon="processing" + status="production" + quality={4} + /> + <CatalogCard + title="Feedback" + description="StatusBadge, StatusPill, ErrorAlert, EmptyState, NoDataEmptyState" + href="/dev/ds/patterns/feedback" + icon="meter" + status="production" + quality={4} + /> + <CatalogCard + title="Copy & Share" + description="CopyField, CopyToClipboard, ShareButton, AddressLink" + href="/dev/ds/patterns/copy-share" + icon="copy" + status="production" + quality={4} + /> + <CatalogCard + title="Layouts" + description="Page layout recipes: centered CTA, pinned footer, scrollable list" + href="/dev/ds/patterns/layouts" + icon="switch" + status="production" + quality={4} + /> + <CatalogCard + title="Cards (Global)" + description="Global Card for stacked lists with position-aware borders" + href="/dev/ds/patterns/cards-global" + icon="docs" + status="production" + quality={4} + /> + <CatalogCard + title="AmountInput" + description="Large currency input with conversion, slider, balance display" + href="/dev/ds/patterns/amount-input" + icon="dollar" + status="needs-refactor" + quality={3} + /> + </CatalogGrid> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/primitives/base-input/page.tsx b/src/app/(mobile-ui)/dev/ds/primitives/base-input/page.tsx new file mode 100644 index 000000000..28ba2c1ae --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/primitives/base-input/page.tsx @@ -0,0 +1,105 @@ +'use client' + +import { useState } from 'react' +import BaseInput from '@/components/0_Bruddle/BaseInput' +import { Playground } from '../../_components/Playground' +import { PropsTable } from '../../_components/PropsTable' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { SectionDivider } from '../../_components/SectionDivider' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function BaseInputPage() { + const [value, setValue] = useState('') + + return ( + <DocPage> + <DocHeader + title="BaseInput" + description="Text input with sm/md/lg size variants and optional right content slot." + status="production" + /> + + <Playground + name="BaseInput" + importPath={`import BaseInput from '@/components/0_Bruddle/BaseInput'`} + defaults={{ variant: 'md', placeholder: 'Enter text...' }} + controls={[ + { type: 'select', prop: 'variant', label: 'variant', options: ['sm', 'md', 'lg'] }, + { type: 'text', prop: 'placeholder', label: 'placeholder', placeholder: 'Placeholder text' }, + { type: 'boolean', prop: 'disabled', label: 'disabled' }, + ]} + render={(props) => ( + <BaseInput + {...props} + className="w-full max-w-xs" + value={value} + onChange={(e) => setValue(e.target.value)} + /> + )} + codeTemplate={(props) => { + const parts = ['<BaseInput'] + if (props.variant && props.variant !== 'md') parts.push(`variant="${props.variant}"`) + if (props.placeholder) parts.push(`placeholder="${props.placeholder}"`) + if (props.disabled) parts.push('disabled') + parts.push('/>') + return parts.join(' ') + }} + /> + + <SectionDivider /> + + <PropsTable + rows={[ + { + name: 'variant', + type: "'sm' | 'md' | 'lg'", + default: "'md'", + description: 'Height: sm=h-10, md=h-16, lg=h-20', + }, + { + name: 'rightContent', + type: 'ReactNode', + default: '(none)', + description: 'Content in the right side of the input', + }, + { name: 'className', type: 'string', default: '(none)' }, + ]} + /> + + <DocSection title="Sizes"> + <DocSection.Content> + <BaseInput variant="sm" placeholder="small (sm)" /> + <BaseInput variant="md" placeholder="medium (md) — default" /> + <BaseInput variant="lg" placeholder="large (lg)" /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import BaseInput from '@/components/0_Bruddle/BaseInput'`} /> + <CodeBlock label="Basic Usage" code={`<BaseInput placeholder="Enter text..." />`} /> + <CodeBlock + label="Size Variants" + code={`<BaseInput variant="sm" placeholder="Small" /> +<BaseInput variant="md" placeholder="Medium" /> +<BaseInput variant="lg" placeholder="Large" />`} + /> + </DocSection.Code> + </DocSection> + + <DocSection title="With Right Content"> + <DocSection.Content> + <BaseInput placeholder="Amount" rightContent={<span className="text-sm text-grey-1">USD</span>} /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="With Right Content" + code={`<BaseInput + placeholder="Amount" + rightContent={<span className="text-sm text-grey-1">USD</span>} +/>`} + /> + </DocSection.Code> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/primitives/base-select/page.tsx b/src/app/(mobile-ui)/dev/ds/primitives/base-select/page.tsx new file mode 100644 index 000000000..5b6b7d5fe --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/primitives/base-select/page.tsx @@ -0,0 +1,83 @@ +'use client' + +import { useState } from 'react' +import BaseSelect from '@/components/0_Bruddle/BaseSelect' +import { PropsTable } from '../../_components/PropsTable' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { SectionDivider } from '../../_components/SectionDivider' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function BaseSelectPage() { + const [value, setValue] = useState('') + + return ( + <DocPage> + <DocHeader + title="BaseSelect" + description="Radix-based dropdown select with error and disabled states." + status="production" + /> + + <SectionDivider /> + + <PropsTable + rows={[ + { name: 'options', type: 'Array<{label, value}>', default: '(required)', required: true }, + { name: 'placeholder', type: 'string', default: "'Select...'" }, + { name: 'value', type: 'string', default: '(none)' }, + { name: 'onValueChange', type: '(value: string) => void', default: '(none)' }, + { name: 'disabled', type: 'boolean', default: 'false' }, + { name: 'error', type: 'boolean', default: 'false' }, + ]} + /> + + <DocSection title="Default"> + <DocSection.Content> + <BaseSelect + options={[ + { label: 'Option 1', value: '1' }, + { label: 'Option 2', value: '2' }, + { label: 'Option 3', value: '3' }, + ]} + placeholder="Select an option" + value={value} + onValueChange={setValue} + /> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import BaseSelect from '@/components/0_Bruddle/BaseSelect'`} /> + <CodeBlock + label="Basic Usage" + code={`<BaseSelect + options={[ + { label: 'Option 1', value: '1' }, + { label: 'Option 2', value: '2' }, + { label: 'Option 3', value: '3' }, + ]} + value={value} + onValueChange={setValue} +/>`} + /> + </DocSection.Code> + </DocSection> + + <DocSection title="States"> + <DocSection.Content> + <div className="flex gap-2"> + <BaseSelect options={[{ label: 'Disabled', value: 'd' }]} placeholder="disabled" disabled /> + <BaseSelect options={[{ label: 'Error', value: 'e' }]} placeholder="error" error /> + </div> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="States" + code={`<BaseSelect options={[...]} disabled /> +<BaseSelect options={[...]} error />`} + /> + </DocSection.Code> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/primitives/button/page.tsx b/src/app/(mobile-ui)/dev/ds/primitives/button/page.tsx new file mode 100644 index 000000000..7044164ec --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/primitives/button/page.tsx @@ -0,0 +1,342 @@ +'use client' + +import { Button } from '@/components/0_Bruddle/Button' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { WhenToUse } from '../../_components/WhenToUse' +import { DoDont } from '../../_components/DoDont' +import { SectionDivider } from '../../_components/SectionDivider' +import { Playground } from '../../_components/Playground' +import { PropsTable } from '../../_components/PropsTable' +import { DesignNote } from '../../_components/DesignNote' +import { StatusTag } from '../../_components/StatusTag' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function ButtonPage() { + return ( + <DocPage> + <DocHeader + title="Button" + description="Primary interaction component. Supports variants, sizes, shadows, icons, loading, and long-press." + status="production" + usages="120+ usages" + /> + + <WhenToUse + use={[ + 'Primary and secondary CTAs in flows', + 'Actions that submit, confirm, or navigate forward', + 'Icon + label combinations for contextual actions (share, copy)', + ]} + dontUse={[ + 'Navigation links — use Next.js Link instead', + 'Toggle states — use Checkbox or Switch', + 'Inline text actions — use underlined text links', + ]} + /> + + <DoDont + doExample={ + <Button variant="purple" shadowSize="4" className="w-full"> + Continue + </Button> + } + doLabel="Default height (no size prop) for primary CTAs" + dontExample={ + <Button variant="purple" size="large" className="w-full"> + Continue + </Button> + } + dontLabel='size="large" is actually shorter (h-10 vs h-13)' + /> + + <SectionDivider /> + + <DocSection title="Interactive Playground"> + <Playground + name="Button" + importPath={`import { Button } from '@/components/0_Bruddle/Button'`} + defaults={{ variant: 'purple', children: 'Continue', shadowSize: '4' }} + controls={[ + { + type: 'select', + prop: 'variant', + label: 'variant', + options: [ + 'purple', + 'stroke', + 'primary-soft', + 'transparent', + 'dark', + 'transparent-dark', + 'transparent-light', + ], + }, + { + type: 'select', + prop: 'size', + label: 'size', + options: ['small', 'medium', 'large'], + }, + { + type: 'select', + prop: 'shadowSize', + label: 'shadowSize', + options: ['3', '4', '6', '8'], + }, + { + type: 'select', + prop: 'icon', + label: 'icon', + options: ['share', 'copy', 'check', 'arrow-up-right', 'plus', 'download'], + }, + { type: 'boolean', prop: 'disabled', label: 'disabled' }, + { type: 'boolean', prop: 'loading', label: 'loading' }, + { type: 'text', prop: 'children', label: 'label', placeholder: 'Button text' }, + ]} + render={(props) => { + const { children, ...rest } = props + return ( + <Button {...rest} className="w-full max-w-xs"> + {children || 'Button'} + </Button> + ) + }} + codeTemplate={(props) => { + const parts = ['<Button'] + if (props.variant && props.variant !== 'purple') parts.push(`variant="${props.variant}"`) + if (props.size) parts.push(`size="${props.size}"`) + if (props.shadowSize) parts.push(`shadowSize="${props.shadowSize}"`) + if (props.icon) parts.push(`icon="${props.icon}"`) + if (props.disabled) parts.push('disabled') + if (props.loading) parts.push('loading') + parts.push(`>${props.children || 'Button'}</Button>`) + return parts.join(' ') + }} + /> + </DocSection> + + <SectionDivider /> + + <DocSection title="Variants" description="Production variants ordered by usage count."> + <DocSection.Content> + <div className="space-y-4"> + {( + [ + ['purple', '59 usages', 'production'], + ['stroke', '27 usages', 'production'], + ['primary-soft', '18 usages', 'production'], + ['transparent', '12 usages', 'production'], + ['dark', '2 usages', 'limited'], + ['transparent-dark', '3 usages', 'limited'], + ] as const + ).map(([variant, count, status]) => ( + <div key={variant}> + <div className="mb-2 flex items-center gap-2"> + <span className="text-sm font-bold">{variant}</span> + <span className="text-xs text-grey-1">{count}</span> + <StatusTag status={status} /> + </div> + <Button variant={variant}>{variant}</Button> + </div> + ))} + <div> + <div className="mb-2 flex items-center gap-2"> + <span className="text-sm font-bold">transparent-light</span> + <span className="text-xs text-grey-1">2 usages</span> + <StatusTag status="limited" /> + </div> + <div className="rounded-sm bg-n-1 p-3"> + <Button variant="transparent-light">transparent-light</Button> + </div> + </div> + </div> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="Variants" + code={`<Button variant="purple">Primary</Button> +<Button variant="stroke">Stroke</Button> +<Button variant="primary-soft">Soft</Button> +<Button variant="transparent">Transparent</Button>`} + /> + </DocSection.Code> + </DocSection> + + <DocSection title="Sizes"> + <DocSection.Content> + <div className="flex flex-wrap items-end gap-4"> + <div className="text-center"> + <Button variant="stroke">default</Button> + <p className="mt-2 text-xs text-grey-1">h-13 (52px)</p> + </div> + <div className="text-center"> + <Button variant="stroke" size="small"> + small + </Button> + <p className="mt-2 text-xs text-grey-1">h-8 · 29 usages</p> + </div> + <div className="text-center"> + <Button variant="stroke" size="medium"> + medium + </Button> + <p className="mt-2 text-xs text-grey-1">h-9 · 10 usages</p> + </div> + <div className="text-center"> + <Button variant="stroke" size="large"> + large + </Button> + <p className="mt-2 text-xs text-grey-1">h-10 · 5 usages</p> + </div> + </div> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="Sizes" + code={`{/* Default: h-13 (tallest) */} +<Button>Default</Button> + +{/* Named sizes are SHORTER */} +<Button size="small">Small (h-8)</Button> +<Button size="medium">Medium (h-9)</Button> +<Button size="large">Large (h-10)</Button>`} + /> + </DocSection.Code> + </DocSection> + + <SectionDivider /> + + <DocSection title="Props"> + <PropsTable + rows={[ + { name: 'variant', type: 'ButtonVariant', default: "'purple'", description: 'Visual style' }, + { + name: 'size', + type: "'small' | 'medium' | 'large'", + default: '(none = h-13)', + description: 'Height override. Default is tallest.', + }, + { name: 'shape', type: "'default' | 'square'", default: "'default'" }, + { + name: 'shadowSize', + type: "'3' | '4' | '6' | '8'", + default: '(none)', + description: "'4' is standard (160+ usages)", + }, + { name: 'shadowType', type: "'primary' | 'secondary'", default: "'primary'" }, + { + name: 'loading', + type: 'boolean', + default: 'false', + description: 'Shows spinner, hides icon', + }, + { name: 'icon', type: 'IconName | ReactNode', default: '(none)' }, + { name: 'iconPosition', type: "'left' | 'right'", default: "'left'" }, + { name: 'iconSize', type: 'number', default: '(auto)' }, + { + name: 'longPress', + type: '{ duration, onLongPress, ... }', + default: '(none)', + description: 'Hold-to-confirm with progress bar', + }, + { name: 'disableHaptics', type: 'boolean', default: 'false' }, + ]} + /> + </DocSection> + + <SectionDivider /> + + <DocSection title="Design Rules"> + <div className="space-y-4"> + <DesignNote type="warning"> + size="large" is h-10 — SHORTER than default h-13. Default is the tallest button. + Primary CTAs should use NO size prop. + </DesignNote> + <DesignNote type="info"> + Primary CTA pattern: variant="purple" shadowSize="4" + className="w-full" — no size prop. + </DesignNote> + </div> + </DocSection> + + <DocSection title="Canonical Patterns"> + <DocSection.Content> + <div className="space-y-6"> + <div> + <p className="text-sm font-bold">Primary CTA (most common)</p> + <Button variant="purple" shadowSize="4" className="mt-2 w-full"> + Continue + </Button> + </div> + <div> + <p className="text-sm font-bold">Secondary CTA</p> + <Button variant="stroke" className="mt-2 w-full"> + Go Back + </Button> + </div> + <div> + <p className="text-sm font-bold">With icon</p> + <div className="mt-2 flex flex-wrap gap-2"> + <Button variant="purple" icon="share"> + Share + </Button> + <Button variant="stroke" icon="copy"> + Copy + </Button> + </div> + </div> + <div> + <p className="text-sm font-bold">States</p> + <div className="mt-2 flex flex-wrap gap-2"> + <Button variant="purple" disabled> + Disabled + </Button> + <Button variant="purple" loading> + Loading + </Button> + </div> + </div> + </div> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import { Button } from '@/components/0_Bruddle/Button'`} /> + <CodeBlock + label="Primary CTA" + code={`<Button variant="purple" shadowSize="4" className="w-full"> + Continue +</Button>`} + /> + <CodeBlock + label="Secondary CTA" + code={`<Button variant="stroke" className="w-full"> + Go Back +</Button>`} + /> + <CodeBlock + label="With icon" + code={`<Button variant="purple" icon="share"> + Share +</Button>`} + /> + <CodeBlock + label="Loading & Disabled" + code={`<Button loading>Loading...</Button> +<Button disabled>Disabled</Button>`} + /> + <CodeBlock + label="Long Press" + code={`<Button + longPress={{ + duration: 2000, + onLongPress: () => handleConfirm(), + }} +> + Hold to confirm +</Button>`} + /> + </DocSection.Code> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/primitives/card/page.tsx b/src/app/(mobile-ui)/dev/ds/primitives/card/page.tsx new file mode 100644 index 000000000..0676a85ec --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/primitives/card/page.tsx @@ -0,0 +1,111 @@ +'use client' + +import { Card } from '@/components/0_Bruddle/Card' +import { Playground } from '../../_components/Playground' +import { PropsTable } from '../../_components/PropsTable' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { SectionDivider } from '../../_components/SectionDivider' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function CardPage() { + return ( + <DocPage> + <DocHeader + title="Card" + description="Standalone container with optional shadow. Compound component with Header, Title, Description, Content sub-components." + status="production" + /> + + <Playground + name="Card" + importPath={`import { Card } from '@/components/0_Bruddle/Card'`} + defaults={{ shadowSize: '4' }} + controls={[ + { type: 'select', prop: 'shadowSize', label: 'shadowSize', options: ['4', '6', '8'] }, + { type: 'select', prop: 'color', label: 'color', options: ['primary', 'secondary'] }, + ]} + render={(props) => ( + <Card {...props} className="w-full max-w-xs p-4"> + <Card.Header> + <Card.Title>Card Title</Card.Title> + <Card.Description>A description of the card content</Card.Description> + </Card.Header> + <Card.Content> + <p className="text-sm">Body content goes here</p> + </Card.Content> + </Card> + )} + codeTemplate={(props) => { + const parts = ['<Card'] + if (props.shadowSize) parts.push(`shadowSize="${props.shadowSize}"`) + if (props.color && props.color !== 'primary') parts.push(`color="${props.color}"`) + parts.push('className="p-4">') + return ( + parts.join(' ') + + '\n <Card.Header>\n <Card.Title>Title</Card.Title>\n <Card.Description>Description</Card.Description>\n </Card.Header>\n <Card.Content>Content</Card.Content>\n</Card>' + ) + }} + /> + + <SectionDivider /> + + <PropsTable + rows={[ + { name: 'shadowSize', type: "'4' | '6' | '8'", default: '(none)' }, + { name: 'color', type: "'primary' | 'secondary'", default: "'primary'" }, + { name: 'className', type: 'string', default: '(none)' }, + ]} + /> + + <DocSection title="Shadow Variants"> + <DocSection.Content> + <div className="space-y-3"> + <Card className="p-4"> + <p className="text-sm">No shadow</p> + </Card> + <Card shadowSize="4" className="p-4"> + <p className="text-sm">shadowSize="4"</p> + </Card> + <Card shadowSize="6" className="p-4"> + <p className="text-sm">shadowSize="6"</p> + </Card> + <Card shadowSize="8" className="p-4"> + <p className="text-sm">shadowSize="8"</p> + </Card> + </div> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import { Card } from '@/components/0_Bruddle/Card'`} /> + </DocSection.Code> + </DocSection> + + <DocSection title="With Sub-components"> + <DocSection.Content> + <Card shadowSize="4" className="p-4"> + <Card.Header> + <Card.Title>Card Title</Card.Title> + <Card.Description>description text</Card.Description> + </Card.Header> + <Card.Content> + <p className="text-sm">body content</p> + </Card.Content> + </Card> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="Sub-components Example" + code={`<Card shadowSize="4" className="p-4"> + <Card.Header> + <Card.Title>Title</Card.Title> + <Card.Description>Description</Card.Description> + </Card.Header> + <Card.Content>Content</Card.Content> +</Card>`} + /> + </DocSection.Code> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/primitives/checkbox/page.tsx b/src/app/(mobile-ui)/dev/ds/primitives/checkbox/page.tsx new file mode 100644 index 000000000..07ca12c08 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/primitives/checkbox/page.tsx @@ -0,0 +1,57 @@ +'use client' + +import { useState } from 'react' +import Checkbox from '@/components/0_Bruddle/Checkbox' +import { PropsTable } from '../../_components/PropsTable' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { SectionDivider } from '../../_components/SectionDivider' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function CheckboxPage() { + const [checked, setChecked] = useState(false) + + return ( + <DocPage> + <DocHeader title="Checkbox" description="Simple checkbox with optional label." status="production" /> + + <SectionDivider /> + + <PropsTable + rows={[ + { name: 'value', type: 'boolean', default: '(required)', required: true }, + { name: 'onChange', type: '(e: ChangeEvent) => void', default: '(required)', required: true }, + { name: 'label', type: 'string', default: '(none)' }, + ]} + /> + + <DocSection title="Examples"> + <DocSection.Content> + <Checkbox + label="I agree to the terms" + value={checked} + onChange={(e) => setChecked(e.target.checked)} + /> + + <div> + <Checkbox value={!checked} onChange={() => {}} /> + <p className="text-xs text-grey-1">Without label</p> + </div> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import Checkbox from '@/components/0_Bruddle/Checkbox'`} /> + <CodeBlock + label="With Label" + code={`<Checkbox + label="I agree to the terms" + value={checked} + onChange={(e) => setChecked(e.target.checked)} +/>`} + /> + <CodeBlock label="Without Label" code={`<Checkbox value={checked} onChange={() => {}} />`} /> + </DocSection.Code> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/primitives/divider/page.tsx b/src/app/(mobile-ui)/dev/ds/primitives/divider/page.tsx new file mode 100644 index 000000000..fd1c7b495 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/primitives/divider/page.tsx @@ -0,0 +1,47 @@ +'use client' + +import Divider from '@/components/0_Bruddle/Divider' +import { PropsTable } from '../../_components/PropsTable' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { SectionDivider } from '../../_components/SectionDivider' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function DividerPage() { + return ( + <DocPage> + <DocHeader title="Divider" description="Horizontal divider with optional text label." status="production" /> + + <SectionDivider /> + + <PropsTable + rows={[ + { name: 'text', type: 'string', default: '(none)', description: 'Center text label' }, + { name: 'dividerClassname', type: 'string', default: '(none)' }, + { name: 'textClassname', type: 'string', default: '(none)' }, + ]} + /> + + <DocSection title="Examples"> + <DocSection.Content> + <div className="space-y-6"> + <div> + <p className="mb-2 text-sm text-grey-1">Default</p> + <Divider /> + </div> + <div> + <p className="mb-2 text-sm text-grey-1">With text</p> + <Divider text="or" /> + </div> + </div> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import Divider from '@/components/0_Bruddle/Divider'`} /> + <CodeBlock label="Default" code={`<Divider />`} /> + <CodeBlock label="With Text" code={`<Divider text="or" />`} /> + </DocSection.Code> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/primitives/page-container/page.tsx b/src/app/(mobile-ui)/dev/ds/primitives/page-container/page.tsx new file mode 100644 index 000000000..669fe696d --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/primitives/page-container/page.tsx @@ -0,0 +1,52 @@ +'use client' + +import { PropsTable } from '../../_components/PropsTable' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { SectionDivider } from '../../_components/SectionDivider' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function PageContainerPage() { + return ( + <DocPage> + <DocHeader + title="PageContainer" + description="Responsive page wrapper with max-width centering. On desktop, applies left padding for sidebar offset." + status="production" + /> + + <SectionDivider /> + + <PropsTable rows={[{ name: 'alignItems', type: "'start' | 'center'", default: "'start'" }]} /> + + <DocSection title="Usage"> + <DocSection.Content> + <p className="text-sm text-grey-1"> + Wraps mobile screens with responsive width constraints. Children inherit full width via the{' '} + <code className="font-mono">*:w-full</code> selector. On desktop (md+), content is offset with{' '} + <code className="font-mono">md:pl-24</code> and capped at{' '} + <code className="font-mono">md:*:max-w-xl</code>. + </p> + </DocSection.Content> + <DocSection.Code> + <CodeBlock + label="Import" + code={`import PageContainer from '@/components/0_Bruddle/PageContainer'`} + /> + <CodeBlock + label="Usage" + code={`<PageContainer> + <div className="flex min-h-[inherit] flex-col gap-8"> + <NavHeader title="Title" /> + <div className="my-auto flex flex-col gap-6"> + {/* content */} + </div> + </div> +</PageContainer>`} + /> + </DocSection.Code> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/primitives/page.tsx b/src/app/(mobile-ui)/dev/ds/primitives/page.tsx new file mode 100644 index 000000000..224b1c9c3 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/primitives/page.tsx @@ -0,0 +1,89 @@ +import { CatalogCard, CatalogGrid } from '../_components/CatalogCard' +import { DocPage } from '../_components/DocPage' + +export default function PrimitivesPage() { + return ( + <DocPage> + <div> + <h1 className="text-h3">Primitives</h1> + <p className="mt-1 text-sm text-grey-1"> + Bruddle base components. The lowest-level building blocks of the UI. + </p> + </div> + + <CatalogGrid> + <CatalogCard + title="Button" + description="Primary interaction component. 7 variants, 3 sizes, shadow options, long-press support" + href="/dev/ds/primitives/button" + icon="switch" + status="production" + quality={4} + usages={120} + /> + <CatalogCard + title="Card" + description="Container with optional shadow. Compound component with Header, Title, Description, Content" + href="/dev/ds/primitives/card" + icon="docs" + status="production" + quality={4} + /> + <CatalogCard + title="BaseInput" + description="Text input with sm/md/lg variants and optional right content slot" + href="/dev/ds/primitives/base-input" + icon="clip" + status="production" + quality={3} + /> + <CatalogCard + title="BaseSelect" + description="Radix-based dropdown select with error and disabled states" + href="/dev/ds/primitives/base-select" + icon="clip" + status="production" + quality={4} + /> + <CatalogCard + title="Checkbox" + description="Simple checkbox with optional label" + href="/dev/ds/primitives/checkbox" + icon="check" + status="production" + quality={3} + /> + <CatalogCard + title="Toast" + description="Context-based toast notification system. 4 types, auto-dismiss" + href="/dev/ds/primitives/toast" + icon="bell" + status="production" + quality={5} + /> + <CatalogCard + title="Divider" + description="Horizontal divider with optional text label" + href="/dev/ds/primitives/divider" + icon="minus-circle" + status="production" + /> + <CatalogCard + title="Title" + description="Knerd display font with filled/outline double-render effect" + href="/dev/ds/primitives/title" + icon="docs" + status="production" + quality={3} + /> + <CatalogCard + title="PageContainer" + description="Responsive page wrapper with max-width and alignment options" + href="/dev/ds/primitives/page-container" + icon="docs" + status="production" + /> + </CatalogGrid> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/primitives/title/page.tsx b/src/app/(mobile-ui)/dev/ds/primitives/title/page.tsx new file mode 100644 index 000000000..c891baf94 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/primitives/title/page.tsx @@ -0,0 +1,56 @@ +'use client' + +import Title from '@/components/0_Bruddle/Title' +import { PropsTable } from '../../_components/PropsTable' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { SectionDivider } from '../../_components/SectionDivider' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function TitlePage() { + return ( + <DocPage> + <DocHeader + title="Title" + description="Knerd display font with filled + outline double-render for drop shadow effect." + status="production" + /> + + <SectionDivider /> + + <PropsTable + rows={[ + { name: 'text', type: 'string', default: '(required)', required: true }, + { + name: 'offset', + type: 'boolean', + default: 'true', + description: 'Horizontal offset for shadow effect', + }, + ]} + /> + + <DocSection title="Examples"> + <DocSection.Content> + <div className="rounded-sm bg-purple-1 p-4"> + <Title text="PEANUT" /> + </div> + + <div className="rounded-sm bg-purple-1 p-4"> + <Title text="NO OFFSET" offset={false} /> + </div> + + <div className="rounded-sm bg-yellow-1 p-4"> + <Title text="ON YELLOW" /> + </div> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import Title from '@/components/0_Bruddle/Title'`} /> + <CodeBlock label="Default" code={`<Title text="PEANUT" />`} /> + <CodeBlock label="Without Offset" code={`<Title text="NO OFFSET" offset={false} />`} /> + </DocSection.Code> + </DocSection> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/ds/primitives/toast/page.tsx b/src/app/(mobile-ui)/dev/ds/primitives/toast/page.tsx new file mode 100644 index 000000000..dc280dc89 --- /dev/null +++ b/src/app/(mobile-ui)/dev/ds/primitives/toast/page.tsx @@ -0,0 +1,75 @@ +'use client' + +import { Button } from '@/components/0_Bruddle/Button' +import { useToast } from '@/components/0_Bruddle/Toast' +import { PropsTable } from '../../_components/PropsTable' +import { DocHeader } from '../../_components/DocHeader' +import { DocSection } from '../../_components/DocSection' +import { SectionDivider } from '../../_components/SectionDivider' +import { DocPage } from '../../_components/DocPage' +import { CodeBlock } from '../../_components/CodeBlock' + +export default function ToastPage() { + const { success, error, info, warning } = useToast() + + return ( + <DocPage> + <DocHeader + title="Toast" + description="Context-based toast notification system. 4 types, auto-dismiss, clean API." + status="production" + /> + + <DocSection title="Interactive Demo" description="Tap each button to trigger a toast notification."> + <DocSection.Content> + <div className="flex flex-wrap gap-2"> + <Button variant="stroke" size="small" onClick={() => success('Operation successful!')}> + success + </Button> + <Button variant="stroke" size="small" onClick={() => error('Something went wrong')}> + error + </Button> + <Button variant="stroke" size="small" onClick={() => info('Did you know?')}> + info + </Button> + <Button variant="stroke" size="small" onClick={() => warning('Check this out')}> + warning + </Button> + </div> + </DocSection.Content> + <DocSection.Code> + <CodeBlock label="Import" code={`import { useToast } from '@/components/0_Bruddle/Toast'`} /> + <CodeBlock label="Hook Usage" code={`const { success, error, info, warning } = useToast()`} /> + <CodeBlock + label="Trigger Toasts" + code={`success('Done!') +error('Failed!') +info('FYI...') +warning('Be careful!')`} + /> + </DocSection.Code> + </DocSection> + + <SectionDivider /> + + <PropsTable + rows={[ + { + name: 'message', + type: 'string', + default: '(required)', + required: true, + description: 'Toast message text', + }, + { + name: 'type', + type: "'success' | 'error' | 'info' | 'warning'", + default: '(method)', + description: 'Determined by which method you call', + }, + { name: 'duration', type: 'number', default: '3000', description: 'Auto-dismiss duration in ms' }, + ]} + /> + </DocPage> + ) +} diff --git a/src/app/(mobile-ui)/dev/page.tsx b/src/app/(mobile-ui)/dev/page.tsx index 446ab6677..e2f74bb67 100644 --- a/src/app/(mobile-ui)/dev/page.tsx +++ b/src/app/(mobile-ui)/dev/page.tsx @@ -27,28 +27,10 @@ export default function DevToolsPage() { icon: 'dollar', }, { - name: 'Shake Test', - description: 'Test progressive shake animation and confetti for perk claiming', - path: '/dev/shake-test', - icon: 'bulb', - }, - { - name: 'Gift Test', - description: 'Test gift box unwrap animations and variants', - path: '/dev/gift-test', - icon: 'gift', - }, - { - name: 'Perk Success Test', - description: 'Test the perk claim success screen with mock perks', - path: '/dev/perk-success-test', - icon: 'check-circle', - }, - { - name: 'Components', - description: 'Design system showcase: buttons, cards, inputs, and all variants', - path: '/dev/components', - icon: 'bulb', + name: 'Design System', + description: 'Foundations, primitives, patterns, and interactive playground', + path: '/dev/ds', + icon: 'docs', }, ] diff --git a/src/app/(mobile-ui)/home/page.tsx b/src/app/(mobile-ui)/home/page.tsx index 51a3b1531..bdcca9036 100644 --- a/src/app/(mobile-ui)/home/page.tsx +++ b/src/app/(mobile-ui)/home/page.tsx @@ -67,7 +67,11 @@ export default function Home() { const { isFetchingUser, fetchUser } = useAuth() const { isUserKycApproved } = useKycStatus() - const { hasPurchased: hasCardPioneerPurchased } = useCardPioneerInfo() + const { + hasPurchased: hasCardPioneerPurchased, + isLoading: isCardInfoLoading, + error: cardInfoError, + } = useCardPioneerInfo() const username = user?.user.username const [showBalanceWarningModal, setShowBalanceWarningModal] = useState(false) @@ -273,8 +277,10 @@ export default function Home() { {/* Card Pioneer Modal - Show to all users who haven't purchased */} {/* Eligibility check happens during the flow (geo screen), not here */} - {/* Only shows if no higher-priority modals are active */} + {/* Only shows if no higher-priority modals are active and card info loaded successfully */} {!underMaintenanceConfig.disableCardPioneers && + !isCardInfoLoading && + !cardInfoError && !showBalanceWarningModal && !showPermissionModal && !showKycModal && diff --git a/src/app/(mobile-ui)/points/invites/page.tsx b/src/app/(mobile-ui)/points/invites/page.tsx index ee1a36597..3a543e76f 100644 --- a/src/app/(mobile-ui)/points/invites/page.tsx +++ b/src/app/(mobile-ui)/points/invites/page.tsx @@ -16,11 +16,17 @@ import Image from 'next/image' import EmptyState from '@/components/Global/EmptyStates/EmptyState' import { getInitialsFromName } from '@/utils/general.utils' import { type PointsInvite } from '@/services/services.types' -import { TRANSITIVITY_MULTIPLIER } from '@/constants/points.consts' +import { formatPoints } from '@/utils/format.utils' +import { useCountUp } from '@/hooks/useCountUp' +import { useInView } from 'framer-motion' +import { useRef } from 'react' +import InviteePointsBadge from '@/components/Points/InviteePointsBadge' const InvitesPage = () => { const router = useRouter() const { user } = useAuth() + const listRef = useRef(null) + const listInView = useInView(listRef, { once: true, margin: '-50px' }) const { data: invites, @@ -33,6 +39,17 @@ const InvitesPage = () => { enabled: !!user?.user.userId, }) + const totalPointsEarned = + invites?.invitees?.reduce((sum: number, invite: PointsInvite) => { + return sum + (invite.contributedPoints ?? 0) + }, 0) || 0 + + const animatedTotal = useCountUp(totalPointsEarned, { + storageKey: 'invites_total', + duration: 1.8, + enabled: !isLoading && !isError, + }) + if (isLoading) { return <PeanutLoading /> } @@ -46,12 +63,6 @@ const InvitesPage = () => { ) } - // Calculate total points earned (50% of each invitee's points) - const totalPointsEarned = - invites?.invitees?.reduce((sum: number, invite: PointsInvite) => { - return sum + Math.floor(invite.totalPoints * TRANSITIVITY_MULTIPLIER) - }, 0) || 0 - return ( <PageContainer className="flex flex-col"> <NavHeader title="Points" onPrev={() => router.back()} /> @@ -63,7 +74,7 @@ const InvitesPage = () => { <span className="flex items-center gap-2"> <Image src={STAR_STRAIGHT_ICON} alt="star" width={20} height={20} /> <span className="text-3xl font-extrabold text-black"> - {totalPointsEarned} {totalPointsEarned === 1 ? 'Point' : 'Points'} + {formatPoints(animatedTotal)} {totalPointsEarned === 1 ? 'Point' : 'Points'} </span> </span> </Card> @@ -71,12 +82,12 @@ const InvitesPage = () => { <h2 className="font-bold">People you invited</h2> {/* Full list */} - <div> + <div ref={listRef}> {invites?.invitees?.map((invite: PointsInvite, i: number) => { const username = invite.username const fullName = invite.fullName const isVerified = invite.kycStatus === 'approved' - const pointsEarned = Math.floor(invite.totalPoints * TRANSITIVITY_MULTIPLIER) + const pointsEarned = invite.contributedPoints ?? 0 // respect user's showFullName preference for avatar and display name const displayName = invite.showFullName && fullName ? fullName : username return ( @@ -104,9 +115,7 @@ const InvitesPage = () => { isVerified={isVerified} /> </div> - <p className="text-grey-1"> - +{pointsEarned} {pointsEarned === 1 ? 'pt' : 'pts'} - </p> + <InviteePointsBadge points={pointsEarned} inView={listInView} /> </div> </Card> ) diff --git a/src/app/(mobile-ui)/points/page.tsx b/src/app/(mobile-ui)/points/page.tsx index dd1c38605..7690531a5 100644 --- a/src/app/(mobile-ui)/points/page.tsx +++ b/src/app/(mobile-ui)/points/page.tsx @@ -19,17 +19,22 @@ import Image from 'next/image' import { pointsApi } from '@/services/points' import EmptyState from '@/components/Global/EmptyStates/EmptyState' import { type PointsInvite } from '@/services/services.types' -import { useEffect, useState } from 'react' +import { useEffect, useRef, useState } from 'react' import InvitesGraph from '@/components/Global/InvitesGraph' import { CashCard } from '@/components/Points/CashCard' -import { TRANSITIVITY_MULTIPLIER } from '@/constants/points.consts' import InviteFriendsModal from '@/components/Global/InviteFriendsModal' +import { formatPoints, shortenPoints } from '@/utils/format.utils' import { Button } from '@/components/0_Bruddle/Button' +import { useCountUp } from '@/hooks/useCountUp' +import { useInView } from 'framer-motion' +import InviteePointsBadge from '@/components/Points/InviteePointsBadge' const PointsPage = () => { const router = useRouter() const { user, fetchUser } = useAuth() const [isInviteModalOpen, setIsInviteModalOpen] = useState(false) + const inviteesRef = useRef(null) + const inviteesInView = useInView(inviteesRef, { once: true, margin: '-50px' }) const getTierBadge = (tier: number) => { const badges = [TIER_0_BADGE, TIER_1_BADGE, TIER_2_BADGE, TIER_3_BADGE] @@ -73,8 +78,15 @@ const PointsPage = () => { const username = user?.user.username + // animated hero points — remembers last-seen value across visits + const animatedTotal = useCountUp(tierInfo?.data?.totalPoints ?? 0, { + storageKey: 'hero_total', + duration: 1.8, + enabled: !!tierInfo?.data, + }) + useEffect(() => { - // Re-fetch user to get the latest invitees list for showing heart Icon + // re-fetch user to get the latest invitees list for showing heart icon fetchUser() }, []) @@ -103,7 +115,16 @@ const PointsPage = () => { <div className="flex items-center justify-center gap-2"> <Image src={STAR_STRAIGHT_ICON} alt="star" width={24} height={24} /> <h2 className="text-4xl font-black text-black"> - {tierInfo.data.totalPoints} {tierInfo.data.totalPoints === 1 ? 'Point' : 'Points'} + {(() => { + const { number, suffix } = shortenPoints(animatedTotal) + return ( + <> + {number} + {suffix && <span className="text-primary-1">{suffix}</span>} + </> + ) + })()}{' '} + {tierInfo.data.totalPoints === 1 ? 'Point' : 'Points'} </h2> </div> @@ -148,7 +169,7 @@ const PointsPage = () => { </div> {tierInfo?.data.currentTier < 2 && ( <p className="text-center text-sm text-grey-1"> - {tierInfo.data.pointsToNextTier}{' '} + {formatPoints(tierInfo.data.pointsToNextTier)}{' '} {tierInfo.data.pointsToNextTier === 1 ? 'point' : 'points'} to next tier </p> )} @@ -157,7 +178,7 @@ const PointsPage = () => { {/* cash section */} {cashStatus?.success && cashStatus.data && ( <CashCard - cashbackAllowance={cashStatus.data.cashbackAllowance} + hasCashbackLeft={cashStatus.data.hasCashbackLeft} lifetimeEarned={cashStatus.data.lifetimeEarned} /> )} @@ -187,7 +208,7 @@ const PointsPage = () => { invited you.{' '} </> )} - You earn rewards whenever friends you invite use Peanut! + <br></br>You earn rewards whenever your friends use Peanut! </p> </> )} @@ -213,12 +234,12 @@ const PointsPage = () => { <NavigationArrow className="text-black" /> </div> - <div> + <div ref={inviteesRef}> {invites.invitees?.slice(0, 5).map((invite: PointsInvite, i: number) => { const username = invite.username const fullName = invite.fullName const isVerified = invite.kycStatus === 'approved' - const pointsEarned = Math.floor(invite.totalPoints * TRANSITIVITY_MULTIPLIER) + const pointsEarned = invite.contributedPoints ?? 0 // respect user's showFullName preference for avatar and display name const displayName = invite.showFullName && fullName ? fullName : username return ( @@ -246,9 +267,7 @@ const PointsPage = () => { isVerified={isVerified} /> </div> - <p className="text-grey-1"> - +{pointsEarned} {pointsEarned === 1 ? 'pt' : 'pts'} - </p> + <InviteePointsBadge points={pointsEarned} inView={inviteesInView} /> </div> </Card> ) diff --git a/src/app/(mobile-ui)/qr-pay/page.tsx b/src/app/(mobile-ui)/qr-pay/page.tsx index 2826a8aeb..822041491 100644 --- a/src/app/(mobile-ui)/qr-pay/page.tsx +++ b/src/app/(mobile-ui)/qr-pay/page.tsx @@ -1274,7 +1274,13 @@ export default function QRPayPage() { <h2 className="text-2xl font-bold">Peanut got you!</h2> <p className="text-base text-gray-900"> {(() => { - const percentage = qrPayment?.perk?.discountPercentage || 100 + const amountSponsored = qrPayment?.perk?.amountSponsored + const transactionUsd = + parseFloat(qrPayment?.details?.paymentAgainstAmount || '0') || 0 + const percentage = + amountSponsored && transactionUsd > 0 + ? Math.round((amountSponsored / transactionUsd) * 100) + : qrPayment?.perk?.discountPercentage || 100 if (percentage === 100) { return 'We paid for this bill! Earn points, climb tiers and unlock even better perks.' } else if (percentage > 100) { diff --git a/src/app/(mobile-ui)/support/layout.tsx b/src/app/(mobile-ui)/support/layout.tsx deleted file mode 100644 index 38ebb96c1..000000000 --- a/src/app/(mobile-ui)/support/layout.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react' - -import { generateMetadata } from '@/app/metadata' - -export const metadata = generateMetadata({ - title: 'Support | Peanut - Instant Global P2P Payments', - description: - 'Get help and support for Peanut. Find answers to your questions about our P2P digital dollar payment app for fast, global transfers.', -}) - -export default function SupportLayout({ children }: { children: React.ReactNode }) { - return children -} diff --git a/src/app/(mobile-ui)/support/page.tsx b/src/app/(mobile-ui)/support/page.tsx deleted file mode 100644 index 5b5d2448f..000000000 --- a/src/app/(mobile-ui)/support/page.tsx +++ /dev/null @@ -1,45 +0,0 @@ -'use client' - -import { useState, useEffect } from 'react' -import { useCrispUserData } from '@/hooks/useCrispUserData' -import { useCrispProxyUrl } from '@/hooks/useCrispProxyUrl' -import PeanutLoading from '@/components/Global/PeanutLoading' - -const SupportPage = () => { - const userData = useCrispUserData() - const crispProxyUrl = useCrispProxyUrl(userData) - const [isLoading, setIsLoading] = useState(true) - - useEffect(() => { - // Listen for ready message from proxy iframe - const handleMessage = (event: MessageEvent) => { - if (event.origin !== window.location.origin) return - - if (event.data.type === 'CRISP_READY') { - setIsLoading(false) - } - } - - window.addEventListener('message', handleMessage) - return () => window.removeEventListener('message', handleMessage) - }, []) - - return ( - <div className="relative h-full w-full md:max-w-[90%] md:pl-24"> - {isLoading && ( - <div className="absolute inset-0 z-10 flex items-center justify-center bg-background"> - <PeanutLoading /> - </div> - )} - <iframe - src={crispProxyUrl} - className="h-full w-full" - allow="storage-access *" - sandbox="allow-same-origin allow-scripts allow-popups allow-forms allow-modals allow-storage-access-by-user-activation" - title="Support Chat" - /> - </div> - ) -} - -export default SupportPage diff --git a/src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx b/src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx index 166f45d07..295994292 100644 --- a/src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx +++ b/src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx @@ -77,6 +77,9 @@ export default function WithdrawBankPage() { ) useEffect(() => { + // Skip redirects when on success view — clearing state during navigation + // would race with router.push('/home') and redirect back to /withdraw + if (view === 'SUCCESS') return if (!amountToWithdraw) { // If no amount, go back to main page router.replace('/withdraw') @@ -84,7 +87,7 @@ export default function WithdrawBankPage() { // If amount is set but no bank account, go to country method selection router.replace(`/withdraw/${country}`) } - }, [bankAccount, router, amountToWithdraw, country]) + }, [bankAccount, router, amountToWithdraw, country, view]) const destinationDetails = (account: Account) => { let countryId: string @@ -264,11 +267,15 @@ export default function WithdrawBankPage() { title={fromSendFlow ? 'Send' : 'Withdraw'} icon={view === 'SUCCESS' ? 'cancel' : undefined} onPrev={() => { - setAmountToWithdraw('') - setSelectedMethod(null) if (view === 'SUCCESS') { + // Navigate first, then reset — otherwise clearing amountToWithdraw + // triggers the useEffect redirect to /withdraw, overriding /home router.push('/home') + setAmountToWithdraw('') + setSelectedMethod(null) } else { + setAmountToWithdraw('') + setSelectedMethod(null) router.back() } }} @@ -374,6 +381,10 @@ export default function WithdrawBankPage() { currencyAmount={`$${amountToWithdraw}`} message={bankAccount ? shortenStringLong(bankAccount.identifier.toUpperCase()) : ''} points={pointsData?.estimatedPoints} + onComplete={() => { + setAmountToWithdraw('') + setSelectedMethod(null) + }} /> )} </div> diff --git a/src/app/(mobile-ui)/withdraw/crypto/page.tsx b/src/app/(mobile-ui)/withdraw/crypto/page.tsx index ad58fbc39..d97db5f86 100644 --- a/src/app/(mobile-ui)/withdraw/crypto/page.tsx +++ b/src/app/(mobile-ui)/withdraw/crypto/page.tsx @@ -382,8 +382,10 @@ export default function WithdrawCryptoPage() { return 0 }, [xChainRoute]) - if (!amountToWithdraw) { + if (!amountToWithdraw && currentView !== 'STATUS') { // Redirect to main withdraw page for amount input + // Guard against STATUS view: resetWithdrawFlow() clears amountToWithdraw, + // which would override the router.push('/home') in handleDone router.push('/withdraw') return <PeanutLoading /> } diff --git a/src/app/[locale]/(marketing)/[country]/page.tsx b/src/app/[locale]/(marketing)/[country]/page.tsx new file mode 100644 index 000000000..a2daeda93 --- /dev/null +++ b/src/app/[locale]/(marketing)/[country]/page.tsx @@ -0,0 +1,70 @@ +import { notFound } from 'next/navigation' +import { type Metadata } from 'next' +import { generateMetadata as metadataHelper } from '@/app/metadata' +import { COUNTRIES_SEO, getCountryName } from '@/data/seo' +import { SUPPORTED_LOCALES, isValidLocale, getBareAlternates } from '@/i18n/config' +import { getTranslations } from '@/i18n' +import { ContentPage } from '@/components/Marketing/ContentPage' +import { readPageContentLocalized } from '@/lib/content' +import { renderContent } from '@/lib/mdx' + +interface PageProps { + params: Promise<{ locale: string; country: string }> +} + +export async function generateStaticParams() { + const countries = Object.keys(COUNTRIES_SEO) + return SUPPORTED_LOCALES.flatMap((locale) => countries.map((country) => ({ locale, country }))) +} +export const dynamicParams = false + +export async function generateMetadata({ params }: PageProps): Promise<Metadata> { + const { locale, country } = await params + if (!isValidLocale(locale)) return {} + + const seo = COUNTRIES_SEO[country] + if (!seo) return {} + + const mdxContent = readPageContentLocalized<{ title: string; description: string; published?: boolean }>( + 'countries', + country, + locale + ) + if (!mdxContent || mdxContent.frontmatter.published === false) return {} + + return { + ...metadataHelper({ + title: mdxContent.frontmatter.title, + description: mdxContent.frontmatter.description, + canonical: `/${locale}/${country}`, + }), + alternates: { + canonical: `/${locale}/${country}`, + languages: getBareAlternates(country), + }, + } +} + +export default async function CountryHubPage({ params }: PageProps) { + const { locale, country } = await params + if (!isValidLocale(locale)) notFound() + if (!COUNTRIES_SEO[country]) notFound() + + const mdxSource = readPageContentLocalized('countries', country, locale) + if (!mdxSource || mdxSource.frontmatter.published === false) notFound() + + const { content } = await renderContent(mdxSource.body) + const i18n = getTranslations(locale) + const countryName = getCountryName(country, locale) + + return ( + <ContentPage + breadcrumbs={[ + { name: i18n.home, href: '/' }, + { name: countryName, href: `/${locale}/${country}` }, + ]} + > + {content} + </ContentPage> + ) +} diff --git a/src/app/[locale]/(marketing)/blog/[slug]/page.tsx b/src/app/[locale]/(marketing)/blog/[slug]/page.tsx new file mode 100644 index 000000000..418455970 --- /dev/null +++ b/src/app/[locale]/(marketing)/blog/[slug]/page.tsx @@ -0,0 +1,147 @@ +import { notFound } from 'next/navigation' +import Link from 'next/link' +import { type Metadata } from 'next' +import { generateMetadata as metadataHelper } from '@/app/metadata' +import { getAllPosts, getPostBySlug } from '@/lib/blog' +import { MarketingShell } from '@/components/Marketing/MarketingShell' +import { JsonLd } from '@/components/Marketing/JsonLd' +import { SUPPORTED_LOCALES, getAlternates, isValidLocale } from '@/i18n/config' +import type { Locale } from '@/i18n/types' +import { getTranslations } from '@/i18n' + +interface PageProps { + params: Promise<{ locale: string; slug: string }> +} + +export async function generateStaticParams() { + if (process.env.NODE_ENV === 'production') return [] + // Generate params for locales that have blog content (fall back to en slugs) + return SUPPORTED_LOCALES.flatMap((locale) => { + let posts = getAllPosts(locale as Locale) + if (posts.length === 0) posts = getAllPosts('en') + return posts.map((post) => ({ locale, slug: post.slug })) + }) +} +// TODO: when blog content is added to src/content/blog/, either remove the +// production guard in generateStaticParams above, or set dynamicParams = true. +// Currently no blog posts exist so this has no effect, but with content present +// the combination of returning [] in prod + dynamicParams = false would 404 all +// blog pages. +export const dynamicParams = false + +export async function generateMetadata({ params }: PageProps): Promise<Metadata> { + const { locale, slug } = await params + if (!isValidLocale(locale)) return {} + + // Try locale-specific post first, fall back to English + const post = (await getPostBySlug(slug, locale as Locale)) ?? (await getPostBySlug(slug, 'en')) + if (!post) return {} + + return { + ...metadataHelper({ + title: `${post.frontmatter.title} | Peanut`, + description: post.frontmatter.description, + canonical: `/${locale}/blog/${slug}`, + }), + alternates: { + canonical: `/${locale}/blog/${slug}`, + languages: getAlternates('blog', slug), + }, + } +} + +export default async function BlogPostPageLocalized({ params }: PageProps) { + const { locale, slug } = await params + if (!isValidLocale(locale)) notFound() + + const post = (await getPostBySlug(slug, locale as Locale)) ?? (await getPostBySlug(slug, 'en')) + if (!post) notFound() + + const i18n = getTranslations(locale) + + const blogPostSchema = { + '@context': 'https://schema.org', + '@type': 'BlogPosting', + headline: post.frontmatter.title, + description: post.frontmatter.description, + datePublished: post.frontmatter.date, + inLanguage: locale, + author: { '@type': 'Organization', name: post.frontmatter.author ?? 'Peanut' }, + publisher: { '@type': 'Organization', name: 'Peanut', url: 'https://peanut.me' }, + mainEntityOfPage: `https://peanut.me/${locale}/blog/${slug}`, + } + + // FAQ schema from frontmatter (optional) + const faqs = post.frontmatter.faqs + const faqSchema = faqs?.length + ? { + '@context': 'https://schema.org', + '@type': 'FAQPage', + mainEntity: faqs.map((faq) => ({ + '@type': 'Question', + name: faq.question, + acceptedAnswer: { '@type': 'Answer', text: faq.answer }, + })), + } + : null + + const breadcrumbs = [ + { name: i18n.home, href: '/' }, + { name: i18n.blog, href: `/${locale}/blog` }, + { name: post.frontmatter.title, href: `/${locale}/blog/${slug}` }, + ] + + const breadcrumbSchema = { + '@context': 'https://schema.org', + '@type': 'BreadcrumbList', + itemListElement: breadcrumbs.map((crumb, i) => ({ + '@type': 'ListItem', + position: i + 1, + name: crumb.name, + item: crumb.href.startsWith('http') ? crumb.href : `https://peanut.me${crumb.href}`, + })), + } + + return ( + <> + <JsonLd data={blogPostSchema} /> + <JsonLd data={breadcrumbSchema} /> + {faqSchema && <JsonLd data={faqSchema} />} + <MarketingShell className="max-w-2xl"> + <nav aria-label="Breadcrumb" className="-mt-2 mb-4"> + <ol className="flex flex-wrap items-center gap-1 text-xs text-grey-1"> + {breadcrumbs.map((crumb, i) => ( + <li key={crumb.href} className="flex items-center gap-1"> + {i > 0 && <span aria-hidden>/</span>} + {i < breadcrumbs.length - 1 ? ( + <Link + href={crumb.href} + className="underline decoration-n-1/30 underline-offset-2 hover:text-n-1" + > + {crumb.name} + </Link> + ) : ( + <span className="max-w-[200px] truncate font-medium text-n-1">{crumb.name}</span> + )} + </li> + ))} + </ol> + </nav> + <header className="mb-8 border-b border-n-1 pb-6"> + {post.frontmatter.category && ( + <span className="mb-2 inline-block rounded-sm bg-primary-1/20 px-2 py-0.5 text-xs font-semibold"> + {post.frontmatter.category} + </span> + )} + <h1 className="text-3xl font-bold md:text-4xl">{post.frontmatter.title}</h1> + <p className="mt-2 text-gray-600">{post.frontmatter.description}</p> + <time className="mt-3 block text-sm text-gray-400">{post.frontmatter.date}</time> + </header> + <article + className="prose prose-lg prose-headings:font-bold prose-a:text-black prose-a:underline prose-pre:border prose-pre:border-n-1 prose-pre:bg-white max-w-none" + dangerouslySetInnerHTML={{ __html: post.html }} + /> + </MarketingShell> + </> + ) +} diff --git a/src/app/[locale]/(marketing)/blog/category/[cat]/page.tsx b/src/app/[locale]/(marketing)/blog/category/[cat]/page.tsx new file mode 100644 index 000000000..71a911f53 --- /dev/null +++ b/src/app/[locale]/(marketing)/blog/category/[cat]/page.tsx @@ -0,0 +1,101 @@ +import { notFound } from 'next/navigation' +import { type Metadata } from 'next' +import { generateMetadata as metadataHelper } from '@/app/metadata' +import { getAllCategories, getPostsByCategory } from '@/lib/blog' +import { MarketingHero } from '@/components/Marketing/MarketingHero' +import { MarketingShell } from '@/components/Marketing/MarketingShell' +import { BlogCard } from '@/components/Marketing/BlogCard' +import Link from 'next/link' +import { SUPPORTED_LOCALES, isValidLocale, getAlternates } from '@/i18n/config' +import type { Locale } from '@/i18n/types' +import { getTranslations } from '@/i18n' + +interface PageProps { + params: Promise<{ locale: string; cat: string }> +} + +export async function generateStaticParams() { + if (process.env.NODE_ENV === 'production') return [] + return SUPPORTED_LOCALES.flatMap((locale) => { + // Use English categories as fallback + const cats = getAllCategories(locale as Locale) + const fallbackCats = cats.length > 0 ? cats : getAllCategories('en') + return fallbackCats.map((cat) => ({ locale, cat })) + }) +} +export const dynamicParams = false + +export async function generateMetadata({ params }: PageProps): Promise<Metadata> { + const { locale, cat } = await params + if (!isValidLocale(locale)) return {} + + const label = cat.replace(/-/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase()) + + return { + ...metadataHelper({ + title: `${label} — Blog | Peanut`, + description: label, + canonical: `/${locale}/blog/category/${cat}`, + }), + alternates: { + canonical: `/${locale}/blog/category/${cat}`, + languages: getAlternates('blog', `category/${cat}`), + }, + } +} + +export default async function BlogCategoryPageLocalized({ params }: PageProps) { + const { locale, cat } = await params + if (!isValidLocale(locale)) notFound() + + const typedLocale = locale as Locale + const i18n = getTranslations(typedLocale) + + let posts = getPostsByCategory(cat, typedLocale) + if (posts.length === 0) posts = getPostsByCategory(cat, 'en') + if (posts.length === 0) notFound() + + const label = cat.replace(/-/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase()) + const categories = getAllCategories(typedLocale).length > 0 ? getAllCategories(typedLocale) : getAllCategories('en') + + return ( + <> + <MarketingHero title={label} subtitle={i18n.allArticles} ctaText="" /> + <MarketingShell> + <div className="mb-8 flex flex-wrap gap-2"> + <Link + href={`/${locale}/blog`} + className="rounded-sm border border-n-1 px-3 py-1 text-sm hover:bg-primary-3/30" + > + {i18n.allArticles} + </Link> + {categories.map((c) => ( + <Link + key={c} + href={`/${locale}/blog/category/${c}`} + className={`rounded-sm border border-n-1 px-3 py-1 text-sm ${ + c === cat ? 'bg-primary-1/20 font-semibold' : 'hover:bg-primary-3/30' + }`} + > + {c} + </Link> + ))} + </div> + + <div className="grid gap-4 md:grid-cols-2"> + {posts.map((post) => ( + <BlogCard + key={post.slug} + slug={post.slug} + title={post.frontmatter.title} + excerpt={post.frontmatter.description} + date={post.frontmatter.date} + category={post.frontmatter.category} + hrefPrefix={`/${locale}/blog`} + /> + ))} + </div> + </MarketingShell> + </> + ) +} diff --git a/src/app/[locale]/(marketing)/blog/page.tsx b/src/app/[locale]/(marketing)/blog/page.tsx new file mode 100644 index 000000000..e30220e20 --- /dev/null +++ b/src/app/[locale]/(marketing)/blog/page.tsx @@ -0,0 +1,98 @@ +import { notFound } from 'next/navigation' +import { type Metadata } from 'next' +import { generateMetadata as metadataHelper } from '@/app/metadata' +import { getAllPosts, getAllCategories } from '@/lib/blog' +import { MarketingHero } from '@/components/Marketing/MarketingHero' +import { MarketingShell } from '@/components/Marketing/MarketingShell' +import { BlogCard } from '@/components/Marketing/BlogCard' +import Link from 'next/link' +import { SUPPORTED_LOCALES, getAlternates, isValidLocale } from '@/i18n/config' +import type { Locale } from '@/i18n/types' +import { getTranslations } from '@/i18n' + +interface PageProps { + params: Promise<{ locale: string }> +} + +export async function generateStaticParams() { + if (process.env.NODE_ENV === 'production') return [] + return SUPPORTED_LOCALES.map((locale) => ({ locale })) +} + +export async function generateMetadata({ params }: PageProps): Promise<Metadata> { + const { locale } = await params + if (!isValidLocale(locale)) return {} + + const i18n = getTranslations(locale as Locale) + + return { + ...metadataHelper({ + title: `${i18n.blog} | Peanut`, + description: i18n.allArticles, + canonical: `/${locale}/blog`, + }), + alternates: { + canonical: `/${locale}/blog`, + languages: getAlternates('blog'), + }, + } +} + +export default async function BlogIndexPageLocalized({ params }: PageProps) { + const { locale } = await params + if (!isValidLocale(locale)) notFound() + + const typedLocale = locale as Locale + const i18n = getTranslations(typedLocale) + + // Try locale-specific posts first, fall back to English + let posts = getAllPosts(typedLocale) + if (posts.length === 0) posts = getAllPosts('en') + + const categories = getAllCategories(typedLocale) + + return ( + <> + <MarketingHero title={i18n.blog} subtitle={i18n.allArticles} ctaText="" /> + <MarketingShell> + {categories.length > 0 && ( + <div className="mb-8 flex flex-wrap gap-2"> + <Link + href={`/${locale}/blog`} + className="rounded-sm border border-n-1 bg-primary-1/20 px-3 py-1 text-sm font-semibold" + > + {i18n.allArticles} + </Link> + {categories.map((cat) => ( + <Link + key={cat} + href={`/${locale}/blog/category/${cat}`} + className="rounded-sm border border-n-1 px-3 py-1 text-sm hover:bg-primary-3/30" + > + {cat} + </Link> + ))} + </div> + )} + + {posts.length > 0 ? ( + <div className="grid gap-4 md:grid-cols-2"> + {posts.map((post) => ( + <BlogCard + key={post.slug} + slug={post.slug} + title={post.frontmatter.title} + excerpt={post.frontmatter.description} + date={post.frontmatter.date} + category={post.frontmatter.category} + hrefPrefix={`/${locale}/blog`} + /> + ))} + </div> + ) : ( + <p className="py-12 text-center text-gray-500">Blog posts coming soon.</p> + )} + </MarketingShell> + </> + ) +} diff --git a/src/app/[locale]/(marketing)/compare/[slug]/page.tsx b/src/app/[locale]/(marketing)/compare/[slug]/page.tsx new file mode 100644 index 000000000..b595c1199 --- /dev/null +++ b/src/app/[locale]/(marketing)/compare/[slug]/page.tsx @@ -0,0 +1,164 @@ +import { notFound } from 'next/navigation' +import { type Metadata } from 'next' +import { generateMetadata as metadataHelper } from '@/app/metadata' +import { COMPETITORS } from '@/data/seo' +import { MarketingHero } from '@/components/Marketing/MarketingHero' +import { MarketingShell } from '@/components/Marketing/MarketingShell' +import { Section } from '@/components/Marketing/Section' +import { ComparisonTable } from '@/components/Marketing/ComparisonTable' +import { FAQSection } from '@/components/Marketing/FAQSection' +import { JsonLd } from '@/components/Marketing/JsonLd' +import { SUPPORTED_LOCALES, getAlternates, isValidLocale } from '@/i18n/config' +import type { Locale } from '@/i18n/types' +import { getTranslations, t, localizedPath } from '@/i18n' +import { RelatedPages } from '@/components/Marketing/RelatedPages' +import { ContentPage } from '@/components/Marketing/ContentPage' +import { readPageContentLocalized } from '@/lib/content' +import { renderContent } from '@/lib/mdx' + +interface PageProps { + params: Promise<{ locale: string; slug: string }> +} + +export async function generateStaticParams() { + const slugs = Object.keys(COMPETITORS) + return SUPPORTED_LOCALES.flatMap((locale) => slugs.map((slug) => ({ locale, slug: `peanut-vs-${slug}` }))) +} +export const dynamicParams = false + +/** Strip the "peanut-vs-" URL prefix to get the data key. Returns null if prefix missing. */ +function parseSlug(raw: string): string | null { + if (!raw.startsWith('peanut-vs-')) return null + return raw.slice('peanut-vs-'.length) +} + +export async function generateMetadata({ params }: PageProps): Promise<Metadata> { + const { locale, slug: rawSlug } = await params + if (!isValidLocale(locale)) return {} + + const slug = parseSlug(rawSlug) + if (!slug) return {} + const competitor = COMPETITORS[slug] + if (!competitor) return {} + + // Try MDX content frontmatter first + const mdxContent = readPageContentLocalized<{ title: string; description: string; published?: boolean }>( + 'compare', + slug, + locale + ) + if (mdxContent && mdxContent.frontmatter.published !== false) { + return { + ...metadataHelper({ + title: mdxContent.frontmatter.title, + description: mdxContent.frontmatter.description, + canonical: `/${locale}/compare/peanut-vs-${slug}`, + }), + alternates: { + canonical: `/${locale}/compare/peanut-vs-${slug}`, + languages: getAlternates('compare', `peanut-vs-${slug}`), + }, + } + } + + // Fallback: i18n-based metadata + const year = new Date().getFullYear() + + return { + ...metadataHelper({ + title: `Peanut vs ${competitor.name} ${year} | Peanut`, + description: `Peanut vs ${competitor.name}: ${competitor.tagline}`, + canonical: `/${locale}/compare/peanut-vs-${slug}`, + }), + alternates: { + canonical: `/${locale}/compare/peanut-vs-${slug}`, + languages: getAlternates('compare', `peanut-vs-${slug}`), + }, + } +} + +export default async function ComparisonPageLocalized({ params }: PageProps) { + const { locale, slug: rawSlug } = await params + if (!isValidLocale(locale)) notFound() + + const slug = parseSlug(rawSlug) + if (!slug) notFound() + const competitor = COMPETITORS[slug] + if (!competitor) notFound() + + // Try MDX content first + const mdxSource = readPageContentLocalized('compare', slug, locale) + if (mdxSource && mdxSource.frontmatter.published !== false) { + const { content } = await renderContent(mdxSource.body) + const i18n = getTranslations(locale) + return ( + <ContentPage + breadcrumbs={[ + { name: i18n.home, href: '/' }, + { name: `Peanut vs ${competitor.name}`, href: `/${locale}/compare/peanut-vs-${slug}` }, + ]} + > + {content} + </ContentPage> + ) + } + + // Fallback: old React-driven page + const i18n = getTranslations(locale as Locale) + const year = new Date().getFullYear() + + const breadcrumbSchema = { + '@context': 'https://schema.org', + '@type': 'BreadcrumbList', + itemListElement: [ + { '@type': 'ListItem', position: 1, name: i18n.home, item: 'https://peanut.me' }, + { + '@type': 'ListItem', + position: 2, + name: `Peanut vs ${competitor.name}`, + item: `https://peanut.me/${locale}/compare/peanut-vs-${slug}`, + }, + ], + } + + return ( + <> + <JsonLd data={breadcrumbSchema} /> + + <MarketingHero + title={`Peanut vs ${competitor.name} [${year}]`} + subtitle={`${competitor.tagline} — ${year}`} + image={competitor.image} + /> + + <MarketingShell> + <Section title={i18n.feature}> + <ComparisonTable competitorName={competitor.name} rows={competitor.rows} /> + </Section> + + <Section title={i18n.verdict}> + <p className="text-gray-700">{competitor.verdict}</p> + </Section> + + <FAQSection faqs={competitor.faqs} /> + + {/* Related comparisons */} + <RelatedPages + title={i18n.relatedPages} + pages={Object.entries(COMPETITORS) + .filter(([s]) => s !== slug) + .slice(0, 5) + .map(([s, c]) => ({ + title: `Peanut vs ${c.name} [${year}]`, + href: localizedPath('compare', locale, `peanut-vs-${s}`), + }))} + /> + + {/* Last updated */} + <p className="py-4 text-xs text-gray-400"> + {t(i18n.lastUpdated, { date: new Date().toISOString().split('T')[0] })} + </p> + </MarketingShell> + </> + ) +} diff --git a/src/app/[locale]/(marketing)/deposit/[exchange]/page.tsx b/src/app/[locale]/(marketing)/deposit/[exchange]/page.tsx new file mode 100644 index 000000000..36d004e36 --- /dev/null +++ b/src/app/[locale]/(marketing)/deposit/[exchange]/page.tsx @@ -0,0 +1,194 @@ +import { notFound } from 'next/navigation' +import { type Metadata } from 'next' +import { generateMetadata as metadataHelper } from '@/app/metadata' +import { EXCHANGES } from '@/data/seo' +import { MarketingHero } from '@/components/Marketing/MarketingHero' +import { MarketingShell } from '@/components/Marketing/MarketingShell' +import { Section } from '@/components/Marketing/Section' +import { Steps } from '@/components/Marketing/Steps' +import { FAQSection } from '@/components/Marketing/FAQSection' +import { JsonLd } from '@/components/Marketing/JsonLd' +import { Card } from '@/components/0_Bruddle/Card' +import { SUPPORTED_LOCALES, getAlternates, isValidLocale } from '@/i18n/config' +import type { Locale } from '@/i18n/types' +import { getTranslations, t, localizedPath } from '@/i18n' +import { RelatedPages } from '@/components/Marketing/RelatedPages' +import { ContentPage } from '@/components/Marketing/ContentPage' +import { readPageContentLocalized } from '@/lib/content' +import { renderContent } from '@/lib/mdx' + +interface PageProps { + params: Promise<{ locale: string; exchange: string }> +} + +export async function generateStaticParams() { + const exchanges = Object.keys(EXCHANGES) + return SUPPORTED_LOCALES.flatMap((locale) => + exchanges.map((exchange) => ({ locale, exchange: `from-${exchange}` })) + ) +} +export const dynamicParams = false + +/** Strip the "from-" URL prefix to get the data key. Returns null if prefix missing. */ +function parseExchange(raw: string): string | null { + if (!raw.startsWith('from-')) return null + return raw.slice('from-'.length) +} + +export async function generateMetadata({ params }: PageProps): Promise<Metadata> { + const { locale, exchange: rawExchange } = await params + if (!isValidLocale(locale)) return {} + + const exchange = parseExchange(rawExchange) + if (!exchange) return {} + const ex = EXCHANGES[exchange] + if (!ex) return {} + + // Try MDX content frontmatter first + const mdxContent = readPageContentLocalized<{ title: string; description: string; published?: boolean }>( + 'deposit', + exchange, + locale + ) + if (mdxContent && mdxContent.frontmatter.published !== false) { + return { + ...metadataHelper({ + title: mdxContent.frontmatter.title, + description: mdxContent.frontmatter.description, + canonical: `/${locale}/deposit/from-${exchange}`, + }), + alternates: { + canonical: `/${locale}/deposit/from-${exchange}`, + languages: getAlternates('deposit', `from-${exchange}`), + }, + } + } + + // Fallback: i18n-based metadata + const i18n = getTranslations(locale as Locale) + + return { + ...metadataHelper({ + title: `${t(i18n.depositFrom, { exchange: ex.name })} | Peanut`, + description: `${t(i18n.depositFrom, { exchange: ex.name })}. ${i18n.recommendedNetwork}: ${ex.recommendedNetwork}.`, + canonical: `/${locale}/deposit/from-${exchange}`, + }), + alternates: { + canonical: `/${locale}/deposit/from-${exchange}`, + languages: getAlternates('deposit', `from-${exchange}`), + }, + } +} + +export default async function DepositPageLocalized({ params }: PageProps) { + const { locale, exchange: rawExchange } = await params + if (!isValidLocale(locale)) notFound() + + const exchange = parseExchange(rawExchange) + if (!exchange) notFound() + const ex = EXCHANGES[exchange] + if (!ex) notFound() + + // Try MDX content first + const mdxSource = readPageContentLocalized('deposit', exchange, locale) + if (mdxSource && mdxSource.frontmatter.published !== false) { + const { content } = await renderContent(mdxSource.body) + const i18n = getTranslations(locale) + return ( + <ContentPage + breadcrumbs={[ + { name: i18n.home, href: '/' }, + { name: ex.name, href: `/${locale}/deposit/from-${exchange}` }, + ]} + > + {content} + </ContentPage> + ) + } + + // Fallback: old React-driven page + const i18n = getTranslations(locale as Locale) + + const steps = ex.steps.map((step, i) => ({ + title: `${i + 1}`, + description: step, + })) + + const howToSchema = { + '@context': 'https://schema.org', + '@type': 'HowTo', + name: t(i18n.depositFrom, { exchange: ex.name }), + inLanguage: locale, + step: steps.map((step, i) => ({ + '@type': 'HowToStep', + position: i + 1, + name: step.title, + text: step.description, + })), + } + + return ( + <> + <JsonLd data={howToSchema} /> + + <MarketingHero + title={t(i18n.depositFrom, { exchange: ex.name })} + subtitle={`${ex.processingTime} · ${ex.recommendedNetwork}`} + image={ex.image} + /> + + <MarketingShell> + <Section title={i18n.howItWorks}> + <div className="grid grid-cols-2 gap-3 md:grid-cols-4"> + {[ + { label: i18n.recommendedNetwork, value: ex.recommendedNetwork }, + { label: i18n.withdrawalFee, value: ex.withdrawalFee }, + { label: i18n.processingTime, value: ex.processingTime }, + ].map((item) => ( + <Card key={item.label} className="p-3 text-center"> + <span className="text-xs text-gray-500">{item.label}</span> + <span className="mt-1 block text-sm font-bold">{item.value}</span> + </Card> + ))} + </div> + </Section> + + <Section title={t(i18n.depositFrom, { exchange: ex.name })}> + <Steps steps={steps} /> + </Section> + + {ex.troubleshooting.length > 0 && ( + <Section title={i18n.troubleshooting}> + <div className="flex flex-col gap-3"> + {ex.troubleshooting.map((item, i) => ( + <Card key={i} className="p-4"> + <h3 className="text-red-700 font-semibold">{item.issue}</h3> + <p className="mt-1 text-sm text-gray-600">{item.fix}</p> + </Card> + ))} + </div> + </Section> + )} + + <FAQSection faqs={ex.faqs} /> + + {/* Related deposit guides */} + <RelatedPages + title={i18n.relatedPages} + pages={Object.entries(EXCHANGES) + .filter(([slug]) => slug !== exchange) + .slice(0, 5) + .map(([slug, e]) => ({ + title: t(i18n.depositFrom, { exchange: e.name }), + href: localizedPath('deposit', locale, `from-${slug}`), + }))} + /> + + {/* Last updated */} + <p className="py-4 text-xs text-gray-400"> + {t(i18n.lastUpdated, { date: new Date().toISOString().split('T')[0] })} + </p> + </MarketingShell> + </> + ) +} diff --git a/src/app/[locale]/(marketing)/error.tsx b/src/app/[locale]/(marketing)/error.tsx new file mode 100644 index 000000000..938173d6a --- /dev/null +++ b/src/app/[locale]/(marketing)/error.tsx @@ -0,0 +1,33 @@ +'use client' + +import { useEffect } from 'react' +import Link from 'next/link' + +export default function MarketingError({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) { + useEffect(() => { + console.error(error) + }, [error]) + + return ( + <div className="flex min-h-[60vh] flex-col items-center justify-center px-4 text-center"> + <h1 className="text-2xl font-bold">Something went wrong</h1> + <p className="mt-2 max-w-md text-gray-600"> + We had trouble loading this page. Please try again or go back to the homepage. + </p> + <div className="mt-6 flex gap-3"> + <button + onClick={reset} + className="rounded-md bg-black px-4 py-2 text-sm font-medium text-white hover:bg-gray-800" + > + Try again + </button> + <Link + href="/" + className="rounded-md border border-gray-300 px-4 py-2 text-sm font-medium hover:bg-gray-50" + > + Go home + </Link> + </div> + </div> + ) +} diff --git a/src/app/[locale]/(marketing)/help/TODO.md b/src/app/[locale]/(marketing)/help/TODO.md new file mode 100644 index 000000000..958fd466f --- /dev/null +++ b/src/app/[locale]/(marketing)/help/TODO.md @@ -0,0 +1,28 @@ +# Help Center — Future Improvements + +## When article count > 25 + +- **Full-text body search**: Current search only matches title + description + category. + Index article body text server-side and pass keyword arrays to HelpLanding, + or use a lightweight client-side lib like Fuse.js for fuzzy matching. + +- **Category filter chips/tabs**: Add clickable category chips at the top of the + landing page so users can filter without scrolling. Alternative: make category + sections collapsible (accordion). + +- **Category landing pages**: At 50+ articles, consider dedicated pages at + `/help/category/payments` etc. with their own SEO value. + +## Nice-to-haves (not blocking) + +- **Search analytics**: Track what users search for (via GA4 event) to identify + content gaps and missing articles. + +- **"Was this helpful?" feedback**: Add thumbs up/down at the bottom of each + article. Store in analytics, no backend needed. + +- **Article-level table of contents**: For longer articles, generate a sticky + sidebar TOC from h2/h3 headings. Only relevant once articles get longer. + +- **Localized landing page Hero**: Hero title/subtitle already use i18n keys. + Consider locale-specific subtitles that highlight region-relevant features. diff --git a/src/app/[locale]/(marketing)/help/[slug]/page.tsx b/src/app/[locale]/(marketing)/help/[slug]/page.tsx new file mode 100644 index 000000000..b4ece4782 --- /dev/null +++ b/src/app/[locale]/(marketing)/help/[slug]/page.tsx @@ -0,0 +1,72 @@ +import { notFound } from 'next/navigation' +import { type Metadata } from 'next' +import { generateMetadata as metadataHelper } from '@/app/metadata' +import { SUPPORTED_LOCALES, getAlternates, isValidLocale } from '@/i18n/config' +import { getTranslations } from '@/i18n' +import { ContentPage } from '@/components/Marketing/ContentPage' +import { readPageContentLocalized, listContentSlugs } from '@/lib/content' +import { renderContent } from '@/lib/mdx' + +interface PageProps { + params: Promise<{ locale: string; slug: string }> +} + +interface HelpFrontmatter { + title: string + description: string + slug: string + category?: string + published?: boolean +} + +const HELP_SLUGS = listContentSlugs('help') + +export async function generateStaticParams() { + return SUPPORTED_LOCALES.flatMap((locale) => HELP_SLUGS.map((slug) => ({ locale, slug }))) +} +export const dynamicParams = false + +export async function generateMetadata({ params }: PageProps): Promise<Metadata> { + const { locale, slug } = await params + if (!isValidLocale(locale)) return {} + + const mdxContent = readPageContentLocalized<HelpFrontmatter>('help', slug, locale) + if (!mdxContent || mdxContent.frontmatter.published === false) return {} + + return { + ...metadataHelper({ + title: mdxContent.frontmatter.title, + description: mdxContent.frontmatter.description, + canonical: `/${locale}/help/${slug}`, + }), + alternates: { + canonical: `/${locale}/help/${slug}`, + languages: getAlternates('help', slug), + }, + } +} + +export default async function HelpArticlePage({ params }: PageProps) { + const { locale, slug } = await params + if (!isValidLocale(locale)) notFound() + + const mdxSource = readPageContentLocalized<HelpFrontmatter>('help', slug, locale) + if (!mdxSource || mdxSource.frontmatter.published === false) notFound() + + const { content } = await renderContent(mdxSource.body) + const i18n = getTranslations(locale) + + const displayTitle = mdxSource.frontmatter.title.replace(/\s*\|\s*Peanut Help$/, '') + + return ( + <ContentPage + breadcrumbs={[ + { name: i18n.home, href: '/' }, + { name: i18n.help, href: `/${locale}/help` }, + { name: displayTitle, href: `/${locale}/help/${slug}` }, + ]} + > + {content} + </ContentPage> + ) +} diff --git a/src/app/[locale]/(marketing)/help/page.tsx b/src/app/[locale]/(marketing)/help/page.tsx new file mode 100644 index 000000000..ebef67f14 --- /dev/null +++ b/src/app/[locale]/(marketing)/help/page.tsx @@ -0,0 +1,106 @@ +import { Suspense } from 'react' +import { type Metadata } from 'next' +import { generateMetadata as metadataHelper } from '@/app/metadata' +import { SUPPORTED_LOCALES, isValidLocale, getAlternates } from '@/i18n/config' +import { getTranslations } from '@/i18n' +import { readPageContentLocalized, listContentSlugs } from '@/lib/content' +import { notFound } from 'next/navigation' +import { ContentPage } from '@/components/Marketing/ContentPage' +import { Hero } from '@/components/Marketing/mdx/Hero' +import HelpLanding from '@/components/Marketing/HelpLanding' + +interface PageProps { + params: Promise<{ locale: string }> +} + +interface HelpFrontmatter { + title: string + description: string + slug: string + category?: string + published?: boolean +} + +/** Map frontmatter category keys → i18n translation keys */ +const CATEGORY_I18N_KEYS: Record<string, keyof import('@/i18n/types').Translations> = { + 'Getting Started': 'categoryGettingStarted', + 'Account & Security': 'categoryAccountSecurity', + Payments: 'categoryPayments', + 'Deposits & Withdrawals': 'categoryDepositsWithdrawals', + 'Sending & Receiving': 'categorySendingReceiving', + Troubleshooting: 'categoryTroubleshooting', +} + +export async function generateStaticParams() { + return SUPPORTED_LOCALES.map((locale) => ({ locale })) +} +export const dynamicParams = false + +export async function generateMetadata({ params }: PageProps): Promise<Metadata> { + const { locale } = await params + if (!isValidLocale(locale)) return {} + + const i18n = getTranslations(locale) + + return { + ...metadataHelper({ + title: `${i18n.helpCenter} | Peanut`, + description: i18n.helpCenterDescription, + canonical: `/${locale}/help`, + }), + alternates: { + canonical: `/${locale}/help`, + languages: getAlternates('help'), + }, + } +} + +export default async function HelpPage({ params }: PageProps) { + const { locale } = await params + if (!isValidLocale(locale)) notFound() + + const i18n = getTranslations(locale) + const slugs = listContentSlugs('help') + const articles = slugs + .map((slug) => { + const content = readPageContentLocalized<HelpFrontmatter>('help', slug, locale) + if (!content || content.frontmatter.published === false) return null + return { + slug, + title: content.frontmatter.title.replace(/\s*\|\s*Peanut Help$/, ''), + description: content.frontmatter.description, + category: content.frontmatter.category ?? 'General', + } + }) + .filter(Boolean) as Array<{ slug: string; title: string; description: string; category: string }> + + // Translate category names + const translatedArticles = articles.map((a) => ({ + ...a, + category: i18n[CATEGORY_I18N_KEYS[a.category] ?? 'help'] ?? a.category, + })) + const categories = [...new Set(translatedArticles.map((a) => a.category))] + + return ( + <ContentPage + breadcrumbs={[ + { name: i18n.home, href: '/' }, + { name: i18n.help, href: `/${locale}/help` }, + ]} + > + <Hero title={i18n.helpCenter} subtitle={i18n.helpCenterDescription} /> + <Suspense> + <HelpLanding + articles={translatedArticles} + categories={categories} + locale={locale} + strings={{ + searchPlaceholder: i18n.searchHelpArticles, + cantFind: i18n.cantFindAnswer, + cantFindDesc: i18n.cantFindAnswerDesc, + }} + /> + </Suspense> + </ContentPage> + ) +} diff --git a/src/app/[locale]/(marketing)/layout.tsx b/src/app/[locale]/(marketing)/layout.tsx new file mode 100644 index 000000000..1b351e777 --- /dev/null +++ b/src/app/[locale]/(marketing)/layout.tsx @@ -0,0 +1,39 @@ +import { notFound } from 'next/navigation' +import Script from 'next/script' +import { SUPPORTED_LOCALES } from '@/i18n/types' +import { isValidLocale } from '@/i18n/config' +import { CRISP_WEBSITE_ID } from '@/constants/crisp' +import Footer from '@/components/LandingPage/Footer' + +interface LayoutProps { + children: React.ReactNode + params: Promise<{ locale: string }> +} + +export async function generateStaticParams() { + return SUPPORTED_LOCALES.map((locale) => ({ locale })) +} +export const dynamicParams = false + +export default async function LocalizedMarketingLayout({ children, params }: LayoutProps) { + const { locale } = await params + + if (!isValidLocale(locale)) { + notFound() + } + + return ( + <main className="flex min-h-dvh flex-col bg-white" lang={locale}> + <div className="flex-1">{children}</div> + <Footer /> + {/* Crisp chat widget on all marketing/SEO pages */} + <Script id="crisp-widget" strategy="lazyOnload"> + {`window.$crisp=[];window.CRISP_WEBSITE_ID="${CRISP_WEBSITE_ID}";(function(){var d=document;var s=d.createElement("script");s.src="https://client.crisp.chat/l.js";s.async=1;d.getElementsByTagName("head")[0].appendChild(s);})();`} + </Script> + {/* Intercept href="#chat" clicks to open Crisp (mousedown fires before navigation) */} + <Script id="crisp-chat-links" strategy="lazyOnload"> + {`document.addEventListener("click",function(e){var a=e.target.closest('[href="#chat"]');if(a&&window.$crisp){e.preventDefault();e.stopPropagation();window.$crisp.push(["do","chat:open"])}},true);`} + </Script> + </main> + ) +} diff --git a/src/app/[locale]/(marketing)/pay-with/[method]/page.tsx b/src/app/[locale]/(marketing)/pay-with/[method]/page.tsx new file mode 100644 index 000000000..9fec9dd8a --- /dev/null +++ b/src/app/[locale]/(marketing)/pay-with/[method]/page.tsx @@ -0,0 +1,70 @@ +import { notFound } from 'next/navigation' +import { type Metadata } from 'next' +import { generateMetadata as metadataHelper } from '@/app/metadata' +import { PAYMENT_METHODS, PAYMENT_METHOD_SLUGS } from '@/data/seo' +import { SUPPORTED_LOCALES, getAlternates, isValidLocale } from '@/i18n/config' +import { getTranslations } from '@/i18n' +import { ContentPage } from '@/components/Marketing/ContentPage' +import { readPageContentLocalized } from '@/lib/content' +import { renderContent } from '@/lib/mdx' + +interface PageProps { + params: Promise<{ locale: string; method: string }> +} + +export async function generateStaticParams() { + return SUPPORTED_LOCALES.flatMap((locale) => PAYMENT_METHOD_SLUGS.map((method) => ({ locale, method }))) +} +export const dynamicParams = false + +export async function generateMetadata({ params }: PageProps): Promise<Metadata> { + const { locale, method } = await params + if (!isValidLocale(locale)) return {} + + const pm = PAYMENT_METHODS[method] + if (!pm) return {} + + const mdxContent = readPageContentLocalized<{ title: string; description: string; published?: boolean }>( + 'pay-with', + method, + locale + ) + if (!mdxContent || mdxContent.frontmatter.published === false) return {} + + return { + ...metadataHelper({ + title: mdxContent.frontmatter.title, + description: mdxContent.frontmatter.description, + canonical: `/${locale}/pay-with/${method}`, + }), + alternates: { + canonical: `/${locale}/pay-with/${method}`, + languages: getAlternates('pay-with', method), + }, + } +} + +export default async function PayWithPage({ params }: PageProps) { + const { locale, method } = await params + if (!isValidLocale(locale)) notFound() + + const pm = PAYMENT_METHODS[method] + if (!pm) notFound() + + const mdxSource = readPageContentLocalized('pay-with', method, locale) + if (!mdxSource || mdxSource.frontmatter.published === false) notFound() + + const { content } = await renderContent(mdxSource.body) + const i18n = getTranslations(locale) + + return ( + <ContentPage + breadcrumbs={[ + { name: i18n.home, href: '/' }, + { name: pm.name, href: `/${locale}/pay-with/${method}` }, + ]} + > + {content} + </ContentPage> + ) +} diff --git a/src/app/[locale]/(marketing)/receive-money-from/[country]/page.tsx b/src/app/[locale]/(marketing)/receive-money-from/[country]/page.tsx new file mode 100644 index 000000000..e650c1652 --- /dev/null +++ b/src/app/[locale]/(marketing)/receive-money-from/[country]/page.tsx @@ -0,0 +1,74 @@ +import { notFound } from 'next/navigation' +import { type Metadata } from 'next' +import { generateMetadata as metadataHelper } from '@/app/metadata' +import { CORRIDORS, getCountryName } from '@/data/seo' +import { SUPPORTED_LOCALES, getAlternates, isValidLocale } from '@/i18n/config' +import type { Locale } from '@/i18n/types' +import { getTranslations, t } from '@/i18n' +import { ReceiveMoneyContent } from '@/components/Marketing/pages/ReceiveMoneyContent' +import { ContentPage } from '@/components/Marketing/ContentPage' +import { readPageContentLocalized } from '@/lib/content' +import { renderContent } from '@/lib/mdx' + +interface PageProps { + params: Promise<{ locale: string; country: string }> +} + +/** Unique sending countries */ +function getReceiveSources(): string[] { + return [...new Set(CORRIDORS.map((c) => c.from))] +} + +export async function generateStaticParams() { + const sources = getReceiveSources() + return SUPPORTED_LOCALES.flatMap((locale) => sources.map((country) => ({ locale, country }))) +} +export const dynamicParams = false + +export async function generateMetadata({ params }: PageProps): Promise<Metadata> { + const { locale, country } = await params + if (!isValidLocale(locale)) return {} + if (!getReceiveSources().includes(country)) return {} + + const i18n = getTranslations(locale as Locale) + const countryName = getCountryName(country, locale as Locale) + + return { + ...metadataHelper({ + title: `${t(i18n.receiveMoneyFrom, { country: countryName })} | Peanut`, + description: t(i18n.receiveMoneyFromDesc, { country: countryName }), + canonical: `/${locale}/receive-money-from/${country}`, + }), + alternates: { + canonical: `/${locale}/receive-money-from/${country}`, + languages: getAlternates('receive-money-from', country), + }, + } +} + +export default async function ReceiveMoneyPage({ params }: PageProps) { + const { locale, country } = await params + if (!isValidLocale(locale)) notFound() + if (!getReceiveSources().includes(country)) notFound() + + // Try MDX content first (future-proofing — no content files exist yet) + const mdxSource = readPageContentLocalized('receive-from', country, locale) + if (mdxSource && mdxSource.frontmatter.published !== false) { + const { content } = await renderContent(mdxSource.body) + const i18n = getTranslations(locale) + const countryName = getCountryName(country, locale) + return ( + <ContentPage + breadcrumbs={[ + { name: i18n.home, href: '/' }, + { name: countryName, href: `/${locale}/receive-money-from/${country}` }, + ]} + > + {content} + </ContentPage> + ) + } + + // Fallback: old React-driven page + return <ReceiveMoneyContent sourceCountry={country} locale={locale as Locale} /> +} diff --git a/src/app/[locale]/(marketing)/send-money-from/[from]/to/[to]/page.tsx b/src/app/[locale]/(marketing)/send-money-from/[from]/to/[to]/page.tsx new file mode 100644 index 000000000..0ec5bf995 --- /dev/null +++ b/src/app/[locale]/(marketing)/send-money-from/[from]/to/[to]/page.tsx @@ -0,0 +1,68 @@ +import { notFound } from 'next/navigation' +import { type Metadata } from 'next' +import { generateMetadata as metadataHelper } from '@/app/metadata' +import { CORRIDORS, getCountryName } from '@/data/seo' +import { SUPPORTED_LOCALES, getAlternates, isValidLocale } from '@/i18n/config' +import { getTranslations } from '@/i18n' +import { ContentPage } from '@/components/Marketing/ContentPage' +import { readCorridorContentLocalized } from '@/lib/content' +import { renderContent } from '@/lib/mdx' + +interface PageProps { + params: Promise<{ locale: string; from: string; to: string }> +} + +export async function generateStaticParams() { + return SUPPORTED_LOCALES.flatMap((locale) => CORRIDORS.map((c) => ({ locale, from: c.from, to: c.to }))) +} +export const dynamicParams = false + +export async function generateMetadata({ params }: PageProps): Promise<Metadata> { + const { locale, from, to } = await params + if (!isValidLocale(locale)) return {} + + if (!CORRIDORS.some((c) => c.from === from && c.to === to)) return {} + + const mdxContent = readCorridorContentLocalized(to, from, locale) + if (!mdxContent || mdxContent.frontmatter.published === false) return {} + + const fm = mdxContent.frontmatter as { title?: string; description?: string } + if (!fm.title || !fm.description) return {} + + return { + ...metadataHelper({ + title: fm.title, + description: fm.description, + canonical: `/${locale}/send-money-from/${from}/to/${to}`, + }), + alternates: { + canonical: `/${locale}/send-money-from/${from}/to/${to}`, + languages: getAlternates('send-money-from', `${from}/to/${to}`), + }, + } +} + +export default async function FromToCorridorPage({ params }: PageProps) { + const { locale, from, to } = await params + if (!isValidLocale(locale)) notFound() + if (!CORRIDORS.some((c) => c.from === from && c.to === to)) notFound() + + const mdxSource = readCorridorContentLocalized(to, from, locale) + if (!mdxSource || mdxSource.frontmatter.published === false) notFound() + + const { content } = await renderContent(mdxSource.body) + const i18n = getTranslations(locale) + const fromName = getCountryName(from, locale) + const toName = getCountryName(to, locale) + + return ( + <ContentPage + breadcrumbs={[ + { name: i18n.home, href: '/' }, + { name: `${fromName} → ${toName}`, href: `/${locale}/send-money-from/${from}/to/${to}` }, + ]} + > + {content} + </ContentPage> + ) +} diff --git a/src/app/[locale]/(marketing)/send-money-to/[country]/page.tsx b/src/app/[locale]/(marketing)/send-money-to/[country]/page.tsx new file mode 100644 index 000000000..3e09b2f79 --- /dev/null +++ b/src/app/[locale]/(marketing)/send-money-to/[country]/page.tsx @@ -0,0 +1,70 @@ +import { notFound } from 'next/navigation' +import { type Metadata } from 'next' +import { generateMetadata as metadataHelper } from '@/app/metadata' +import { COUNTRIES_SEO, getCountryName } from '@/data/seo' +import { SUPPORTED_LOCALES, getAlternates, isValidLocale, localizedPath } from '@/i18n/config' +import type { Locale } from '@/i18n/types' +import { getTranslations } from '@/i18n' +import { ContentPage } from '@/components/Marketing/ContentPage' +import { readPageContentLocalized } from '@/lib/content' +import { renderContent } from '@/lib/mdx' + +interface PageProps { + params: Promise<{ locale: string; country: string }> +} + +export async function generateStaticParams() { + const countries = Object.keys(COUNTRIES_SEO) + return SUPPORTED_LOCALES.flatMap((locale) => countries.map((country) => ({ locale, country }))) +} +export const dynamicParams = false + +export async function generateMetadata({ params }: PageProps): Promise<Metadata> { + const { locale, country } = await params + if (!isValidLocale(locale)) return {} + + const seo = COUNTRIES_SEO[country] + if (!seo) return {} + + const mdxContent = readPageContentLocalized<{ title: string; description: string; published?: boolean }>( + 'send-to', + country, + locale + ) + if (!mdxContent || mdxContent.frontmatter.published === false) return {} + + return { + ...metadataHelper({ + title: mdxContent.frontmatter.title, + description: mdxContent.frontmatter.description, + canonical: `/${locale}/send-money-to/${country}`, + }), + alternates: { + canonical: `/${locale}/send-money-to/${country}`, + languages: getAlternates('send-money-to', country), + }, + } +} + +export default async function SendMoneyToCountryPageLocalized({ params }: PageProps) { + const { locale, country } = await params + if (!isValidLocale(locale)) notFound() + + const mdxSource = readPageContentLocalized('send-to', country, locale) + if (!mdxSource || mdxSource.frontmatter.published === false) notFound() + + const { content } = await renderContent(mdxSource.body) + const i18n = getTranslations(locale) + const countryName = getCountryName(country, locale) + + return ( + <ContentPage + breadcrumbs={[ + { name: i18n.home, href: '/' }, + { name: countryName, href: localizedPath('send-money-to', locale, country) }, + ]} + > + {content} + </ContentPage> + ) +} diff --git a/src/app/[locale]/(marketing)/team/page.tsx b/src/app/[locale]/(marketing)/team/page.tsx new file mode 100644 index 000000000..5f523c846 --- /dev/null +++ b/src/app/[locale]/(marketing)/team/page.tsx @@ -0,0 +1,128 @@ +import { notFound } from 'next/navigation' +import { type Metadata } from 'next' +import { generateMetadata as metadataHelper } from '@/app/metadata' +import { TEAM_MEMBERS } from '@/data/team' +import { MarketingHero } from '@/components/Marketing/MarketingHero' +import { MarketingShell } from '@/components/Marketing/MarketingShell' +import { JsonLd } from '@/components/Marketing/JsonLd' +import { Card } from '@/components/0_Bruddle/Card' +import { SUPPORTED_LOCALES, getAlternates, isValidLocale } from '@/i18n/config' +import type { Locale } from '@/i18n/types' +import { getTranslations } from '@/i18n' + +interface PageProps { + params: Promise<{ locale: string }> +} + +export async function generateStaticParams() { + if (process.env.NODE_ENV === 'production') return [] + return SUPPORTED_LOCALES.map((locale) => ({ locale })) +} + +export async function generateMetadata({ params }: PageProps): Promise<Metadata> { + const { locale } = await params + if (!isValidLocale(locale)) return {} + + const i18n = getTranslations(locale as Locale) + + return { + ...metadataHelper({ + title: `${i18n.teamTitle} | Peanut`, + description: i18n.teamSubtitle, + canonical: `/${locale}/team`, + }), + alternates: { + canonical: `/${locale}/team`, + languages: getAlternates('team'), + }, + } +} + +export default async function TeamPage({ params }: PageProps) { + const { locale } = await params + if (!isValidLocale(locale)) notFound() + + const i18n = getTranslations(locale as Locale) + + const orgSchema = { + '@context': 'https://schema.org', + '@type': 'Organization', + name: 'Peanut', + url: 'https://peanut.me', + member: TEAM_MEMBERS.map((m) => ({ + '@type': 'Person', + name: m.name, + jobTitle: m.role, + ...(m.social?.linkedin ? { sameAs: [m.social.linkedin] } : {}), + })), + } + + return ( + <> + <JsonLd data={orgSchema} /> + + <MarketingHero title={i18n.teamTitle} subtitle={i18n.teamSubtitle} ctaText="" /> + + <MarketingShell> + <div className="grid gap-6 md:grid-cols-2"> + {TEAM_MEMBERS.map((member) => ( + <Card key={member.slug} className="gap-3 p-6"> + {member.image ? ( + <img + src={member.image} + alt={member.name} + width={80} + height={80} + className="rounded-full border border-n-1" + /> + ) : ( + <div className="flex size-20 items-center justify-center rounded-full bg-primary-1/30 text-2xl font-bold"> + {member.name.charAt(0)} + </div> + )} + <div> + <h2 className="text-lg font-bold">{member.name}</h2> + <p className="text-sm font-medium text-gray-500">{member.role}</p> + </div> + <p className="text-sm text-gray-700">{member.bio}</p> + {member.social && ( + <div className="flex gap-3"> + {member.social.linkedin && ( + <a + href={member.social.linkedin} + className="text-sm text-black underline" + target="_blank" + rel="noopener noreferrer" + > + LinkedIn + </a> + )} + {member.social.twitter && ( + <a + href={member.social.twitter} + className="text-sm text-black underline" + target="_blank" + rel="noopener noreferrer" + > + X / Twitter + </a> + )} + {member.social.github && ( + <a + href={member.social.github} + className="text-sm text-black underline" + target="_blank" + rel="noopener noreferrer" + > + GitHub + </a> + )} + </div> + )} + </Card> + ))} + </div> + </MarketingShell> + </> + ) +} diff --git a/src/app/actions/card.ts b/src/app/actions/card.ts index a3bd088ed..b6436ea3d 100644 --- a/src/app/actions/card.ts +++ b/src/app/actions/card.ts @@ -4,7 +4,10 @@ import { PEANUT_API_URL } from '@/constants/general.consts' import { fetchWithSentry } from '@/utils/sentry.utils' import { getJWTCookie } from '@/utils/cookie-migration.utils' -const API_KEY = process.env.PEANUT_API_KEY! +const API_KEY = process.env.PEANUT_API_KEY +if (!API_KEY) { + throw new Error('PEANUT_API_KEY environment variable is not set') +} export interface CardInfoResponse { hasPurchased: boolean diff --git a/src/app/api/peanut/user/get-jwt-token/route.ts b/src/app/api/peanut/user/get-jwt-token/route.ts index 158178ea0..4f8a1c187 100644 --- a/src/app/api/peanut/user/get-jwt-token/route.ts +++ b/src/app/api/peanut/user/get-jwt-token/route.ts @@ -43,6 +43,7 @@ export async function POST(request: NextRequest) { secure: process.env.NODE_ENV === 'production', path: '/', sameSite: 'lax', + maxAge: 30 * 24 * 60 * 60, // 30 days }) return new NextResponse(JSON.stringify(data), { diff --git a/src/app/api/peanut/user/get-user-from-cookie/__tests__/route.test.ts b/src/app/api/peanut/user/get-user-from-cookie/__tests__/route.test.ts new file mode 100644 index 000000000..1747a237a --- /dev/null +++ b/src/app/api/peanut/user/get-user-from-cookie/__tests__/route.test.ts @@ -0,0 +1,124 @@ +/** + * @jest-environment node + */ +import { NextRequest } from 'next/server' + +// --- Mocks --- + +const mockCookieGet = jest.fn() +const mockCookieSet = jest.fn() +jest.mock('next/headers', () => ({ + cookies: jest.fn(async () => ({ + get: mockCookieGet, + set: mockCookieSet, + })), +})) + +// Mock getJWTCookie to use our mock cookie store +jest.mock('@/utils/cookie-migration.utils', () => ({ + getJWTCookie: jest.fn(async () => mockCookieGet('jwt-token')), +})) + +const mockFetch = jest.fn() +jest.mock('@/utils/sentry.utils', () => ({ + fetchWithSentry: (...args: unknown[]) => mockFetch(...args), +})) + +jest.mock('@/constants/general.consts', () => ({ + PEANUT_API_URL: 'https://api.test', +})) + +// --- Tests --- + +import { GET } from '../route' + +function makeRequest() { + return new NextRequest('http://localhost/api/peanut/user/get-user-from-cookie') +} + +beforeEach(() => { + jest.clearAllMocks() + process.env.PEANUT_API_KEY = 'test-api-key' +}) + +describe('GET /api/peanut/user/get-user-from-cookie', () => { + it('returns 400 when no JWT cookie exists', async () => { + mockCookieGet.mockReturnValue(undefined) + + const res = await GET(makeRequest()) + + expect(res.status).toBe(400) + expect(mockFetch).not.toHaveBeenCalled() + }) + + it('returns user data and refreshes cookie on successful auth (200)', async () => { + mockCookieGet.mockReturnValue({ name: 'jwt-token', value: 'valid-token' }) + mockFetch.mockResolvedValue({ + status: 200, + json: async () => ({ user: { userId: '123', email: 'test@test.com' } }), + }) + + const res = await GET(makeRequest()) + const body = await res.json() + + expect(res.status).toBe(200) + expect(body.user.userId).toBe('123') + + // Cookie should be refreshed with 30-day maxAge + expect(mockCookieSet).toHaveBeenCalledWith('jwt-token', 'valid-token', { + httpOnly: false, + secure: false, // NODE_ENV !== 'production' in tests + path: '/', + sameSite: 'lax', + maxAge: 30 * 24 * 60 * 60, + }) + }) + + it('clears cookie and sets Clear-Site-Data on 401 (expired JWT)', async () => { + mockCookieGet.mockReturnValue({ name: 'jwt-token', value: 'expired-token' }) + mockFetch.mockResolvedValue({ + status: 401, + }) + + const res = await GET(makeRequest()) + + expect(res.status).toBe(401) + + // Cookie should be cleared + expect(res.headers.get('Set-Cookie')).toBe('jwt-token=; Path=/; Max-Age=0; SameSite=Lax') + expect(res.headers.get('Clear-Site-Data')).toBe('"cache"') + + // Cookie should NOT be refreshed + expect(mockCookieSet).not.toHaveBeenCalled() + }) + + it('does NOT refresh cookie on non-200 responses', async () => { + mockCookieGet.mockReturnValue({ name: 'jwt-token', value: 'some-token' }) + mockFetch.mockResolvedValue({ + status: 500, + }) + + const res = await GET(makeRequest()) + + expect(res.status).toBe(500) + expect(mockCookieSet).not.toHaveBeenCalled() + }) + + it('still returns 200 if cookie refresh fails', async () => { + mockCookieGet.mockReturnValue({ name: 'jwt-token', value: 'valid-token' }) + mockFetch.mockResolvedValue({ + status: 200, + json: async () => ({ user: { userId: '123' } }), + }) + mockCookieSet.mockImplementation(() => { + throw new Error('cookies() can only be used in server components') + }) + + const res = await GET(makeRequest()) + + // Should still succeed — cookie refresh is best-effort + expect(res.status).toBe(200) + const body = await res.json() + expect(body.user.userId).toBe('123') + }) +}) diff --git a/src/app/api/peanut/user/get-user-from-cookie/route.ts b/src/app/api/peanut/user/get-user-from-cookie/route.ts index 5e4814ccc..29e7b172c 100644 --- a/src/app/api/peanut/user/get-user-from-cookie/route.ts +++ b/src/app/api/peanut/user/get-user-from-cookie/route.ts @@ -1,6 +1,7 @@ import { PEANUT_API_URL } from '@/constants/general.consts' import { fetchWithSentry } from '@/utils/sentry.utils' import { NextRequest, NextResponse } from 'next/server' +import { cookies } from 'next/headers' import { getJWTCookie } from '@/utils/cookie-migration.utils' export async function GET(_request: NextRequest) { @@ -39,6 +40,23 @@ export async function GET(_request: NextRequest) { } const data = await response.json() + + // Refresh cookie expiry only when backend confirms JWT is valid. + // This keeps active users logged in indefinitely without refreshing + // expired JWTs (which caused infinite loading loops). + try { + const cookieStore = await cookies() + cookieStore.set('jwt-token', token.value, { + httpOnly: false, + secure: process.env.NODE_ENV === 'production', + path: '/', + sameSite: 'lax', + maxAge: 30 * 24 * 60 * 60, // 30 days + }) + } catch { + // cookie refresh is best-effort + } + return new NextResponse(JSON.stringify(data), { status: 200, headers: { diff --git a/src/app/api/peanut/user/login-user/route.ts b/src/app/api/peanut/user/login-user/route.ts index dcffd05c5..b81446403 100644 --- a/src/app/api/peanut/user/login-user/route.ts +++ b/src/app/api/peanut/user/login-user/route.ts @@ -40,6 +40,7 @@ export async function POST(request: NextRequest) { secure: process.env.NODE_ENV === 'production', path: '/', sameSite: 'lax', + maxAge: 30 * 24 * 60 * 60, // 30 days }) return new NextResponse(JSON.stringify(data), { diff --git a/src/app/api/peanut/user/register-user/route.ts b/src/app/api/peanut/user/register-user/route.ts index 87da22491..0b07fac51 100644 --- a/src/app/api/peanut/user/register-user/route.ts +++ b/src/app/api/peanut/user/register-user/route.ts @@ -46,6 +46,7 @@ export async function POST(request: NextRequest) { secure: process.env.NODE_ENV === 'production', path: '/', sameSite: 'lax', + maxAge: 30 * 24 * 60 * 60, // 30 days }) return new NextResponse(JSON.stringify(data), { status: 200, diff --git a/src/app/layout.tsx b/src/app/layout.tsx index ebc435325..da454dad8 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -8,6 +8,7 @@ import { PEANUT_API_URL, BASE_URL } from '@/constants/general.consts' import { type Metadata } from 'next' const baseUrl = BASE_URL || 'https://peanut.me' +const IS_PRODUCTION_DOMAIN = baseUrl === 'https://peanut.me' export const metadata: Metadata = { title: 'Peanut - Instant Global P2P Payments in Digital Dollars', @@ -15,8 +16,11 @@ export const metadata: Metadata = { 'Send and receive money instantly with Peanut - a fast, peer-to-peer payments app powered by digital dollars. Easily transfer funds across borders. Enjoy cheap, instant remittances and cash out to local banks without technical hassle.', metadataBase: new URL(baseUrl), icons: { icon: '/favicon.ico' }, + alternates: { canonical: '/' }, keywords: 'peer-to-peer payments, send money instantly, request money, fast global transfers, remittances, digital dollar transfers, Latin America, Argentina, Brazil, P2P payments, crypto payments, stablecoin, digital dollars', + // Block staging/preview deploys from indexing (belt-and-suspenders with robots.ts) + robots: IS_PRODUCTION_DOMAIN ? { index: true, follow: true } : { index: false, follow: false }, openGraph: { type: 'website', title: 'Peanut - Instant Global P2P Payments in Digital Dollars', @@ -38,6 +42,51 @@ export const metadata: Metadata = { applicationName: process.env.NODE_ENV === 'development' ? 'Peanut Dev' : 'Peanut', } +// JSON-LD structured data — site-wide schemas (Organization, WebApplication, WebSite) +// FAQPage schema moved to page.tsx (homepage) where it belongs +const jsonLd = { + '@context': 'https://schema.org', + '@graph': [ + { + '@type': 'Organization', + '@id': `${baseUrl}/#organization`, + name: 'Peanut', + url: baseUrl, + logo: { + '@type': 'ImageObject', + url: `${baseUrl}/metadata-img.png`, + }, + sameAs: [ + 'https://twitter.com/PeanutProtocol', + 'https://github.com/peanutprotocol', + 'https://www.linkedin.com/company/peanut-trade/', + ], + }, + { + '@type': 'WebApplication', + '@id': `${baseUrl}/#app`, + name: 'Peanut', + url: baseUrl, + applicationCategory: 'FinanceApplication', + operatingSystem: 'Web', + offers: { + '@type': 'Offer', + price: '0', + priceCurrency: 'USD', + }, + description: + 'Send and receive money instantly with Peanut — a fast, peer-to-peer payments app powered by digital dollars.', + }, + { + '@type': 'WebSite', + '@id': `${baseUrl}/#website`, + name: 'Peanut', + url: baseUrl, + publisher: { '@id': `${baseUrl}/#organization` }, + }, + ], +} + const roboto = Roboto_Flex({ subsets: ['latin'], display: 'swap', @@ -94,6 +143,12 @@ export default function RootLayout({ children }: { children: React.ReactNode }) <head> <meta name="color-scheme" content="light" /> + {/* JSON-LD structured data */} + <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} /> + + {/* AI-readable product description (llms.txt spec) */} + <link rel="author" type="text/markdown" href="/llms.txt" /> + {/* DNS prefetch for API */} <link rel="dns-prefetch" href={apiHostname} /> <link rel="preconnect" href={apiHostname} crossOrigin="anonymous" /> diff --git a/src/app/lp/card/CardLandingPage.tsx b/src/app/lp/card/CardLandingPage.tsx index 1cd3a6bbf..913f9eb40 100644 --- a/src/app/lp/card/CardLandingPage.tsx +++ b/src/app/lp/card/CardLandingPage.tsx @@ -1,16 +1,14 @@ 'use client' import { motion } from 'framer-motion' import Image from 'next/image' -import Layout from '@/components/Global/Layout' import { Button } from '@/components/0_Bruddle/Button' import { FAQsPanel } from '@/components/Global/FAQs' import PioneerCard3D from '@/components/LandingPage/PioneerCard3D' -import Footer from '@/components/LandingPage/Footer' import { Marquee } from '@/components/LandingPage' import { useAuth } from '@/context/authContext' import { useRouter } from 'next/navigation' import { Star, HandThumbsUp } from '@/assets' -import { useState, useEffect } from 'react' +import { useEffect } from 'react' import underMaintenanceConfig from '@/config/underMaintenance.config' const faqQuestions = [ @@ -44,8 +42,6 @@ const faqQuestions = [ const CardLandingPage = () => { const { user } = useAuth() const router = useRouter() - const [isMobile, setIsMobile] = useState(false) - // feature flag: redirect to landing if card pioneers is disabled useEffect(() => { if (underMaintenanceConfig.disableCardPioneers) { @@ -53,13 +49,6 @@ const CardLandingPage = () => { } }, [router]) - useEffect(() => { - const checkMobile = () => setIsMobile(window.innerWidth < 768) - checkMobile() - window.addEventListener('resize', checkMobile) - return () => window.removeEventListener('resize', checkMobile) - }, []) - if (underMaintenanceConfig.disableCardPioneers) { return null } @@ -79,10 +68,10 @@ const CardLandingPage = () => { } return ( - <Layout className="enable-select !m-0 w-full !p-0"> + <> {/* Hero Section - Yellow with card */} <section id="hero" className="relative overflow-hidden bg-yellow-1 py-16 md:py-24"> - {!isMobile && <FloatingStars />} + <FloatingStars /> <div className="relative mx-auto max-w-6xl px-4"> <div className="flex flex-col items-center text-center"> @@ -146,7 +135,7 @@ const CardLandingPage = () => { className="relative overflow-hidden py-20" style={{ backgroundColor: '#F9F4F0' }} > - {!isMobile && <FloatingStars />} + <FloatingStars /> <div className="relative mx-auto max-w-5xl px-4"> <motion.h2 @@ -193,7 +182,7 @@ const CardLandingPage = () => { className="relative overflow-hidden py-20" style={{ backgroundColor: '#F9F4F0' }} > - {!isMobile && <FloatingStars />} + <FloatingStars /> <div className="mx-auto max-w-5xl px-4"> <div className="flex flex-col items-center gap-12 md:flex-row"> {/* Visual - Simplified Invite Visual */} @@ -632,7 +621,7 @@ const CardLandingPage = () => { {/* Coverage - Yellow */} <section id="coverage" className="relative overflow-hidden bg-yellow-1 py-20"> - {!isMobile && <FloatingStars />} + <FloatingStars /> <div className="relative mx-auto max-w-4xl px-4 text-center"> <motion.h2 @@ -722,7 +711,7 @@ const CardLandingPage = () => { {/* FAQ - Cream */} <section id="faq" className="relative overflow-hidden py-12" style={{ backgroundColor: '#F9F4F0' }}> - {!isMobile && <FloatingStars />} + <FloatingStars /> <div className="relative mx-auto max-w-3xl px-4"> <FAQsPanel heading="FAQ" questions={faqQuestions} /> @@ -744,7 +733,7 @@ const CardLandingPage = () => { {/* Final CTA - Secondary Yellow */} <section id="join" className="relative overflow-hidden bg-secondary-1 py-24 text-center text-n-1"> - {!isMobile && <FloatingStars />} + <FloatingStars /> <div className="relative mx-auto max-w-2xl px-4"> <motion.div @@ -793,15 +782,12 @@ const CardLandingPage = () => { </section> <Marquee {...marqueeProps} /> - - <Footer /> - </Layout> + </> ) } -// Floating stars component - matches Manteca.tsx pattern exactly +// Floating stars component const FloatingStars = () => { - // Match Manteca's star configuration pattern const starConfigs = [ { className: 'absolute left-12 top-10', delay: 0.2 }, { className: 'absolute left-56 top-1/2', delay: 0.2 }, @@ -820,7 +806,6 @@ const FloatingStars = () => { width={50} height={50} className={`${config.className} hidden md:block`} - // Exact Manteca animation pattern initial={{ opacity: 0, translateY: 20, translateX: 5, rotate: 22 }} whileInView={{ opacity: 1, translateY: 0, translateX: 0, rotate: 22 }} transition={{ type: 'spring', damping: 5, delay: config.delay }} diff --git a/src/app/lp/card/page.tsx b/src/app/lp/card/page.tsx index 4952bf794..5446cf17c 100644 --- a/src/app/lp/card/page.tsx +++ b/src/app/lp/card/page.tsx @@ -1,4 +1,6 @@ import { generateMetadata as generateMeta } from '@/app/metadata' +import { LandingPageShell } from '@/components/LandingPage/LandingPageShell' +import Footer from '@/components/LandingPage/Footer' import CardLandingPage from './CardLandingPage' export const metadata = generateMeta({ @@ -10,5 +12,10 @@ export const metadata = generateMeta({ }) export default function CardLPPage() { - return <CardLandingPage /> + return ( + <LandingPageShell> + <CardLandingPage /> + <Footer /> + </LandingPageShell> + ) } diff --git a/src/app/lp/layout.tsx b/src/app/lp/layout.tsx new file mode 100644 index 000000000..60b9e0126 --- /dev/null +++ b/src/app/lp/layout.tsx @@ -0,0 +1,10 @@ +import { type Metadata } from 'next' + +// /lp is an alias for the root landing page — canonical points to / +export const metadata: Metadata = { + alternates: { canonical: '/' }, +} + +export default function LpLayout({ children }: { children: React.ReactNode }) { + return children +} diff --git a/src/app/lp/page.tsx b/src/app/lp/page.tsx index e613c7406..fe98c7c1e 100644 --- a/src/app/lp/page.tsx +++ b/src/app/lp/page.tsx @@ -3,6 +3,33 @@ /** * /lp route - Landing page that is ALWAYS accessible regardless of auth state. * This allows logged-in users to view the marketing landing page. - * For SEO, the root "/" remains the canonical landing page URL. + * Uses Layout (client) instead of LandingPageShell since SSR doesn't matter here. */ -export { default } from '@/app/page' + +import Layout from '@/components/Global/Layout' +import { LandingPageClient } from '@/components/LandingPage/LandingPageClient' +import Manteca from '@/components/LandingPage/Manteca' +import { RegulatedRails } from '@/components/LandingPage/RegulatedRails' +import { YourMoney } from '@/components/LandingPage/yourMoney' +import { SecurityBuiltIn } from '@/components/LandingPage/securityBuiltIn' +import { SendInSeconds } from '@/components/LandingPage/sendInSeconds' +import Footer from '@/components/LandingPage/Footer' +import { heroConfig, faqData, marqueeMessages } from '@/components/LandingPage/landingPageData' + +export default function LPPage() { + return ( + <Layout className="enable-select !m-0 w-full !p-0"> + <LandingPageClient + heroConfig={heroConfig} + faqData={faqData} + marqueeMessages={marqueeMessages} + mantecaSlot={<Manteca />} + regulatedRailsSlot={<RegulatedRails />} + yourMoneySlot={<YourMoney />} + securitySlot={<SecurityBuiltIn />} + sendInSecondsSlot={<SendInSeconds />} + footerSlot={<Footer />} + /> + </Layout> + ) +} diff --git a/src/app/metadata.ts b/src/app/metadata.ts index c7aeb73c7..64c4cbb50 100644 --- a/src/app/metadata.ts +++ b/src/app/metadata.ts @@ -6,11 +6,14 @@ export function generateMetadata({ description, image = '/metadata-img.png', keywords, + canonical, }: { title: string description: string image?: string keywords?: string + /** Canonical URL path (e.g. '/careers') or full URL. Resolved against metadataBase. */ + canonical?: string }): Metadata { return { title, @@ -22,7 +25,7 @@ export function generateMetadata({ type: 'website', title, description, - url: BASE_URL, + url: canonical ? `${BASE_URL}${canonical}` : BASE_URL, siteName: 'Peanut', images: [{ url: image, width: 1200, height: 630, alt: title }], }, @@ -35,5 +38,6 @@ export function generateMetadata({ site: '@PeanutProtocol', }, applicationName: process.env.NODE_ENV === 'development' ? 'Peanut Dev' : 'Peanut', + ...(canonical ? { alternates: { canonical } } : {}), } } diff --git a/src/app/page.tsx b/src/app/page.tsx index e129e937c..cbdb5e6c6 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,228 +1,34 @@ -'use client' - -import Layout from '@/components/Global/Layout' -import { - DropLink, - FAQs, - Hero, - Marquee, - NoFees, - SecurityBuiltIn, - SendInSeconds, - YourMoney, - RegulatedRails, - CardPioneers, -} from '@/components/LandingPage' -import Footer from '@/components/LandingPage/Footer' +import { Suspense } from 'react' +import { LandingPageShell } from '@/components/LandingPage/LandingPageShell' +import { LandingPageClient } from '@/components/LandingPage/LandingPageClient' import Manteca from '@/components/LandingPage/Manteca' -import TweetCarousel from '@/components/LandingPage/TweetCarousel' -import underMaintenanceConfig from '@/config/underMaintenance.config' -import { useFooterVisibility } from '@/context/footerVisibility' -import { useEffect, useState, useRef } from 'react' +import { RegulatedRails } from '@/components/LandingPage/RegulatedRails' +import { YourMoney } from '@/components/LandingPage/yourMoney' +import { SecurityBuiltIn } from '@/components/LandingPage/securityBuiltIn' +import { SendInSeconds } from '@/components/LandingPage/sendInSeconds' +import Footer from '@/components/LandingPage/Footer' +import { faqSchema, JsonLd } from '@/lib/seo/schemas' +import { heroConfig, faqData, marqueeMessages } from '@/components/LandingPage/landingPageData' export default function LandingPage() { - const { isFooterVisible } = useFooterVisibility() - const [buttonVisible, setButtonVisible] = useState(true) - const [isScrollFrozen, setIsScrollFrozen] = useState(false) - const [buttonScale, setButtonScale] = useState(1) - const [animationComplete, setAnimationComplete] = useState(false) - const [shrinkingPhase, setShrinkingPhase] = useState(false) - const [hasGrown, setHasGrown] = useState(false) - const sendInSecondsRef = useRef<HTMLDivElement>(null) - const frozenScrollY = useRef(0) - const virtualScrollY = useRef(0) - const previousScrollY = useRef(0) - - const hero = { - heading: 'Peanut', - marquee: { - visible: true, - message: ['No fees', 'Instant', '24/7', 'USD', 'EUR', 'CRYPTO', 'GLOBAL', 'SELF-CUSTODIAL'], - }, - primaryCta: { - label: 'SIGN UP', - href: '/setup', - subtext: 'currently in waitlist', - }, - } - - const faqs = { - heading: 'Faqs', - questions: [ - { - id: '0', - question: 'Why Peanut?', - answer: `It's time to take control of your money. No banks, no borders. Just buttery smooth global money.`, - }, - { - id: '1', - question: 'What is Peanut?', - answer: 'Peanut is the easiest way to send digital dollars to anyone anywhere. Peanut’s tech is powered by cutting-edge cryptography and the security of biometric user authentication as well as a network of modern and fully licensed banking providers.', - }, - { - id: '2', - question: 'Do I have to KYC?', - answer: 'No! You can use core functionalities (like sending and receiving money) without KYC. Bank connections, however, trigger a one‑time check handled by Persona, a SOC2 Type 2 certified and GDPR compliant ISO 27001–certified provider used by brands like Square and Robinhood. Your documents remain locked away with Persona, not Peanut, and Peanut only gets a yes/no response, keeping your privacy intact.', - }, - { - id: '3', - question: 'Could a thief drain my wallet if they stole my phone?', - answer: 'Not without your face or fingerprint. The passkey is sealed in the Secure Enclave of your phone and never exported. It’s secured by NIST‑recommended P‑256 Elliptic Curve cryptography. Defeating that would be tougher than guessing all 10¹⁰¹⁰ combinations of a 30‑character password made of emoji.\n This means your account is yours alone. Neither Peanut nor anyone else can freeze or seize it — because we never hold your keys. Your key never touches our servers; compliance requests only see cryptographic and encrypted signatures. Cracking those signatures would demand more energy than the Sun outputs in a full century.', - }, - { - id: '4', - question: 'What happens to my funds if Peanut’s servers were breached?', - answer: "Nothing. Your funds sit in your self‑custodied smart account (not on Peanut servers). Every transfer still needs a signature from your biometric passkey, so a server‑side attacker has no way to move a cent without the private key sealed in your device's Secure Enclave. Even if Peanut were offline, you could point any ERC‑4337‑compatible wallet at your smart account and recover access independently.", - }, - { - id: '5', - question: 'How does Peanut make money?', - answer: 'We plan to charge merchants for accepting Peanut as a payment method, whilst still being much cheaper than VISA and Mastercard. For users, we only charge minimal amounts!', - }, - { - id: '6', - question: 'My question is not here', - answer: 'Check out our full FAQ page at https://peanutprotocol.notion.site/FAQ-2a4838117579805dad62ff47c9d2eb7a or visit our support page at https://peanut.me/support for more help.', - }, - ], - marquee: { - visible: false, - message: 'Peanut', - }, - } - - useEffect(() => { - if (isFooterVisible) { - setButtonVisible(false) - } else { - setButtonVisible(true) - } - }, [isFooterVisible]) - - useEffect(() => { - const handleScroll = () => { - if (sendInSecondsRef.current) { - const targetElement = document.getElementById('sticky-button-target') - if (!targetElement) return - - const targetRect = targetElement.getBoundingClientRect() - const currentScrollY = window.scrollY - - // Check if the sticky button should "freeze" at the target position - // Calculate where the sticky button currently is (bottom-4 = 16px from bottom) - const stickyButtonTop = window.innerHeight - 16 - 52 // 16px bottom margin, ~52px button height - const stickyButtonBottom = window.innerHeight - 16 - - // Freeze when the target element overlaps with the sticky button position (even lower) - const shouldFreeze = - targetRect.top <= stickyButtonBottom - 60 && - targetRect.bottom >= stickyButtonTop - 60 && - !animationComplete && - !shrinkingPhase && - !hasGrown - - if (shouldFreeze && !isScrollFrozen) { - // Start freeze - prevent normal scrolling - setIsScrollFrozen(true) - frozenScrollY.current = currentScrollY - virtualScrollY.current = 0 - document.body.style.overflow = 'hidden' - window.scrollTo(0, frozenScrollY.current) - } else if (isScrollFrozen && !animationComplete) { - // During freeze - maintain scroll position - window.scrollTo(0, frozenScrollY.current) - } else if (animationComplete && !shrinkingPhase && currentScrollY > frozenScrollY.current + 50) { - // Start shrinking phase when user scrolls further after animation complete - setShrinkingPhase(true) - } else if (shrinkingPhase) { - // Shrink button back to original size based on scroll distance - const shrinkDistance = Math.max(0, currentScrollY - (frozenScrollY.current + 50)) - const maxShrinkDistance = 200 - const shrinkProgress = Math.min(1, shrinkDistance / maxShrinkDistance) - const newScale = 1.5 - shrinkProgress * 0.5 // Scale from 1.5 back to 1 - setButtonScale(Math.max(1, newScale)) - } else if (animationComplete && currentScrollY < frozenScrollY.current - 100) { - // Reset everything when scrolling back up past the SendInSeconds component - setAnimationComplete(false) - setShrinkingPhase(false) - setButtonScale(1) - setHasGrown(false) - } - - // Update previous scroll position for direction tracking - previousScrollY.current = currentScrollY - } - } - - const handleWheel = (event: WheelEvent) => { - if (isScrollFrozen && !animationComplete) { - event.preventDefault() - - // Only increase scale when scrolling down (positive deltaY) - if (event.deltaY > 0) { - virtualScrollY.current += event.deltaY - - // Scale button based on virtual scroll (max scale of 1.5) - requires more scrolling - const maxVirtualScroll = 500 // Increased from 200 to require more scrolling - const newScale = Math.min(1.5, 1 + (virtualScrollY.current / maxVirtualScroll) * 0.5) - setButtonScale(newScale) - - // Complete animation when we reach max scale - if (newScale >= 1.5) { - setAnimationComplete(true) - setHasGrown(true) - document.body.style.overflow = '' - setIsScrollFrozen(false) - } - } - // When scrolling up (negative deltaY), don't change the scale - } - } - - window.addEventListener('scroll', handleScroll) - window.addEventListener('wheel', handleWheel, { passive: false }) - handleScroll() // Check initial state - - return () => { - window.removeEventListener('scroll', handleScroll) - window.removeEventListener('wheel', handleWheel) - document.body.style.overflow = '' // Cleanup - } - }, [isScrollFrozen, animationComplete, shrinkingPhase, hasGrown]) - - const marqueeProps = { visible: hero.marquee.visible, message: hero.marquee.message } + const faqJsonLd = faqSchema(faqData.questions.map((q) => ({ question: q.question, answer: q.answer }))) return ( - <Layout className="enable-select !m-0 w-full !p-0"> - <Hero primaryCta={hero.primaryCta} buttonVisible={buttonVisible} buttonScale={buttonScale} /> - <Marquee {...marqueeProps} /> - <Manteca /> - <Marquee {...marqueeProps} /> - {!underMaintenanceConfig.disableCardPioneers && ( - <> - <CardPioneers /> - <Marquee {...marqueeProps} /> - </> - )} - <TweetCarousel /> - <Marquee {...marqueeProps} /> - <RegulatedRails /> - <Marquee {...marqueeProps} /> - <YourMoney /> - <Marquee {...marqueeProps} /> - <DropLink /> - <Marquee {...marqueeProps} /> - <SecurityBuiltIn /> - <Marquee {...marqueeProps} /> - <div ref={sendInSecondsRef}> - <SendInSeconds /> - </div> - <Marquee {...marqueeProps} /> - <NoFees /> - <Marquee {...marqueeProps} /> - <FAQs heading={faqs.heading} questions={faqs.questions} marquee={faqs.marquee} /> - <Marquee {...marqueeProps} /> - <Footer /> - </Layout> + <LandingPageShell> + <JsonLd data={faqJsonLd} /> + <Suspense> + <LandingPageClient + heroConfig={heroConfig} + faqData={faqData} + marqueeMessages={marqueeMessages} + mantecaSlot={<Manteca />} + regulatedRailsSlot={<RegulatedRails />} + yourMoneySlot={<YourMoney />} + securitySlot={<SecurityBuiltIn />} + sendInSecondsSlot={<SendInSeconds />} + footerSlot={<Footer />} + /> + </Suspense> + </LandingPageShell> ) } diff --git a/src/app/robots.ts b/src/app/robots.ts index d9d154d42..9ce741e3f 100644 --- a/src/app/robots.ts +++ b/src/app/robots.ts @@ -1,27 +1,85 @@ import type { MetadataRoute } from 'next' import { BASE_URL } from '@/constants/general.consts' +import { SUPPORTED_LOCALES } from '@/i18n/types' + +const IS_PRODUCTION_DOMAIN = BASE_URL === 'https://peanut.me' export default function robots(): MetadataRoute.Robots { + // Block indexing on staging, preview deploys, and non-production domains + if (!IS_PRODUCTION_DOMAIN) { + return { + rules: [{ userAgent: '*', disallow: ['/'] }], + } + } + return { rules: [ + // Allow Twitterbot to fetch OG images for link previews { userAgent: 'Twitterbot', allow: ['/api/og'], disallow: [], }, + + // AI search engine crawlers — explicitly welcome { - userAgent: '*', - allow: ['/', '/about', '/send', '/request/create', '/cashout', '/jobs'], - disallow: ['/api/', '/sdk/', '/*dashboard', '/*profile'], - }, - { - userAgent: 'AhrefsBot', - crawlDelay: 10, + userAgent: [ + 'GPTBot', + 'ChatGPT-User', + 'PerplexityBot', + 'ClaudeBot', + 'Google-Extended', + 'Applebot-Extended', + ], + allow: ['/'], + disallow: ['/api/', '/home', '/profile', '/settings', '/setup', '/dev/'], }, + + // Default rules for all crawlers { - userAgent: 'SemrushBot', - crawlDelay: 10, + userAgent: '*', + allow: [ + '/', + '/careers', + '/privacy', + '/terms', + '/exchange', + '/lp/card', + // SEO routes (all locale-prefixed) + ...SUPPORTED_LOCALES.map((l) => `/${l}/`), + ], + disallow: [ + '/api/', + '/sdk/', + // Auth-gated app routes + '/home', + '/profile', + '/settings', + '/send', + '/request', + '/setup', + '/claim', + '/pay', + '/dev/', + '/qr', + '/history', + '/points', + '/invite', + '/kyc', + '/maintenance', + '/quests', + '/receipt', + '/crisp-proxy', + '/card-payment', + '/add-money', + '/withdraw', + ], }, + + // Rate-limit aggressive SEO crawlers + { userAgent: 'AhrefsBot', crawlDelay: 10 }, + { userAgent: 'SemrushBot', crawlDelay: 10 }, + { userAgent: 'MJ12bot', crawlDelay: 10 }, ], sitemap: `${BASE_URL}/sitemap.xml`, } diff --git a/src/app/sitemap.ts b/src/app/sitemap.ts index 22b241b80..cc16d1d33 100644 --- a/src/app/sitemap.ts +++ b/src/app/sitemap.ts @@ -1,19 +1,127 @@ import { type MetadataRoute } from 'next' +import { BASE_URL } from '@/constants/general.consts' +import { COUNTRIES_SEO, CORRIDORS, COMPETITORS, EXCHANGES, PAYMENT_METHOD_SLUGS } from '@/data/seo' +import { SUPPORTED_LOCALES } from '@/i18n/config' +import { listContentSlugs } from '@/lib/content' + +// TODO (infra): Update GitHub org, Twitter bio, LinkedIn, npm package.json → peanut.me +// TODO (GA4): Create data filter to exclude trafficheap.com referral traffic + +/** Build date used for non-content pages that don't have their own date. */ +const BUILD_DATE = new Date() async function generateSitemap(): Promise<MetadataRoute.Sitemap> { - const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'https://peanut.me' + type SitemapEntry = { + path: string + priority: number + changeFrequency: MetadataRoute.Sitemap[number]['changeFrequency'] + lastModified?: Date + } - const staticPages = ['', '/about', '/jobs'] + const pages: SitemapEntry[] = [ + // Homepage + { path: '', priority: 1.0, changeFrequency: 'weekly' }, - // generate entries for static pages - const staticEntries = staticPages.map((page) => ({ - url: `${baseUrl}${page}`, - lastModified: new Date(), - changeFrequency: 'weekly' as const, - priority: 1.0, - })) + // Product pages + { path: '/lp/card', priority: 0.9, changeFrequency: 'weekly' }, + + // Public pages + { path: '/careers', priority: 0.7, changeFrequency: 'monthly' }, + { path: '/exchange', priority: 0.7, changeFrequency: 'weekly' }, + + // Legal + { path: '/privacy', priority: 0.5, changeFrequency: 'yearly' }, + { path: '/terms', priority: 0.5, changeFrequency: 'yearly' }, + ] + + // --- Programmatic SEO pages (all locales with /{locale}/ prefix) --- + for (const locale of SUPPORTED_LOCALES) { + const isDefault = locale === 'en' + const basePriority = isDefault ? 1.0 : 0.9 // EN gets slightly higher priority + + // Country hub pages + for (const country of Object.keys(COUNTRIES_SEO)) { + pages.push({ path: `/${locale}/${country}`, priority: 0.9 * basePriority, changeFrequency: 'weekly' }) + } + + // Send-money-to country pages + for (const country of Object.keys(COUNTRIES_SEO)) { + pages.push({ + path: `/${locale}/send-money-to/${country}`, + priority: 0.8 * basePriority, + changeFrequency: 'weekly', + }) + } - return staticEntries + // From-to corridor pages + for (const corridor of CORRIDORS) { + pages.push({ + path: `/${locale}/send-money-from/${corridor.from}/to/${corridor.to}`, + priority: 0.85 * basePriority, + changeFrequency: 'weekly', + }) + } + + // Receive money pages (unique sending countries from corridors) + const receiveSources = [...new Set(CORRIDORS.map((c) => c.from))] + for (const source of receiveSources) { + pages.push({ + path: `/${locale}/receive-money-from/${source}`, + priority: 0.7 * basePriority, + changeFrequency: 'weekly', + }) + } + + // Comparison pages + for (const slug of Object.keys(COMPETITORS)) { + pages.push({ + path: `/${locale}/compare/peanut-vs-${slug}`, + priority: 0.7 * basePriority, + changeFrequency: 'monthly', + }) + } + + // Deposit pages + for (const exchange of Object.keys(EXCHANGES)) { + pages.push({ + path: `/${locale}/deposit/from-${exchange}`, + priority: 0.7 * basePriority, + changeFrequency: 'monthly', + }) + } + + // Pay-with pages + for (const method of PAYMENT_METHOD_SLUGS) { + pages.push({ + path: `/${locale}/pay-with/${method}`, + priority: 0.7 * basePriority, + changeFrequency: 'monthly', + }) + } + + // Help center + pages.push({ + path: `/${locale}/help`, + priority: 0.7 * basePriority, + changeFrequency: 'weekly', + }) + for (const slug of listContentSlugs('help')) { + pages.push({ + path: `/${locale}/help/${slug}`, + priority: 0.6 * basePriority, + changeFrequency: 'monthly', + }) + } + + // Blog and team pages excluded from production sitemap (not yet launched) + } + + return pages.map((page) => ({ + url: `${BASE_URL}${page.path}`, + lastModified: page.lastModified ?? BUILD_DATE, + changeFrequency: page.changeFrequency, + priority: page.priority, + })) } export default generateSitemap diff --git a/src/app/sw.ts b/src/app/sw.ts index 22a34cf60..910994044 100644 --- a/src/app/sw.ts +++ b/src/app/sw.ts @@ -1,6 +1,6 @@ import { defaultCache } from '@serwist/next/worker' import type { PrecacheEntry, SerwistGlobalConfig } from 'serwist' -import { Serwist } from 'serwist' +import { NetworkOnly, Serwist } from 'serwist' // This declares the value of `injectionPoint` to TypeScript. // `injectionPoint` is the string that will be replaced by the @@ -20,7 +20,15 @@ const serwist = new Serwist({ skipWaiting: true, clientsClaim: true, navigationPreload: true, - runtimeCaching: defaultCache, + runtimeCaching: [ + // Never cache auth/user API responses — stale 401s cause infinite loading loops + { + matcher: ({ sameOrigin, url: { pathname } }: { sameOrigin: boolean; url: URL }) => + sameOrigin && pathname.startsWith('/api/peanut/user/'), + handler: new NetworkOnly(), + }, + ...defaultCache, + ], disableDevLogs: false, }) diff --git a/src/assets/cards/DEPRECATED_Cart Gradient 5.svg b/src/assets/cards/DEPRECATED_Cart Gradient 5.svg deleted file mode 100644 index 9133d2123..000000000 --- a/src/assets/cards/DEPRECATED_Cart Gradient 5.svg +++ /dev/null @@ -1,625 +0,0 @@ -<svg width="1211" height="768" viewBox="0 0 1211 768" fill="none" xmlns="http://www.w3.org/2000/svg"> -<rect x="5.1533" y="5.1533" width="1203.69" height="760.114" rx="62.4456" fill="#FF90E8" stroke="url(#paint0_linear_17007_2405)" stroke-width="4.3066"/> -<mask id="mask0_17007_2405" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="1208" height="765"> -<rect width="1208" height="764.421" rx="64.5989" fill="#FF90E8"/> -</mask> -<g mask="url(#mask0_17007_2405)"> -<path d="M415.562 272.075C412 271.892 398.967 272.4 396.449 271.738C395.914 270.784 395.944 264.607 396.385 263.4C397.639 262.775 421.529 263.042 424.847 263.033C424.565 265.354 424.643 269.853 424.765 272.22C427.73 272.356 431.472 272.268 434.511 272.293C434.549 275.414 434.513 278.604 434.511 281.729C431.296 281.697 428.081 281.701 424.866 281.743C424.728 283.895 424.184 289.48 425.217 290.987C426.617 291.985 432.311 291.457 434.51 291.42C434.772 288.475 434.619 284.799 434.57 281.773L458.946 281.766C462.784 281.766 468.834 281.607 472.454 281.992C472.594 284.778 472.421 288.648 472.36 291.478C474.397 291.413 480.486 291.763 481.86 291.201C482.482 289.224 482.243 275.276 482.236 272.234C486.654 272.081 497.126 272.616 500.876 272.104C500.883 275.066 500.984 278.811 500.717 281.69C497.758 281.814 494.232 281.743 491.24 281.745C491.074 284.914 491.166 288.263 491.208 291.443C494.441 291.48 507.815 290.959 509.797 292.047C510.846 294.089 510.141 297.968 510.613 300.471C501.59 300.113 491.975 300.427 482.932 300.558C480.929 300.588 482.826 307.77 481.6 309.57C480.044 310.213 474.308 309.899 472.348 309.864L472.352 319.314C474.559 319.507 478.152 319.39 480.45 319.385C483.946 319.378 487.871 319.434 491.335 319.231C491.413 322.114 491.15 326.767 491.431 329.298C485.81 329.632 478.262 329.427 472.504 329.415C472.317 332.361 472.389 335.702 472.393 338.687C474.75 338.906 479.468 338.724 481.978 338.687C482.07 341.791 482.065 344.898 481.964 348.005C479.304 348.231 475.372 348.072 472.453 348.191C472.221 350.798 472.33 355.251 472.317 357.991C477.974 357.975 485.916 357.719 491.388 358.06C491.664 367.44 492.681 367.108 482.904 366.611C482.591 367.5 481.051 373.956 481.097 374.654C481.295 377.685 489.408 375.352 491.03 376.611C491.759 378.251 491.312 384.193 491.429 386.634L500.883 386.613C501.27 391.868 500.652 399.786 500.689 405.537C503.863 405.562 507.138 405.497 510.323 405.477C510.68 402.743 510.53 396.092 510.503 393.137C510.45 387.705 510.632 381.828 510.452 376.442C507.405 376.387 504.199 376.477 501.102 376.442C501.019 367.067 501.014 357.694 501.088 348.318C504.234 348.261 507.382 348.261 510.53 348.321C510.712 352.614 510.182 355.838 509.585 359.978C509.383 361.37 509.472 365.518 509.477 367.088C516.145 367.302 522.766 366.735 529.581 367.424C529.768 364.393 529.698 361.063 529.694 358C535.695 357.814 542.185 357.924 548.2 357.968C548.295 367.509 548.293 377.053 548.189 386.597C557.286 386.825 567.311 386.604 576.488 386.62C576.756 390.208 576.613 401.838 576.414 405.253C573.305 405.486 570.183 405.449 567.067 405.415C567.21 402.363 567.2 398.922 567.145 395.869C564.488 395.686 560.542 395.76 557.848 395.802C557.717 398.874 557.627 402.43 557.797 405.474C554.939 405.26 551.425 405.502 548.327 405.35C548.376 402.172 548.383 398.996 548.355 395.818C545.933 395.569 541.312 395.786 538.707 395.841C538.627 399.086 538.763 402.209 538.41 405.442C535.262 405.461 532.406 405.922 529.284 406.371C529.214 403.456 529.583 400.844 529.65 397.993C529.735 394.357 529.692 390.598 529.685 386.952C532.183 386.733 536.345 386.846 538.97 386.848C539.221 382.992 538.8 379.92 538.548 376.085C534.985 376.064 532.877 376.14 529.316 375.659C526.997 375.864 521.706 374.735 519.959 375.712C519.154 378.06 519.364 404.619 520.413 405.885C522.455 406.71 526.97 406.468 529.284 406.371C529.261 408.825 529.159 411.877 529.249 414.276C524.098 414.267 514.84 414.009 510.051 414.458C509.917 417.68 509.917 420.727 509.926 423.953C513.116 423.935 516.389 423.877 519.567 424.002C519.735 428.166 519.32 432.209 519.36 436.362C519.433 444.29 519.175 452.204 518.933 460.126C518.818 463.926 518.977 467.839 518.864 471.658L510.367 471.628C509.758 463.087 510.865 452.267 510.549 443.29C507.997 443.299 503.354 443.17 500.966 443.373C500.874 446.256 501.026 450.536 500.673 453.186L491.189 453.2C491.097 449.879 491.217 446.431 491.104 443.209C488.484 443.232 474.183 443.062 472.773 443.638C472.036 445.251 472.357 450.616 472.311 452.734C469.521 452.485 465.946 452.555 463.15 452.721L463.069 465.219C463.061 466.726 462.948 470.25 463.087 471.633C456.823 471.471 450.505 471.748 444.219 471.566C444.151 469.45 443.638 464.666 444.694 463.163C446.07 462.186 451.584 462.615 453.795 462.608C454.047 456.53 453.882 449.448 453.877 443.297C450.714 443.251 447.394 443.313 444.219 443.324C444.433 440.273 444.411 436.897 444.448 433.811C438.264 433.815 431.005 434.002 424.92 433.684C424.669 436.537 424.69 440.644 424.723 443.527L444.163 443.5C444.156 446.546 444.091 449.591 443.97 452.633C442.05 452.651 436.694 452.324 435.283 452.87C434.02 454.182 434.582 459.731 434.35 462.405C431.257 462.435 428.164 462.437 425.072 462.416C425.011 459.238 425.058 455.975 425.013 452.769C422.805 452.449 417.781 452.651 415.446 452.725C415.633 449.814 415.584 446.182 415.524 443.264C410.831 443.186 406.101 443.34 401.403 443.269C399.827 443.246 398.201 443.221 396.639 443.426C395.95 444.677 396.298 450.999 396.171 453.142C394.645 453.209 390.819 453.451 389.504 453.158C385.591 452.287 383.377 451.914 379.376 451.955C378.644 452.624 378.277 453.103 377.645 453.878C377.563 455.91 377.029 460.596 377.913 462.041C379.077 462.953 384.947 462.603 387.035 462.704C387.262 464.995 387.323 478.83 386.65 480.517C385.03 481.183 352.72 480.845 348.49 480.812C348.729 475.191 348.562 468.397 348.566 462.691C351.816 462.522 355.073 462.518 358.324 462.681C358.515 465.523 358.352 469.01 358.499 472.068C361.318 472.179 365.07 472.168 367.869 472.05C368.131 469.04 367.984 464.802 367.973 461.67C367.934 455.622 367.934 449.572 367.972 443.525C369.914 443.536 375.181 443.707 376.692 443.41C378.634 443.027 376.683 436.258 377.776 434.251C379.394 433.543 384.841 433.877 387.085 433.866C387.31 431.428 387.745 426.074 387.729 423.907C391.641 423.967 391.967 425.295 396.498 425.422C399.614 423.799 402.24 424.154 405.744 424.145C405.804 427.367 405.753 430.582 405.822 433.813C408.534 434.016 412.554 433.93 415.367 433.949C415.639 430.884 415.537 426.744 415.516 423.656L405.967 423.721C405.788 417.738 405.999 411.646 405.742 405.686L396.521 405.705C396.446 402.656 396.491 399.425 396.485 396.362C393.338 396.184 390.585 396.532 387.133 396.223C386.92 405.096 387.079 414.649 387.085 423.585C384.603 423.58 383.902 423.543 381.599 424.424C378.599 423.375 373.294 423.578 370.227 423.96C369.723 424.023 368.985 423.808 368.703 423.396C367.595 421.778 367.927 416.477 367.93 414.424C365.412 414.262 360.937 414.223 358.447 414.421C358.502 411.158 358.513 407.894 358.481 404.633C355.564 404.654 351.355 404.808 348.539 404.633L348.555 396.078L358.261 395.998C358.257 398.766 358.197 401.718 358.25 404.47C364.456 404.334 371.365 404.578 377.368 404.329C377.401 401.568 377.449 398.846 377.368 396.083C371.025 396.03 364.756 395.686 358.437 395.795C358.462 392.81 358.56 389.381 358.43 386.438L339.12 386.38L339.301 377.625C343.86 377.638 347.88 377.638 352.444 377.201C354.183 377.035 356.572 377.24 358.401 377.074C358.737 367.489 358.464 356.693 358.511 346.986C355.639 347.198 351.283 347.244 348.42 347.023L348.551 338.855C351.381 338.572 355.056 338.662 357.962 338.703C358.098 335.739 358.124 332.775 358.04 329.812C354.863 329.888 351.685 329.906 348.508 329.871C348.537 323.4 348.305 315.988 348.567 309.648C351.427 309.579 355.575 309.408 358.295 309.934L358.208 329.629C360.21 329.646 366.229 329.89 367.664 329.242C368.616 327.449 367.001 319.952 368.604 319.802C374.284 319.27 380.648 319.482 386.365 319.666C387.543 319.706 386.899 328.473 386.922 329.632C385.507 329.523 383.928 329.537 382.508 329.593C377.684 329.777 372.745 329.417 367.938 329.535C367.851 336.698 367.847 343.863 367.928 351.029C367.959 352.948 367.871 356.203 368.016 357.993L385.912 358.051C385.913 355.285 385.782 351.181 385.947 348.523C388.76 348.196 393.44 348.332 396.397 348.364C396.403 351.57 396.365 354.776 396.283 357.982C402.098 357.991 409.742 357.756 415.371 358.042C415.438 361.312 415.783 373.889 414.992 376.205C414.211 376.94 410.846 377.083 409.626 377.362C408.409 377.641 407.165 378.122 405.965 378.288C405.946 380.989 405.995 383.704 405.668 386.385C402.885 386.396 399.137 386.304 396.434 386.468C396.502 383.227 396.523 379.985 396.496 376.742C406.69 376.594 406.407 378.436 405.832 367.378C405.824 367.212 405.813 367.048 405.798 366.882C402.977 366.906 399.267 367.018 396.498 366.869C396.498 364.333 396.589 360.736 396.366 358.318C393.131 358.302 389.913 358.429 386.68 358.457L386.597 366.813C380.447 366.873 374.079 366.972 367.936 366.855C367.929 370.017 367.823 373.79 367.949 376.901C372.897 377.265 381.537 376.924 386.87 376.933C386.88 379.482 386.766 384.244 386.986 386.666C389.696 386.76 393.545 386.7 396.311 386.611L396.299 395.998C403.39 396.15 410.506 395.968 417.599 396.034C419.556 396.053 422.841 395.852 424.626 396.422C425.074 397.846 424.909 402.624 424.756 404.214C424.577 406.078 417.18 405.35 415.564 405.527C415.216 410.796 415.448 418.003 415.401 423.469C418.211 423.359 421.023 423.29 423.835 423.262C424.427 423.681 425.176 424.251 425.774 424.624C427.82 424.613 433.913 425.306 435.209 424.871C438.665 423.709 440.903 424.46 444.191 423.974C444.037 427.613 444.096 430.434 444.885 433.995C447.347 434.013 451.489 434.147 453.829 433.894C454.085 431.596 453.897 426.327 453.854 423.944C450.896 423.801 447.172 423.926 444.191 423.974C444.047 414.689 444.455 405.057 444.195 395.832C441.297 395.682 437.612 395.767 434.656 395.753C434.472 393.188 434.577 389.3 434.573 386.631C440.928 386.597 447.283 386.597 453.637 386.629C453.823 389.167 453.697 393.315 453.731 396.034C459.905 396.083 466.08 396.078 472.254 396.025C472.457 392.635 472.729 380.063 472.124 377.071C469.424 376.788 466.446 377.311 463.7 377.12C457.168 376.67 450.759 376.567 444.226 376.424C443.975 371.024 444.201 363.439 444.201 357.86C448.906 358.138 453.687 357.719 458.393 358.127C459.817 358.249 461.159 358.327 462.59 358.281C462.651 360.39 462.01 365.808 463.227 367.23C464.165 368.328 470.906 368.157 471.962 367.604C472.618 367.26 472.445 358.984 472.446 358.028C470.394 357.88 464.671 357.767 462.749 357.979C462.801 354.013 462.761 350.581 463.356 346.659C463.604 345.025 463.673 340.362 463.196 338.825C462.09 338.281 454.983 338.332 454.149 338.599C453.5 339.853 453.671 346.189 453.631 348.097C450.663 348.097 447.114 348.019 444.204 348.24C444.144 350.916 443.937 355.172 444.118 357.717C440.938 357.588 437.842 357.721 434.581 357.553C434.487 354.513 434.533 351.194 434.514 348.129C431.488 348.03 428.124 348.076 425.075 348.053C425.036 345.013 425.069 341.907 425.069 338.86C428.06 338.786 442.061 339.162 443.82 338.454C444.51 336.852 444.215 331.328 444.189 329.323C440.87 329.272 437.936 329.394 434.548 329.219C434.366 326.502 434.402 322.344 434.49 319.62C436.408 319.454 438.871 319.625 440.855 319.517C445.171 319.281 449.354 319.235 453.677 319.275C453.69 322.453 453.653 325.818 453.801 328.975C456.999 328.945 460.03 328.774 463.317 328.774C463.558 323.04 463.365 315.76 463.368 309.931C466.169 309.793 469.501 309.844 472.326 309.828C471.842 306.836 472.096 295.299 472.119 291.641C467.82 291.593 463.526 291.787 459.223 291.71C455.253 291.641 448.227 290.636 444.472 291.473C443.74 292.911 444.006 298.516 444.018 300.404C440.898 300.397 437.743 300.353 434.628 300.473C434.421 303.01 434.517 307.242 434.498 309.908C431.188 309.975 428.391 309.987 425.088 309.844L425.05 300.429C418.825 300.183 412.274 300.586 405.951 300.383C405.864 297.472 405.894 294.368 405.873 291.441C407.669 291.448 414.388 291.761 415.34 291.038C415.841 288.846 415.612 275.071 415.562 272.075ZM463.644 433.354C468.954 433.366 474.421 433.456 479.691 432.831C483.204 432.416 486.366 432.449 489.89 432.476L490.745 432.372C491.819 430.95 490.878 416.274 491.235 413.442C491.36 412.435 491.229 406.929 491.093 405.917C490.622 405.412 489.101 405.345 488.375 405.343C480.014 405.311 471.6 405.433 463.24 405.32C462.635 406.952 462.906 409.137 462.751 410.856C462.208 416.878 462.337 422.64 463.234 428.63C463.464 430.162 463.359 431.778 463.644 433.354ZM500.779 433.919C503.851 433.926 506.921 433.912 509.993 433.873C510.235 431.105 510.072 426.88 510.021 424.004C507.02 423.926 504.02 423.896 501.021 423.912C500.756 426.235 500.708 431.474 500.779 433.919Z" fill="#9E2184"/> -<path d="M472.281 414.223L481.893 414.159C481.982 416.212 481.989 420.646 481.655 422.545L472.143 422.769C472.106 420.821 471.944 415.933 472.281 414.223Z" fill="#9E2184"/> -<path d="M643.087 224.994C644.469 214.075 641.957 215.113 652.847 214.718C652.49 217.366 652.478 222.028 652.312 224.958C655.836 225.123 660.524 225.137 664.036 225.036C672.531 224.793 671.526 224.66 671.448 232.867L671.393 243.43C668.316 243.307 665.447 243.54 662.259 243.288C662.165 241.216 662.522 235.823 661.99 234.309C661.093 233.685 653.598 233.594 652.766 234.144C652.056 235.802 652.375 243.517 652.596 245.713C653.061 250.355 652.073 258.56 652.971 262.754C654.403 263.964 668.185 262.114 670.724 263.713C671.596 265.045 671.248 270.12 671.227 272.061C668.233 272.079 665.237 272.065 662.241 272.024C662.024 274.547 662.054 279.36 662.135 281.959C664.599 282.107 668.447 281.978 671.017 281.971C670.759 284.428 670.819 286.407 670.492 289.498C670.061 293.561 664.824 290.45 663.555 292.211C662.137 294.176 662.333 308.353 662.354 310.024C665.343 310.116 668.521 310.06 671.526 310.051C671.464 314.195 671.441 318.339 671.46 322.485C671.457 324.518 671.358 327.742 671.483 329.659L643.107 329.682C643.165 327.597 642.743 321.298 643.575 320.109C644.976 319.18 650.213 319.533 652.384 319.514C652.593 316.659 652.501 312.782 652.506 309.844L643.094 309.867C640.1 309.869 636.661 309.802 633.709 310.005C633.349 315.244 633.619 324.354 633.601 329.8C636.59 329.606 640.008 329.786 643.107 329.682C642.794 335.115 643.029 342.46 642.898 348.24C640.724 348.072 636.382 348.323 633.764 348.251C633.559 345.546 633.665 341.342 633.656 338.521C631.107 338.431 626.673 338.438 624.181 338.562L624.17 329.473C622.934 329.429 615.184 329.832 614.769 328.933C613.907 327.064 615.267 321.344 614.124 319.643C612.526 319.037 598.924 319.493 595.603 319.251L595.571 309.977C592.632 309.816 589.074 309.894 586.085 309.892C586.039 306.813 585.951 303.746 586.103 300.671L605.013 300.683C605.135 297.998 605.128 294.236 604.965 291.577C602.904 291.362 598.041 291.528 595.61 291.478L595.575 262.835L585.983 262.844C585.739 268.366 586.327 276.585 585.688 281.731C582.658 281.75 579.629 281.733 576.601 281.683C576.889 276.622 576.82 271.325 576.594 266.262C576.44 262.789 576.059 259.323 576.228 255.84C576.258 255.253 576.26 254.407 576.7 253.964C577.991 252.667 592.625 253.358 595.61 253.215C595.698 250.046 595.629 246.552 595.631 243.359C592.402 243.365 589.362 243.46 586.135 243.225C586.048 240.203 586.066 237.022 586.027 233.982C583.504 233.749 579.136 233.867 576.571 233.968C576.804 231.554 576.61 227.502 576.548 225.001C582.881 224.991 589.217 225.02 595.55 225.089C595.725 227.827 595.656 231.453 595.665 234.226C598.537 234.344 601.969 234.261 604.884 234.263C604.843 237.44 604.868 240.677 604.863 243.861C607.917 243.99 611.388 243.888 614.479 243.858C614.513 246.619 614.61 251.003 614.225 253.646C611.517 253.667 608.938 253.678 606.23 253.84C606.302 257.078 606.527 260.27 606.594 263.533C609.178 263.566 611.759 263.637 614.338 263.743C614.594 266.345 614.444 269.618 614.4 272.28L624.142 272.261C624.373 266.287 624.218 259.399 624.218 253.356L632.234 253.393C632.296 250.254 632.179 247.587 631.992 244.455C629.286 244.441 626.583 244.402 623.877 244.338C623.713 241.91 623.63 227.203 624.19 225.398C625.739 224.699 640.146 225.035 643.087 224.994ZM623.854 308.749C623.833 306.631 623.421 301.773 624.458 300.314C625.891 299.36 631.704 299.818 633.923 299.793L633.932 299.355C633.969 297.82 634.08 296.659 634.393 295.22C634.949 292.658 634.834 283.688 633.589 281.828C632.13 280.95 626.232 281.275 624.091 281.284C622.58 285.732 626.06 291.916 620.685 291.775C618.749 291.724 616.781 291.791 614.84 291.775C614.336 294.515 614.518 306.905 614.548 310.305C616.564 310.353 622.116 310.754 623.552 309.89C623.849 309.337 623.891 309.364 623.854 308.749ZM643.006 291.411C645.078 291.441 650.692 291.625 652.591 291.415C653.216 288.242 653.057 275.575 652.861 272.051C649.623 272.022 646.385 272.04 643.149 272.104C642.833 273.828 642.826 289.36 643.006 291.411Z" fill="#9E2184"/> -<path d="M519.682 24.151C525.645 23.9874 532.626 24.0218 538.636 24.1053C538.643 26.9675 538.546 30.8496 538.745 33.6259C541.9 33.7552 545.145 33.7179 548.311 33.7187C548.042 36.1395 548.235 40.152 548.18 42.7784C545.039 42.7537 541.865 42.692 538.728 42.8095C538.692 45.7339 538.574 49.2815 538.689 52.188C537.164 52.1502 530.632 51.887 529.62 52.5364C528.901 54.527 529.362 67.849 529.205 71.2344C527.968 71.36 520.756 71.189 520.39 71.7296C519.341 73.2798 519.712 87.9277 519.883 90.6228C522.987 90.6753 526.09 90.6788 529.192 90.6334C529.254 93.8752 529.284 97.1176 529.277 100.36C527.689 100.096 519.046 100.107 516.912 100.118C512.563 100.14 505.366 99.6177 501.333 100.071C500.657 101.239 500.699 108.478 500.897 110.016C498.973 110.056 493.266 109.682 492.017 110.382C491.095 111.516 491.455 117.353 491.406 119.514C488.362 119.679 485.163 119.583 482.105 119.548C481.941 122.47 482.026 126.36 481.969 129.4C477.91 129.603 467.279 129.63 463.518 129.365C463.06 124.705 463.415 114.949 463.353 109.768L454.183 109.842C454.043 106.825 454.109 103.215 454.087 100.152C450.91 100.222 447.481 100.394 444.335 100.203C444.123 97.6594 444.227 93.4191 444.215 90.7447C455.771 91.8224 453.983 91.1837 453.853 81.033C450.9 80.8534 447.215 80.9737 444.198 81.003C444.276 77.9021 444.457 74.4895 444.133 71.442C440.942 71.4019 437.966 71.6043 434.717 71.4201C434.448 68.5784 434.568 65.1574 434.589 62.2668C436.557 62.2677 442.013 62.5985 443.482 61.9744C444.644 60.8269 444.069 54.8614 444.217 52.4553C447.329 52.2396 450.82 52.5429 453.849 52.2207L453.785 62.2947C456.714 62.4459 460.191 62.3387 463.139 62.3037C463.433 59.7298 463.344 55.011 463.216 52.3576C465.782 52.3795 470.021 52.4807 472.445 52.2417C472.43 55.7303 472.469 59.2189 472.563 62.7063C478.541 62.9469 485.041 62.4132 491.173 62.3788C491.277 59.9691 490.858 54.432 491.542 52.6102C493.266 51.8015 506.963 52.3186 510.102 52.1864C510.093 54.9077 509.98 59.7918 510.431 62.3164C512.957 62.3542 517.24 62.5966 519.572 62.4067C519.977 60.3671 519.795 54.5196 519.752 52.2841C517.032 52.0845 512.93 52.1924 510.102 52.1864L510.141 43.2317C513.31 42.9932 516.829 43.2458 519.563 42.9946C519.943 36.8346 519.295 29.9342 519.682 24.151ZM463.592 100.345L491.388 100.387C491.881 99.4251 491.886 74.9892 491.678 71.6748C485.458 71.5656 479.152 71.7697 472.933 71.7331C470.24 71.7172 465.873 71.9246 463.354 71.4932C462.029 73.3146 463.146 82.6675 463.296 85.4905C463.562 90.4847 463.532 95.3612 463.592 100.345ZM472.498 119.567C475.529 119.645 478.714 119.474 481.69 119.668C482.068 119.368 482.275 119.342 482.224 118.624C482.056 116.31 482.722 112.038 481.692 110.154C481.39 109.91 480.961 109.57 480.565 109.579C477.908 109.641 475.253 109.801 472.587 109.79C472.39 112.078 472.253 117.318 472.498 119.567ZM500.69 90.9334L510.259 90.8908C510.646 89.0676 510.484 82.9788 510.362 80.9196C507.23 80.971 504.098 80.9839 500.966 80.9583C500.567 82.9489 500.685 88.6514 500.69 90.9334Z" fill="#9E2184"/> -<path d="M472.532 81.2385C475.686 81.1961 478.838 81.1908 481.991 81.2224C482.049 83.4485 482.309 88.7083 481.719 90.6308C479.016 90.7663 475.006 90.7239 472.317 90.6099C472.172 88.9205 472.074 82.773 472.532 81.2385Z" fill="#9E2184"/> -<path d="M690.854 376.537C693.606 376.747 697.355 376.518 700.473 376.691C700.582 379.814 700.485 383.439 700.478 386.599L709.397 386.611C709.542 388.95 709.556 393.527 709.217 395.795L700.499 395.811C700.414 398.978 700.469 402.34 700.471 405.523C702.209 405.569 707.895 405.189 709.012 405.811C709.865 407.825 709.489 420.978 709.169 423.887C704.062 424.126 695.998 424.085 690.865 423.894C690.798 420.685 690.909 417.549 690.789 414.297C686.931 414.092 675.101 414.131 671.469 414.407C671.391 417.576 671.444 420.953 671.441 424.136L681.11 424.2C681.319 430.453 681.137 437.194 681.176 443.511C684.389 443.548 687.604 443.534 690.819 443.47L690.826 433.91C693.871 433.783 697.348 433.861 700.427 433.871C700.483 436.986 700.266 440.089 700.381 443.26C697.194 443.315 694.004 443.336 690.817 443.322C690.685 446.212 690.796 449.81 690.815 452.751C689.068 452.453 682.582 452.28 681.188 453.483C679.966 454.537 675.037 454.076 673.105 454.02C672.866 456.825 672.85 459.812 672.868 462.635C678.911 462.642 684.788 462.4 690.803 462.391C690.621 464.032 690.52 470.103 690.815 471.582C688.657 471.236 684.97 471.331 682.762 471.306C679.358 471.266 682.372 478.263 680.605 480.607C679.093 481.158 673.762 480.861 671.9 480.817C671.28 475.267 672.725 468.109 672.594 462.43C669.144 462.375 665.691 462.377 662.241 462.439C662.077 466.415 662.587 477.226 661.914 480.527C661.033 481.262 654.518 480.905 652.981 480.877C653.112 472.038 652.955 462.99 652.907 454.133L649.593 454.085C647.304 452.483 646.14 452.757 643.322 452.783C643.345 449.618 643.34 446.456 643.306 443.294C640.713 443.17 637.371 443.246 634.732 443.241L633.774 441.149C631.817 441.49 626.848 441.577 624.493 441.746C624.237 436.945 625.419 417.696 623.774 414.679C621.821 413.907 608.468 414.347 605.043 414.235C605.027 411.342 605.057 408.452 605.131 405.562C609.807 405.292 619.662 405.968 623.704 405.352C624.518 404.214 624.207 397.807 624.191 396.051H652.301C652.412 393.905 652.119 388.634 652.79 387.012C654.179 386.445 669.939 386.332 671.172 387.035C671.948 388.627 671.469 402.548 671.501 405.498C673.767 405.652 676.936 405.548 679.296 405.555C683.041 405.569 687.046 405.693 690.768 405.564C690.909 402.52 690.828 398.927 690.828 395.839C687.791 395.728 684.408 395.774 681.352 395.756C681.31 392.753 681.299 389.75 681.322 386.747C683.737 386.514 688.148 386.62 690.75 386.581C690.911 383.522 690.831 379.657 690.854 376.537ZM662.269 405.456C656.698 405.313 651.128 405.285 645.557 405.371C643.398 405.394 634.984 405.138 633.681 405.827C632.34 408.544 634.069 428.957 634.126 433.813L650.137 433.857L662.225 433.891C662.384 425.645 662.672 413.617 662.269 405.456ZM652.794 453.67C655.836 453.612 658.878 453.594 661.921 453.617C662.467 452.739 662.257 444.986 662.248 443.297C659.478 443.29 655.979 443.37 653.299 443.119C652.142 444.497 652.663 451.536 652.794 453.67ZM633.866 441.054C633.87 440.178 633.983 438.369 633.679 437.648L633.299 437.367C633.287 438.494 633.186 439.655 633.497 440.72L633.866 441.054Z" fill="#9E2184"/> -<path d="M643.244 414.732C646.063 414.613 649.63 414.571 652.412 414.707C652.426 416.576 652.672 422.525 651.986 423.96C648.932 424.096 646.146 424.209 643.106 423.868C643.039 421.762 642.781 416.532 643.244 414.732Z" fill="#9E2184"/> -<path d="M633.299 437.367L633.68 437.648C633.984 438.369 633.871 440.178 633.866 441.054L633.497 440.72C633.186 439.655 633.288 438.494 633.299 437.367Z" fill="#9E2184"/> -<path d="M405.211 100.624C402.919 100.501 398.509 100.898 396.811 100.119C395.614 98.7212 395.111 56.0986 396.571 52.7554C398.045 51.9949 404.149 52.1737 406.052 52.2848C406.153 55.2876 405.533 69.6877 406.237 71.1118C407.398 71.6525 414.595 72.0876 415.351 70.9205C416.47 69.1913 415.794 64.6001 415.833 62.3365C418.103 62.2318 423.145 62.3848 424.869 62.1696C424.869 65.2362 425.162 89.3983 424.425 90.3976C422.881 90.9093 419.903 90.6986 418.214 90.6565L415.681 90.6945C415.5 92.6691 415.151 98.9061 415.879 100.55C417.849 101.74 424.164 99.7724 424.616 101.928C425.061 104.049 424.594 107.686 424.883 110.184C430.838 110.256 436.793 110.279 442.748 110.253C446.218 110.256 450.751 110.383 454.15 110.215C454.099 112.616 453.653 114.481 453.471 116.863C453.219 120.145 453.963 126.515 452.527 129.448C451.149 129.878 445.965 129.643 444.22 129.611C444.205 127.869 444.435 120.706 443.766 119.765C442.397 119.328 434.469 118.709 434.451 121.168C434.432 123.807 434.56 126.707 434.47 129.409C431.496 129.451 428.456 129.394 425.51 129.457C425.422 132.903 426.276 135.699 426.486 139.108C429.339 138.832 431.656 138.825 434.521 139.032C434.527 144.846 434.308 152.513 434.567 158.203C437.711 158.304 440.949 158.248 444.104 158.231C444 160.612 443.892 165.456 444.063 167.743C446.694 167.86 451.175 167.917 453.775 167.701C453.949 164.548 453.891 161.311 453.881 158.147C456.967 158.212 460.054 158.229 463.14 158.196C463.187 164.562 463.195 170.929 463.164 177.295C463.158 179.961 463.019 184.174 463.176 186.733C465.991 186.745 469.827 186.66 472.556 186.857C472.465 190.088 472.319 193.491 472.37 196.708C474.303 196.755 480.221 197.266 481.372 196.099C482.724 194.726 482.925 188.786 482.941 186.771C485.628 186.756 488.371 186.701 491.054 186.828C490.894 193.16 491.593 198.795 491.185 205.411C488.05 205.675 485.041 205.306 482.109 205.543C482.024 207.181 482.192 213.796 481.57 214.64C480.378 215.082 473.662 215.076 472.48 214.51C471.953 212.896 472.303 199.332 472.337 196.793C466.353 196.708 461.016 196.646 454.999 196.251C451.724 196.037 447.637 196.332 444.222 196.191C444.197 193.035 444.193 189.878 444.209 186.722C446.382 186.756 452.048 187.258 453.439 186.209C454.399 184.711 453.893 179.436 453.85 177.192C442.722 176.95 444.125 175.37 443.986 186.476C442.529 186.377 436.144 186.195 435.195 186.912C434.386 188.87 434.897 195.63 433.691 195.738C429.008 196.16 420.014 195.945 415.411 195.958C415.43 201.722 415.633 208.984 415.341 214.62C412.64 214.959 408.697 214.877 405.91 214.862C405.921 212.031 406.044 208.209 405.893 205.459C402.806 205.451 399.529 205.499 396.457 205.424C396.351 202.628 396.499 198.782 396.269 196.22C393.209 196.179 390.148 196.192 387.088 196.26C387.181 193.298 387.255 189.687 387.148 186.726C390.986 186.711 399.372 186.474 402.917 186.79C403.051 189.752 402.981 192.631 402.933 195.592C406.961 195.819 411.36 195.766 415.421 195.79C415.441 190.041 415.717 182.242 415.479 176.631C419.156 176.648 422.945 176.629 426.613 176.767C429.39 176.872 431.927 177.411 434.774 177.295C434.765 174.235 434.855 170.478 434.704 167.473C428.313 167.384 421.922 167.375 415.531 167.445C415.516 165.783 415.157 159.132 415.858 158.314C418.233 157.314 423.171 158.749 424.653 157.601C425.388 155.466 425.041 151.209 425.079 148.737C420.055 148.764 410.626 149.079 405.84 148.692C405.674 145.612 405.825 141.982 405.887 138.854C404.038 138.861 397.26 139.18 396.238 138.339C395.784 136.495 395.183 129.179 398.315 129.446C400.77 129.655 403.386 129.66 405.866 129.637C405.788 131.914 405.677 136.809 405.847 138.971C407.957 138.979 413.918 139.413 415.276 138.539C416.312 137.07 415.864 131.79 415.842 129.619C418.863 129.611 422.071 129.651 425.074 129.546C425.085 127.468 425.321 121.216 424.634 119.682C423.67 119.303 417.065 119.376 416.048 119.609C414.824 120.826 415.7 127.525 415.717 129.586C413.05 129.313 408.705 129.427 405.895 129.427C405.876 126.262 406.166 123.985 406.406 120.869C406.537 119.168 406.226 116.489 406.255 114.679C406.332 109.97 405.163 105.232 405.211 100.624Z" fill="#9E2184"/> -<path d="M339.109 62.2917C344.502 62.2717 353.064 62.513 358.286 62.1493C358.259 64.1751 357.84 69.4091 358.783 70.7767C360.001 71.6554 365.788 71.2482 367.902 71.339C367.969 73.5527 367.555 79.5416 368.469 80.788C369.879 81.6815 375.363 81.2847 377.311 81.1314C377.391 77.9442 377.417 74.7559 377.39 71.5681C379.649 71.5231 384.713 71.2019 386.661 71.8979C387.831 73.3443 386.974 94.6569 387.145 98.2923C387.344 102.515 378.07 98.0969 377.56 101.218C377.328 102.641 377.177 108.922 377.682 109.893C378.638 110.456 385.126 110.149 387.029 110.312C387.262 112.5 387.113 127.755 386.378 129.027C383.823 130.354 371.939 128.633 368.609 129.614C367.542 129.929 367.907 137.722 367.962 138.809C365.848 138.819 360.396 138.54 358.692 139.034C357.617 140.438 358.612 145.833 358.135 147.586C357.46 150.066 351.369 147.607 348.878 149.01C348.169 150.171 348.351 157.566 348.325 159.519C347.028 159.48 343.628 159.818 342.747 159.266C342.66 158.959 342.473 158.186 342.254 158.144C339.591 157.627 332.218 157.977 329.688 157.854C329.52 151.686 329.683 145.066 329.629 138.826C326.416 138.793 323.28 138.75 320.068 138.853C319.83 141.537 320.052 145.487 319.904 148.491C316.742 148.7 313.63 148.441 310.503 148.705C310.566 145.431 310.594 142.157 310.587 138.883C307.711 138.719 304.034 138.825 301.094 138.84C301.115 135.761 301.104 132.682 301.061 129.603C309.94 129.794 320.746 129.771 329.621 129.553C329.693 126.219 329.699 122.885 329.64 119.552C326.9 119.372 323.163 119.517 320.213 119.422C320.139 117.244 320.601 111.767 319.708 110.402C318.395 109.459 312.769 110.016 310.57 110.051L310.601 109.767C312.128 94.5848 308.485 102.29 301.694 99.5816C300.404 99.0669 301.105 92.9699 301.117 91.8678C301.112 91.4804 301.137 91.1985 301.419 91.0367C303.776 89.6852 319.359 91.992 320.064 89.7097C320.803 87.3174 319.245 73.41 320.807 71.6218C322.587 71.0802 327.692 71.2106 329.633 71.4001C329.792 80.6043 329.239 91.7115 329.689 100.566C331.306 100.576 337.215 100.225 338.195 100.958C339.532 103.537 338.708 115.682 338.892 119.481C342.873 119.543 346.855 119.554 350.837 119.516C352.749 119.51 356.166 119.61 357.894 119.329C359.896 116.925 356.513 110.97 359.968 110.645C361.806 110.471 365.899 111.159 367.68 110.311C368.409 108.362 368.422 92.9872 367.705 91.1713C364.418 89.6311 349.536 92.4209 348.375 89.7984C347.654 88.1674 349.391 83.9984 347.608 83.0279C345.785 82.0357 340.594 83.998 339.485 81.9028C338.621 80.2722 339.1 65.2795 339.109 62.2917ZM348.164 138.935C348.55 137.22 348.885 130.983 348.152 129.655C346.653 129.167 341.061 129.342 339.238 129.351C338.868 130.74 338.645 137.637 339.117 138.703C340.509 139.201 346.467 139.05 348.164 138.935Z" fill="#9E2184"/> -<path d="M282.421 291.404C284.503 291.409 289.778 291.017 291.108 291.982C292.065 293.446 291.55 298.456 291.604 300.653L302.873 300.639C304.917 300.639 308.656 300.544 310.544 300.908C310.546 303.729 310.626 306.951 310.41 309.733C304.793 310.067 297.42 309.881 291.663 309.869L291.608 329.473L300.984 329.408C301.015 332.6 301.045 335.329 300.827 338.507C297.792 338.385 294.611 338.47 291.636 338.293C291.522 344.474 291.339 351.881 291.532 357.996L302.684 357.975C305.117 357.979 308.119 358.065 310.506 357.899C310.725 355.089 310.591 351.245 310.559 348.339C319.704 348.3 329.907 348.06 338.973 348.35C339.037 351.356 338.915 354.55 338.847 357.572C332.607 357.661 326.385 357.565 320.151 357.615C319.887 360.227 319.981 364.223 319.978 366.963C315.77 366.634 305.62 366.889 301.085 366.995C301.039 370.381 301.035 373.767 301.072 377.152L310.524 377.173C310.549 380.3 310.534 383.43 310.48 386.558C308.369 386.253 303.395 386.389 301.087 386.419C300.836 389.005 301.017 393.285 301.063 396.018C304.214 396.078 307.365 396.081 310.516 396.028C310.621 392.889 310.586 389.759 310.573 386.62C313.666 386.615 316.915 386.664 319.994 386.599C319.991 389.332 319.878 393.343 320.166 395.998C323.333 396.104 326.485 396.06 329.655 396.037C329.652 398.869 329.736 402.499 329.546 405.256C331.813 405.511 336.499 405.454 338.906 405.396C338.917 408.187 339.015 411.506 338.917 414.253C333.403 414.324 325.609 414.566 320.234 414.251C320.196 411.248 320.194 408.245 320.228 405.239C315.606 405.219 312.656 405.338 308.093 406.009C304.977 406.465 301.301 406.223 298.075 407.035C296.615 407.242 294.214 407.083 292.681 407.042C292.953 399.565 291.825 392.379 291.399 384.983C291.074 379.325 291.631 372.709 291.308 366.917C286.105 366.82 277.841 366.719 272.74 366.993C272.772 364.043 272.845 360.614 272.682 357.673C270.169 357.602 266.253 357.595 263.755 357.756C263.751 354.661 263.794 351.411 263.706 348.33C269.273 348.33 276.743 348.565 282.149 348.304C282.172 344.027 282.47 342.619 283.058 338.466C283.269 336.979 283.146 331.443 283.142 329.62L272.726 329.669C272.707 332.704 272.754 335.615 272.462 338.636C269.964 338.636 265.898 338.509 263.527 338.671C263.49 341.865 263.484 345.059 263.509 348.254C260.566 347.956 256.861 348.238 253.727 348.076C254.234 341.519 253.728 335.573 254.145 329.77C260.239 329.491 266.801 330.003 272.685 329.724C272.646 326.26 272.456 321.289 272.702 317.945C274.464 317.892 281.143 317.873 282.247 317.26C282.604 315.573 282.558 308.279 282.515 306.142C282.425 301.662 282.746 295.764 282.421 291.404Z" fill="#9E2184"/> -<path d="M387.286 215.107C391.92 214.57 400.715 215.048 405.911 214.862C405.558 220.333 405.76 228.694 405.728 234.315C408.697 234.359 411.88 234.281 414.866 234.264C415.037 231.56 414.947 227.906 414.952 225.132C418.453 224.863 441.901 224.592 443.703 225.482C444.323 225.789 444.432 226.323 444.583 226.953C445.413 230.433 444.85 236.62 444.87 240.306C444.888 243.529 445.192 246.933 444.891 250.129C444.815 250.938 444.719 251.588 444.272 252.273C442.757 253.065 436.927 252.653 434.589 252.819C434.337 256.018 434.651 259.33 434.322 262.771C431.214 262.84 428.009 262.817 424.893 262.833C425.322 258.219 425.066 248.511 425.071 243.508C428.241 243.522 431.405 243.563 434.573 243.44C434.742 241.905 435.057 234.885 434.281 234.098C432.619 233.725 426.886 233.584 425.282 234.435C425.054 234.702 424.679 235.139 424.674 235.494C424.636 238.068 424.832 240.819 424.876 243.392C420.455 243.196 410.138 243.141 405.964 243.461L405.943 234.451C403.923 234.41 397.635 234.729 396.028 236.168C395.093 237.005 395.83 241.671 395.91 243.506C398.194 243.674 403.599 243.692 405.853 243.457C405.698 246.46 405.842 249.581 405.678 252.727C399.604 252.883 393.046 252.568 387.068 252.84C387.016 247.013 387.244 240.607 387.239 234.649L386.971 234.075C385.811 233.481 379.113 233.843 377.502 233.957C377.288 238.339 377.557 245.195 377.585 249.763C380.237 249.576 382.991 249.648 385.651 249.708C385.571 252.953 386.196 253.886 386.373 256.907C386.443 258.106 385.524 260.821 385.542 262.34C385.573 264.889 386.316 267.467 386.321 269.938C386.338 277.115 386.062 284.186 386.378 291.369C382.752 290.961 372.183 291.259 367.981 291.226C368.16 288.908 367.975 284.241 367.95 281.75C370.966 281.842 374.274 281.768 377.313 281.757C377.462 278.802 377.455 275.004 377.332 272.063C374.483 271.945 370.979 272.049 368.08 272.061C368.146 269.067 368.078 265.831 368.069 262.817C365.297 262.662 361.268 262.775 358.422 262.764C358.385 259.71 358.395 256.654 358.453 253.598C360.337 253.626 366.322 253.835 367.797 253.526C368.404 251.952 368.303 236.099 367.978 233.924C366.794 233.228 360.834 233.586 358.788 233.419L358.485 233.392C358.061 228.896 358.309 219.628 358.356 214.876C361.408 215.131 364.844 215.068 367.942 215.077C367.926 218.398 367.935 221.719 367.969 225.04L387.2 225.029C387.412 222.442 387.282 217.822 387.286 215.107Z" fill="#9E2184"/> -<path d="M614.723 158.19C623.863 158.432 633.64 158.128 642.897 158.231C643.144 160.893 642.946 164.71 642.863 167.439C640.906 167.548 635.366 167.275 634.163 167.972C633.236 169.112 633.575 175.167 633.534 177.265C639.768 177.369 646.159 176.83 652.427 177.336L652.411 186.736L662.197 186.812C662.344 192.994 662.162 199.659 662.215 205.928L681.314 205.7L681.33 214.735C672.45 214.332 661.976 214.626 652.962 214.638C652.997 211.834 653.033 199.063 652.437 196.716C651.593 195.929 644.84 196.216 643.167 196.219C643.128 192.977 643.22 189.773 643.13 186.521C640.185 186.355 636.742 186.496 633.656 186.386C633.58 183.424 633.649 180.206 633.658 177.224L614.672 177.303C614.709 180.32 614.601 183.366 614.527 186.384C612.478 186.397 607.428 186.283 605.691 186.789C604.64 187.88 605.483 191.607 605.276 193.019C604.76 196.559 605.366 202.168 604.736 205.517L603.51 205.508C597.668 205.583 591.826 205.547 585.986 205.399C585.773 208.416 585.854 211.801 585.684 214.951C582.711 214.909 579.454 214.865 576.513 215.176C576.46 217.494 576.214 222.953 576.483 224.987C574.063 224.756 568.894 224.932 566.276 224.95C566.17 221.927 566.292 218.345 566.329 215.28C564.34 215.339 559.491 215.037 558.145 215.929C557.195 217.245 557.58 222.581 557.548 224.775C554.485 224.861 551.452 224.805 548.368 224.943C548.373 222.072 547.914 208.485 548.58 206.812C549.537 204.419 573.13 207.484 576.227 205.635C576.921 203.308 576.85 189.506 576.428 186.88C575.571 186.098 568.924 186.351 567.172 186.339C567.018 183.711 567.076 180.332 567.053 177.649C569.744 177.801 584.204 177.044 585.366 178.044C585.833 178.448 585.967 179.173 586.006 179.758C586.158 182.008 585.695 184.476 585.571 186.738C585.386 190.113 585.444 193.53 585.527 196.908C588.191 197.064 592.66 196.928 595.37 196.8C595.882 191.818 595.545 182.829 595.644 177.403C601.604 177.11 608.638 177.31 614.727 177.249C614.766 170.896 614.766 164.543 614.723 158.19Z" fill="#9E2184"/> -<path d="M605.062 71.3865C606.444 71.5381 613.909 71.0654 614.26 72.1316C615.345 75.4524 613.702 87.9247 614.889 90.2778C616.306 90.8648 622.294 90.7675 623.872 90.4974C623.644 92.2856 623.884 97.2985 623.531 99.2584C623.372 99.4117 623.213 99.5647 623.054 99.718C621.24 100.358 616.804 100.022 614.608 100.132C614.543 102.893 614.679 106.963 614.446 109.53C609.443 109.902 558.548 109.405 558.145 109.926C557.255 111.075 557.576 117.76 557.749 119.416C563.697 119.493 570.526 119.543 576.453 119.349C576.622 122.683 576.288 126.478 576.553 129.559C574.995 129.286 569.046 129.368 567.115 129.365C566.951 130.852 567.023 132.707 566.79 134.112C565.619 141.174 567.087 148.262 567.009 155.363C566.926 162.682 566.744 170.034 566.753 177.382C561.759 177.268 557.179 177.371 552.261 178.185C551.298 178.344 549.198 178.232 548.184 178.209C547.643 166.73 544.824 168.153 557.364 167.811C557.509 162.766 557.246 157.241 557.417 152.126C557.592 146.861 558.924 134.545 557.942 129.78C556.559 129.132 550.302 129.41 548.382 129.434C548.394 127.369 548.889 122.008 548.03 120.754C546.665 119.801 541.413 120.226 539.288 120.229C539.493 118.205 539.454 112.794 539.297 110.745C541.017 110.676 546.138 110.903 547.366 110.611C549.449 110.114 547.569 103.53 548.611 100.879C550.579 99.4177 572.913 101.192 576.099 100.054C576.894 98.9339 576.573 92.4986 576.566 90.7021L585.953 90.658C585.806 93.5435 585.907 97.4896 585.986 100.411C588.041 100.644 593.285 100.415 595.529 100.369C595.711 97.4534 595.617 93.5795 595.624 90.5935C598.302 90.7583 602.266 90.6571 604.999 90.6124C605.393 86.183 605.078 76.286 605.062 71.3865Z" fill="#9E2184"/> -<path d="M538.717 319.39C541.155 319.576 545.834 319.36 548.373 319.286C547.965 324.336 548.23 333.658 548.164 339.116C550.773 339.132 555.306 339.298 557.765 339.118C557.823 335.979 557.839 332.842 557.811 329.703C561.416 329.676 565.105 329.609 568.703 329.703C568.77 332.732 568.606 337.074 568.823 339.865C573.492 340.031 578.168 339.941 582.828 339.597C584.935 339.436 587.088 339.106 589.171 338.98C591.155 338.86 593.338 339.014 595.348 338.913C595.318 341.837 595.242 345.168 595.348 348.083C592.262 348.06 589.03 348.085 585.956 347.996C585.908 351.337 585.898 354.679 585.928 358.019C589.153 358.194 592.554 358.085 595.797 358.037C595.811 354.741 595.281 351.31 595.364 348.334C597.307 348.32 602.808 348.141 604.451 348.613C605.142 349.413 604.88 352.119 604.866 353.246C604.847 354.884 603.746 357.184 603.064 358.726L596.44 358.715C596.375 362.126 596.018 364.746 595.783 368.085C595.599 370.674 595.643 374.197 595.61 376.848C592.497 376.901 589.222 376.995 586.117 376.823C585.903 373.476 586.097 370.261 585.984 366.97C583.271 366.958 579.374 367.037 576.737 366.772C576.737 364.329 576.822 361.109 576.673 358.731C574.937 358.731 573.135 358.754 571.411 358.576C569.636 358.394 567.329 357.694 565.601 357.638C559.908 357.452 554.015 357.588 548.332 357.774L548.364 348.526C544.398 348.592 542.107 348.325 538.136 348.023C535.681 347.839 532.231 347.975 529.692 347.892C529.696 344.981 529.756 341.796 529.65 338.91C523.861 339.016 516.308 339.199 510.579 339.005C510.369 335.96 510.471 332.709 510.498 329.643L500.929 329.648C500.908 326.228 501.035 322.729 500.95 319.323C504.087 319.298 507.223 319.314 510.358 319.369C510.514 322.42 510.381 326.421 510.413 329.602C519.051 329.929 529.844 329.673 538.622 329.62C538.846 326.714 538.747 322.363 538.717 319.39Z" fill="#9E2184"/> -<path d="M538.771 129.637L548.368 129.57C548.44 133.817 548.603 154.323 547.446 157.633C546.474 158.285 540.396 158.003 538.564 158.013C538.322 161.181 538.647 164.388 538.269 167.616C535.266 167.718 532.258 167.639 529.265 167.378C529.115 170.244 529.228 174.167 529.225 177.113C531.152 177.135 536.817 176.818 538.294 177.464C539.092 179.515 538.88 193.503 537.889 196.039C537.061 196.713 521.906 196.49 519.631 196.506C519.709 194.379 519.875 178.524 519.419 177.632L518.698 177.57C516.017 177.685 513.337 177.759 510.654 177.792C510.606 175.548 511.21 169.364 510.332 168.094C509.027 167.14 502.899 167.606 500.878 167.633C500.919 164.453 500.919 161.273 500.88 158.094C497.912 158.052 494.379 158.538 491.502 157.994C490.345 157.776 490.546 150.656 491.189 149.631C492.98 149.029 507.495 148.723 509.682 149.118C510.431 150.303 510.133 156.384 510.131 158.298C516.232 158.385 522.689 158.245 528.845 158.267C528.9 156.097 528.49 149.23 529.331 148.093C530.8 147.172 535.941 147.644 538.255 147.467L538.58 147.441C539.062 144.406 538.714 133.492 538.771 129.637Z" fill="#9E2184"/> -<path d="M558.016 405.689L566.848 405.691C566.822 411.981 567.249 417.913 567.175 424.145C563.172 424.08 551.535 423.511 548.293 423.864C548 429.586 548.182 437.169 548.154 443.011C550.786 443.013 554.024 442.93 556.613 443.039C556.742 446.263 556.935 449.803 556.905 453.009C563.464 452.969 570.024 452.976 576.583 453.029C576.546 449.888 576.576 446.747 576.675 443.608C579.71 443.525 582.745 443.495 585.781 443.518C586.085 445.583 585.949 451.082 585.677 453.11C582.619 453.163 579.558 453.161 576.5 453.103L576.52 462.88C574.036 462.267 561.102 462.398 557.843 462.398C557.615 465.542 557.624 468.501 557.61 471.651C554.824 471.695 552.038 471.688 549.251 471.633C549.323 468.303 549.346 465.887 549.069 462.536C548.8 459.303 548.323 456.062 548.336 452.845C544.937 453.011 541.74 452.822 538.346 452.727C535.32 452.644 532.347 452.778 529.327 452.495C529.21 446.323 529.355 439.971 529.429 433.785C531.367 433.778 537.154 434.062 538.419 433.393C539 432.149 539.438 423.778 537.647 423.373C535.661 422.921 531.657 423.297 529.353 423.244C529.302 420.254 529.267 417.265 529.249 414.276C533.16 414.246 537.288 414.225 541.16 414.288C544.764 414.345 554.769 415.518 557.659 414.56C558.272 413.064 557.97 407.682 558.016 405.689Z" fill="#9E2184"/> -<path d="M681.377 348.374C684.539 348.268 687.517 348.307 690.683 348.353C690.849 351.395 690.778 354.893 690.778 357.977C692.981 357.959 708.155 357.521 709.084 358.369C709.729 359.846 709.612 365.152 709.135 366.537C708.328 367.159 700.425 366.917 698.81 366.908C696.148 366.947 693.486 366.929 690.824 366.848C690.78 370.04 690.759 373.232 690.757 376.426C687.623 376.484 684.486 376.486 681.349 376.428V366.859C679.206 366.788 674.182 366.693 672.243 367.048C670.457 367.373 672.296 373.656 671.103 376.004C669.872 376.954 646.756 376.456 643.112 376.518C642.861 379.561 643.036 383.061 642.822 386.329C639.775 386.394 636.724 386.399 633.674 386.339C633.55 379.987 633.642 373.402 633.658 367.035C636.016 367.256 640.632 367.134 643.091 367.127C643.391 361.704 643.133 353.99 643.114 348.369C645.836 348.346 660.238 348.014 661.865 348.735C662.531 350.395 662.193 355.67 662.147 357.698C658.959 357.599 655.788 357.645 652.603 357.671C652.28 359.849 652.315 364.88 652.43 367.166C655.687 367.205 658.941 367.198 662.197 367.15C662.301 364.186 662.227 360.883 662.218 357.892C664.405 358.032 679.266 358.102 680.916 357.68C681.649 356.541 681.365 350.328 681.377 348.374Z" fill="#9E2184"/> -<path d="M529.482 205.984C531.844 205.874 535.937 205.807 538.302 205.99C538.703 211.977 538.21 219.006 538.364 225.135C541.63 224.994 544.9 225.041 548.168 225.054C548.178 228.012 548.118 231.272 548.208 234.204C551.229 234.23 554.919 234.159 557.885 234.31C557.88 236.865 557.754 241.117 557.963 243.536L567.067 243.538C566.991 249.567 567.118 256.682 566.788 262.612C563.794 262.706 560.798 262.757 557.8 262.759C557.816 259.436 557.885 255.969 557.839 252.66L548.318 252.545C548.318 249.565 548.373 246.375 548.295 243.413C541.886 243.496 534.82 243.881 528.551 243.685C528.498 245.711 528.258 250.798 528.489 252.653C523.688 252.713 515.525 252.462 511.095 252.805C511.068 249.871 510.987 246.649 511.15 243.734C516.944 243.651 522.741 243.632 528.535 243.676C528.406 241.146 527.786 233.428 529.074 231.602C529.823 230.543 529.464 226.858 529.519 225.435C529.482 219.962 529.166 211.314 529.482 205.984Z" fill="#9E2184"/> -<path d="M425.078 24.105L434.57 24.0826L434.522 42.6728L434.494 62.0891C431.468 62.0032 428.121 62.0728 425.07 62.0746L425.097 52.2472L415.692 52.1612C415.688 50.9172 416.28 43.2709 415.062 42.987C410.486 41.9206 390.706 43.9005 387.731 42.2278C387.031 40.73 387.369 26.7233 387.396 24.1272C390.461 24.0274 393.871 24.0925 396.962 24.0863C396.947 25.7203 396.652 32.4675 397.39 33.476C398.729 33.8685 404.392 34.1427 405.589 33.0337C406.575 32.1209 405.989 29.3788 405.978 28.0332C405.968 26.7665 406.017 25.4029 406.081 24.0907L415.612 24.0916L415.649 33.4705C426.816 34.9397 425.148 33.751 425.078 24.105Z" fill="#9E2184"/> -<path d="M339.097 243.28C345.507 243.247 351.917 243.388 358.319 243.702C358.348 246.958 358.357 250.215 358.345 253.471C355.87 253.059 351.175 252.953 348.551 253.171C348.496 256.087 348.364 260.106 348.568 263.001C351.729 263.003 355.115 263.04 358.266 262.84L358.243 272.091C354.969 272.045 351.826 272.008 348.554 272.095C348.527 273.96 348.306 280.226 348.485 281.747C345.956 281.69 341.37 281.6 338.922 281.793L338.894 300.408C334.34 300.425 324.335 300.703 320.232 300.319C320.179 298.265 319.694 293.287 320.784 291.89C322.13 291.028 327.673 291.494 329.85 291.427C330.038 285.852 329.987 280.272 330.082 274.697C330.124 272.243 328.98 264.974 330.489 263.268C332.913 262.217 337.08 264.554 339 262.459C339.242 261.736 339.197 261.298 339.205 260.544L339.097 243.28Z" fill="#9E2184"/> -<path d="M586.106 119.481C589.291 119.352 592.437 119.443 595.624 119.501C595.633 128.67 595.327 139.682 595.642 148.699C597.809 148.729 603.128 149.192 604.578 148.155C605.513 146.731 605.039 141.151 605.124 138.894C608.86 138.812 620.533 138.612 623.764 139.099L623.723 148.409C621.828 148.996 615.145 148.177 614.808 149.378C614.184 151.59 614.486 155.534 614.516 157.975C611.872 157.972 607.694 157.858 605.228 158.135C605.122 160.322 605.426 165.971 604.49 167.28C603.02 168.252 598.03 167.695 595.645 167.868C595.612 164.665 595.67 161.152 595.564 157.986C592.545 157.93 589.023 158.049 586.11 157.908C586.143 151.724 586.272 145 586.103 138.837C583.531 138.815 579.072 138.933 576.689 138.694C576.673 135.787 576.726 132.422 576.553 129.559C579.272 129.629 583.255 129.722 585.944 129.553C585.967 126.889 585.854 121.955 586.106 119.481Z" fill="#9E2184"/> -<path d="M253.881 252.713C257.04 252.664 260.257 252.685 263.421 252.674L263.556 262.95C266.003 263.1 269.914 263.029 272.347 262.918C272.11 268.38 272.74 275.9 272.814 281.775C274.871 281.83 280.048 281.487 281.574 282.015C282.995 283.361 282.08 288.871 282.342 291.187C279.481 291.197 265.462 290.932 263.704 291.653C263.465 292.752 264.089 298.189 264.155 299.908C266.687 300.282 270.508 299.726 272.718 300.445C272.76 303.589 272.752 306.732 272.693 309.876C266.618 309.876 260.117 310.035 254.089 309.835L254.107 281.934C257.082 281.641 260.523 281.927 263.663 281.796C263.838 278.924 263.719 275.006 263.707 272.049C260.501 272.042 257.315 272.056 254.111 271.913C254.04 268.673 254.087 265.363 254.027 262.114C253.981 259.675 253.032 254.812 253.881 252.713Z" fill="#9E2184"/> -<path d="M348.536 186.751C351.628 186.839 355.06 186.737 358.227 186.78C358.399 189.452 358.272 193.658 358.286 196.458C361.49 196.535 364.655 196.446 367.915 196.555C367.962 199.517 367.959 202.48 367.906 205.442C364.699 205.538 361.49 205.513 358.284 205.367C358.127 208.142 358.24 211.891 358.249 214.741C355.263 214.549 351.345 214.583 348.542 214.213C348.531 216.859 348.497 231.908 347.986 233.563C346.867 234.356 340.669 234.094 338.885 234.09C338.875 236.566 338.749 240.858 339.025 243.178C337.264 243.251 330.65 243.012 329.698 243.54C329.677 246.866 329.581 250.187 329.41 253.506C326.816 253.755 322.864 253.639 320.25 253.561C320.113 247.223 320.217 240.594 320.237 234.232C325.926 234.344 332.855 234.336 338.496 234.199C338.775 230.615 339.079 227.238 339.616 223.646C339.905 221.713 338.424 214.52 339.422 213.109C340.664 212.41 346.921 212.783 348.476 213.08C348.834 204.967 348.474 195.105 348.536 186.751Z" fill="#9E2184"/> -<path d="M652.149 119.46C653.269 119.515 661.552 119.827 661.854 119.084C663.071 116.108 661.299 102.468 662.799 100.575C664.145 100.116 669.695 100.042 670.946 100.664C672.755 101.565 670.568 116.507 671.594 119.205C671.727 119.555 672.02 119.552 672.34 119.68C674.417 119.664 679.314 119.115 680.762 120.162C681.651 121.466 681.163 127.315 681.154 129.541C674.15 129.287 666.217 129.536 659.125 129.427C655.489 129.371 646.339 129.225 643.057 129.602C643.05 125.845 643.022 122.019 643.082 118.268C643.133 115.271 643.37 112.761 643.264 109.738C640.363 109.475 636.809 109.722 633.665 109.54C633.624 107.747 633.306 101.612 634.007 100.39C639.561 100.168 646.931 100.249 652.527 100.401C652.854 103.731 652.31 106.898 652.163 110.215C652.027 113.288 652.071 116.386 652.149 119.46Z" fill="#9E2184"/> -<path d="M348.543 414.507C351.853 414.472 355.135 414.55 358.448 414.421C358.305 420.195 358.046 428.132 358.363 433.818C361.55 433.877 364.737 433.903 367.925 433.896C368.053 436.768 367.947 440.354 367.936 443.278C361.741 443.375 354.781 443.414 348.611 443.246C348.47 440.423 348.569 436.705 348.56 433.813C345.413 433.774 342.16 433.822 339.005 433.827C338.632 438.381 338.897 447.235 338.867 452.167C338.682 452.578 338.643 452.919 338.198 452.919C336.188 452.912 332.263 453.244 330.516 452.601C330.087 451.465 330.318 446.304 330.324 444.825C330.337 441.1 329.779 437.712 329.589 433.967C328.15 433.85 321.296 434.58 321.211 432.647C321.126 430.729 320.687 426.883 321.502 425.2C323.582 423.619 338.386 423.732 341.826 423.525C343.356 423.435 346.624 423.663 348.084 423.264C348.836 421.911 348.555 416.332 348.543 414.507Z" fill="#9E2184"/> -<path d="M681.38 214.923C684.457 214.954 687.568 214.814 690.619 215.13C690.896 220.009 690.714 224.93 690.64 229.814C690.622 231.156 690.58 232.392 690.94 233.699C692.608 235.138 705.814 233.454 708.854 234.548C709.963 235.816 709.317 250.21 709.227 252.823C706.176 252.989 703.12 252.941 700.078 252.678C691.219 252.761 680.37 253.019 671.603 252.681C671.394 249.59 671.626 246.695 671.477 243.678C674.701 243.669 678.128 243.713 681.331 243.568C681.488 234.371 681.587 224.096 681.38 214.923Z" fill="#9E2184"/> -<path d="M548.387 43.0875C550.392 42.9231 556.089 42.9105 558.037 43.1354C558.223 49.5104 557.917 56.0299 558.094 62.3261C559.648 62.3307 565.836 61.8296 566.566 62.6761C567.981 64.3125 567.103 70.2277 566.253 72.1915C564.34 72.2102 560.016 71.9078 558.777 72.9272C558.193 73.9753 558.484 79.9643 558.41 82.0424C558.408 91.7749 558.73 91.4887 548.359 90.4857C548.371 87.7624 548.511 83.4967 548.322 80.9009C545.1 80.9726 541.89 81.0735 538.668 80.9991C538.668 78.3955 538.532 74.1546 538.7 71.6833C541.104 71.5656 546.737 72.1417 548.014 70.9852C548.843 69.4213 548.345 64.2387 548.274 62.1606C545.17 62.0908 541.752 62.1956 538.728 62.0571C538.62 58.7579 538.663 55.4881 538.689 52.188C540.892 52.5012 545.921 52.3871 548.32 52.3657C548.435 49.3099 548.392 46.1538 548.387 43.0875Z" fill="#9E2184"/> -<path d="M662.264 52.1181C662.204 50.4074 661.724 44.3938 662.734 43.2958C664.663 42.7802 679.24 42.8298 681.001 43.3255C681.432 46.0554 680.959 49.5994 681.236 52.3537C684.22 52.3717 698.371 52.0336 700.028 52.7395C700.715 53.9278 700.8 61.693 699.982 61.8515C697.35 62.3616 693.607 62.0283 690.837 62.0905C690.738 65.5005 691.13 78.4964 690.408 80.6336C689.141 81.3462 683.181 81.0104 681.365 81.0159C681.363 78.083 681.466 74.4061 681.333 71.5349C679.41 71.5031 673.1 71.7661 671.876 71.0302C670.579 68.6895 672.231 56.427 671.402 53.1875C670.975 51.5215 664.029 52.238 662.264 52.1181Z" fill="#9E2184"/> -<path d="M557.8 262.759C557.717 264.188 557.71 265.737 557.712 267.175C557.731 275.225 557.489 283.388 557.724 291.429C560.775 291.521 574.124 291.07 576.104 291.865C576.89 293.499 576.507 307.133 576.468 309.89C573.568 309.802 570.321 310.024 567.251 309.966C567.263 306.82 567.256 303.672 567.226 300.526C562.84 300.111 553.451 300.422 548.597 300.374C548.634 294.091 548.288 288.058 548.33 281.724C545.412 281.597 541.759 281.729 538.719 281.687C538.546 278.79 538.664 275.154 538.708 272.245C541.715 272.16 545.004 272.236 548.035 272.252C548.235 269.242 548.159 265.889 548.15 262.842C551.077 262.895 554.93 262.953 557.8 262.759Z" fill="#9E2184"/> -<path d="M348.554 24.12C358.49 23.9694 368.735 24.0851 378.696 24.097C378.763 27.3361 378.815 31.0246 378.554 34.2314C369.274 34.0368 357.382 34.5879 348.406 33.9669C348.26 39.9531 348.481 45.9596 348.264 52.0193C345.797 52.3074 342.512 52.2117 339.97 52.2101C339.743 52.2198 339.487 52.3129 339.255 52.377C338.632 53.6243 338.883 60.4409 339.03 62.1014C333.14 62.1221 326.024 62.318 320.238 62.0389C320.13 60.3807 319.834 54.0384 320.574 52.81C322.656 52.014 335.637 52.4231 339.085 52.2899C339.255 46.1527 338.982 39.8494 339.229 33.7106C342.229 33.6544 345.369 33.7374 348.381 33.7788C348.392 30.8204 348.267 26.9697 348.554 24.12Z" fill="#9E2184"/> -<path d="M463.254 252.738C468.071 252.717 473.81 252.441 478.54 252.736C489.33 253.411 500.012 253.208 510.826 253.19C510.914 257.062 510.616 259.804 510.181 263.662C509.93 265.891 510.393 269.512 509.593 271.602C507.966 272.333 503.336 272.061 501.349 272.04C500.844 271.69 501.086 264.63 501.093 263.508C496.532 263.185 487.095 263.515 482.236 263.533C482.082 266.29 482.066 269.281 482.004 272.058L472.427 272.072C472.27 269.173 472.322 265.661 472.293 262.713C469.273 262.505 466.394 262.955 463.089 262.563C463.003 260.837 462.767 254.063 463.254 252.738Z" fill="#9E2184"/> -<path d="M624.094 24.0927L633.658 24.1033C633.727 27.5903 633.923 50.2938 633.264 51.8427C631.722 52.4745 625.924 52.1426 624.002 52.1016C623.72 55.3818 624.018 58.6365 623.686 62.0643C621.162 62.2102 616.553 62.2544 614.066 62.0096C613.875 55.7729 614.124 49.1158 613.995 42.7899C611.104 42.6742 608.062 42.7574 605.161 42.7862C605.246 41.6968 604.734 34.2336 605.599 33.8794C608.869 32.5371 620.964 34.6863 623.672 33.2273C624.416 31.8523 624.114 26.1142 624.094 24.0927Z" fill="#9E2184"/> -<path d="M529.276 100.36C531.466 100.661 536.898 99.8254 538.182 101.05C538.841 103.136 538.935 115.141 538.832 118.06C538.716 121.32 537.746 125.598 538.645 129.406L519.772 129.433L519.765 119.943C518.297 119.374 503.876 119.826 500.97 119.671C500.901 116.412 500.975 113.492 501.005 110.257C510.468 110.264 520.276 110.412 529.712 110.285C529.733 106.5 529.668 104.161 529.276 100.36Z" fill="#9E2184"/> -<path d="M387.609 158.043C390.459 158.017 393.393 158.113 396.249 158.172C396.259 161.204 396.2 164.632 396.407 167.622C399.383 167.758 403.018 167.648 406.07 167.704C408.57 167.75 413.049 167.895 415.379 167.631C415.404 170.533 415.371 173.474 415.364 176.379C411.078 176.533 406.844 176.688 402.556 176.531C399.03 176.402 390.905 175.415 387.601 176.02C387.114 176.678 387.162 176.711 387.056 177.498C386.881 179.911 386.735 184.033 386.957 186.454C381.09 186.072 374.364 186.729 368.06 186.296C367.905 184.201 367.347 179.238 368.524 177.694C369.907 176.794 375.039 177.134 377.234 177.092C377.597 174.74 377.537 170.876 377.558 168.372C380.028 168.252 383.151 168.377 385.52 168.312C389.241 168.209 385.558 160.503 387.609 158.043Z" fill="#9E2184"/> -<path d="M604.977 386.597C605.426 380.95 604.972 374.82 605.057 369.136C605.069 368.51 605.315 368.079 605.67 367.602C606.166 367.281 606.629 367.046 607.235 367.035C612.79 366.942 618.397 367.191 623.949 367.005C623.94 372.976 623.9 380.383 623.679 386.325C621.605 386.433 616.403 386.046 615.087 386.839C614.216 387.91 614.548 393.725 614.49 395.767C609.114 395.991 601.033 395.85 595.65 395.746C595.541 392.727 595.597 389.745 595.631 386.724C598.268 386.505 602.276 386.599 604.977 386.597Z" fill="#9E2184"/> -<path d="M265.08 33.3913L281.106 33.3325C283.132 33.3234 288.288 33.1667 290.085 33.5606C291.264 34.7065 291.383 50.439 290.709 51.6784C290.062 52.129 289.444 52.0292 288.629 52.0428C280.554 52.146 270.765 52.4279 262.799 52.0776C262.921 46.3668 262.441 39.5145 262.396 33.5114L265.08 33.3913Z" fill="#9E2184"/> -<path d="M272.553 62.3238C281.901 62.1166 291.339 62.3892 300.696 62.2818C303.948 62.2447 307.27 62.2546 310.516 62.3657C310.545 64.4985 310.966 69.4312 309.965 70.8951C308.644 71.799 302.485 71.351 300.287 71.3561C298.176 71.3927 293.547 71.0447 291.945 71.6465C290.657 72.9608 291.214 78.4022 291.086 80.9106C286.83 81.2402 276.68 81.1346 272.307 80.9698C272.173 78.3496 271.862 63.9818 272.553 62.3238Z" fill="#9E2184"/> -<path d="M652.503 80.768C653.054 76.2837 653.268 72.684 652.902 68.1961C652.831 67.3222 652.748 63.0945 653.236 62.5692C654.695 62.15 660.572 62.0873 661.846 62.7287C662.513 63.9712 662.162 78.5236 662.141 81.1123C664.879 81.3238 669.062 81.1842 671.897 81.2024C674.414 81.2187 679.051 81.3222 681.365 81.0159C681.245 83.3706 681.685 88.1215 680.929 90.0139C679.749 90.5202 646.281 90.6585 643.522 90.2766C642.902 89.1088 642.851 83.2181 643.296 82.0305C643.987 80.1856 650.77 82.1485 652.503 80.768Z" fill="#9E2184"/> -<path d="M329.879 167.733C332.523 167.587 336.163 167.688 338.882 167.685L338.921 177.059C341.787 177.124 345.47 176.923 348.367 176.828C348.336 180.03 348.346 183.232 348.399 186.434C345.532 186.336 341.801 186.362 338.927 186.456C338.67 191.57 339.316 200.74 338.603 205.346C337.111 205.75 331.435 205.642 329.655 205.638C329.553 199.27 329.781 192.855 329.589 186.485C326.82 186.247 323.247 186.342 320.403 186.346C320.543 183.419 320.62 180.585 320.483 177.656C321.784 177.622 324.147 177.461 325.388 177.696C332.418 179.026 328.537 171.888 329.879 167.733Z" fill="#9E2184"/> -<path d="M701.282 281.846C703.255 281.786 707.505 281.443 709.153 282.153C709.865 283.478 709.381 315.495 709.19 319.54C705.283 319.606 703.386 319.47 699.616 319.086C696.684 319.097 693.755 319.083 690.824 319.049C690.803 313.059 690.708 306.852 690.828 300.883C693.691 300.646 697.242 300.791 700.227 300.708C700.519 295.769 699.886 287.398 700.519 282.353C700.554 282.07 700.946 281.994 701.282 281.846Z" fill="#9E2184"/> -<path d="M311.156 443.606C312.514 443.449 318.769 443.403 319.865 443.619C320.776 445.057 319.965 459.847 319.426 462.048C318.666 462.675 312.241 462.421 310.582 462.437C310.379 468.277 310.85 475.058 310.411 480.755C308.704 481.008 303.867 480.875 301.987 480.859C302.039 474.776 299.947 447.219 301.611 444.567C303.258 443.601 308.258 444.06 310.826 443.659L311.156 443.606Z" fill="#9E2184"/> -<path d="M259.705 405.594C261.006 405.553 262.307 405.539 263.609 405.553C263.375 410.715 263.905 419.164 263.226 423.907C261.398 423.967 255.481 423.661 254.302 424.253C253.62 426.295 253.895 440.206 253.818 443.58L249.222 443.506C247.61 442.877 246.878 442.677 245.175 442.308L245.335 424.539C245.339 421.61 244.998 408.132 245.839 406.067C247.399 405.428 257.217 405.67 259.705 405.594Z" fill="#9E2184"/> -<path d="M652.732 148.736C655.843 148.693 658.957 148.691 662.071 148.732C662.28 151.654 661.995 155.079 662.124 158.196C664.246 158.223 669.625 157.846 670.962 158.776C671.815 160.099 671.43 165.495 671.448 167.656C673.838 167.735 676.221 167.575 678.605 167.615C682.055 167.672 681.483 170.408 681.329 172.849C681.236 174.318 681.213 175.719 680.967 177.181C676.821 177.605 666.735 177.299 662.267 177.283L662.216 167.664C659.144 167.564 655.666 167.633 652.566 167.627C652.419 165.044 652.177 150.661 652.732 148.736Z" fill="#9E2184"/> -<path d="M693.861 177.198C696.147 177.199 708.093 176.826 709.144 177.566C709.833 179.386 709.452 184.31 709.174 186.318C695.488 187.105 702.264 184.916 699.828 195.427C699.713 195.925 692.465 195.674 691.575 195.966C691.126 196.114 688.553 196.448 687.809 196.461C682.409 196.5 677.012 196.474 671.612 196.384C671.377 193.774 671.464 189.453 671.522 186.779C677.689 186.575 684.606 186.702 690.764 186.8C690.821 183.652 690.847 180.504 690.84 177.357C691.766 177.268 692.914 177.245 693.861 177.198Z" fill="#9E2184"/> -<path d="M254.247 376.947C257.021 376.848 260.948 377.27 263.456 376.896L263.447 386.583C267.215 386.809 278.938 386.17 281.603 387C281.786 387.217 282.006 387.505 282.039 387.8C283.239 398.63 281.151 396.198 272.922 396.387C272.972 399.162 272.794 402.591 272.722 405.412C270.781 405.232 266.038 405.415 263.725 405.368C263.737 402.193 263.729 399.017 263.702 395.841C260.614 395.617 257.391 395.859 254.107 395.62C254.051 393.347 253.896 378.457 254.247 376.947Z" fill="#9E2184"/> -<path d="M576.884 24.1766C582.826 23.9435 589.618 24.0919 595.626 24.0991C595.64 27.08 595.73 30.3117 595.497 33.2654C592.531 33.3937 589.067 33.2741 586.006 33.3281C585.852 36.205 585.935 39.8453 585.93 42.7819C583.872 42.7459 578.329 42.5579 576.585 43.0179C576.354 45.6321 576.541 49.2666 576.368 52.185C573.365 52.2505 570.362 52.2468 567.359 52.1737L567.322 51.7042C567.182 49.6849 566.935 34.8042 567.733 33.8947C569.514 33.219 574.335 33.5774 576.43 33.6414C576.686 31.2205 576.241 25.91 576.884 24.1766Z" fill="#9E2184"/> -<path d="M272.8 443.52C275.874 443.615 279.101 443.548 282.189 443.527C282.16 446.668 282.167 449.81 282.208 452.949L291.588 453.022C291.528 458.192 291.507 463.359 291.524 468.528C291.56 471.329 291.883 478.257 291.431 480.743C289.614 481.029 284.764 481.121 283.065 480.446C282.342 479.252 282.794 473.696 282.618 471.992C282.29 468.835 281.869 465.638 281.931 462.462C279.85 462.322 274.581 462.815 273.212 462.052C272.389 460.052 272.754 446.443 272.8 443.52Z" fill="#9E2184"/> -<path d="M614.626 462.504C620.04 462.223 628.507 462.946 633.462 462.432C633.504 465.44 633.451 468.547 633.437 471.564C631.298 471.522 625.608 470.946 624.368 471.866C623.451 473.262 623.789 477.991 623.794 479.987L623.642 480.52C622.526 481.133 607.633 480.845 605.108 480.812C605.091 474.97 604.978 468.687 605.163 462.882C608.366 462.638 611.337 463.089 614.626 462.504Z" fill="#9E2184"/> -<path d="M520.162 291.464C523.2 291.397 526.237 291.448 529.27 291.616C529.409 297.663 529.289 304.027 529.254 310.093L538.482 310.102C538.655 313.144 538.374 316.223 538.604 319.194C536.074 319.113 531.195 319.47 529.137 318.666C528.54 318.392 521.683 318.323 520.427 318.231C520.397 315.465 520.416 312.697 520.478 309.931C517.579 309.756 513.686 309.908 510.593 309.825L510.565 300.63C513.578 300.724 516.661 300.669 519.68 300.653C519.796 298.625 519.409 292.775 520.162 291.464Z" fill="#9E2184"/> -<path d="M587.104 462.972C588.643 462.834 594.101 462.744 595.447 463.228C596.083 464.76 595.643 478.259 595.615 480.826C589.515 480.941 583.112 480.842 576.989 480.84C567.537 478.962 568.129 482.11 568.588 471.186C570.353 471.17 574.88 471.566 576.087 470.983C577.138 469.872 576.733 465.085 576.721 463.198C579.784 463.17 584.168 463.288 587.104 462.972Z" fill="#9E2184"/> -<path d="M291.41 110.261C295.498 110.136 299.64 110.276 303.73 110.242C305.85 110.224 308.503 110.35 310.57 110.051C310.541 112.539 310.601 117.093 310.353 119.451C308.193 119.528 302.722 119.277 301.427 120.209C300.6 121.484 300.953 127.776 301.061 129.603C299.259 129.238 284.505 129.388 282.258 129.556C282.27 127.397 281.974 121.896 282.575 120.194C283.071 118.79 288.655 120.301 290.92 119.357C291.757 118.211 291.402 112.278 291.41 110.261Z" fill="#9E2184"/> -<path d="M263.695 90.6641C266.217 90.6569 280.929 90.2324 282.054 91.2094C282.576 93.2999 282.232 97.627 282.134 99.9351C279.644 100.049 275.469 99.6805 273.339 100.281C271.661 102.394 274.104 108.924 271.866 109.641C265.916 109.839 260.041 109.683 254.094 109.515C254.101 99.2426 251.706 97.9075 263.359 99.9446C263.49 97.4447 262.991 92.6235 263.695 90.6641Z" fill="#9E2184"/> -<path d="M576.511 415.027C578.205 414.444 592.794 414.615 595.576 414.744C595.772 417.71 595.686 421.174 595.673 424.188C597.74 424.198 603.216 423.845 604.539 424.776C605.447 426.104 604.988 431.667 605.08 433.838C599.15 433.834 591.964 434.043 586.161 433.76C586.05 430.476 586.016 427.187 586.057 423.9L576.597 423.967C576.5 420.987 576.47 418.007 576.511 415.027Z" fill="#9E2184"/> -<path d="M462.762 23.0588L462.978 23.0221C463.629 23.8924 463.122 48.6563 463.277 52.1884C460.169 52.2036 457.06 52.1963 453.952 52.1661C454.089 49.6498 454.005 46.3412 454.004 43.7669L453.758 43.1444C452.455 42.4889 446.318 42.8254 444.208 42.712C444.159 39.7164 444.156 36.7201 444.198 33.7241C447.019 33.4445 449.591 33.748 452.424 33.596C454.376 33.7694 454.065 31.0288 453.879 29.6922C452.827 22.1226 456.329 23.5895 462.762 23.0588Z" fill="#9E2184"/> -<path d="M367.962 138.809C373.041 138.919 382.492 138.497 386.982 139C387.024 141.115 387.367 146.485 386.635 148.208C385.06 149.303 379.424 147.823 377.866 148.98C377.107 149.543 377.384 156.368 377.308 157.471C376.408 157.461 373.07 157.39 372.407 157.595C369.961 158.353 370.857 158.661 368.078 158.679C367.965 160.794 368.255 165.608 367.423 167.038C366.008 168.23 360.428 167.637 358.231 167.589C358.167 164.622 358.848 164.098 358.768 161.582C358.734 160.529 358.447 160.542 358.845 159.414C359.859 159.166 366.461 158.632 367.916 158.529C368.35 152.852 367.944 144.748 367.962 138.809Z" fill="#9E2184"/> -<path d="M605.08 433.838C607.903 433.847 611.805 433.746 614.541 433.912C614.536 437.065 614.483 440.344 614.536 443.488L623.808 443.534C623.829 447.217 625.287 454.576 620.406 453.785C618.502 453.479 616.17 453.735 614.207 453.43L612.199 452.045C606.239 451.884 601.473 452.824 595.615 452.73C595.608 449.814 595.52 446.445 595.631 443.566C606.617 443.481 605.414 445.203 605.08 433.838Z" fill="#9E2184"/> -<path d="M681.559 148.79C684.264 148.762 698.132 149.076 699.996 150.056C700.704 151.444 700.261 156.554 700.469 158.6C705.357 158.706 709.913 156.772 709.406 163.113C709.286 164.612 710.038 165.712 709.418 167.488C707.263 167.626 692.409 167.83 691.158 167.276C690.104 165.473 691.381 161.146 690.632 158.836C687.244 155.989 680.261 162.152 681.268 153.131C681.427 151.712 681.042 150.262 681.559 148.79Z" fill="#9E2184"/> -<path d="M614.974 186.527C617.281 186.905 622.356 186.137 623.467 187.046C623.838 189.585 623.672 195.455 623.64 198.201C623.578 203.687 623.67 209.414 623.52 214.88C620.699 215.013 617.055 214.918 614.17 214.924C611.135 214.937 608.12 214.981 605.087 214.829C604.939 212.285 605.073 208.549 605.094 205.92L614.177 205.905C614.338 204.749 614.486 203.456 614.46 202.288C614.34 196.955 615.082 191.86 614.974 186.527Z" fill="#9E2184"/> -<path d="M300.157 23.1212C303.602 23.4958 307.294 23.9351 310.734 24.1496C310.603 27.6865 310.827 51.6397 310.246 52.476C307.625 52.8086 302.8 53.3949 300.358 53.5641C300.413 43.5846 300.202 33.1362 300.157 23.1212Z" fill="#9E2184"/> -<path d="M320.2 308.279C322.724 308.26 325.248 308.256 327.772 308.27L329.386 309.593C332.185 309.576 336.241 309.659 338.923 309.401C338.92 314.317 339.059 323.99 338.704 329.205C338.59 329.334 338.476 329.466 338.362 329.595C324.752 329.832 331.246 329.166 329.381 320.231C329.18 319.265 323 321.183 320.711 320.434C319.726 319.293 320.175 310.517 320.2 308.279Z" fill="#9E2184"/> -<path d="M380.114 51.6081C381.367 51.5577 385.678 51.2795 386.434 51.704C387.714 52.4242 387.019 60.4994 386.546 61.7105C385.589 62.5098 368.045 62.1394 365.667 62.1403L358.428 62.1108C358.386 58.7282 358.4 55.345 358.468 51.9626C365.183 52.047 373.179 51.6466 380.114 51.6081Z" fill="#9E2184"/> -<path d="M331.211 366.901C333.701 366.878 336.442 366.795 338.913 366.832C338.947 370.363 338.942 373.896 338.899 377.426L338.43 377.383C335.667 377.111 332.416 375.7 330.488 376.12C329.515 376.91 329.44 377.657 329.525 378.897C329.697 381.423 329.541 384.075 329.663 386.578C328.104 386.327 321.702 386.313 320.141 386.495L320.224 367.067C323.811 367.175 327.635 367.18 331.211 366.901Z" fill="#9E2184"/> -<path d="M491.457 129.599C500.136 129.778 511.031 129.772 519.685 129.582C519.468 132.756 519.719 136.153 519.491 139.477C515.776 139.555 511.646 139.243 507.869 139.132L491.194 138.806C491.102 136.624 490.888 131.48 491.457 129.599Z" fill="#9E2184"/> -<path d="M683.152 264.093L690.619 263.893C690.653 270.252 690.907 276.26 690.773 282.644C686.5 282.764 683.315 282.121 679.119 282.109C676.475 282.132 673.829 282.081 671.19 281.964C671.285 278.744 671.269 275.389 671.299 272.157C673.336 272.22 679.688 272.505 681.273 271.872C682.956 269.936 680.084 265.306 683.152 264.093Z" fill="#9E2184"/> -<path d="M595.138 42.9934C597.848 43.0015 602.54 43.1582 605.092 42.9524C605.08 45.957 605.126 49.1617 605.046 52.1493C601.916 52.2108 598.786 52.2348 595.656 52.2216C595.571 55.3851 595.435 58.9585 595.493 62.1002C592.9 61.7882 588.802 61.9666 586 61.8861C586.016 55.8292 586.163 48.9582 585.977 42.9729L595.138 42.9934Z" fill="#9E2184"/> -<path d="M348.485 281.747C351.782 281.803 355.079 281.8 358.376 281.734C358.138 284.559 358.246 288.486 358.312 291.363C360.503 291.671 365.507 291.459 367.912 291.411C367.905 293.766 367.996 298.203 367.762 300.385L355.453 300.42C353.601 300.427 350.207 300.367 348.457 300.581C348.743 295.827 348.581 286.619 348.485 281.747Z" fill="#9E2184"/> -<path d="M463.087 471.633C469.257 471.681 475.428 471.686 481.598 471.651C484.124 471.649 488.878 471.527 491.213 471.819C491.261 473.61 491.531 479.388 491.038 480.838C490.621 480.985 490.798 480.992 490.512 480.939C485.44 481.149 479.664 480.895 474.502 480.969C471.852 481.006 465.574 481.147 463.151 480.921C463.221 477.913 463.126 474.661 463.087 471.633Z" fill="#9E2184"/> -<path d="M581.568 62.1975C583.091 62.2261 584.354 62.2221 585.873 62.1537L585.921 80.9701L576.511 80.992L576.44 90.4347L571.955 90.4617C570.399 90.4691 568.846 90.4488 567.292 90.4009C566.211 78.8145 567.062 81.7968 576.313 81.0648C576.267 79.8733 576.255 78.7288 576.366 77.5391C576.838 72.4893 576.737 67.4464 576.735 62.3756C578.247 62.2627 580.033 62.2473 581.568 62.1975Z" fill="#9E2184"/> -<path d="M386.402 291.482C389.672 291.503 393.005 291.452 396.281 291.436L396.313 306.444C396.315 308.56 396.43 313.485 396.02 315.377C394.069 315.426 389.731 315.654 388.081 315.304C387.643 314.773 387.496 314.405 387.514 313.66C387.635 308.514 387.441 303.289 386.854 298.177C386.575 295.741 386.28 293.928 386.402 291.482Z" fill="#9E2184"/> -<path d="M528.564 252.784L548.161 252.704V262.759C541.701 262.628 535.02 262.93 528.576 262.611C528.597 259.337 528.592 256.062 528.564 252.784Z" fill="#9E2184"/> -<path d="M614.702 119.722C620.775 119.546 627.558 119.596 633.64 119.689C633.649 121.216 633.794 128.753 633.391 129.427C627.187 129.224 620.51 129.716 614.32 129.352C614.253 127.316 613.773 121.053 614.702 119.722Z" fill="#9E2184"/> -<path d="M501.14 215.121C503.924 215.14 517.824 214.507 519.099 215.705C519.661 217.592 519.578 223.113 519.075 224.948C514.413 225.485 506.467 224.908 501.689 224.793C500.368 224.762 500.654 216.452 501.14 215.121Z" fill="#9E2184"/> -<path d="M301.094 138.84C301.001 142.054 301.053 145.388 300.972 148.655C294.933 148.42 288.596 148.774 282.357 148.52C282.13 146.081 282.292 141.56 282.28 138.914C288.142 138.786 295.451 139.17 301.094 138.84Z" fill="#9E2184"/> -<path d="M491.674 167.937C494.591 167.836 497.763 167.885 500.699 167.879L500.685 178.197L510.549 178.026C510.574 180.076 510.837 184.555 510.074 186.437C509.959 186.721 509.521 186.752 509.132 186.867C505.043 186.884 504.734 188.05 499.913 187.384C500.259 185.339 500.362 180.539 500.468 178.247C498.226 178.253 495.004 178.636 492.99 177.898C492.598 176.869 492.294 174.81 492.169 173.66C491.98 171.916 490.876 169.466 491.674 167.937Z" fill="#9E2184"/> -<path d="M405.942 453.011C408.901 452.884 412.411 452.967 415.412 452.965C415.435 456.424 415.701 468.899 415.261 471.642L405.953 471.681C405.9 468.625 405.275 455.371 405.942 453.011Z" fill="#9E2184"/> -<path d="M633.723 129.574C636.166 129.733 640.321 129.595 642.893 129.591C643.02 135.85 643.004 142.11 642.847 148.367C640.95 149.089 635.832 148.784 633.693 148.685C633.442 143.739 633.594 134.573 633.723 129.574Z" fill="#9E2184"/> -<path d="M643.97 24.1378C649.008 23.9449 655.823 24.0488 660.939 24.177C661.209 24.254 661.856 24.3423 661.912 24.6792C662.177 26.2644 662.986 32.6635 661.356 33.3271C657.775 33.5213 646.33 33.5973 643.124 33.2459C643.055 30.7187 642.9 27.8315 643.098 25.3117C643.156 24.5609 643.481 24.4571 643.97 24.1378Z" fill="#9E2184"/> -<path d="M681.319 129.616C684.447 129.763 698.876 129.068 700.319 130.177C700.932 132.024 700.547 136.502 700.457 138.613C698.867 139.189 684.073 138.842 681.342 138.812L681.319 129.616Z" fill="#9E2184"/> -<path d="M491.44 329.415C493.932 329.782 498.299 329.655 500.929 329.648C500.705 334.974 500.806 342.725 500.866 348.122C497.852 348.141 494.386 348.233 491.417 348.053C491.203 342.326 491.424 335.221 491.44 329.415Z" fill="#9E2184"/> -<path d="M454.316 214.936C455.592 214.916 462.855 214.532 463.001 215.545C463.428 218.523 463.143 231.252 462.276 233.756C460.743 234.268 456 234.547 455.083 233.902C453.102 232.508 453.642 216.112 454.316 214.936Z" fill="#9E2184"/> -<path d="M303.713 414.585C306.052 414.555 308.185 414.523 310.529 414.654C310.576 417.415 310.842 431.467 310.17 433.218C309.372 433.852 309.818 433.633 308.741 433.811C306.987 433.845 303.309 434.089 301.875 433.419C301.522 432.287 301.326 415.461 301.538 415.009C302.185 414.509 302.859 414.61 303.713 414.585Z" fill="#9E2184"/> -<path d="M671.482 329.659C675.244 329.701 679.005 329.71 682.768 329.687C685.082 329.682 688.399 329.588 690.616 329.895C690.731 332.748 690.634 335.753 690.593 338.618C685.375 338.187 677.313 338.638 671.6 338.456L671.482 329.659Z" fill="#9E2184"/> -<path d="M529.383 462.658C532.278 462.476 535.585 462.575 538.482 462.651C538.586 464.995 538.448 479.07 537.959 480.835C537.696 480.87 537.431 480.9 537.166 480.925C535.733 481.061 530.333 481.469 529.927 480.607C528.743 478.09 529.19 465.104 529.383 462.658Z" fill="#9E2184"/> -<path d="M501.033 196.688L519.553 196.68C519.542 198.488 519.772 204.352 519.051 205.477C513.787 205.567 506.062 205.79 500.909 205.442C500.849 203.315 500.653 198.567 501.033 196.688Z" fill="#9E2184"/> -<path d="M623.951 355.502C625.67 355.477 631.035 355.318 632.37 355.689C632.48 355.947 632.589 356.101 632.598 356.352C634.059 361.612 633.345 361.87 633.515 366.988C630.408 366.887 627.074 366.972 623.948 367.005C623.946 363.216 623.886 359.277 623.951 355.502Z" fill="#9E2184"/> -<path d="M671.602 300.321C674.442 300.097 678.203 300.136 681.102 300.194C681.437 302.552 681.201 307.362 681.118 309.897C677.922 309.998 674.723 310.049 671.526 310.051C671.672 306.716 671.487 303.563 671.602 300.321Z" fill="#9E2184"/> -<path d="M473.279 167.762C475.951 167.613 479.357 167.745 482.031 167.859C482.238 170.272 482.1 173.396 482.056 175.854C482.042 176.732 481.989 176.864 481.5 177.308C478.431 177.36 475.358 177.353 472.29 177.284C472.257 174.851 472.002 170.551 472.477 168.184C472.537 167.885 472.875 167.888 473.279 167.762Z" fill="#9E2184"/> -<path d="M519.728 348.129C522.976 348.088 526.223 348.072 529.47 348.079C529.491 351.148 529.558 354.617 529.369 357.65C526.331 357.406 523.188 357.892 519.786 357.544C519.678 354.518 519.597 351.139 519.728 348.129Z" fill="#9E2184"/> -<path d="M472.638 24.0825L482.022 24.0941C482.054 26.2823 482.25 32.0676 481.75 33.9572L481.459 33.995C470.971 35.292 472.552 33.3459 472.638 24.0825Z" fill="#9E2184"/> -<path d="M406.16 319.558C409.239 319.528 412.319 319.523 415.398 319.544C415.43 321.57 415.724 327.659 415.004 329.208C411.957 329.247 408.924 329.321 405.88 329.173C405.697 327.274 405.577 321.187 406.16 319.558Z" fill="#9E2184"/> -<path d="M697.523 90.2859C698.367 90.1211 699.482 90.0386 700.275 90.3986C700.83 91.6189 700.501 98.1372 700.459 99.9552C698.3 100.011 695.917 99.957 693.739 99.9545C692.776 99.9499 691.785 99.9114 690.819 99.8865C690.738 96.821 690.74 93.754 690.823 90.6885C693.234 90.5341 695.048 90.78 697.523 90.2859Z" fill="#9E2184"/> -<path d="M472.459 225.057C475.649 224.974 478.843 224.978 482.033 225.066C482.328 227.148 482.307 232.16 482.024 234.258C478.79 234.296 475.555 234.29 472.32 234.239C472.262 232.172 472.044 226.878 472.459 225.057Z" fill="#9E2184"/> -<path d="M692.689 110.124C695.431 110.089 697.941 110.167 700.679 110.267C700.746 112.459 701.029 116.65 700.506 118.815C700.377 119.344 699.794 119.368 699.386 119.438C697.303 119.433 693.06 119.716 691.264 119.244C690.483 117.527 690.492 112.692 691.045 110.767C691.686 110.067 691.486 110.29 692.689 110.124Z" fill="#9E2184"/> -<path d="M519.827 272.273C522.948 272.151 526.112 272.236 529.24 272.28C529.279 274.704 529.422 279.468 529.136 281.74C525.986 281.773 522.833 281.766 519.68 281.717C519.615 279.256 519.445 274.575 519.827 272.273Z" fill="#9E2184"/> -<path d="M301.181 319.53C304.298 319.466 307.416 319.477 310.533 319.567C310.536 322.635 310.612 326.145 310.429 329.164C307.396 329.261 304.133 329.208 301.082 329.208C301.09 326.458 300.942 322.123 301.181 319.53Z" fill="#9E2184"/> -<path d="M425.094 376.65L434.481 376.592C434.539 379.886 434.327 383.154 434.427 386.442C431.864 386.263 427.722 386.378 425.073 386.378C425.027 383.578 424.841 379.325 425.094 376.65Z" fill="#9E2184"/> -<path d="M616.896 338.756C619.242 338.671 621.59 338.8 623.973 338.719C623.978 340.69 624.114 346.228 623.819 347.843C623.164 348.327 623.155 348.159 622.155 348.198C619.599 348.219 616.845 348.129 614.275 348.085C614.25 346.15 614.036 340.768 614.526 339.136C615.128 338.733 616.121 338.791 616.896 338.756Z" fill="#9E2184"/> -<path d="M443.916 81.1298C444.406 81.5633 444.065 89.1816 444.181 90.6294L435.041 90.6509C433.993 89.7958 434.244 82.9046 435.183 81.5653C436.557 80.6831 441.861 81.1911 443.916 81.1298Z" fill="#9E2184"/> -<path d="M358.423 272.167C361.549 272.282 364.821 272.243 367.961 272.25C367.924 275.414 367.905 278.578 367.906 281.743L358.375 281.734L358.423 272.167Z" fill="#9E2184"/> -<path d="M623.942 81.2247L633.607 81.2342C634.015 92.8242 634.81 90.1496 623.872 90.4974C623.882 87.7901 623.727 83.7845 623.942 81.2247Z" fill="#9E2184"/> -<path d="M453.937 138.888C456.991 138.832 460.045 138.831 463.098 138.884C463.261 141.989 463.154 145.428 463.114 148.566L453.853 148.536C453.924 145.57 453.732 141.647 453.937 138.888Z" fill="#9E2184"/> -<path d="M282.582 414.557C285.598 414.516 288.543 414.454 291.559 414.583C291.677 416.383 291.905 422.718 291.124 423.949C288.551 424.189 284.839 424.122 282.17 424.136C282.195 422.428 281.839 415.541 282.582 414.557Z" fill="#9E2184"/> -<path d="M548.438 309.892C551.132 309.874 555.391 309.731 557.982 310.074C557.943 312.759 558.111 316.737 557.855 319.238C554.963 319.24 551.197 319.136 548.374 319.286C548.362 316.152 548.328 313.024 548.438 309.892Z" fill="#9E2184"/> -<path d="M585.99 81.0662C589.247 81.2282 592.416 81.1662 595.649 81.2533L595.624 90.5935C593.732 90.3156 588.189 90.4409 586.018 90.4465C586.009 87.3522 586.046 84.1501 585.99 81.0662Z" fill="#9E2184"/> -<path d="M453.852 148.536C453.554 149.968 453.709 156.382 453.838 158.026C450.671 158 447.542 157.944 444.377 158.088C443.879 157.435 444.165 150.044 444.211 148.776C446.59 148.646 451.93 148.876 453.852 148.536Z" fill="#9E2184"/> -<path d="M406.315 338.751L415.371 338.692C415.415 340.844 415.576 345.38 415.314 347.641C415.174 347.793 415.034 347.947 414.894 348.099C412.941 348.088 407.695 348.754 406.344 347.684C405.473 346.258 405.29 339.888 406.315 338.751Z" fill="#9E2184"/> -<path d="M700.487 443.442C702.942 443.594 706.867 443.46 709.427 443.451C709.482 446.131 709.664 450.755 709.155 453.239C707.572 453.755 702.19 453.49 700.379 453.066L700.487 443.442Z" fill="#9E2184"/> -<path d="M681.861 24.1371C684.837 24.0848 687.812 24.0539 690.79 24.0447C690.833 26.6415 690.988 29.9815 690.688 32.5799C690.619 33.1574 690.382 33.1897 689.983 33.4412C687.081 33.5337 684.175 33.5469 681.271 33.4809C681.177 31.6226 680.866 25.2424 681.861 24.1371Z" fill="#9E2184"/> -<path d="M282.202 433.827C285.343 433.824 288.484 433.848 291.624 433.898C291.644 436.998 291.694 440.086 291.567 443.184C289.673 443.502 284.308 443.364 282.216 443.352C282.271 440.178 282.266 437.003 282.202 433.827Z" fill="#9E2184"/> -<path d="M567.29 424.186C570.104 424.29 573.614 424.177 576.481 424.165C576.521 426.853 576.647 431.109 576.359 433.67C574.884 433.979 569.072 433.834 567.35 433.815C567.191 430.639 567.265 427.374 567.29 424.186Z" fill="#9E2184"/> -<path d="M397.109 281.84C399.752 281.731 403.196 281.706 405.803 281.888C405.763 283.72 406.034 289.961 405.524 291.22L404.846 291.229C402.075 291.243 399.23 291.213 396.468 291.358C396.453 288.599 396.241 285.734 396.341 282.978C396.367 282.271 396.67 282.148 397.109 281.84Z" fill="#9E2184"/> -<path d="M272.91 424.38C275.908 424.034 278.966 424.255 281.995 424.152C282.101 427.369 282.145 430.589 282.126 433.806L272.882 433.836C272.96 430.655 272.845 427.523 272.91 424.38Z" fill="#9E2184"/> -<path d="M472.396 452.949C475.596 452.873 478.797 452.875 481.996 452.956C482.04 455.611 482.148 459.533 481.888 462.112C479.108 462.23 475.313 462.184 472.542 462.066C472.291 459.701 472.39 455.463 472.396 452.949Z" fill="#9E2184"/> -<path d="M548.385 24.1128C551.499 24.0522 554.753 24.0995 557.88 24.0995C557.924 27.0029 558.025 30.4661 557.797 33.3151C554.73 33.4974 551.432 33.486 548.339 33.5244L548.385 24.1128Z" fill="#9E2184"/> -<path d="M633.878 453.011C636.95 452.926 640.024 452.949 643.096 453.082C643.096 455.689 643.212 459.918 642.806 462.322C640.098 462.485 636.413 462.393 633.629 462.4C633.608 460.425 633.438 454.663 633.878 453.011Z" fill="#9E2184"/> -<path d="M263.7 433.88C266.761 433.85 269.821 433.834 272.882 433.836C272.653 435.394 272.756 441.531 272.751 443.419C269.733 443.479 266.714 443.513 263.696 443.52C263.623 440.319 263.49 437.072 263.7 433.88Z" fill="#9E2184"/> -<path d="M448.934 262.699C450.322 262.607 452.256 262.653 453.687 262.646C453.683 265.67 453.746 269.014 453.532 271.996C452.184 272.068 450.366 272.019 448.982 272.022L444.183 271.996C444.107 269.042 444.171 265.817 444.172 262.842L448.934 262.699Z" fill="#9E2184"/> -<path d="M301.975 281.849C304.626 281.724 307.774 281.793 310.471 281.796C310.484 283.409 310.824 290.422 309.828 291.194C306.919 291.27 304.009 291.247 301.102 291.13C300.998 288.88 300.842 284.605 301.218 282.337C301.272 282.012 301.56 282.012 301.975 281.849Z" fill="#9E2184"/> -<path d="M301.076 338.666L310.517 338.668C310.565 341.782 310.519 344.896 310.38 348.007C309.314 348.173 302.537 348.277 301.437 347.813C300.841 346.657 301.064 340.399 301.076 338.666Z" fill="#9E2184"/> -<path d="M690.814 471.582C693.829 471.619 697.415 471.573 700.386 471.72C700.351 474.723 700.271 477.839 700.287 480.835C697.254 480.852 693.829 480.939 690.831 480.812C690.773 477.736 690.766 474.659 690.814 471.582Z" fill="#9E2184"/> -<path d="M501.044 24.1224C504.155 24.0454 507.421 24.0981 510.546 24.1056C510.546 27.1769 510.473 30.2478 510.325 33.3156L500.89 33.2845C500.844 31.3506 500.641 25.7657 501.044 24.1224Z" fill="#9E2184"/> -<path d="M473.127 43.0851C475.285 43.0384 480.148 42.5567 481.633 43.5383C482.679 45.0181 482.059 50.0276 481.96 52.161C478.911 52.252 475.599 52.193 472.53 52.1926C472.502 49.5719 472.443 46.7671 472.548 44.1497C472.579 43.3748 472.638 43.4903 473.127 43.0851Z" fill="#9E2184"/> -<path d="M263.265 443.894C263.871 444.129 263.497 451.713 263.096 452.817C261.648 453.511 256.203 453.211 254.351 453.186C253.827 452.402 254.055 445.382 254.07 443.974C257.092 443.99 260.258 444.062 263.265 443.894Z" fill="#9E2184"/> -<path d="M491.436 309.876L500.853 309.878C500.929 312.794 500.611 316.412 500.807 319.083C497.882 318.982 494.388 319.081 491.42 319.088C491.233 316.02 491.237 312.944 491.436 309.876Z" fill="#9E2184"/> -<path d="M434.569 205.83L444 205.829C444.061 208.352 444.193 212.414 443.892 214.843C440.771 214.928 437.647 214.939 434.525 214.876C434.343 212.156 434.337 208.554 434.569 205.83Z" fill="#9E2184"/> -<path d="M444.221 300.634L453.661 300.692C453.693 303.734 453.666 306.776 453.58 309.816C450.454 309.869 447.328 309.876 444.202 309.837C444.147 306.836 444.211 303.649 444.221 300.634Z" fill="#9E2184"/> -<path d="M633.601 471.617C636.639 471.681 639.861 471.628 642.915 471.631C643.083 474.675 643.004 477.717 642.894 480.762C641.055 480.997 635.659 480.856 633.668 480.842C633.528 477.95 633.601 474.551 633.601 471.617Z" fill="#9E2184"/> -<path d="M387.026 196.445C386.92 199.505 387.06 202.329 386.754 205.431C383.63 205.491 380.506 205.494 377.382 205.441C377.346 203.442 377.167 198.183 377.572 196.486L387.026 196.445Z" fill="#9E2184"/> -<path d="M690.814 452.75C693.873 452.806 697.323 452.769 700.34 452.958C700.31 454.813 700.388 460.467 700.04 461.939C697.351 461.962 693.481 461.884 690.872 462.055C690.886 458.952 690.865 455.853 690.814 452.75Z" fill="#9E2184"/> -<path d="M700.482 338.867C703.465 338.818 706.452 338.825 709.434 338.885C709.478 340.743 709.881 346.903 708.952 347.972C707.231 348.085 701.305 348.5 700.247 347.569C699.833 345.979 699.975 340.441 700.482 338.867Z" fill="#9E2184"/> -<path d="M463.203 148.627C464.767 148.819 470.622 148.72 472.575 148.745C472.588 151.006 472.698 155.737 472.373 157.793C471.064 158.112 464.929 157.989 463.302 157.982C463.341 154.863 463.308 151.744 463.203 148.627Z" fill="#9E2184"/> -<path d="M254.125 358.032C256.847 357.848 260.748 357.968 263.56 357.979C263.55 360.547 263.683 364.232 263.926 366.788C260.565 366.935 257.44 367.083 254.073 366.749C254.056 363.873 253.99 360.897 254.125 358.032Z" fill="#9E2184"/> -<path d="M605.401 225.088C608.187 225.013 611.642 224.974 614.391 225.143C614.562 227.147 614.726 232.412 614.2 234.19L604.988 234.162C604.991 232.228 604.689 226.175 605.401 225.088Z" fill="#9E2184"/> -<path d="M700.934 262.895C703.654 262.851 706.675 262.775 709.36 263.049C709.492 264.84 709.84 271.132 708.95 272.259C706.712 272.215 702.356 272.812 701.031 272.031C699.86 270.616 699.784 264.294 700.934 262.895Z" fill="#9E2184"/> -<path d="M595.493 62.1002C598.535 62.2166 601.988 62.117 604.924 62.3309C604.901 64.4833 604.735 69.3471 604.938 71.3448C602.082 71.3667 598.399 71.4821 595.622 71.3005C595.608 68.3056 595.648 65.0779 595.493 62.1002Z" fill="#9E2184"/> -<path d="M301.094 148.751L310.49 148.735C310.286 150.758 310.366 155.387 310.316 157.67C308.677 158.15 303.009 157.97 301.091 157.956C301.148 154.935 301.099 151.783 301.094 148.751Z" fill="#9E2184"/> -<path d="M634.021 196.519C637.028 196.478 640.036 196.463 643.043 196.474C642.76 199.4 643.336 201.965 642.746 205.39C640.861 205.613 636.424 206.117 634.696 205.45C633.002 204.796 633.276 197.66 634.021 196.519Z" fill="#9E2184"/> -<path d="M329.663 386.578C332.795 386.634 335.927 386.643 339.059 386.606C338.797 389.478 338.928 392.743 338.859 395.659C336.646 395.915 332.101 395.822 329.696 395.841L329.663 386.578Z" fill="#9E2184"/> -<path d="M529.47 81.2397C532.443 81.1155 535.538 81.2489 538.599 81.127C538.421 83.9353 538.834 87.7297 538.304 90.4091L529.274 90.435C529.318 88.2236 529.076 83.1277 529.47 81.2397Z" fill="#9E2184"/> -<path d="M558.435 366.873C561.06 366.735 564.386 366.806 567.062 366.793C567.126 368.41 567.564 375 566.347 375.758C564.603 375.737 558.733 376.534 557.981 374.981C557.223 373.412 557.525 369.59 557.636 367.733C557.668 367.187 558.048 367.101 558.435 366.873Z" fill="#9E2184"/> -<path d="M576.686 310.143C578.795 310.323 583.566 310.134 585.949 310.116C585.785 313.096 586.094 316.189 585.785 319.166C583.925 319.461 578.507 319.245 576.502 319.164C576.702 316.119 576.677 313.19 576.686 310.143Z" fill="#9E2184"/> -<path d="M576.489 234.211C576.493 236.921 576.599 240.604 576.263 243.217C573.428 243.391 570.029 243.335 567.146 243.348C567.265 240.521 567.194 237.153 567.231 234.263C570.284 234.206 573.426 234.228 576.489 234.211Z" fill="#9E2184"/> -<path d="M254.088 462.912C257.213 462.875 260.339 462.877 263.464 462.926C263.646 464.767 263.432 470.222 262.911 472.002C260.373 471.995 257.613 472.128 255.133 471.672C254.364 471.506 254.496 469.632 254.413 469.01C254.08 466.507 253.08 465.477 254.088 462.912Z" fill="#9E2184"/> -<path d="M595.555 329.655C598.565 329.586 601.796 329.664 604.825 329.689C604.848 332.013 604.963 336.461 604.631 338.629L595.546 338.636C595.357 336.191 595.445 332.107 595.555 329.655Z" fill="#9E2184"/> -<path d="M330.108 462.677C333.037 462.592 335.969 462.587 338.899 462.663C338.957 464.949 339.227 470.183 338.437 472.089C336.562 472.098 334.458 471.903 332.598 471.797C329.553 471.626 329.582 469.287 329.783 466.941C329.911 465.456 329.824 464.196 330.108 462.677Z" fill="#9E2184"/> -<path d="M700.061 205.878C704.113 205.938 710.197 204.297 709.547 210.039C709.363 211.685 709.812 213.221 709.169 214.899C707.229 214.891 702.467 215.417 701.269 214.689C700.503 213.745 699.95 207.236 700.061 205.878Z" fill="#9E2184"/> -<path d="M387.234 329.676L396.452 329.705C396.521 332.333 396.562 335.958 396.328 338.523C394.013 338.768 389.594 338.583 387.265 338.431L387.234 329.676Z" fill="#9E2184"/> -<path d="M339.119 300.657C342.01 300.667 345.638 300.766 348.457 300.581C348.261 302.098 348.356 307.428 348.353 309.247C345.707 309.079 341.819 309.203 339.077 309.215C339.194 306.573 339.116 303.34 339.119 300.657Z" fill="#9E2184"/> -<path d="M272.74 366.993C272.747 369.823 272.811 372.773 272.615 375.587C267.011 375.41 268.517 375.901 263.626 376.809C263.616 372.854 264.934 370.381 264.675 367.048C267.363 367.069 270.052 367.051 272.74 366.993Z" fill="#9E2184"/> -<path d="M254.078 138.61L265.091 138.891C267.139 138.956 270.913 139.171 272.798 138.883C272.74 145.113 272.728 151.343 272.76 157.573C272.762 160.261 272.608 165.234 272.811 167.713C276.158 167.909 279.82 167.741 283.2 167.75C285.738 167.756 288.862 167.893 291.331 167.593C291.38 164.46 291.398 161.327 291.387 158.194C294.618 158.151 297.849 158.16 301.08 158.22C300.811 160.089 301.035 165.573 301.08 167.733C307.078 167.883 314.264 167.44 320.064 167.876C320.135 170.74 319.926 174.947 320.143 177.522C319.007 177.445 317.467 177.319 316.333 177.43C311.309 177.92 306.357 177.89 301.313 177.923C301.246 180.716 301.087 183.978 301.121 186.734C305.112 186.798 309.105 186.815 313.097 186.786C314.85 186.78 318.429 186.833 320.019 186.617C320.011 192.783 319.84 199.761 320.03 205.859L329.55 205.893C329.529 208.74 329.571 212.059 329.388 214.873C326.004 214.964 313.009 214.608 310.926 215.347C310.192 216.359 310.521 223.236 310.54 225.008L319.99 225.049C320.022 228.035 320.03 231.022 320.015 234.008C314.417 233.946 306.313 233.722 300.891 234.04L300.875 243.637C303.847 243.646 307.611 243.552 310.519 243.704C310.548 245.799 310.999 250.864 309.919 252.277C308.58 253.146 303.227 252.717 301.085 252.805C301.011 256.087 300.819 260.132 300.961 263.349C304.918 263.379 308.883 263.42 312.84 263.513C314.811 263.559 317.444 263.31 319.32 263.63C320.422 264.942 320.248 279.83 319.578 281.468C318.056 281.989 312.522 281.685 310.538 281.743C310.588 278.592 310.712 275.195 310.518 272.068C306.654 272.024 284.725 272.393 282.833 271.602C280.935 269.394 283.769 262.478 281.074 262.457C278.552 262.436 275.366 262.644 272.699 262.598L272.709 252.768C275.515 252.872 278.512 252.745 281.249 252.957C281.251 249.751 281.301 246.4 281.226 243.208C278.278 243.259 275.221 243.272 272.284 243.381C272.288 245.979 272.174 249.98 272.35 252.464C269.464 252.473 266.578 252.466 263.692 252.446C263.797 246.451 263.676 240.487 263.74 234.511C266.447 234.814 269.273 234.442 272.06 234.672C272.043 231.914 272.113 228.515 271.813 225.844L271.77 225.448L271.741 225.21C269.05 225.367 266.44 225.28 263.748 225.228C263.512 228.057 263.555 231.353 263.528 234.23C256.685 234.168 249.843 234.156 243 234.196V225.042L263.843 225.041C264.142 221.705 264.213 219.299 264.228 215.965C261.089 215.707 256.808 215.821 253.567 215.826C253.944 209.026 254.405 203.031 254.126 196.126C253.994 192.863 253.6 189.546 253.62 186.362L263.468 186.319C263.396 189.708 263.371 193.098 263.393 196.487L274.461 196.496C276.467 196.502 279.45 196.632 281.362 196.363C282.55 195.315 282.037 193.491 282.402 192.054C282.799 190.496 283.619 187.471 282.669 186.002C279.326 186.634 267.748 186.362 263.736 186.345C263.882 183.82 263.78 180.571 263.761 177.986C260.581 178.133 257.259 178.059 254.063 178.034L254.086 167.682L263.454 167.68C263.666 161.867 263.591 154.44 263.492 148.611L254.073 148.541L254.078 138.61ZM291.179 224.984C287.933 225 284.268 224.934 281.057 225.054C280.829 227.55 280.531 241.019 281.197 242.807C282.732 243.418 288.242 243.094 290.389 243.195C290.829 242.981 291.1 242.975 291.137 242.601C291.628 237.592 291.323 229.97 291.336 225.04C294.259 225.027 298.13 225.125 300.977 224.96C301.11 221.58 301.043 218.247 301.001 214.865L291.445 214.854C290.955 216.672 291.152 222.852 291.179 224.984ZM272.942 205.472C272.489 206.905 272.343 213.357 272.734 214.698C273.541 215.361 280.432 215.084 281.957 215.07C282.667 213.663 282.254 207.338 282.222 205.404L272.942 205.472ZM310.526 196.252C307.391 196.185 304.255 196.165 301.119 196.192C300.59 198.063 300.835 203.761 300.883 205.933C303.988 205.914 307.305 205.955 310.391 205.863C310.692 203.446 310.555 198.828 310.526 196.252ZM283.69 187.465C286.5 187.325 289.058 187.307 291.87 187.307C291.902 183.552 291.84 179.538 291.956 175.816C289.723 175.707 284.994 176.119 283.577 174.916C283.601 178.316 283.408 184.327 283.69 187.465Z" fill="#9E2184"/> -<path d="M272.946 129.659C276.024 129.664 279.102 129.646 282.179 129.606L282.197 138.825C279.086 138.806 275.898 138.738 272.797 138.883C273.03 135.74 272.742 132.677 272.946 129.659Z" fill="#9E2184"/> -<path d="M395.562 725.075C392 724.892 378.967 725.4 376.449 724.738C375.914 723.784 375.944 717.607 376.385 716.4C377.639 715.775 401.529 716.042 404.847 716.033C404.565 718.354 404.643 722.853 404.765 725.22C407.73 725.356 411.472 725.268 414.511 725.293C414.549 728.414 414.513 731.604 414.511 734.729C411.296 734.697 408.081 734.701 404.866 734.743C404.728 736.895 404.184 742.48 405.217 743.987C406.617 744.985 412.311 744.457 414.51 744.42C414.772 741.475 414.619 737.799 414.57 734.773L438.946 734.766C442.784 734.766 448.834 734.607 452.454 734.992C452.594 737.778 452.421 741.648 452.36 744.478C454.397 744.413 460.486 744.763 461.86 744.201C462.482 742.224 462.243 728.276 462.236 725.234C466.654 725.081 477.126 725.616 480.876 725.104C480.883 728.066 480.984 731.811 480.717 734.69C477.758 734.814 474.232 734.743 471.24 734.745C471.074 737.914 471.166 741.263 471.208 744.443C474.441 744.48 487.815 743.959 489.797 745.047C490.846 747.089 490.141 750.968 490.613 753.471C481.59 753.113 471.975 753.427 462.932 753.558C460.929 753.588 462.826 760.77 461.6 762.57C460.044 763.213 454.308 762.899 452.348 762.864L452.352 772.314C454.559 772.507 458.152 772.39 460.45 772.385C463.946 772.378 467.871 772.434 471.335 772.231C471.413 775.114 471.15 779.767 471.431 782.298C465.81 782.632 458.262 782.427 452.504 782.415C452.317 785.361 452.389 788.702 452.393 791.687C454.75 791.906 459.468 791.724 461.978 791.687C462.07 794.791 462.065 797.898 461.964 801.005C459.304 801.231 455.372 801.072 452.453 801.191C452.221 803.798 452.33 808.251 452.317 810.991C457.974 810.975 465.916 810.719 471.388 811.06C471.664 820.44 472.681 820.108 462.904 819.611C462.591 820.5 461.051 826.956 461.097 827.654C461.295 830.685 469.408 828.352 471.03 829.611C471.759 831.251 471.312 837.193 471.429 839.634L480.883 839.613C481.27 844.868 480.652 852.786 480.689 858.537C483.863 858.562 487.138 858.497 490.323 858.477C490.68 855.743 490.53 849.092 490.503 846.137C490.45 840.705 490.632 834.828 490.452 829.442C487.405 829.387 484.199 829.477 481.102 829.442C481.019 820.067 481.014 810.694 481.088 801.318C484.234 801.261 487.382 801.261 490.53 801.321C490.712 805.614 490.182 808.838 489.585 812.978C489.383 814.37 489.472 818.518 489.477 820.088C496.145 820.302 502.766 819.735 509.581 820.424C509.768 817.393 509.698 814.063 509.694 811C515.695 810.814 522.185 810.924 528.2 810.968C528.295 820.509 528.293 830.053 528.189 839.597C537.286 839.825 547.311 839.604 556.488 839.62C556.756 843.208 556.613 854.838 556.414 858.253C553.305 858.486 550.183 858.449 547.067 858.415C547.21 855.363 547.2 851.922 547.145 848.869C544.488 848.686 540.542 848.76 537.848 848.802C537.717 851.874 537.627 855.43 537.797 858.474C534.939 858.26 531.425 858.502 528.327 858.35C528.376 855.172 528.383 851.996 528.355 848.818C525.933 848.569 521.312 848.786 518.707 848.841C518.627 852.086 518.763 855.209 518.41 858.442C515.262 858.461 512.406 858.922 509.284 859.371C509.214 856.456 509.583 853.844 509.65 850.993C509.735 847.357 509.692 843.598 509.685 839.952C512.183 839.733 516.345 839.846 518.97 839.848C519.221 835.992 518.8 832.92 518.548 829.085C514.985 829.064 512.877 829.14 509.316 828.659C506.997 828.864 501.706 827.735 499.959 828.712C499.154 831.06 499.364 857.619 500.413 858.885C502.455 859.71 506.97 859.468 509.284 859.371C509.261 861.825 509.159 864.877 509.249 867.276C504.098 867.267 494.84 867.009 490.051 867.458C489.917 870.68 489.917 873.727 489.926 876.953C493.116 876.935 496.389 876.877 499.567 877.002C499.735 881.166 499.32 885.209 499.36 889.362C499.433 897.29 499.175 905.204 498.933 913.126C498.818 916.926 498.977 920.839 498.864 924.658L490.367 924.628C489.758 916.087 490.865 905.267 490.549 896.29C487.997 896.299 483.354 896.17 480.966 896.373C480.874 899.256 481.026 903.536 480.673 906.186L471.189 906.2C471.097 902.879 471.217 899.431 471.104 896.209C468.484 896.232 454.183 896.062 452.773 896.638C452.036 898.251 452.357 903.616 452.311 905.734C449.521 905.485 445.946 905.555 443.15 905.721L443.069 918.219C443.061 919.726 442.948 923.25 443.087 924.633C436.823 924.471 430.505 924.748 424.219 924.566C424.151 922.45 423.638 917.666 424.694 916.163C426.07 915.186 431.584 915.615 433.795 915.608C434.047 909.53 433.882 902.448 433.877 896.297C430.714 896.251 427.394 896.313 424.219 896.324C424.433 893.273 424.411 889.897 424.448 886.811C418.264 886.815 411.005 887.002 404.92 886.684C404.669 889.537 404.69 893.644 404.723 896.527L424.163 896.5C424.156 899.546 424.091 902.591 423.97 905.633C422.05 905.651 416.694 905.324 415.283 905.87C414.02 907.182 414.582 912.731 414.35 915.405C411.257 915.435 408.164 915.437 405.072 915.416C405.011 912.238 405.058 908.975 405.013 905.769C402.805 905.449 397.781 905.651 395.446 905.725C395.633 902.814 395.584 899.182 395.524 896.264C390.831 896.186 386.101 896.34 381.403 896.269C379.827 896.246 378.201 896.221 376.639 896.426C375.95 897.677 376.298 903.999 376.171 906.142C374.645 906.209 370.819 906.451 369.504 906.158C365.591 905.287 363.377 904.914 359.376 904.955C358.644 905.624 358.277 906.103 357.645 906.878C357.563 908.91 357.029 913.596 357.913 915.041C359.077 915.953 364.947 915.603 367.035 915.704C367.262 917.995 367.323 931.83 366.65 933.517C365.03 934.183 332.72 933.845 328.49 933.812C328.729 928.191 328.562 921.397 328.566 915.691C331.816 915.522 335.073 915.518 338.324 915.681C338.515 918.523 338.352 922.01 338.499 925.068C341.318 925.179 345.07 925.168 347.869 925.05C348.131 922.04 347.984 917.802 347.973 914.67C347.934 908.622 347.934 902.572 347.972 896.525C349.914 896.536 355.181 896.707 356.692 896.41C358.634 896.027 356.683 889.258 357.776 887.251C359.394 886.543 364.841 886.877 367.085 886.866C367.31 884.428 367.745 879.074 367.729 876.907C371.641 876.967 371.967 878.295 376.498 878.422C379.614 876.799 382.24 877.154 385.744 877.145C385.804 880.367 385.753 883.582 385.822 886.813C388.534 887.016 392.554 886.93 395.367 886.949C395.639 883.884 395.537 879.744 395.516 876.656L385.967 876.721C385.788 870.738 385.999 864.646 385.742 858.686L376.521 858.705C376.446 855.656 376.491 852.425 376.485 849.362C373.338 849.184 370.585 849.532 367.133 849.223C366.92 858.096 367.079 867.649 367.085 876.585C364.603 876.58 363.902 876.543 361.599 877.424C358.599 876.375 353.294 876.578 350.227 876.96C349.723 877.023 348.985 876.808 348.703 876.396C347.595 874.778 347.927 869.477 347.93 867.424C345.412 867.262 340.937 867.223 338.447 867.421C338.502 864.158 338.513 860.894 338.481 857.633C335.564 857.654 331.355 857.808 328.539 857.633L328.555 849.078L338.261 848.998C338.257 851.766 338.197 854.718 338.25 857.47C344.456 857.334 351.365 857.578 357.368 857.329C357.401 854.568 357.449 851.846 357.368 849.083C351.025 849.03 344.756 848.686 338.437 848.795C338.462 845.81 338.56 842.381 338.43 839.438L319.12 839.38L319.301 830.625C323.86 830.638 327.88 830.638 332.444 830.201C334.183 830.035 336.572 830.24 338.401 830.074C338.737 820.489 338.464 809.693 338.511 799.986C335.639 800.198 331.283 800.244 328.42 800.023L328.551 791.855C331.381 791.572 335.056 791.662 337.962 791.703C338.098 788.739 338.124 785.775 338.04 782.812C334.863 782.888 331.685 782.906 328.508 782.871C328.537 776.4 328.305 768.988 328.567 762.648C331.427 762.579 335.575 762.408 338.295 762.934L338.208 782.629C340.21 782.646 346.229 782.89 347.664 782.242C348.616 780.449 347.001 772.952 348.604 772.802C354.284 772.27 360.648 772.482 366.365 772.666C367.543 772.706 366.899 781.473 366.922 782.632C365.507 782.523 363.928 782.537 362.508 782.593C357.684 782.777 352.745 782.417 347.938 782.535C347.851 789.698 347.847 796.863 347.928 804.029C347.959 805.948 347.871 809.203 348.016 810.993L365.912 811.051C365.913 808.285 365.782 804.181 365.947 801.523C368.76 801.196 373.44 801.332 376.397 801.364C376.403 804.57 376.365 807.776 376.283 810.982C382.098 810.991 389.742 810.756 395.371 811.042C395.438 814.312 395.783 826.889 394.992 829.205C394.211 829.94 390.846 830.083 389.626 830.362C388.409 830.641 387.165 831.122 385.965 831.288C385.946 833.989 385.995 836.704 385.668 839.385C382.885 839.396 379.137 839.304 376.434 839.468C376.502 836.227 376.523 832.985 376.496 829.742C386.69 829.594 386.407 831.436 385.832 820.378C385.824 820.212 385.813 820.048 385.798 819.882C382.977 819.906 379.267 820.018 376.498 819.869C376.498 817.333 376.589 813.736 376.366 811.318C373.131 811.302 369.913 811.429 366.68 811.457L366.597 819.813C360.447 819.873 354.079 819.972 347.936 819.855C347.929 823.017 347.823 826.79 347.949 829.901C352.897 830.265 361.537 829.924 366.87 829.933C366.88 832.482 366.766 837.244 366.986 839.666C369.696 839.76 373.545 839.7 376.311 839.611L376.299 848.998C383.39 849.15 390.506 848.968 397.599 849.034C399.556 849.053 402.841 848.852 404.626 849.422C405.074 850.846 404.909 855.624 404.756 857.214C404.577 859.078 397.18 858.35 395.564 858.527C395.216 863.796 395.448 871.003 395.401 876.469C398.211 876.359 401.023 876.29 403.835 876.262C404.427 876.681 405.176 877.251 405.774 877.624C407.82 877.613 413.913 878.306 415.209 877.871C418.665 876.709 420.903 877.46 424.191 876.974C424.037 880.613 424.096 883.434 424.885 886.995C427.347 887.013 431.489 887.147 433.829 886.894C434.085 884.596 433.897 879.327 433.854 876.944C430.896 876.801 427.172 876.926 424.191 876.974C424.047 867.689 424.455 858.057 424.195 848.832C421.297 848.682 417.612 848.767 414.656 848.753C414.472 846.188 414.577 842.3 414.573 839.631C420.928 839.597 427.283 839.597 433.637 839.629C433.823 842.167 433.697 846.315 433.731 849.034C439.905 849.083 446.08 849.078 452.254 849.025C452.457 845.635 452.729 833.063 452.124 830.071C449.424 829.788 446.446 830.311 443.7 830.12C437.168 829.67 430.759 829.567 424.226 829.424C423.975 824.024 424.201 816.439 424.201 810.86C428.906 811.138 433.687 810.719 438.393 811.127C439.817 811.249 441.159 811.327 442.59 811.281C442.651 813.39 442.01 818.808 443.227 820.23C444.165 821.328 450.906 821.157 451.962 820.604C452.618 820.26 452.445 811.984 452.446 811.028C450.394 810.88 444.671 810.767 442.749 810.979C442.801 807.013 442.761 803.581 443.356 799.659C443.604 798.025 443.673 793.362 443.196 791.825C442.09 791.281 434.983 791.332 434.149 791.599C433.5 792.853 433.671 799.189 433.631 801.097C430.663 801.097 427.114 801.019 424.204 801.24C424.144 803.916 423.937 808.172 424.118 810.717C420.938 810.588 417.842 810.721 414.581 810.553C414.487 807.513 414.533 804.194 414.514 801.129C411.488 801.03 408.124 801.076 405.075 801.053C405.036 798.013 405.069 794.907 405.069 791.86C408.06 791.786 422.061 792.162 423.82 791.454C424.51 789.852 424.215 784.328 424.189 782.323C420.87 782.272 417.936 782.394 414.548 782.219C414.366 779.502 414.402 775.344 414.49 772.62C416.408 772.454 418.871 772.625 420.855 772.517C425.171 772.281 429.354 772.235 433.677 772.275C433.69 775.453 433.653 778.818 433.801 781.975C436.999 781.945 440.03 781.774 443.317 781.774C443.558 776.04 443.365 768.76 443.368 762.931C446.169 762.793 449.501 762.844 452.326 762.828C451.842 759.836 452.096 748.299 452.119 744.641C447.82 744.593 443.526 744.787 439.223 744.71C435.253 744.641 428.227 743.636 424.472 744.473C423.74 745.911 424.006 751.516 424.018 753.404C420.898 753.397 417.743 753.353 414.628 753.473C414.421 756.01 414.517 760.242 414.498 762.908C411.188 762.975 408.391 762.987 405.088 762.844L405.05 753.429C398.825 753.183 392.274 753.586 385.951 753.383C385.864 750.472 385.894 747.368 385.873 744.441C387.669 744.448 394.388 744.761 395.34 744.038C395.841 741.846 395.612 728.071 395.562 725.075ZM443.644 886.354C448.954 886.366 454.421 886.456 459.691 885.831C463.204 885.416 466.366 885.449 469.89 885.476L470.745 885.372C471.819 883.95 470.878 869.274 471.235 866.442C471.36 865.435 471.229 859.929 471.093 858.917C470.622 858.412 469.101 858.345 468.375 858.343C460.014 858.311 451.6 858.433 443.24 858.32C442.635 859.952 442.906 862.137 442.751 863.856C442.208 869.878 442.337 875.64 443.234 881.63C443.464 883.162 443.359 884.778 443.644 886.354ZM480.779 886.919C483.851 886.926 486.921 886.912 489.993 886.873C490.235 884.105 490.072 879.88 490.021 877.004C487.02 876.926 484.02 876.896 481.021 876.912C480.756 879.235 480.708 884.474 480.779 886.919Z" fill="#9E2184"/> -<path d="M623.087 677.994C624.469 667.075 621.957 668.113 632.847 667.718C632.49 670.366 632.478 675.028 632.312 677.958C635.836 678.123 640.524 678.137 644.036 678.036C652.531 677.793 651.526 677.66 651.448 685.867L651.393 696.43C648.316 696.307 645.447 696.54 642.259 696.288C642.165 694.216 642.522 688.823 641.99 687.309C641.093 686.685 633.598 686.594 632.766 687.144C632.056 688.802 632.375 696.517 632.596 698.713C633.061 703.355 632.073 711.56 632.971 715.754C634.403 716.964 648.185 715.114 650.724 716.713C651.596 718.045 651.248 723.12 651.227 725.061C648.233 725.079 645.237 725.065 642.241 725.024C642.024 727.547 642.054 732.36 642.135 734.959C644.599 735.107 648.447 734.978 651.017 734.971C650.759 737.428 650.819 739.407 650.492 742.498C650.061 746.561 644.824 743.45 643.555 745.211C642.137 747.176 642.333 761.353 642.354 763.024C645.343 763.116 648.521 763.06 651.526 763.051C651.464 767.195 651.441 771.339 651.46 775.485C651.457 777.518 651.358 780.742 651.483 782.659L623.107 782.682C623.165 780.597 622.743 774.298 623.575 773.109C624.976 772.18 630.213 772.533 632.384 772.514C632.593 769.659 632.501 765.782 632.506 762.844L623.094 762.867C620.1 762.869 616.661 762.802 613.709 763.005C613.349 768.244 613.619 777.354 613.601 782.8C616.59 782.606 620.008 782.786 623.107 782.682C622.794 788.115 623.029 795.46 622.898 801.24C620.724 801.072 616.382 801.323 613.764 801.251C613.559 798.546 613.665 794.342 613.656 791.521C611.107 791.431 606.673 791.438 604.181 791.562L604.17 782.473C602.934 782.429 595.184 782.832 594.769 781.933C593.907 780.064 595.267 774.344 594.124 772.643C592.526 772.037 578.924 772.493 575.603 772.251L575.571 762.977C572.632 762.816 569.074 762.894 566.085 762.892C566.039 759.813 565.951 756.746 566.103 753.671L585.013 753.683C585.135 750.998 585.128 747.236 584.965 744.577C582.904 744.362 578.041 744.528 575.61 744.478L575.575 715.835L565.983 715.844C565.739 721.366 566.327 729.585 565.688 734.731C562.658 734.75 559.629 734.733 556.601 734.683C556.889 729.622 556.82 724.325 556.594 719.262C556.44 715.789 556.059 712.323 556.228 708.84C556.258 708.253 556.26 707.407 556.7 706.964C557.991 705.667 572.625 706.358 575.61 706.215C575.698 703.046 575.629 699.552 575.631 696.359C572.402 696.365 569.362 696.46 566.135 696.225C566.048 693.203 566.066 690.022 566.027 686.982C563.504 686.749 559.136 686.867 556.571 686.968C556.804 684.554 556.61 680.502 556.548 678.001C562.881 677.991 569.217 678.02 575.55 678.089C575.725 680.827 575.656 684.453 575.665 687.226C578.537 687.344 581.969 687.261 584.884 687.263C584.843 690.44 584.868 693.677 584.863 696.861C587.917 696.99 591.388 696.888 594.479 696.858C594.513 699.619 594.61 704.003 594.225 706.646C591.517 706.667 588.938 706.678 586.23 706.84C586.302 710.078 586.527 713.27 586.594 716.533C589.178 716.566 591.759 716.637 594.338 716.743C594.594 719.345 594.444 722.618 594.4 725.28L604.142 725.261C604.373 719.287 604.218 712.399 604.218 706.356L612.234 706.393C612.296 703.254 612.179 700.587 611.992 697.455C609.286 697.441 606.583 697.402 603.877 697.338C603.713 694.91 603.63 680.203 604.19 678.398C605.739 677.699 620.146 678.035 623.087 677.994ZM603.854 761.749C603.833 759.631 603.421 754.773 604.458 753.314C605.891 752.36 611.704 752.818 613.923 752.793L613.932 752.355C613.969 750.82 614.08 749.659 614.393 748.22C614.949 745.658 614.834 736.688 613.589 734.828C612.13 733.95 606.232 734.275 604.091 734.284C602.58 738.732 606.06 744.916 600.685 744.775C598.749 744.724 596.781 744.791 594.84 744.775C594.336 747.515 594.518 759.905 594.548 763.305C596.564 763.353 602.116 763.754 603.552 762.89C603.849 762.337 603.891 762.364 603.854 761.749ZM623.006 744.411C625.078 744.441 630.692 744.625 632.591 744.415C633.216 741.242 633.057 728.575 632.861 725.051C629.623 725.022 626.385 725.04 623.149 725.104C622.833 726.828 622.826 742.36 623.006 744.411Z" fill="#9E2184"/> -<path d="M499.682 477.151C505.645 476.987 512.626 477.022 518.636 477.105C518.643 479.968 518.546 483.85 518.745 486.626C521.9 486.755 525.145 486.718 528.311 486.719C528.042 489.14 528.235 493.152 528.18 495.778C525.039 495.754 521.865 495.692 518.728 495.81C518.692 498.734 518.574 502.282 518.689 505.188C517.164 505.15 510.632 504.887 509.62 505.536C508.901 507.527 509.362 520.849 509.205 524.234C507.968 524.36 500.756 524.189 500.39 524.73C499.341 526.28 499.712 540.928 499.883 543.623C502.987 543.675 506.09 543.679 509.192 543.633C509.254 546.875 509.284 550.118 509.277 553.36C507.689 553.096 499.046 553.107 496.912 553.118C492.563 553.14 485.366 552.618 481.333 553.071C480.657 554.239 480.699 561.478 480.897 563.016C478.973 563.056 473.266 562.682 472.017 563.382C471.095 564.516 471.455 570.353 471.406 572.514C468.362 572.679 465.163 572.583 462.105 572.548C461.941 575.47 462.026 579.36 461.969 582.4C457.91 582.603 447.279 582.63 443.518 582.365C443.06 577.705 443.415 567.949 443.353 562.768L434.183 562.842C434.043 559.825 434.109 556.215 434.087 553.152C430.91 553.222 427.481 553.394 424.335 553.203C424.123 550.659 424.227 546.419 424.215 543.745C435.771 544.822 433.983 544.184 433.853 534.033C430.9 533.853 427.215 533.974 424.198 534.003C424.276 530.902 424.457 527.49 424.133 524.442C420.942 524.402 417.966 524.604 414.717 524.42C414.448 521.578 414.568 518.157 414.589 515.267C416.557 515.268 422.013 515.599 423.482 514.974C424.644 513.827 424.069 507.861 424.217 505.455C427.329 505.24 430.82 505.543 433.849 505.221L433.785 515.295C436.714 515.446 440.191 515.339 443.139 515.304C443.433 512.73 443.344 508.011 443.216 505.358C445.782 505.38 450.021 505.481 452.445 505.242C452.43 508.73 452.469 512.219 452.563 515.706C458.541 515.947 465.041 515.413 471.173 515.379C471.277 512.969 470.858 507.432 471.542 505.61C473.266 504.802 486.963 505.319 490.102 505.186C490.093 507.908 489.98 512.792 490.431 515.316C492.957 515.354 497.24 515.597 499.572 515.407C499.977 513.367 499.795 507.52 499.752 505.284C497.032 505.085 492.93 505.192 490.102 505.186L490.141 496.232C493.31 495.993 496.829 496.246 499.563 495.995C499.943 489.835 499.295 482.934 499.682 477.151ZM443.592 553.345L471.388 553.387C471.881 552.425 471.886 527.989 471.678 524.675C465.458 524.566 459.152 524.77 452.933 524.733C450.24 524.717 445.873 524.925 443.354 524.493C442.029 526.315 443.146 535.667 443.296 538.491C443.562 543.485 443.532 548.361 443.592 553.345ZM452.498 572.567C455.529 572.645 458.714 572.474 461.69 572.668C462.068 572.368 462.275 572.342 462.224 571.624C462.056 569.31 462.722 565.038 461.692 563.154C461.39 562.91 460.961 562.57 460.565 562.579C457.908 562.641 455.253 562.801 452.587 562.79C452.39 565.079 452.253 570.318 452.498 572.567ZM480.69 543.933L490.259 543.891C490.646 542.068 490.484 535.979 490.362 533.92C487.23 533.971 484.098 533.984 480.966 533.958C480.567 535.949 480.685 541.651 480.69 543.933Z" fill="#9E2184"/> -<path d="M452.532 534.239C455.686 534.196 458.838 534.191 461.991 534.222C462.049 536.449 462.309 541.708 461.719 543.631C459.016 543.766 455.006 543.724 452.317 543.61C452.172 541.921 452.074 535.773 452.532 534.239Z" fill="#9E2184"/> -<path d="M385.211 553.624C382.919 553.501 378.509 553.898 376.811 553.119C375.614 551.721 375.111 509.099 376.571 505.755C378.045 504.995 384.149 505.174 386.052 505.285C386.153 508.288 385.533 522.688 386.237 524.112C387.398 524.652 394.595 525.088 395.351 523.92C396.47 522.191 395.794 517.6 395.833 515.336C398.103 515.232 403.145 515.385 404.869 515.17C404.869 518.236 405.162 542.398 404.425 543.398C402.881 543.909 399.903 543.699 398.214 543.656L395.681 543.694C395.5 545.669 395.151 551.906 395.879 553.55C397.849 554.74 404.164 552.772 404.616 554.927C405.061 557.049 404.594 560.686 404.883 563.184C410.838 563.256 416.793 563.279 422.748 563.253C426.218 563.256 430.751 563.383 434.15 563.215C434.099 565.616 433.653 567.481 433.471 569.863C433.219 573.145 433.963 579.515 432.527 582.448C431.149 582.878 425.965 582.643 424.22 582.611C424.205 580.869 424.435 573.706 423.766 572.765C422.397 572.328 414.469 571.709 414.451 574.168C414.432 576.807 414.56 579.707 414.47 582.409C411.496 582.451 408.456 582.394 405.51 582.457C405.422 585.903 406.276 588.699 406.486 592.108C409.339 591.832 411.656 591.825 414.521 592.032C414.527 597.846 414.308 605.513 414.567 611.203C417.711 611.304 420.949 611.248 424.104 611.231C424 613.612 423.892 618.456 424.063 620.743C426.694 620.86 431.175 620.917 433.775 620.701C433.949 617.548 433.891 614.311 433.881 611.147C436.967 611.212 440.054 611.228 443.14 611.196C443.187 617.562 443.195 623.929 443.164 630.295C443.158 632.961 443.019 637.174 443.176 639.733C445.991 639.745 449.827 639.66 452.556 639.857C452.465 643.088 452.319 646.491 452.37 649.708C454.303 649.755 460.221 650.266 461.372 649.099C462.724 647.726 462.925 641.786 462.941 639.771C465.628 639.756 468.371 639.701 471.054 639.828C470.894 646.16 471.593 651.795 471.185 658.411C468.05 658.675 465.041 658.306 462.109 658.543C462.024 660.181 462.192 666.796 461.57 667.64C460.378 668.082 453.662 668.076 452.48 667.51C451.953 665.896 452.303 652.332 452.337 649.793C446.353 649.708 441.016 649.646 434.999 649.251C431.724 649.037 427.637 649.332 424.222 649.191C424.197 646.035 424.193 642.878 424.209 639.722C426.382 639.756 432.048 640.258 433.439 639.209C434.399 637.71 433.893 632.436 433.85 630.192C422.722 629.95 424.125 628.37 423.986 639.476C422.529 639.377 416.144 639.194 415.195 639.912C414.386 641.87 414.897 648.63 413.691 648.738C409.008 649.16 400.014 648.945 395.411 648.958C395.43 654.722 395.633 661.984 395.341 667.62C392.64 667.959 388.697 667.877 385.91 667.862C385.921 665.031 386.044 661.209 385.893 658.459C382.806 658.451 379.529 658.499 376.457 658.424C376.351 655.628 376.499 651.782 376.269 649.22C373.209 649.179 370.148 649.192 367.088 649.26C367.181 646.298 367.255 642.687 367.148 639.726C370.986 639.71 379.372 639.474 382.917 639.79C383.051 642.752 382.981 645.631 382.933 648.592C386.961 648.819 391.36 648.766 395.421 648.79C395.441 643.041 395.717 635.242 395.479 629.631C399.156 629.648 402.945 629.629 406.613 629.767C409.39 629.872 411.927 630.411 414.774 630.295C414.765 627.235 414.855 623.478 414.704 620.473C408.313 620.384 401.922 620.375 395.531 620.445C395.516 618.783 395.157 612.132 395.858 611.314C398.233 610.314 403.171 611.749 404.653 610.601C405.388 608.466 405.041 604.209 405.079 601.737C400.055 601.764 390.626 602.079 385.84 601.692C385.674 598.612 385.825 594.982 385.887 591.854C384.038 591.861 377.26 592.18 376.238 591.339C375.784 589.495 375.183 582.179 378.315 582.446C380.77 582.655 383.386 582.66 385.866 582.637C385.788 584.914 385.677 589.809 385.847 591.971C387.957 591.979 393.918 592.413 395.276 591.539C396.312 590.07 395.864 584.79 395.842 582.619C398.863 582.611 402.071 582.651 405.074 582.546C405.085 580.468 405.321 574.216 404.634 572.682C403.67 572.303 397.065 572.376 396.048 572.609C394.824 573.826 395.7 580.525 395.717 582.586C393.05 582.313 388.705 582.427 385.895 582.427C385.876 579.262 386.166 576.985 386.406 573.869C386.537 572.168 386.226 569.489 386.255 567.679C386.332 562.97 385.163 558.232 385.211 553.624Z" fill="#9E2184"/> -<path d="M319.109 515.292C324.502 515.272 333.064 515.513 338.286 515.149C338.259 517.175 337.84 522.409 338.783 523.777C340.001 524.655 345.788 524.248 347.902 524.339C347.969 526.553 347.555 532.542 348.469 533.788C349.879 534.682 355.363 534.285 357.311 534.131C357.391 530.944 357.417 527.756 357.39 524.568C359.649 524.523 364.713 524.202 366.661 524.898C367.831 526.344 366.974 547.657 367.145 551.292C367.344 555.515 358.07 551.097 357.56 554.218C357.328 555.641 357.177 561.922 357.682 562.893C358.638 563.456 365.126 563.149 367.029 563.312C367.262 565.5 367.113 580.755 366.378 582.027C363.823 583.354 351.939 581.633 348.609 582.614C347.542 582.929 347.907 590.722 347.962 591.809C345.848 591.819 340.396 591.54 338.692 592.034C337.617 593.438 338.612 598.833 338.135 600.586C337.46 603.066 331.369 600.607 328.878 602.01C328.169 603.171 328.351 610.566 328.325 612.519C327.028 612.48 323.628 612.818 322.747 612.266C322.66 611.959 322.473 611.186 322.254 611.144C319.591 610.627 312.218 610.977 309.688 610.854C309.52 604.686 309.683 598.066 309.629 591.826C306.416 591.793 303.28 591.75 300.068 591.853C299.83 594.537 300.052 598.487 299.904 601.491C296.742 601.7 293.63 601.441 290.503 601.705C290.566 598.431 290.594 595.157 290.587 591.883C287.711 591.719 284.034 591.825 281.094 591.84C281.115 588.761 281.104 585.682 281.061 582.603C289.94 582.794 300.746 582.771 309.621 582.553C309.693 579.219 309.699 575.885 309.64 572.552C306.9 572.372 303.163 572.517 300.213 572.422C300.139 570.244 300.601 564.767 299.708 563.402C298.395 562.459 292.769 563.016 290.57 563.051L290.601 562.767C292.128 547.585 288.485 555.29 281.694 552.582C280.404 552.067 281.105 545.97 281.117 544.868C281.112 544.48 281.137 544.198 281.419 544.037C283.776 542.685 299.359 544.992 300.064 542.71C300.803 540.317 299.245 526.41 300.807 524.622C302.587 524.08 307.692 524.211 309.633 524.4C309.792 533.604 309.239 544.712 309.689 553.566C311.306 553.576 317.215 553.225 318.195 553.958C319.532 556.537 318.708 568.682 318.892 572.481C322.873 572.543 326.855 572.554 330.837 572.516C332.749 572.51 336.166 572.61 337.894 572.329C339.896 569.925 336.513 563.97 339.968 563.645C341.806 563.471 345.899 564.159 347.68 563.311C348.409 561.362 348.422 545.987 347.705 544.171C344.418 542.631 329.536 545.421 328.375 542.798C327.654 541.167 329.391 536.998 327.608 536.028C325.785 535.036 320.594 536.998 319.485 534.903C318.621 533.272 319.1 518.28 319.109 515.292ZM328.164 591.935C328.55 590.22 328.885 583.983 328.152 582.655C326.653 582.167 321.061 582.342 319.238 582.351C318.868 583.74 318.645 590.637 319.117 591.703C320.509 592.201 326.467 592.05 328.164 591.935Z" fill="#9E2184"/> -<path d="M262.421 744.404C264.503 744.409 269.778 744.017 271.108 744.982C272.065 746.446 271.55 751.456 271.604 753.653L282.873 753.639C284.917 753.639 288.656 753.544 290.544 753.908C290.546 756.729 290.626 759.951 290.41 762.733C284.793 763.067 277.42 762.881 271.663 762.869L271.608 782.473L280.984 782.408C281.015 785.6 281.045 788.329 280.827 791.507C277.792 791.385 274.611 791.47 271.636 791.293C271.522 797.474 271.339 804.881 271.532 810.996L282.684 810.975C285.117 810.979 288.119 811.065 290.506 810.899C290.725 808.089 290.591 804.245 290.559 801.339C299.704 801.3 309.907 801.06 318.973 801.35C319.037 804.356 318.915 807.55 318.847 810.571C312.607 810.661 306.385 810.565 300.151 810.615C299.887 813.226 299.981 817.223 299.978 819.963C295.77 819.633 285.62 819.889 281.085 819.995C281.039 823.381 281.035 826.767 281.072 830.152L290.524 830.173C290.549 833.3 290.534 836.43 290.48 839.558C288.369 839.253 283.395 839.389 281.087 839.419C280.836 842.005 281.017 846.285 281.063 849.018C284.214 849.078 287.365 849.08 290.516 849.027C290.621 845.888 290.586 842.759 290.573 839.62C293.666 839.615 296.915 839.664 299.994 839.599C299.991 842.332 299.878 846.343 300.166 848.998C303.333 849.104 306.485 849.06 309.655 849.037C309.652 851.869 309.736 855.499 309.546 858.255C311.813 858.511 316.499 858.454 318.906 858.396C318.917 861.187 319.015 864.506 318.917 867.253C313.403 867.324 305.609 867.566 300.234 867.251C300.196 864.248 300.194 861.245 300.228 858.239C295.606 858.219 292.656 858.338 288.093 859.009C284.977 859.465 281.301 859.223 278.075 860.035C276.615 860.242 274.214 860.083 272.681 860.042C272.953 852.565 271.825 845.379 271.399 837.983C271.074 832.325 271.631 825.709 271.308 819.917C266.105 819.82 257.841 819.719 252.74 819.993C252.772 817.043 252.845 813.614 252.682 810.673C250.169 810.601 246.253 810.595 243.755 810.756C243.751 807.661 243.794 804.411 243.706 801.33C249.273 801.33 256.743 801.565 262.149 801.304C262.172 797.027 262.47 795.619 263.058 791.466C263.269 789.979 263.146 784.443 263.142 782.62L252.726 782.669C252.707 785.704 252.754 788.615 252.462 791.636C249.964 791.636 245.898 791.509 243.527 791.671C243.49 794.865 243.484 798.059 243.509 801.254C240.566 800.956 236.861 801.237 233.727 801.076C234.234 794.519 233.728 788.573 234.145 782.77C240.239 782.491 246.801 783.003 252.685 782.724C252.646 779.26 252.456 774.289 252.702 770.945C254.464 770.892 261.143 770.873 262.247 770.26C262.604 768.573 262.558 761.279 262.515 759.142C262.425 754.662 262.746 748.764 262.421 744.404Z" fill="#9E2184"/> -<path d="M367.286 668.107C371.92 667.57 380.715 668.048 385.911 667.862C385.558 673.333 385.76 681.694 385.728 687.315C388.697 687.359 391.88 687.281 394.866 687.264C395.037 684.56 394.947 680.906 394.952 678.132C398.453 677.863 421.901 677.592 423.703 678.482C424.323 678.789 424.432 679.323 424.583 679.953C425.413 683.433 424.85 689.62 424.87 693.306C424.888 696.529 425.192 699.933 424.891 703.129C424.815 703.938 424.719 704.588 424.272 705.273C422.757 706.065 416.927 705.653 414.589 705.819C414.337 709.018 414.651 712.33 414.322 715.77C411.214 715.84 408.009 715.817 404.893 715.833C405.322 711.219 405.066 701.511 405.071 696.508C408.241 696.522 411.405 696.563 414.573 696.44C414.742 694.905 415.057 687.885 414.281 687.098C412.619 686.725 406.886 686.584 405.282 687.435C405.054 687.702 404.679 688.139 404.674 688.494C404.636 691.068 404.832 693.819 404.876 696.392C400.455 696.196 390.138 696.141 385.964 696.461L385.943 687.451C383.923 687.41 377.635 687.729 376.028 689.168C375.093 690.005 375.83 694.671 375.91 696.506C378.194 696.674 383.599 696.692 385.853 696.457C385.698 699.46 385.842 702.581 385.678 705.727C379.604 705.883 373.046 705.568 367.068 705.84C367.016 700.013 367.244 693.607 367.239 687.649L366.971 687.075C365.811 686.481 359.113 686.842 357.502 686.957C357.288 691.338 357.557 698.195 357.585 702.763C360.237 702.576 362.991 702.648 365.651 702.707C365.571 705.952 366.196 706.886 366.373 709.907C366.443 711.106 365.524 713.821 365.542 715.339C365.573 717.888 366.316 720.467 366.321 722.938C366.338 730.115 366.062 737.186 366.378 744.369C362.752 743.961 352.183 744.259 347.981 744.226C348.16 741.908 347.975 737.241 347.95 734.75C350.966 734.842 354.274 734.768 357.313 734.756C357.462 731.802 357.455 728.004 357.332 725.063C354.483 724.945 350.979 725.049 348.08 725.061C348.146 722.067 348.078 718.831 348.069 715.817C345.297 715.662 341.268 715.775 338.422 715.764C338.385 712.71 338.395 709.654 338.453 706.598C340.337 706.625 346.322 706.835 347.797 706.526C348.404 704.952 348.303 689.099 347.978 686.924C346.794 686.228 340.834 686.586 338.788 686.419L338.485 686.392C338.061 681.896 338.309 672.628 338.356 667.876C341.408 668.131 344.844 668.068 347.942 668.077C347.926 671.398 347.935 674.719 347.969 678.04L367.2 678.029C367.412 675.442 367.282 670.822 367.286 668.107Z" fill="#9E2184"/> -<path d="M594.723 611.19C603.863 611.432 613.64 611.128 622.897 611.231C623.144 613.893 622.946 617.71 622.863 620.439C620.906 620.548 615.366 620.275 614.163 620.972C613.236 622.112 613.575 628.167 613.534 630.265C619.768 630.369 626.159 629.83 632.427 630.336L632.411 639.736L642.197 639.812C642.344 645.994 642.162 652.659 642.215 658.928L661.314 658.7L661.33 667.735C652.45 667.332 641.976 667.626 632.962 667.638C632.997 664.834 633.033 652.063 632.437 649.716C631.593 648.929 624.84 649.216 623.167 649.218C623.128 645.977 623.22 642.773 623.13 639.521C620.185 639.355 616.742 639.496 613.656 639.386C613.58 636.424 613.649 633.206 613.658 630.224L594.672 630.303C594.709 633.32 594.601 636.366 594.527 639.384C592.478 639.397 587.428 639.282 585.691 639.789C584.64 640.88 585.483 644.607 585.276 646.019C584.76 649.559 585.366 655.168 584.736 658.517L583.51 658.507C577.668 658.583 571.826 658.547 565.986 658.399C565.773 661.416 565.854 664.801 565.684 667.951C562.711 667.909 559.454 667.865 556.513 668.176C556.46 670.493 556.214 675.953 556.483 677.987C554.063 677.756 548.894 677.932 546.276 677.95C546.17 674.927 546.292 671.345 546.329 668.28C544.34 668.339 539.491 668.037 538.145 668.929C537.195 670.245 537.58 675.581 537.548 677.775C534.485 677.861 531.452 677.805 528.368 677.943C528.373 675.072 527.914 661.484 528.58 659.812C529.537 657.419 553.13 660.484 556.227 658.634C556.921 656.308 556.85 642.506 556.428 639.88C555.571 639.098 548.924 639.35 547.172 639.339C547.018 636.711 547.076 633.332 547.053 630.649C549.744 630.801 564.204 630.044 565.366 631.044C565.833 631.448 565.967 632.173 566.006 632.758C566.158 635.008 565.695 637.476 565.571 639.738C565.386 643.113 565.444 646.53 565.527 649.908C568.191 650.064 572.66 649.928 575.37 649.8C575.882 644.818 575.545 635.829 575.644 630.403C581.604 630.11 588.638 630.31 594.727 630.249C594.766 623.896 594.766 617.543 594.723 611.19Z" fill="#9E2184"/> -<path d="M585.062 524.386C586.444 524.538 593.909 524.065 594.26 525.132C595.345 528.452 593.702 540.925 594.889 543.278C596.306 543.865 602.294 543.768 603.872 543.497C603.644 545.286 603.884 550.299 603.531 552.258C603.372 552.412 603.213 552.565 603.054 552.718C601.24 553.358 596.804 553.022 594.608 553.132C594.543 555.893 594.679 559.963 594.446 562.53C589.443 562.902 538.548 562.405 538.145 562.926C537.255 564.075 537.576 570.76 537.749 572.416C543.697 572.493 550.526 572.543 556.453 572.349C556.622 575.683 556.288 579.478 556.553 582.559C554.995 582.286 549.046 582.368 547.115 582.365C546.951 583.852 547.023 585.707 546.79 587.112C545.619 594.174 547.087 601.262 547.009 608.363C546.926 615.682 546.744 623.034 546.753 630.382C541.759 630.268 537.179 630.371 532.261 631.185C531.298 631.344 529.198 631.232 528.184 631.209C527.643 619.73 524.824 621.153 537.364 620.811C537.509 615.766 537.246 610.241 537.417 605.126C537.592 599.861 538.924 587.545 537.942 582.78C536.559 582.132 530.302 582.41 528.382 582.434C528.394 580.369 528.889 575.008 528.03 573.754C526.665 572.801 521.413 573.226 519.288 573.229C519.493 571.205 519.454 565.794 519.297 563.745C521.017 563.676 526.138 563.903 527.366 563.611C529.449 563.114 527.569 556.53 528.611 553.879C530.579 552.418 552.913 554.192 556.099 553.054C556.894 551.934 556.573 545.499 556.566 543.702L565.953 543.658C565.806 546.544 565.907 550.49 565.986 553.411C568.041 553.644 573.285 553.415 575.529 553.369C575.711 550.453 575.617 546.579 575.624 543.594C578.302 543.758 582.266 543.657 584.999 543.612C585.393 539.183 585.078 529.286 585.062 524.386Z" fill="#9E2184"/> -<path d="M518.771 582.637L528.368 582.57C528.44 586.817 528.603 607.323 527.446 610.633C526.474 611.285 520.396 611.003 518.564 611.013C518.322 614.181 518.647 617.388 518.269 620.616C515.266 620.718 512.258 620.639 509.265 620.378C509.115 623.244 509.228 627.167 509.225 630.113C511.152 630.135 516.817 629.818 518.294 630.464C519.092 632.515 518.88 646.503 517.889 649.039C517.061 649.713 501.906 649.49 499.631 649.506C499.709 647.379 499.875 631.524 499.419 630.632L498.698 630.57C496.017 630.685 493.337 630.759 490.654 630.792C490.606 628.548 491.21 622.364 490.332 621.094C489.027 620.14 482.899 620.606 480.878 620.633C480.919 617.453 480.919 614.273 480.88 611.094C477.912 611.052 474.379 611.538 471.502 610.994C470.345 610.776 470.546 603.656 471.189 602.631C472.98 602.029 487.495 601.723 489.682 602.118C490.431 603.303 490.133 609.384 490.131 611.298C496.232 611.385 502.689 611.245 508.845 611.267C508.9 609.097 508.49 602.23 509.331 601.093C510.8 600.172 515.941 600.644 518.255 600.467L518.58 600.441C519.062 597.406 518.714 586.492 518.771 582.637Z" fill="#9E2184"/> -<path d="M509.482 658.984C511.844 658.874 515.937 658.807 518.302 658.99C518.703 664.977 518.21 672.006 518.364 678.135C521.63 677.994 524.9 678.041 528.168 678.054C528.178 681.012 528.118 684.272 528.208 687.204C531.229 687.23 534.919 687.159 537.885 687.31C537.88 689.865 537.754 694.117 537.963 696.536L547.067 696.538C546.991 702.567 547.118 709.682 546.788 715.612C543.794 715.706 540.798 715.757 537.8 715.759C537.816 712.436 537.885 708.969 537.839 705.66L528.318 705.545C528.318 702.565 528.373 699.375 528.295 696.413C521.886 696.496 514.82 696.881 508.551 696.685C508.498 698.711 508.258 703.798 508.489 705.653C503.688 705.713 495.525 705.462 491.095 705.805C491.068 702.871 490.987 699.649 491.15 696.734C496.944 696.651 502.741 696.632 508.535 696.676C508.406 694.146 507.786 686.428 509.074 684.602C509.823 683.543 509.464 679.858 509.519 678.435C509.482 672.962 509.166 664.314 509.482 658.984Z" fill="#9E2184"/> -<path d="M405.078 477.105L414.57 477.083L414.522 495.673L414.494 515.089C411.468 515.003 408.121 515.073 405.07 515.075L405.097 505.247L395.692 505.161C395.688 503.917 396.28 496.271 395.062 495.987C390.486 494.921 370.706 496.901 367.731 495.228C367.031 493.73 367.369 479.723 367.396 477.127C370.461 477.027 373.871 477.093 376.962 477.086C376.947 478.72 376.652 485.468 377.39 486.476C378.729 486.869 384.392 487.143 385.589 486.034C386.575 485.121 385.989 482.379 385.978 481.033C385.968 479.767 386.017 478.403 386.081 477.091L395.612 477.092L395.649 486.471C406.816 487.94 405.148 486.751 405.078 477.105Z" fill="#9E2184"/> -<path d="M319.097 696.28C325.507 696.247 331.917 696.388 338.319 696.702C338.348 699.958 338.357 703.215 338.345 706.471C335.87 706.059 331.175 705.953 328.551 706.171C328.496 709.087 328.364 713.106 328.568 716.001C331.729 716.003 335.115 716.04 338.266 715.84L338.243 725.091C334.969 725.045 331.826 725.008 328.554 725.095C328.527 726.96 328.306 733.226 328.485 734.747C325.956 734.69 321.37 734.6 318.922 734.793L318.894 753.408C314.34 753.425 304.335 753.703 300.232 753.319C300.179 751.265 299.694 746.287 300.784 744.89C302.13 744.028 307.673 744.494 309.85 744.427C310.038 738.852 309.987 733.272 310.082 727.697C310.124 725.243 308.98 717.974 310.489 716.268C312.913 715.217 317.08 717.554 319 715.459C319.242 714.736 319.197 714.298 319.205 713.544L319.097 696.28Z" fill="#9E2184"/> -<path d="M566.106 572.481C569.291 572.352 572.437 572.443 575.624 572.501C575.633 581.67 575.327 592.682 575.642 601.699C577.809 601.729 583.128 602.192 584.578 601.155C585.513 599.731 585.039 594.151 585.124 591.894C588.86 591.812 600.533 591.612 603.764 592.099L603.723 601.409C601.828 601.996 595.145 601.177 594.808 602.378C594.184 604.59 594.486 608.534 594.516 610.975C591.872 610.972 587.694 610.858 585.228 611.135C585.122 613.322 585.426 618.971 584.49 620.28C583.02 621.252 578.03 620.695 575.645 620.868C575.612 617.665 575.67 614.152 575.564 610.986C572.545 610.93 569.023 611.049 566.11 610.908C566.143 604.724 566.272 598 566.103 591.837C563.531 591.815 559.072 591.933 556.689 591.694C556.673 588.787 556.726 585.422 556.553 582.559C559.272 582.629 563.255 582.722 565.944 582.553C565.967 579.889 565.854 574.955 566.106 572.481Z" fill="#9E2184"/> -<path d="M233.881 705.713C237.04 705.664 240.257 705.685 243.421 705.674L243.556 715.95C246.003 716.1 249.914 716.029 252.347 715.918C252.11 721.38 252.74 728.9 252.814 734.775C254.871 734.83 260.048 734.487 261.574 735.015C262.995 736.361 262.08 741.871 262.342 744.187C259.481 744.197 245.462 743.932 243.704 744.653C243.465 745.752 244.089 751.189 244.155 752.908C246.687 753.282 250.508 752.726 252.718 753.445C252.76 756.589 252.752 759.732 252.693 762.876C246.618 762.876 240.117 763.035 234.089 762.835L234.107 734.934C237.082 734.641 240.523 734.927 243.663 734.796C243.838 731.924 243.719 728.006 243.707 725.049C240.501 725.042 237.315 725.056 234.111 724.913C234.04 721.673 234.087 718.363 234.027 715.114C233.981 712.675 233.032 707.812 233.881 705.713Z" fill="#9E2184"/> -<path d="M328.536 639.751C331.628 639.839 335.06 639.737 338.227 639.78C338.399 642.452 338.272 646.658 338.286 649.458C341.49 649.535 344.655 649.446 347.915 649.555C347.962 652.517 347.959 655.48 347.906 658.442C344.699 658.538 341.49 658.513 338.284 658.367C338.127 661.142 338.24 664.891 338.249 667.741C335.263 667.549 331.345 667.583 328.542 667.213C328.531 669.859 328.497 684.908 327.986 686.563C326.867 687.356 320.669 687.094 318.885 687.09C318.875 689.566 318.749 693.858 319.025 696.178C317.264 696.251 310.65 696.012 309.698 696.54C309.677 699.866 309.581 703.187 309.41 706.506C306.816 706.755 302.864 706.639 300.25 706.561C300.113 700.223 300.217 693.594 300.237 687.232C305.926 687.344 312.855 687.336 318.496 687.199C318.775 683.615 319.079 680.238 319.616 676.646C319.905 674.713 318.424 667.52 319.422 666.109C320.664 665.41 326.921 665.783 328.476 666.08C328.834 657.967 328.474 648.105 328.536 639.751Z" fill="#9E2184"/> -<path d="M632.149 572.46C633.269 572.515 641.552 572.827 641.854 572.084C643.071 569.108 641.299 555.468 642.799 553.575C644.145 553.116 649.695 553.042 650.946 553.664C652.755 554.565 650.568 569.507 651.594 572.205C651.727 572.555 652.02 572.552 652.34 572.68C654.417 572.664 659.314 572.115 660.762 573.162C661.651 574.466 661.163 580.315 661.154 582.541C654.15 582.287 646.217 582.536 639.125 582.427C635.489 582.371 626.339 582.225 623.057 582.602C623.05 578.845 623.022 575.019 623.082 571.268C623.133 568.271 623.37 565.761 623.264 562.738C620.363 562.475 616.809 562.722 613.665 562.54C613.624 560.747 613.306 554.612 614.007 553.39C619.561 553.168 626.931 553.249 632.527 553.401C632.854 556.731 632.31 559.898 632.163 563.215C632.027 566.288 632.071 569.386 632.149 572.46Z" fill="#9E2184"/> -<path d="M661.38 667.923C664.457 667.954 667.568 667.814 670.619 668.13C670.896 673.009 670.714 677.93 670.64 682.814C670.622 684.156 670.58 685.392 670.94 686.699C672.608 688.138 685.814 686.454 688.854 687.548C689.963 688.816 689.317 703.21 689.227 705.823C686.176 705.989 683.12 705.941 680.078 705.678C671.219 705.761 660.37 706.019 651.603 705.681C651.394 702.59 651.626 699.695 651.477 696.678C654.701 696.669 658.128 696.713 661.331 696.568C661.488 687.371 661.587 677.096 661.38 667.923Z" fill="#9E2184"/> -<path d="M528.387 496.087C530.392 495.923 536.089 495.91 538.037 496.135C538.223 502.51 537.917 509.03 538.094 515.326C539.648 515.331 545.836 514.83 546.566 515.676C547.981 517.312 547.103 523.228 546.253 525.192C544.34 525.21 540.016 524.908 538.777 525.927C538.193 526.975 538.484 532.964 538.41 535.042C538.408 544.775 538.73 544.489 528.359 543.486C528.371 540.762 528.511 536.497 528.322 533.901C525.1 533.973 521.89 534.074 518.668 533.999C518.668 531.395 518.532 527.155 518.7 524.683C521.104 524.566 526.737 525.142 528.014 523.985C528.843 522.421 528.345 517.239 528.274 515.161C525.17 515.091 521.752 515.196 518.728 515.057C518.62 511.758 518.663 508.488 518.689 505.188C520.892 505.501 525.921 505.387 528.32 505.366C528.435 502.31 528.392 499.154 528.387 496.087Z" fill="#9E2184"/> -<path d="M642.264 505.118C642.204 503.407 641.724 497.394 642.734 496.296C644.663 495.78 659.24 495.83 661.001 496.326C661.432 499.055 660.959 502.599 661.236 505.354C664.22 505.372 678.371 505.034 680.028 505.739C680.715 506.928 680.8 514.693 679.982 514.852C677.35 515.362 673.607 515.028 670.837 515.091C670.738 518.501 671.13 531.496 670.408 533.634C669.141 534.346 663.181 534.01 661.365 534.016C661.363 531.083 661.466 527.406 661.333 524.535C659.41 524.503 653.1 524.766 651.876 524.03C650.579 521.69 652.231 509.427 651.402 506.188C650.975 504.521 644.029 505.238 642.264 505.118Z" fill="#9E2184"/> -<path d="M537.8 715.759C537.717 717.188 537.71 718.737 537.712 720.175C537.731 728.225 537.489 736.388 537.724 744.429C540.775 744.521 554.124 744.07 556.104 744.865C556.89 746.499 556.507 760.133 556.468 762.89C553.568 762.802 550.321 763.023 547.251 762.966C547.263 759.82 547.256 756.672 547.226 753.526C542.84 753.111 533.451 753.422 528.597 753.374C528.634 747.091 528.288 741.057 528.33 734.724C525.412 734.597 521.759 734.729 518.719 734.687C518.546 731.79 518.664 728.154 518.708 725.245C521.715 725.16 525.004 725.236 528.035 725.252C528.235 722.242 528.159 718.889 528.15 715.842C531.077 715.895 534.93 715.953 537.8 715.759Z" fill="#9E2184"/> -<path d="M328.554 477.12C338.49 476.969 348.735 477.085 358.696 477.097C358.763 480.336 358.815 484.025 358.554 487.231C349.274 487.037 337.382 487.588 328.406 486.967C328.26 492.953 328.481 498.96 328.264 505.019C325.797 505.307 322.512 505.212 319.97 505.21C319.743 505.22 319.487 505.313 319.255 505.377C318.632 506.624 318.883 513.441 319.03 515.101C313.14 515.122 306.024 515.318 300.238 515.039C300.13 513.381 299.834 507.038 300.574 505.81C302.656 505.014 315.637 505.423 319.085 505.29C319.255 499.153 318.982 492.849 319.229 486.711C322.229 486.654 325.369 486.737 328.381 486.779C328.392 483.82 328.267 479.97 328.554 477.12Z" fill="#9E2184"/> -<path d="M443.254 705.738C448.071 705.717 453.81 705.441 458.54 705.736C469.33 706.411 480.012 706.208 490.826 706.19C490.914 710.062 490.616 712.804 490.181 716.662C489.93 718.891 490.393 722.512 489.593 724.602C487.966 725.333 483.336 725.061 481.349 725.04C480.844 724.69 481.086 717.63 481.093 716.508C476.532 716.185 467.095 716.515 462.236 716.533C462.082 719.29 462.066 722.281 462.004 725.058L452.427 725.072C452.27 722.173 452.322 718.661 452.293 715.713C449.273 715.505 446.394 715.955 443.089 715.563C443.003 713.837 442.767 707.063 443.254 705.738Z" fill="#9E2184"/> -<path d="M604.094 477.093L613.658 477.103C613.727 480.59 613.923 503.294 613.264 504.843C611.722 505.474 605.924 505.143 604.002 505.102C603.72 508.382 604.018 511.636 603.686 515.064C601.162 515.21 596.553 515.254 594.066 515.01C593.875 508.773 594.124 502.116 593.995 495.79C591.104 495.674 588.062 495.757 585.161 495.786C585.246 494.697 584.734 487.234 585.599 486.879C588.869 485.537 600.964 487.686 603.672 486.227C604.416 484.852 604.114 479.114 604.094 477.093Z" fill="#9E2184"/> -<path d="M509.276 553.36C511.466 553.661 516.898 552.825 518.182 554.05C518.841 556.136 518.935 568.141 518.832 571.06C518.716 574.32 517.746 578.598 518.645 582.406L499.772 582.433L499.765 572.943C498.297 572.374 483.876 572.826 480.97 572.671C480.901 569.412 480.975 566.492 481.005 563.257C490.468 563.264 500.276 563.412 509.712 563.285C509.733 559.5 509.668 557.161 509.276 553.36Z" fill="#9E2184"/> -<path d="M367.609 611.043C370.459 611.017 373.393 611.113 376.249 611.172C376.259 614.204 376.2 617.632 376.407 620.622C379.383 620.758 383.018 620.648 386.07 620.704C388.57 620.75 393.049 620.895 395.379 620.631C395.404 623.532 395.371 626.474 395.364 629.379C391.078 629.533 386.844 629.688 382.556 629.531C379.03 629.402 370.905 628.415 367.601 629.02C367.114 629.678 367.162 629.711 367.056 630.498C366.881 632.911 366.735 637.033 366.957 639.454C361.09 639.072 354.364 639.729 348.06 639.296C347.905 637.201 347.347 632.238 348.524 630.694C349.907 629.794 355.039 630.134 357.234 630.092C357.597 627.74 357.537 623.876 357.558 621.372C360.028 621.252 363.151 621.377 365.52 621.312C369.241 621.209 365.558 613.503 367.609 611.043Z" fill="#9E2184"/> -<path d="M245.08 486.391L261.106 486.333C263.132 486.323 268.288 486.167 270.085 486.561C271.264 487.707 271.383 503.439 270.709 504.678C270.062 505.129 269.444 505.029 268.629 505.043C260.554 505.146 250.765 505.428 242.799 505.078C242.921 499.367 242.441 492.515 242.396 486.511L245.08 486.391Z" fill="#9E2184"/> -<path d="M252.553 515.324C261.901 515.117 271.339 515.389 280.696 515.282C283.948 515.245 287.27 515.255 290.516 515.366C290.545 517.498 290.966 522.431 289.965 523.895C288.644 524.799 282.485 524.351 280.287 524.356C278.176 524.393 273.547 524.045 271.945 524.646C270.657 525.961 271.214 531.402 271.086 533.911C266.83 534.24 256.68 534.135 252.307 533.97C252.173 531.35 251.862 516.982 252.553 515.324Z" fill="#9E2184"/> -<path d="M632.503 533.768C633.054 529.284 633.268 525.684 632.902 521.196C632.831 520.322 632.748 516.094 633.236 515.569C634.695 515.15 640.572 515.087 641.846 515.729C642.513 516.971 642.162 531.524 642.141 534.112C644.879 534.324 649.062 534.184 651.897 534.202C654.414 534.219 659.051 534.322 661.365 534.016C661.245 536.371 661.685 541.121 660.929 543.014C659.749 543.52 626.281 543.658 623.522 543.277C622.902 542.109 622.851 536.218 623.296 535.03C623.987 533.186 630.77 535.148 632.503 533.768Z" fill="#9E2184"/> -<path d="M309.879 620.733C312.523 620.587 316.163 620.688 318.882 620.685L318.921 630.059C321.787 630.124 325.47 629.923 328.367 629.828C328.336 633.03 328.346 636.232 328.399 639.434C325.532 639.336 321.801 639.362 318.927 639.456C318.67 644.57 319.316 653.74 318.603 658.346C317.111 658.75 311.435 658.642 309.655 658.638C309.553 652.27 309.781 645.855 309.589 639.485C306.82 639.247 303.247 639.342 300.403 639.346C300.543 636.419 300.62 633.585 300.483 630.656C301.784 630.622 304.147 630.461 305.388 630.696C312.418 632.026 308.537 624.888 309.879 620.733Z" fill="#9E2184"/> -<path d="M681.282 734.846C683.255 734.786 687.505 734.443 689.153 735.153C689.865 736.478 689.381 768.495 689.19 772.54C685.283 772.606 683.386 772.47 679.616 772.086C676.684 772.097 673.755 772.083 670.824 772.049C670.803 766.059 670.708 759.852 670.828 753.883C673.691 753.646 677.242 753.791 680.227 753.708C680.519 748.769 679.886 740.398 680.519 735.353C680.554 735.07 680.946 734.994 681.282 734.846Z" fill="#9E2184"/> -<path d="M632.732 601.736C635.843 601.693 638.957 601.691 642.071 601.732C642.28 604.654 641.995 608.079 642.124 611.196C644.246 611.223 649.625 610.846 650.962 611.776C651.815 613.099 651.43 618.495 651.448 620.656C653.838 620.735 656.221 620.575 658.605 620.615C662.055 620.672 661.483 623.408 661.329 625.849C661.236 627.318 661.213 628.719 660.967 630.181C656.821 630.605 646.735 630.299 642.267 630.283L642.216 620.664C639.144 620.564 635.666 620.633 632.566 620.627C632.419 618.044 632.177 603.661 632.732 601.736Z" fill="#9E2184"/> -<path d="M673.861 630.198C676.147 630.199 688.093 629.826 689.144 630.566C689.833 632.386 689.452 637.31 689.174 639.319C675.488 640.105 682.264 637.916 679.828 648.427C679.713 648.925 672.465 648.674 671.575 648.966C671.126 649.114 668.553 649.448 667.809 649.461C662.409 649.5 657.012 649.474 651.612 649.385C651.377 646.774 651.464 642.453 651.522 639.779C657.689 639.575 664.606 639.702 670.764 639.8C670.821 636.652 670.847 633.505 670.84 630.357C671.766 630.268 672.914 630.245 673.861 630.198Z" fill="#9E2184"/> -<path d="M556.884 477.177C562.826 476.943 569.618 477.092 575.626 477.099C575.64 480.08 575.73 483.312 575.497 486.265C572.531 486.394 569.067 486.274 566.006 486.328C565.852 489.205 565.935 492.845 565.93 495.782C563.872 495.746 558.329 495.558 556.585 496.018C556.354 498.632 556.541 502.267 556.368 505.185C553.365 505.25 550.362 505.247 547.359 505.174L547.322 504.704C547.182 502.685 546.935 487.804 547.733 486.895C549.514 486.219 554.335 486.577 556.43 486.641C556.686 484.22 556.241 478.91 556.884 477.177Z" fill="#9E2184"/> -<path d="M500.162 744.464C503.2 744.397 506.237 744.448 509.27 744.616C509.409 750.663 509.289 757.027 509.254 763.093L518.482 763.102C518.655 766.144 518.374 769.223 518.604 772.194C516.074 772.113 511.195 772.47 509.137 771.666C508.54 771.392 501.683 771.323 500.427 771.23C500.397 768.465 500.416 765.697 500.478 762.931C497.579 762.756 493.686 762.908 490.593 762.825L490.565 753.63C493.578 753.724 496.661 753.669 499.68 753.653C499.796 751.624 499.409 745.775 500.162 744.464Z" fill="#9E2184"/> -<path d="M271.41 563.261C275.498 563.136 279.64 563.276 283.73 563.242C285.85 563.224 288.503 563.35 290.57 563.051C290.541 565.539 290.601 570.093 290.353 572.451C288.193 572.528 282.722 572.277 281.427 573.209C280.6 574.484 280.953 580.776 281.061 582.603C279.259 582.238 264.505 582.388 262.258 582.556C262.27 580.397 261.974 574.896 262.575 573.194C263.071 571.79 268.655 573.301 270.92 572.357C271.757 571.211 271.402 565.278 271.41 563.261Z" fill="#9E2184"/> -<path d="M243.695 543.664C246.217 543.657 260.929 543.232 262.054 544.209C262.576 546.3 262.232 550.627 262.134 552.935C259.644 553.049 255.469 552.68 253.339 553.281C251.661 555.394 254.104 561.924 251.866 562.641C245.916 562.839 240.041 562.683 234.094 562.515C234.101 552.243 231.706 550.907 243.359 552.945C243.49 550.445 242.991 545.624 243.695 543.664Z" fill="#9E2184"/> -<path d="M442.762 476.059L442.978 476.022C443.629 476.892 443.122 501.656 443.277 505.188C440.169 505.204 437.06 505.196 433.952 505.166C434.089 502.65 434.005 499.341 434.004 496.767L433.758 496.144C432.455 495.489 426.318 495.825 424.208 495.712C424.159 492.716 424.156 489.72 424.198 486.724C427.019 486.445 429.591 486.748 432.424 486.596C434.376 486.769 434.065 484.029 433.879 482.692C432.827 475.123 436.329 476.59 442.762 476.059Z" fill="#9E2184"/> -<path d="M347.962 591.809C353.041 591.919 362.492 591.497 366.982 592C367.024 594.115 367.367 599.485 366.635 601.208C365.06 602.303 359.424 600.823 357.866 601.98C357.107 602.543 357.384 609.368 357.308 610.471C356.408 610.461 353.07 610.39 352.407 610.595C349.961 611.353 350.857 611.661 348.078 611.679C347.965 613.794 348.255 618.608 347.423 620.037C346.008 621.23 340.428 620.637 338.231 620.589C338.167 617.622 338.848 617.098 338.768 614.582C338.734 613.529 338.447 613.542 338.845 612.414C339.859 612.166 346.461 611.632 347.916 611.529C348.35 605.852 347.944 597.748 347.962 591.809Z" fill="#9E2184"/> -<path d="M661.559 601.79C664.264 601.762 678.132 602.076 679.996 603.056C680.704 604.444 680.261 609.554 680.469 611.6C685.357 611.706 689.913 609.772 689.406 616.113C689.286 617.612 690.038 618.712 689.418 620.488C687.263 620.626 672.409 620.83 671.158 620.276C670.104 618.473 671.381 614.146 670.632 611.836C667.244 608.989 660.261 615.152 661.268 606.131C661.427 604.712 661.042 603.262 661.559 601.79Z" fill="#9E2184"/> -<path d="M594.974 639.527C597.281 639.905 602.356 639.137 603.467 640.046C603.838 642.585 603.672 648.455 603.64 651.202C603.578 656.687 603.67 662.415 603.52 667.88C600.699 668.013 597.055 667.918 594.17 667.925C591.135 667.937 588.12 667.981 585.087 667.829C584.939 665.285 585.073 661.549 585.094 658.92L594.177 658.905C594.338 657.749 594.486 656.456 594.46 655.288C594.34 649.955 595.082 644.86 594.974 639.527Z" fill="#9E2184"/> -<path d="M280.157 476.121C283.602 476.496 287.294 476.935 290.734 477.15C290.603 480.687 290.827 504.64 290.246 505.476C287.625 505.809 282.8 506.395 280.358 506.564C280.413 496.585 280.202 486.136 280.157 476.121Z" fill="#9E2184"/> -<path d="M300.2 761.279C302.724 761.26 305.248 761.256 307.772 761.27L309.386 762.593C312.185 762.576 316.241 762.659 318.923 762.401C318.92 767.317 319.059 776.99 318.704 782.205C318.59 782.334 318.476 782.466 318.362 782.595C304.752 782.832 311.246 782.166 309.381 773.231C309.18 772.265 303 774.183 300.711 773.434C299.726 772.293 300.175 763.517 300.2 761.279Z" fill="#9E2184"/> -<path d="M360.114 504.608C361.367 504.558 365.678 504.279 366.434 504.704C367.714 505.424 367.019 513.499 366.546 514.711C365.589 515.51 348.045 515.139 345.667 515.14L338.428 515.111C338.386 511.728 338.4 508.345 338.468 504.963C345.183 505.047 353.179 504.647 360.114 504.608Z" fill="#9E2184"/> -<path d="M471.457 582.599C480.136 582.778 491.031 582.772 499.685 582.582C499.468 585.756 499.719 589.153 499.491 592.477C495.776 592.555 491.646 592.243 487.869 592.132L471.194 591.806C471.102 589.624 470.888 584.48 471.457 582.599Z" fill="#9E2184"/> -<path d="M663.152 717.093L670.619 716.893C670.653 723.251 670.907 729.26 670.773 735.644C666.5 735.764 663.315 735.121 659.119 735.109C656.475 735.132 653.829 735.081 651.19 734.964C651.285 731.744 651.269 728.389 651.299 725.157C653.336 725.22 659.688 725.505 661.273 724.872C662.956 722.936 660.084 718.306 663.152 717.093Z" fill="#9E2184"/> -<path d="M575.138 495.993C577.848 496.001 582.54 496.158 585.092 495.952C585.08 498.957 585.126 502.162 585.046 505.149C581.916 505.211 578.786 505.235 575.656 505.222C575.571 508.385 575.435 511.958 575.493 515.1C572.9 514.788 568.802 514.967 566 514.886C566.016 508.829 566.163 501.958 565.977 495.973L575.138 495.993Z" fill="#9E2184"/> -<path d="M328.485 734.747C331.782 734.803 335.079 734.8 338.376 734.734C338.138 737.559 338.246 741.486 338.312 744.363C340.503 744.671 345.507 744.459 347.912 744.411C347.905 746.766 347.996 751.203 347.762 753.385L335.453 753.42C333.601 753.427 330.207 753.367 328.457 753.581C328.743 748.827 328.581 739.619 328.485 734.747Z" fill="#9E2184"/> -<path d="M561.568 515.197C563.091 515.226 564.354 515.222 565.873 515.154L565.921 533.97L556.511 533.992L556.44 543.435L551.955 543.462C550.399 543.469 548.846 543.449 547.292 543.401C546.211 531.815 547.062 534.797 556.313 534.065C556.267 532.873 556.255 531.729 556.366 530.539C556.838 525.489 556.737 520.446 556.735 515.376C558.247 515.263 560.033 515.247 561.568 515.197Z" fill="#9E2184"/> -<path d="M366.402 744.482C369.672 744.503 373.005 744.452 376.281 744.436L376.313 759.444C376.315 761.56 376.43 766.485 376.02 768.377C374.069 768.426 369.731 768.654 368.081 768.304C367.643 767.774 367.496 767.405 367.514 766.66C367.635 761.514 367.441 756.289 366.854 751.177C366.575 748.741 366.28 746.928 366.402 744.482Z" fill="#9E2184"/> -<path d="M508.564 705.784L528.161 705.704V715.759C521.701 715.628 515.02 715.93 508.576 715.611C508.597 712.337 508.592 709.062 508.564 705.784Z" fill="#9E2184"/> -<path d="M594.702 572.722C600.775 572.546 607.558 572.596 613.64 572.689C613.649 574.216 613.794 581.753 613.391 582.427C607.187 582.224 600.51 582.716 594.32 582.352C594.253 580.316 593.773 574.053 594.702 572.722Z" fill="#9E2184"/> -<path d="M481.14 668.121C483.924 668.14 497.824 667.507 499.099 668.705C499.661 670.592 499.578 676.113 499.075 677.948C494.413 678.485 486.467 677.908 481.689 677.793C480.368 677.762 480.654 669.452 481.14 668.121Z" fill="#9E2184"/> -<path d="M281.094 591.84C281.001 595.054 281.053 598.388 280.972 601.655C274.933 601.42 268.596 601.774 262.357 601.52C262.13 599.081 262.292 594.56 262.28 591.914C268.142 591.786 275.451 592.17 281.094 591.84Z" fill="#9E2184"/> -<path d="M471.674 620.937C474.591 620.836 477.763 620.885 480.699 620.879L480.685 631.197L490.549 631.026C490.574 633.076 490.837 637.555 490.074 639.437C489.959 639.721 489.521 639.752 489.132 639.867C485.043 639.884 484.734 641.05 479.913 640.384C480.259 638.339 480.362 633.539 480.468 631.247C478.226 631.253 475.004 631.636 472.99 630.898C472.598 629.869 472.294 627.81 472.169 626.66C471.98 624.916 470.876 622.466 471.674 620.937Z" fill="#9E2184"/> -<path d="M613.723 582.574C616.166 582.733 620.321 582.595 622.893 582.591C623.02 588.85 623.004 595.11 622.847 601.367C620.95 602.089 615.832 601.784 613.693 601.685C613.442 596.739 613.594 587.573 613.723 582.574Z" fill="#9E2184"/> -<path d="M623.97 477.138C629.008 476.945 635.823 477.049 640.939 477.177C641.209 477.254 641.856 477.342 641.912 477.679C642.177 479.264 642.986 485.663 641.356 486.327C637.775 486.521 626.33 486.597 623.124 486.246C623.055 483.719 622.9 480.831 623.098 478.312C623.156 477.561 623.481 477.457 623.97 477.138Z" fill="#9E2184"/> -<path d="M661.319 582.616C664.447 582.763 678.876 582.068 680.319 583.177C680.932 585.024 680.547 589.502 680.457 591.613C678.867 592.189 664.073 591.842 661.342 591.812L661.319 582.616Z" fill="#9E2184"/> -<path d="M434.316 667.936C435.592 667.916 442.855 667.532 443.001 668.545C443.428 671.523 443.143 684.252 442.276 686.756C440.743 687.268 436 687.547 435.083 686.902C433.102 685.508 433.642 669.112 434.316 667.936Z" fill="#9E2184"/> -<path d="M481.033 649.688L499.553 649.68C499.542 651.488 499.772 657.352 499.051 658.477C493.787 658.567 486.062 658.79 480.909 658.442C480.849 656.315 480.653 651.567 481.033 649.688Z" fill="#9E2184"/> -<path d="M651.602 753.321C654.442 753.097 658.203 753.136 661.102 753.194C661.437 755.552 661.201 760.362 661.118 762.897C657.922 762.998 654.723 763.049 651.526 763.051C651.672 759.716 651.487 756.563 651.602 753.321Z" fill="#9E2184"/> -<path d="M453.279 620.762C455.951 620.613 459.357 620.746 462.031 620.859C462.238 623.272 462.1 626.396 462.056 628.854C462.042 629.732 461.989 629.864 461.5 630.308C458.431 630.36 455.358 630.353 452.29 630.284C452.257 627.851 452.002 623.551 452.477 621.184C452.537 620.885 452.875 620.888 453.279 620.762Z" fill="#9E2184"/> -<path d="M452.638 477.082L462.022 477.094C462.054 479.282 462.25 485.068 461.75 486.957L461.459 486.995C450.971 488.292 452.552 486.346 452.638 477.082Z" fill="#9E2184"/> -<path d="M677.523 543.286C678.367 543.121 679.482 543.039 680.275 543.399C680.83 544.619 680.501 551.137 680.459 552.955C678.3 553.011 675.917 552.957 673.739 552.954C672.776 552.95 671.785 552.911 670.819 552.887C670.738 549.821 670.74 546.754 670.823 543.688C673.234 543.534 675.048 543.78 677.523 543.286Z" fill="#9E2184"/> -<path d="M452.459 678.057C455.649 677.974 458.843 677.978 462.033 678.066C462.328 680.148 462.307 685.16 462.024 687.258C458.79 687.296 455.555 687.29 452.32 687.239C452.262 685.172 452.044 679.878 452.459 678.057Z" fill="#9E2184"/> -<path d="M672.689 563.124C675.431 563.089 677.941 563.167 680.679 563.267C680.746 565.459 681.029 569.65 680.506 571.815C680.377 572.344 679.794 572.368 679.386 572.438C677.303 572.433 673.06 572.716 671.264 572.244C670.483 570.527 670.492 565.692 671.045 563.767C671.686 563.067 671.486 563.29 672.689 563.124Z" fill="#9E2184"/> -<path d="M499.827 725.273C502.948 725.151 506.112 725.236 509.24 725.28C509.279 727.704 509.422 732.468 509.136 734.74C505.986 734.773 502.833 734.766 499.68 734.717C499.615 732.256 499.445 727.575 499.827 725.273Z" fill="#9E2184"/> -<path d="M423.916 534.13C424.406 534.563 424.065 542.182 424.181 543.629L415.041 543.651C413.993 542.796 414.244 535.905 415.183 534.565C416.557 533.683 421.861 534.191 423.916 534.13Z" fill="#9E2184"/> -<path d="M338.423 725.167C341.549 725.282 344.821 725.243 347.961 725.25C347.924 728.414 347.905 731.578 347.906 734.743L338.375 734.734L338.423 725.167Z" fill="#9E2184"/> -<path d="M603.942 534.225L613.607 534.234C614.015 545.824 614.81 543.15 603.872 543.497C603.882 540.79 603.727 536.785 603.942 534.225Z" fill="#9E2184"/> -<path d="M433.937 591.888C436.991 591.832 440.045 591.831 443.098 591.884C443.261 594.989 443.154 598.429 443.114 601.566L433.853 601.536C433.924 598.571 433.732 594.647 433.937 591.888Z" fill="#9E2184"/> -<path d="M528.438 762.892C531.132 762.874 535.391 762.731 537.982 763.074C537.943 765.759 538.111 769.737 537.855 772.238C534.963 772.24 531.197 772.136 528.374 772.286C528.362 769.152 528.328 766.024 528.438 762.892Z" fill="#9E2184"/> -<path d="M565.99 534.066C569.247 534.228 572.416 534.166 575.649 534.253L575.624 543.594C573.732 543.316 568.189 543.441 566.018 543.446C566.009 540.352 566.046 537.15 565.99 534.066Z" fill="#9E2184"/> -<path d="M433.852 601.536C433.554 602.968 433.709 609.382 433.838 611.026C430.671 611 427.542 610.944 424.377 611.088C423.879 610.435 424.165 603.044 424.211 601.776C426.59 601.646 431.93 601.876 433.852 601.536Z" fill="#9E2184"/> -<path d="M661.861 477.137C664.837 477.085 667.812 477.054 670.79 477.045C670.833 479.642 670.988 482.981 670.688 485.58C670.619 486.157 670.382 486.19 669.983 486.441C667.081 486.534 664.175 486.547 661.271 486.481C661.177 484.623 660.866 478.242 661.861 477.137Z" fill="#9E2184"/> -<path d="M377.109 734.84C379.752 734.731 383.196 734.706 385.803 734.888C385.763 736.72 386.034 742.961 385.524 744.22L384.846 744.229C382.075 744.243 379.23 744.213 376.468 744.358C376.453 741.599 376.241 738.734 376.341 735.978C376.367 735.271 376.67 735.148 377.109 734.84Z" fill="#9E2184"/> -<path d="M528.385 477.113C531.499 477.052 534.753 477.099 537.88 477.099C537.924 480.003 538.025 483.466 537.797 486.315C534.73 486.497 531.432 486.486 528.339 486.524L528.385 477.113Z" fill="#9E2184"/> -<path d="M428.934 715.699C430.322 715.607 432.256 715.653 433.687 715.646C433.683 718.67 433.746 722.014 433.532 724.996C432.184 725.068 430.366 725.019 428.982 725.022L424.183 724.996C424.107 722.042 424.171 718.817 424.172 715.842L428.934 715.699Z" fill="#9E2184"/> -<path d="M281.975 734.849C284.626 734.724 287.774 734.793 290.471 734.796C290.484 736.409 290.824 743.422 289.828 744.194C286.919 744.27 284.009 744.247 281.102 744.13C280.998 741.88 280.842 737.605 281.218 735.337C281.272 735.012 281.56 735.012 281.975 734.849Z" fill="#9E2184"/> -<path d="M481.044 477.122C484.155 477.045 487.421 477.098 490.546 477.106C490.546 480.177 490.473 483.248 490.325 486.316L480.89 486.285C480.844 484.351 480.641 478.766 481.044 477.122Z" fill="#9E2184"/> -<path d="M453.127 496.085C455.285 496.038 460.148 495.557 461.633 496.538C462.679 498.018 462.059 503.028 461.96 505.161C458.911 505.252 455.599 505.193 452.53 505.193C452.502 502.572 452.443 499.767 452.548 497.15C452.579 496.375 452.638 496.49 453.127 496.085Z" fill="#9E2184"/> -<path d="M471.436 762.876L480.853 762.878C480.929 765.794 480.611 769.412 480.807 772.083C477.882 771.982 474.388 772.081 471.42 772.088C471.233 769.02 471.237 765.944 471.436 762.876Z" fill="#9E2184"/> -<path d="M414.569 658.83L424 658.829C424.061 661.352 424.193 665.414 423.892 667.843C420.771 667.928 417.647 667.94 414.525 667.876C414.343 665.156 414.337 661.554 414.569 658.83Z" fill="#9E2184"/> -<path d="M424.221 753.634L433.661 753.692C433.693 756.734 433.666 759.776 433.58 762.816C430.454 762.869 427.328 762.876 424.202 762.837C424.147 759.836 424.211 756.649 424.221 753.634Z" fill="#9E2184"/> -<path d="M367.026 649.445C366.92 652.505 367.06 655.329 366.754 658.431C363.63 658.491 360.506 658.494 357.382 658.441C357.346 656.442 357.167 651.183 357.572 649.486L367.026 649.445Z" fill="#9E2184"/> -<path d="M443.203 601.627C444.767 601.819 450.622 601.72 452.575 601.745C452.588 604.006 452.698 608.737 452.373 610.793C451.064 611.112 444.929 610.989 443.302 610.982C443.341 607.863 443.308 604.744 443.203 601.627Z" fill="#9E2184"/> -<path d="M585.401 678.088C588.187 678.013 591.642 677.974 594.391 678.143C594.562 680.147 594.726 685.412 594.2 687.19L584.988 687.162C584.991 685.228 584.689 679.175 585.401 678.088Z" fill="#9E2184"/> -<path d="M680.934 715.895C683.654 715.851 686.675 715.775 689.36 716.049C689.492 717.84 689.84 724.132 688.95 725.259C686.712 725.215 682.356 725.812 681.031 725.031C679.86 723.616 679.784 717.294 680.934 715.895Z" fill="#9E2184"/> -<path d="M575.493 515.1C578.535 515.217 581.988 515.117 584.924 515.331C584.901 517.483 584.735 522.347 584.938 524.345C582.082 524.367 578.399 524.482 575.622 524.301C575.608 521.306 575.648 518.078 575.493 515.1Z" fill="#9E2184"/> -<path d="M281.094 601.751L290.49 601.735C290.286 603.758 290.366 608.387 290.316 610.67C288.677 611.15 283.009 610.97 281.091 610.956C281.148 607.935 281.099 604.783 281.094 601.751Z" fill="#9E2184"/> -<path d="M614.021 649.519C617.028 649.478 620.036 649.463 623.043 649.474C622.76 652.4 623.336 654.965 622.746 658.39C620.861 658.613 616.424 659.117 614.696 658.45C613.002 657.796 613.276 650.66 614.021 649.519Z" fill="#9E2184"/> -<path d="M509.47 534.24C512.443 534.115 515.538 534.249 518.599 534.127C518.421 536.935 518.834 540.73 518.304 543.409L509.274 543.435C509.318 541.224 509.076 536.128 509.47 534.24Z" fill="#9E2184"/> -<path d="M556.686 763.143C558.795 763.323 563.566 763.134 565.949 763.116C565.785 766.096 566.094 769.189 565.785 772.166C563.925 772.461 558.507 772.245 556.502 772.164C556.702 769.119 556.677 766.19 556.686 763.143Z" fill="#9E2184"/> -<path d="M556.489 687.211C556.493 689.921 556.599 693.604 556.263 696.217C553.428 696.391 550.029 696.335 547.146 696.348C547.265 693.521 547.194 690.153 547.231 687.263C550.284 687.206 553.426 687.228 556.489 687.211Z" fill="#9E2184"/> -<path d="M680.061 658.878C684.113 658.938 690.197 657.297 689.547 663.039C689.363 664.685 689.812 666.221 689.169 667.899C687.229 667.891 682.467 668.417 681.269 667.689C680.503 666.745 679.95 660.236 680.061 658.878Z" fill="#9E2184"/> -<path d="M319.119 753.657C322.01 753.667 325.638 753.766 328.457 753.581C328.261 755.098 328.356 760.429 328.353 762.247C325.707 762.079 321.819 762.203 319.077 762.215C319.194 759.573 319.116 756.34 319.119 753.657Z" fill="#9E2184"/> -<path d="M234.078 591.61L245.091 591.891C247.139 591.956 250.913 592.171 252.798 591.883C252.74 598.113 252.728 604.343 252.76 610.573C252.762 613.261 252.608 618.234 252.811 620.713C256.158 620.909 259.82 620.741 263.2 620.75C265.738 620.756 268.862 620.893 271.331 620.593C271.38 617.46 271.398 614.327 271.387 611.194C274.618 611.151 277.849 611.16 281.08 611.22C280.811 613.089 281.035 618.573 281.08 620.733C287.078 620.883 294.264 620.44 300.064 620.876C300.135 623.74 299.926 627.947 300.143 630.522C299.007 630.445 297.467 630.319 296.333 630.43C291.309 630.92 286.357 630.89 281.313 630.923C281.246 633.716 281.087 636.978 281.121 639.734C285.112 639.798 289.105 639.815 293.097 639.786C294.85 639.78 298.429 639.833 300.019 639.617C300.011 645.783 299.84 652.761 300.03 658.859L309.55 658.893C309.529 661.74 309.571 665.059 309.388 667.873C306.004 667.964 293.009 667.608 290.926 668.347C290.192 669.359 290.521 676.236 290.54 678.008L299.99 678.049C300.022 681.035 300.03 684.022 300.015 687.008C294.417 686.946 286.313 686.722 280.891 687.04L280.875 696.637C283.847 696.646 287.611 696.552 290.519 696.704C290.548 698.799 290.999 703.864 289.919 705.277C288.58 706.146 283.227 705.717 281.085 705.805C281.011 709.087 280.819 713.132 280.961 716.349C284.918 716.379 288.883 716.42 292.84 716.513C294.811 716.559 297.444 716.31 299.32 716.63C300.422 717.942 300.248 732.83 299.578 734.468C298.056 734.989 292.522 734.685 290.538 734.743C290.588 731.592 290.712 728.195 290.518 725.068C286.654 725.024 264.725 725.393 262.833 724.602C260.935 722.394 263.769 715.478 261.074 715.457C258.552 715.436 255.366 715.644 252.699 715.598L252.709 705.768C255.515 705.872 258.512 705.745 261.249 705.957C261.251 702.751 261.301 699.4 261.226 696.208C258.278 696.259 255.221 696.272 252.284 696.381C252.288 698.979 252.174 702.98 252.35 705.464C249.464 705.473 246.578 705.466 243.692 705.446C243.797 699.451 243.676 693.487 243.74 687.511C246.447 687.814 249.273 687.442 252.06 687.672C252.043 684.914 252.113 681.515 251.813 678.844L251.77 678.448L251.741 678.21C249.05 678.367 246.44 678.28 243.748 678.228C243.512 681.057 243.555 684.353 243.528 687.23C236.685 687.168 229.843 687.156 223 687.196V678.042L243.843 678.041C244.142 674.705 244.213 672.299 244.228 668.965C241.089 668.707 236.808 668.821 233.567 668.826C233.944 662.026 234.405 656.031 234.126 649.126C233.994 645.863 233.6 642.546 233.62 639.362L243.468 639.319C243.396 642.708 243.371 646.098 243.393 649.487L254.461 649.496C256.467 649.502 259.45 649.632 261.362 649.363C262.55 648.315 262.037 646.491 262.402 645.054C262.799 643.496 263.619 640.471 262.669 639.002C259.326 639.634 247.748 639.362 243.736 639.345C243.882 636.82 243.78 633.571 243.761 630.986C240.581 631.133 237.259 631.059 234.063 631.034L234.086 620.682L243.454 620.68C243.666 614.867 243.591 607.44 243.492 601.611L234.073 601.541L234.078 591.61ZM271.179 677.984C267.933 678 264.268 677.934 261.057 678.054C260.829 680.55 260.531 694.019 261.197 695.807C262.732 696.418 268.242 696.094 270.389 696.195C270.829 695.981 271.1 695.975 271.137 695.601C271.628 690.592 271.323 682.97 271.336 678.04C274.259 678.027 278.13 678.125 280.977 677.96C281.11 674.58 281.043 671.247 281.001 667.865L271.445 667.854C270.955 669.672 271.152 675.852 271.179 677.984ZM252.942 658.472C252.489 659.905 252.343 666.357 252.734 667.698C253.541 668.361 260.432 668.084 261.957 668.07C262.667 666.663 262.254 660.338 262.222 658.404L252.942 658.472ZM290.526 649.252C287.391 649.185 284.255 649.165 281.119 649.192C280.59 651.063 280.835 656.761 280.883 658.933C283.988 658.914 287.305 658.955 290.391 658.863C290.692 656.446 290.555 651.828 290.526 649.252ZM263.69 640.465C266.5 640.325 269.058 640.307 271.87 640.307C271.902 636.552 271.84 632.538 271.956 628.816C269.723 628.707 264.994 629.119 263.577 627.916C263.601 631.316 263.408 637.327 263.69 640.465Z" fill="#9E2184"/> -<path d="M252.946 582.659C256.024 582.664 259.102 582.646 262.179 582.606L262.197 591.825C259.086 591.805 255.898 591.738 252.797 591.883C253.03 588.74 252.742 585.677 252.946 582.659Z" fill="#9E2184"/> -<path d="M1216.11 521.292C1221.5 521.272 1230.06 521.513 1235.29 521.149C1235.26 523.175 1234.84 528.409 1235.78 529.777C1237 530.655 1242.79 530.248 1244.9 530.339C1244.97 532.553 1244.56 538.542 1245.47 539.788C1246.88 540.682 1252.36 540.285 1254.31 540.131C1254.39 536.944 1254.42 533.756 1254.39 530.568C1256.65 530.523 1261.71 530.202 1263.66 530.898C1264.83 532.344 1263.97 553.657 1264.15 557.292C1264.34 561.515 1255.07 557.097 1254.56 560.218C1254.33 561.641 1254.18 567.922 1254.68 568.893C1255.64 569.456 1262.13 569.149 1264.03 569.312C1264.26 571.5 1264.11 586.755 1263.38 588.027C1260.82 589.354 1248.94 587.633 1245.61 588.614C1244.54 588.929 1244.91 596.722 1244.96 597.809C1242.85 597.819 1237.4 597.54 1235.69 598.034C1234.62 599.438 1235.61 604.833 1235.14 606.586C1234.46 609.066 1228.37 606.607 1225.88 608.01C1225.17 609.171 1225.35 616.566 1225.33 618.519C1224.03 618.48 1220.63 618.818 1219.75 618.266C1219.66 617.959 1219.47 617.186 1219.25 617.144C1216.59 616.627 1209.22 616.977 1206.69 616.854C1206.52 610.686 1206.68 604.066 1206.63 597.826C1203.42 597.793 1200.28 597.75 1197.07 597.853C1196.83 600.537 1197.05 604.487 1196.9 607.491C1193.74 607.7 1190.63 607.441 1187.5 607.705C1187.57 604.431 1187.59 601.157 1187.59 597.883C1184.71 597.719 1181.03 597.825 1178.09 597.84C1178.12 594.761 1178.1 591.682 1178.06 588.603C1186.94 588.794 1197.75 588.771 1206.62 588.553C1206.69 585.219 1206.7 581.885 1206.64 578.552C1203.9 578.372 1200.16 578.517 1197.21 578.422C1197.14 576.244 1197.6 570.767 1196.71 569.402C1195.4 568.459 1189.77 569.016 1187.57 569.051L1187.6 568.767C1189.13 553.585 1185.49 561.29 1178.69 558.582C1177.4 558.067 1178.1 551.97 1178.12 550.868C1178.11 550.48 1178.14 550.198 1178.42 550.037C1180.78 548.685 1196.36 550.992 1197.06 548.71C1197.8 546.317 1196.24 532.41 1197.81 530.622C1199.59 530.08 1204.69 530.211 1206.63 530.4C1206.79 539.604 1206.24 550.712 1206.69 559.566C1208.31 559.576 1214.22 559.225 1215.2 559.958C1216.53 562.537 1215.71 574.682 1215.89 578.481C1219.87 578.543 1223.86 578.554 1227.84 578.516C1229.75 578.51 1233.17 578.61 1234.89 578.329C1236.9 575.925 1233.51 569.97 1236.97 569.645C1238.81 569.471 1242.9 570.159 1244.68 569.311C1245.41 567.362 1245.42 551.987 1244.7 550.171C1241.42 548.631 1226.54 551.421 1225.38 548.798C1224.65 547.167 1226.39 542.998 1224.61 542.028C1222.78 541.036 1217.59 542.998 1216.48 540.903C1215.62 539.272 1216.1 524.28 1216.11 521.292ZM1225.16 597.935C1225.55 596.22 1225.88 589.983 1225.15 588.655C1223.65 588.167 1218.06 588.342 1216.24 588.351C1215.87 589.74 1215.65 596.637 1216.12 597.703C1217.51 598.201 1223.47 598.05 1225.16 597.935Z" fill="#9E2184"/> -<path d="M1159.42 750.404C1161.5 750.409 1166.78 750.017 1168.11 750.982C1169.06 752.446 1168.55 757.456 1168.6 759.653L1179.87 759.639C1181.92 759.639 1185.66 759.544 1187.54 759.908C1187.55 762.729 1187.63 765.951 1187.41 768.733C1181.79 769.067 1174.42 768.881 1168.66 768.869L1168.61 788.473L1177.98 788.408C1178.01 791.6 1178.04 794.329 1177.83 797.507C1174.79 797.385 1171.61 797.47 1168.64 797.293C1168.52 803.474 1168.34 810.881 1168.53 816.996L1179.68 816.975C1182.12 816.979 1185.12 817.065 1187.51 816.899C1187.73 814.089 1187.59 810.245 1187.56 807.339C1196.7 807.3 1206.91 807.06 1215.97 807.35C1216.04 810.356 1215.92 813.55 1215.85 816.571C1209.61 816.661 1203.38 816.565 1197.15 816.615C1196.89 819.226 1196.98 823.223 1196.98 825.963C1192.77 825.633 1182.62 825.889 1178.08 825.995C1178.04 829.381 1178.03 832.767 1178.07 836.152L1187.52 836.173C1187.55 839.3 1187.53 842.43 1187.48 845.558C1185.37 845.253 1180.4 845.389 1178.09 845.419C1177.84 848.005 1178.02 852.285 1178.06 855.018C1181.21 855.078 1184.37 855.08 1187.52 855.027C1187.62 851.888 1187.59 848.759 1187.57 845.62C1190.67 845.615 1193.92 845.664 1196.99 845.599C1196.99 848.332 1196.88 852.343 1197.17 854.998C1200.33 855.104 1203.49 855.06 1206.65 855.037C1206.65 857.869 1206.74 861.499 1206.55 864.255C1208.81 864.511 1213.5 864.454 1215.91 864.396C1215.92 867.187 1216.01 870.506 1215.92 873.253C1210.4 873.324 1202.61 873.566 1197.23 873.251C1197.2 870.248 1197.19 867.245 1197.23 864.239C1192.61 864.219 1189.66 864.338 1185.09 865.009C1181.98 865.465 1178.3 865.223 1175.08 866.035C1173.62 866.242 1171.21 866.083 1169.68 866.042C1169.95 858.565 1168.83 851.379 1168.4 843.983C1168.07 838.325 1168.63 831.709 1168.31 825.917C1163.1 825.82 1154.84 825.719 1149.74 825.993C1149.77 823.043 1149.85 819.614 1149.68 816.673C1147.17 816.601 1143.25 816.595 1140.75 816.756C1140.75 813.661 1140.79 810.411 1140.71 807.33C1146.27 807.33 1153.74 807.565 1159.15 807.304C1159.17 803.027 1159.47 801.619 1160.06 797.466C1160.27 795.979 1160.15 790.443 1160.14 788.62L1149.73 788.669C1149.71 791.704 1149.75 794.615 1149.46 797.636C1146.96 797.636 1142.9 797.509 1140.53 797.671C1140.49 800.865 1140.48 804.059 1140.51 807.254C1137.57 806.956 1133.86 807.237 1130.73 807.076C1131.23 800.519 1130.73 794.573 1131.15 788.77C1137.24 788.491 1143.8 789.003 1149.68 788.724C1149.65 785.26 1149.46 780.289 1149.7 776.945C1151.46 776.892 1158.14 776.873 1159.25 776.26C1159.6 774.573 1159.56 767.279 1159.52 765.142C1159.43 760.662 1159.75 754.764 1159.42 750.404Z" fill="#9E2184"/> -<path d="M1216.1 702.28C1222.51 702.247 1228.92 702.388 1235.32 702.702C1235.35 705.958 1235.36 709.215 1235.34 712.471C1232.87 712.059 1228.17 711.953 1225.55 712.171C1225.5 715.087 1225.36 719.106 1225.57 722.001C1228.73 722.003 1232.11 722.04 1235.27 721.84L1235.24 731.091C1231.97 731.045 1228.83 731.008 1225.55 731.095C1225.53 732.96 1225.31 739.226 1225.48 740.747C1222.96 740.69 1218.37 740.6 1215.92 740.793L1215.89 759.408C1211.34 759.425 1201.33 759.703 1197.23 759.319C1197.18 757.265 1196.69 752.287 1197.78 750.89C1199.13 750.028 1204.67 750.494 1206.85 750.427C1207.04 744.852 1206.99 739.272 1207.08 733.697C1207.12 731.243 1205.98 723.974 1207.49 722.268C1209.91 721.217 1214.08 723.554 1216 721.459C1216.24 720.736 1216.2 720.298 1216.2 719.544L1216.1 702.28Z" fill="#9E2184"/> -<path d="M1130.88 711.713C1134.04 711.664 1137.26 711.685 1140.42 711.674L1140.56 721.95C1143 722.1 1146.91 722.029 1149.35 721.918C1149.11 727.38 1149.74 734.9 1149.81 740.775C1151.87 740.83 1157.05 740.487 1158.57 741.015C1160 742.361 1159.08 747.871 1159.34 750.187C1156.48 750.197 1142.46 749.932 1140.7 750.653C1140.47 751.752 1141.09 757.189 1141.16 758.908C1143.69 759.282 1147.51 758.726 1149.72 759.445C1149.76 762.589 1149.75 765.732 1149.69 768.876C1143.62 768.876 1137.12 769.035 1131.09 768.835L1131.11 740.934C1134.08 740.641 1137.52 740.927 1140.66 740.796C1140.84 737.924 1140.72 734.006 1140.71 731.049C1137.5 731.042 1134.31 731.056 1131.11 730.913C1131.04 727.673 1131.09 724.363 1131.03 721.114C1130.98 718.675 1130.03 713.812 1130.88 711.713Z" fill="#9E2184"/> -<path d="M1225.54 645.751C1228.63 645.839 1232.06 645.737 1235.23 645.78C1235.4 648.452 1235.27 652.658 1235.29 655.458C1238.49 655.535 1241.66 655.446 1244.92 655.555C1244.96 658.517 1244.96 661.48 1244.91 664.442C1241.7 664.538 1238.49 664.513 1235.28 664.367C1235.13 667.142 1235.24 670.891 1235.25 673.741C1232.26 673.549 1228.35 673.583 1225.54 673.213C1225.53 675.859 1225.5 690.908 1224.99 692.563C1223.87 693.356 1217.67 693.094 1215.89 693.09C1215.88 695.566 1215.75 699.858 1216.03 702.178C1214.26 702.251 1207.65 702.012 1206.7 702.54C1206.68 705.866 1206.58 709.187 1206.41 712.506C1203.82 712.755 1199.86 712.639 1197.25 712.561C1197.11 706.223 1197.22 699.594 1197.24 693.232C1202.93 693.344 1209.86 693.336 1215.5 693.199C1215.78 689.615 1216.08 686.238 1216.62 682.646C1216.91 680.713 1215.42 673.52 1216.42 672.109C1217.66 671.41 1223.92 671.783 1225.48 672.08C1225.83 663.967 1225.47 654.105 1225.54 645.751Z" fill="#9E2184"/> -<path d="M1225.55 483.12C1235.49 482.969 1245.73 483.085 1255.7 483.097C1255.76 486.336 1255.81 490.025 1255.55 493.231C1246.27 493.037 1234.38 493.588 1225.41 492.967C1225.26 498.953 1225.48 504.96 1225.26 511.019C1222.8 511.307 1219.51 511.212 1216.97 511.21C1216.74 511.22 1216.49 511.313 1216.25 511.377C1215.63 512.624 1215.88 519.441 1216.03 521.101C1210.14 521.122 1203.02 521.318 1197.24 521.039C1197.13 519.381 1196.83 513.038 1197.57 511.81C1199.66 511.014 1212.64 511.423 1216.08 511.29C1216.25 505.153 1215.98 498.849 1216.23 492.711C1219.23 492.654 1222.37 492.737 1225.38 492.779C1225.39 489.82 1225.27 485.97 1225.55 483.12Z" fill="#9E2184"/> -<path d="M1142.08 492.391L1158.11 492.333C1160.13 492.323 1165.29 492.167 1167.08 492.561C1168.26 493.707 1168.38 509.439 1167.71 510.678C1167.06 511.129 1166.44 511.029 1165.63 511.043C1157.55 511.146 1147.76 511.428 1139.8 511.078C1139.92 505.367 1139.44 498.515 1139.4 492.511L1142.08 492.391Z" fill="#9E2184"/> -<path d="M1149.55 521.324C1158.9 521.117 1168.34 521.389 1177.7 521.282C1180.95 521.245 1184.27 521.255 1187.52 521.366C1187.54 523.498 1187.97 528.431 1186.96 529.895C1185.64 530.799 1179.49 530.351 1177.29 530.356C1175.18 530.393 1170.55 530.045 1168.95 530.646C1167.66 531.961 1168.21 537.402 1168.09 539.911C1163.83 540.24 1153.68 540.135 1149.31 539.97C1149.17 537.35 1148.86 522.982 1149.55 521.324Z" fill="#9E2184"/> -<path d="M1206.88 626.733C1209.52 626.587 1213.16 626.688 1215.88 626.685L1215.92 636.059C1218.79 636.124 1222.47 635.923 1225.37 635.828C1225.34 639.03 1225.35 642.232 1225.4 645.434C1222.53 645.336 1218.8 645.362 1215.93 645.456C1215.67 650.57 1216.32 659.74 1215.6 664.346C1214.11 664.75 1208.44 664.642 1206.66 664.638C1206.55 658.27 1206.78 651.855 1206.59 645.485C1203.82 645.247 1200.25 645.342 1197.4 645.346C1197.54 642.419 1197.62 639.585 1197.48 636.656C1198.78 636.622 1201.15 636.461 1202.39 636.696C1209.42 638.026 1205.54 630.888 1206.88 626.733Z" fill="#9E2184"/> -<path d="M1168.41 569.261C1172.5 569.136 1176.64 569.276 1180.73 569.242C1182.85 569.224 1185.5 569.35 1187.57 569.051C1187.54 571.539 1187.6 576.093 1187.35 578.451C1185.19 578.528 1179.72 578.277 1178.43 579.209C1177.6 580.484 1177.95 586.776 1178.06 588.603C1176.26 588.238 1161.5 588.388 1159.26 588.556C1159.27 586.397 1158.97 580.896 1159.58 579.194C1160.07 577.79 1165.66 579.301 1167.92 578.357C1168.76 577.211 1168.4 571.278 1168.41 569.261Z" fill="#9E2184"/> -<path d="M1140.7 549.664C1143.22 549.657 1157.93 549.232 1159.05 550.209C1159.58 552.3 1159.23 556.627 1159.13 558.935C1156.64 559.049 1152.47 558.68 1150.34 559.281C1148.66 561.394 1151.1 567.924 1148.87 568.641C1142.92 568.839 1137.04 568.683 1131.09 568.515C1131.1 558.243 1128.71 556.907 1140.36 558.945C1140.49 556.445 1139.99 551.624 1140.7 549.664Z" fill="#9E2184"/> -<path d="M1177.16 482.121C1180.6 482.496 1184.29 482.935 1187.73 483.15C1187.6 486.687 1187.83 510.64 1187.25 511.476C1184.62 511.809 1179.8 512.395 1177.36 512.564C1177.41 502.585 1177.2 492.136 1177.16 482.121Z" fill="#9E2184"/> -<path d="M1178.09 597.84C1178 601.054 1178.05 604.388 1177.97 607.655C1171.93 607.42 1165.6 607.774 1159.36 607.52C1159.13 605.081 1159.29 600.56 1159.28 597.914C1165.14 597.786 1172.45 598.17 1178.09 597.84Z" fill="#9E2184"/> -<path d="M1178.98 740.849C1181.63 740.724 1184.77 740.793 1187.47 740.796C1187.48 742.409 1187.82 749.422 1186.83 750.194C1183.92 750.27 1181.01 750.247 1178.1 750.13C1178 747.88 1177.84 743.605 1178.22 741.337C1178.27 741.012 1178.56 741.012 1178.98 740.849Z" fill="#9E2184"/> -<path d="M1178.09 607.751L1187.49 607.735C1187.29 609.758 1187.37 614.387 1187.32 616.67C1185.68 617.15 1180.01 616.97 1178.09 616.956C1178.15 613.935 1178.1 610.783 1178.09 607.751Z" fill="#9E2184"/> -<path d="M1131.08 597.61L1142.09 597.891C1144.14 597.956 1147.91 598.171 1149.8 597.883C1149.74 604.113 1149.73 610.343 1149.76 616.573C1149.76 619.261 1149.61 624.234 1149.81 626.713C1153.16 626.909 1156.82 626.741 1160.2 626.75C1162.74 626.756 1165.86 626.893 1168.33 626.593C1168.38 623.46 1168.4 620.327 1168.39 617.194C1171.62 617.151 1174.85 617.16 1178.08 617.22C1177.81 619.089 1178.04 624.573 1178.08 626.733C1184.08 626.883 1191.26 626.44 1197.06 626.876C1197.14 629.74 1196.93 633.947 1197.14 636.522C1196.01 636.445 1194.47 636.319 1193.33 636.43C1188.31 636.92 1183.36 636.89 1178.31 636.923C1178.25 639.716 1178.09 642.978 1178.12 645.734C1182.11 645.798 1186.1 645.815 1190.1 645.786C1191.85 645.78 1195.43 645.833 1197.02 645.617C1197.01 651.783 1196.84 658.761 1197.03 664.859L1206.55 664.893C1206.53 667.74 1206.57 671.059 1206.39 673.873C1203 673.964 1190.01 673.608 1187.93 674.347C1187.19 675.359 1187.52 682.236 1187.54 684.008L1196.99 684.049C1197.02 687.035 1197.03 690.022 1197.01 693.008C1191.42 692.946 1183.31 692.722 1177.89 693.04L1177.87 702.637C1180.85 702.646 1184.61 702.552 1187.52 702.704C1187.55 704.799 1188 709.864 1186.92 711.277C1185.58 712.146 1180.23 711.717 1178.09 711.805C1178.01 715.087 1177.82 719.132 1177.96 722.349C1181.92 722.379 1185.88 722.42 1189.84 722.513C1191.81 722.559 1194.44 722.31 1196.32 722.63C1197.42 723.942 1197.25 738.83 1196.58 740.468C1195.06 740.989 1189.52 740.685 1187.54 740.743C1187.59 737.592 1187.71 734.195 1187.52 731.068C1183.65 731.024 1161.72 731.393 1159.83 730.602C1157.94 728.394 1160.77 721.478 1158.07 721.457C1155.55 721.436 1152.37 721.644 1149.7 721.598L1149.71 711.768C1152.52 711.872 1155.51 711.745 1158.25 711.957C1158.25 708.751 1158.3 705.4 1158.23 702.208C1155.28 702.259 1152.22 702.272 1149.28 702.381C1149.29 704.979 1149.17 708.98 1149.35 711.464C1146.46 711.473 1143.58 711.466 1140.69 711.446C1140.8 705.451 1140.68 699.487 1140.74 693.511C1143.45 693.814 1146.27 693.442 1149.06 693.672C1149.04 690.914 1149.11 687.515 1148.81 684.844L1148.77 684.448L1148.74 684.21C1146.05 684.367 1143.44 684.28 1140.75 684.228C1140.51 687.057 1140.56 690.353 1140.53 693.23C1133.69 693.168 1126.84 693.156 1120 693.196V684.042L1140.84 684.041C1141.14 680.705 1141.21 678.299 1141.23 674.965C1138.09 674.707 1133.81 674.821 1130.57 674.826C1130.94 668.026 1131.41 662.031 1131.13 655.126C1130.99 651.863 1130.6 648.546 1130.62 645.362L1140.47 645.319C1140.4 648.708 1140.37 652.098 1140.39 655.487L1151.46 655.496C1153.47 655.502 1156.45 655.632 1158.36 655.363C1159.55 654.315 1159.04 652.491 1159.4 651.054C1159.8 649.496 1160.62 646.471 1159.67 645.002C1156.33 645.634 1144.75 645.362 1140.74 645.345C1140.88 642.82 1140.78 639.571 1140.76 636.986C1137.58 637.133 1134.26 637.059 1131.06 637.034L1131.09 626.682L1140.45 626.68C1140.67 620.867 1140.59 613.44 1140.49 607.611L1131.07 607.541L1131.08 597.61ZM1168.18 683.984C1164.93 684 1161.27 683.934 1158.06 684.054C1157.83 686.55 1157.53 700.019 1158.2 701.807C1159.73 702.418 1165.24 702.094 1167.39 702.195C1167.83 701.981 1168.1 701.975 1168.14 701.601C1168.63 696.592 1168.32 688.97 1168.34 684.04C1171.26 684.027 1175.13 684.125 1177.98 683.96C1178.11 680.58 1178.04 677.247 1178 673.865L1168.44 673.854C1167.95 675.672 1168.15 681.852 1168.18 683.984ZM1149.94 664.472C1149.49 665.905 1149.34 672.357 1149.73 673.698C1150.54 674.361 1157.43 674.084 1158.96 674.07C1159.67 672.663 1159.25 666.338 1159.22 664.404L1149.94 664.472ZM1187.53 655.252C1184.39 655.185 1181.25 655.165 1178.12 655.192C1177.59 657.063 1177.83 662.761 1177.88 664.933C1180.99 664.914 1184.3 664.955 1187.39 664.863C1187.69 662.446 1187.56 657.828 1187.53 655.252ZM1160.69 646.465C1163.5 646.325 1166.06 646.307 1168.87 646.307C1168.9 642.552 1168.84 638.538 1168.96 634.816C1166.72 634.707 1161.99 635.119 1160.58 633.916C1160.6 637.316 1160.41 643.327 1160.69 646.465Z" fill="#9E2184"/> -<path d="M1149.95 588.659C1153.02 588.664 1156.1 588.646 1159.18 588.606L1159.2 597.825C1156.09 597.805 1152.9 597.738 1149.8 597.883C1150.03 594.74 1149.74 591.677 1149.95 588.659Z" fill="#9E2184"/> -<path d="M889.562 -183.925C886 -184.108 872.967 -183.6 870.449 -184.262C869.914 -185.216 869.944 -191.393 870.385 -192.6C871.639 -193.225 895.529 -192.958 898.847 -192.967C898.565 -190.646 898.643 -186.147 898.765 -183.78C901.73 -183.644 905.472 -183.732 908.511 -183.707C908.549 -180.586 908.513 -177.396 908.511 -174.271C905.296 -174.303 902.081 -174.299 898.866 -174.257C898.728 -172.105 898.184 -166.52 899.217 -165.013C900.617 -164.015 906.311 -164.543 908.51 -164.58C908.772 -167.525 908.619 -171.201 908.57 -174.227L932.946 -174.234C936.784 -174.234 942.834 -174.393 946.454 -174.008C946.594 -171.222 946.421 -167.352 946.36 -164.522C948.397 -164.587 954.486 -164.237 955.86 -164.799C956.482 -166.776 956.243 -180.724 956.236 -183.766C960.654 -183.919 971.126 -183.384 974.876 -183.895C974.883 -180.934 974.984 -177.189 974.717 -174.31C971.758 -174.186 968.232 -174.257 965.24 -174.255C965.074 -171.086 965.166 -167.737 965.208 -164.557C968.441 -164.52 981.815 -165.041 983.797 -163.953C984.846 -161.911 984.141 -158.032 984.613 -155.529C975.59 -155.887 965.975 -155.573 956.932 -155.442C954.929 -155.412 956.826 -148.23 955.6 -146.43C954.044 -145.787 948.308 -146.101 946.348 -146.135L946.352 -136.686C948.559 -136.493 952.152 -136.61 954.45 -136.615C957.946 -136.622 961.871 -136.566 965.335 -136.769C965.413 -133.886 965.15 -129.233 965.431 -126.702C959.81 -126.368 952.262 -126.573 946.504 -126.585C946.317 -123.639 946.389 -120.298 946.393 -117.313C948.75 -117.094 953.468 -117.276 955.978 -117.313C956.07 -114.209 956.065 -111.102 955.964 -107.995C953.304 -107.769 949.372 -107.928 946.453 -107.809C946.221 -105.202 946.33 -100.749 946.317 -98.009C951.974 -98.0251 959.916 -98.281 965.388 -97.9399C965.664 -88.5598 966.681 -88.8916 956.904 -89.3895C956.591 -88.4998 955.051 -82.0444 955.097 -81.3461C955.295 -78.3155 963.408 -80.6478 965.03 -79.3894C965.759 -77.7485 965.312 -71.807 965.429 -69.3664L974.883 -69.3871C975.27 -64.1324 974.652 -56.2135 974.689 -50.4633C977.863 -50.438 981.138 -50.5025 984.323 -50.5232C984.68 -53.2566 984.53 -59.9079 984.503 -62.8625C984.45 -68.2947 984.632 -74.1716 984.452 -79.5577C981.405 -79.613 978.199 -79.5231 975.102 -79.5577C975.019 -88.9332 975.014 -98.3063 975.088 -107.682C978.234 -107.739 981.382 -107.739 984.53 -107.679C984.712 -103.386 984.182 -100.162 983.585 -96.0224C983.383 -94.6303 983.472 -90.4819 983.477 -88.9124C990.145 -88.6981 996.766 -89.265 1003.58 -88.5759C1003.77 -91.6066 1003.7 -94.9369 1003.69 -97.9998C1009.7 -98.1865 1016.19 -98.0758 1022.2 -98.032C1022.29 -88.4906 1022.29 -78.9469 1022.19 -69.4032C1031.29 -69.175 1041.31 -69.3963 1050.49 -69.3802C1050.76 -65.7918 1050.61 -54.1623 1050.41 -50.7468C1047.31 -50.514 1044.18 -50.5509 1041.07 -50.5854C1041.21 -53.6368 1041.2 -57.0777 1041.14 -60.1315C1038.49 -60.3135 1034.54 -60.2398 1031.85 -60.1983C1031.72 -57.1262 1031.63 -53.57 1031.8 -50.5255C1028.94 -50.7399 1025.42 -50.4979 1022.33 -50.65C1022.38 -53.8281 1022.38 -57.004 1022.35 -60.1822C1019.93 -60.4311 1015.31 -60.2144 1012.71 -60.1591C1012.63 -56.9141 1012.76 -53.7913 1012.41 -50.5578C1009.26 -50.5393 1006.41 -50.0784 1003.28 -49.629C1003.21 -52.5444 1003.58 -55.1556 1003.65 -58.0065C1003.74 -61.6433 1003.69 -65.4023 1003.68 -69.0483C1006.18 -69.2673 1010.35 -69.1543 1012.97 -69.152C1013.22 -73.0078 1012.8 -76.0799 1012.55 -79.9149C1008.99 -79.9356 1006.88 -79.8596 1003.32 -80.3413C1001 -80.1362 995.706 -81.2654 993.959 -80.2882C993.154 -77.9398 993.364 -51.3806 994.413 -50.1153C996.455 -49.2902 1000.97 -49.5322 1003.28 -49.629C1003.26 -47.1745 1003.16 -44.1231 1003.25 -41.7239C998.098 -41.7331 988.84 -41.9913 984.051 -41.5418C983.917 -38.3199 983.917 -35.2731 983.926 -32.0465C987.116 -32.065 990.389 -32.1226 993.567 -31.9982C993.735 -27.8336 993.32 -23.7912 993.36 -19.6381C993.433 -11.71 993.175 -3.7957 992.933 4.12552C992.818 7.92595 992.977 11.8393 992.864 15.6582L984.367 15.6282C983.758 7.08705 984.865 -3.73344 984.549 -12.7102C981.997 -12.701 977.354 -12.8301 974.966 -12.6272C974.874 -9.74408 975.026 -5.46428 974.673 -2.81389L965.189 -2.80005C965.097 -6.12111 965.217 -9.56891 965.104 -12.7909C962.484 -12.7678 948.183 -12.9384 946.773 -12.3622C946.036 -10.7489 946.357 -5.38361 946.311 -3.26561C943.521 -3.51451 939.946 -3.44539 937.15 -3.27945L937.069 9.2189C937.061 10.7262 936.948 14.25 937.087 15.6328C930.823 15.4715 924.505 15.7481 918.219 15.566C918.151 13.4503 917.638 8.66576 918.694 7.1631C920.07 6.18591 925.584 6.61458 927.795 6.60767C928.047 0.530212 927.882 -6.55208 927.877 -12.7033C924.714 -12.7494 921.394 -12.6871 918.219 -12.6756C918.433 -15.727 918.411 -19.1034 918.448 -22.1894C912.264 -22.1848 905.005 -21.9981 898.92 -22.3162C898.669 -19.463 898.69 -15.356 898.723 -12.4728L918.163 -12.5005C918.156 -9.45367 918.091 -6.40918 917.97 -3.36699C916.05 -3.34856 910.694 -3.67584 909.283 -3.12964C908.02 -1.81827 908.582 3.73141 908.35 6.40486C905.257 6.43481 902.164 6.43713 899.072 6.4164C899.011 3.23822 899.058 -0.0252075 899.013 -3.23103C896.805 -3.55138 891.781 -3.34859 889.446 -3.27483C889.633 -6.18565 889.584 -9.81783 889.524 -12.7355C884.831 -12.8139 880.101 -12.6595 875.403 -12.7309C873.827 -12.754 872.201 -12.7794 870.639 -12.5742C869.95 -11.3228 870.298 -5.00102 870.171 -2.85767C868.645 -2.79083 864.819 -2.54886 863.504 -2.84155C859.591 -3.71272 857.377 -4.08607 853.376 -4.04459C852.644 -3.37624 852.277 -2.89687 851.645 -2.12248C851.563 -0.0897522 851.029 4.59569 851.913 6.04073C853.077 6.95338 858.947 6.60307 861.035 6.70448C861.262 8.99533 861.323 22.8304 860.65 24.5174C859.03 25.1835 826.72 24.8447 822.49 24.8124C822.729 19.1913 822.562 12.397 822.566 6.69063C825.816 6.5224 829.073 6.51781 832.324 6.68144C832.515 9.52312 832.352 13.0101 832.499 16.0684C835.318 16.179 839.07 16.1675 841.869 16.05C842.131 13.0401 841.984 8.80174 841.973 5.66968C841.934 -0.377823 841.934 -6.42763 841.972 -12.4751C843.914 -12.4636 849.181 -12.2931 850.692 -12.5904C852.634 -12.9729 850.683 -19.7418 851.776 -21.7492C853.394 -22.4567 858.841 -22.1226 861.085 -22.1341C861.31 -24.5724 861.745 -29.9262 861.729 -32.0926C865.641 -32.0327 865.967 -30.7052 870.498 -30.5785C873.614 -32.201 876.24 -31.846 879.744 -31.8553C879.804 -28.6333 879.753 -25.4183 879.822 -22.1871C882.534 -21.9843 886.554 -22.0695 889.367 -22.0511C889.639 -25.1163 889.537 -29.2556 889.516 -32.3439L879.967 -32.2793C879.788 -38.2623 879.999 -44.3536 879.742 -50.3135L870.521 -50.2951C870.446 -53.3442 870.491 -56.5753 870.485 -59.6383C867.338 -59.8157 864.585 -59.4677 861.133 -59.7765C860.92 -50.9035 861.079 -41.3506 861.085 -32.4153C858.603 -32.4199 857.902 -32.4568 855.599 -31.5764C852.599 -32.625 847.294 -32.4222 844.227 -32.0396C843.723 -31.9774 842.985 -32.1917 842.703 -32.6043C841.595 -34.2222 841.927 -39.5229 841.93 -41.5764C839.412 -41.7377 834.937 -41.7769 832.447 -41.5787C832.502 -44.8422 832.513 -48.1056 832.481 -51.3667C829.564 -51.346 825.355 -51.1916 822.539 -51.3667L822.555 -59.9217L832.261 -60.0024C832.257 -57.2345 832.197 -54.2822 832.25 -51.5304C838.456 -51.6664 845.365 -51.4221 851.368 -51.671C851.401 -54.432 851.449 -57.1538 851.368 -59.9171C845.025 -59.9702 838.756 -60.3136 832.437 -60.2052C832.462 -63.1898 832.56 -66.6192 832.43 -69.5623L813.12 -69.6199L813.301 -78.3754C817.86 -78.3615 821.88 -78.3615 826.444 -78.7994C828.183 -78.9654 830.572 -78.7603 832.401 -78.9262C832.737 -88.5114 832.464 -99.3065 832.511 -109.014C829.639 -108.802 825.283 -108.756 822.42 -108.977L822.551 -117.145C825.381 -117.428 829.056 -117.338 831.962 -117.297C832.098 -120.261 832.124 -123.225 832.04 -126.188C828.863 -126.112 825.685 -126.094 822.508 -126.128C822.537 -132.6 822.305 -140.012 822.567 -146.352C825.427 -146.421 829.575 -146.592 832.295 -146.066L832.208 -126.37C834.21 -126.354 840.229 -126.11 841.664 -126.758C842.616 -128.551 841.001 -136.048 842.604 -136.198C848.284 -136.73 854.648 -136.518 860.365 -136.334C861.543 -136.294 860.899 -127.527 860.922 -126.368C859.507 -126.477 857.928 -126.463 856.508 -126.407C851.684 -126.223 846.745 -126.583 841.938 -126.465C841.851 -119.302 841.847 -112.137 841.928 -104.971C841.959 -103.052 841.871 -99.7974 842.016 -98.0067L859.912 -97.9491C859.913 -100.715 859.782 -104.819 859.947 -107.477C862.76 -107.804 867.44 -107.668 870.397 -107.636C870.403 -104.43 870.365 -101.224 870.283 -98.0182C876.098 -98.009 883.742 -98.2441 889.371 -97.9583C889.438 -94.6879 889.783 -82.1113 888.992 -79.7951C888.211 -79.0599 884.846 -78.917 883.626 -78.6381C882.409 -78.3592 881.165 -77.8776 879.965 -77.7116C879.946 -75.0105 879.995 -72.2956 879.668 -69.6153C876.885 -69.6037 873.137 -69.6959 870.434 -69.5323C870.502 -72.7727 870.523 -76.0154 870.496 -79.2581C880.69 -79.4056 880.407 -77.5641 879.832 -88.622C879.824 -88.7879 879.813 -88.9516 879.798 -89.1175C876.977 -89.0945 873.267 -88.9815 870.498 -89.1313C870.498 -91.6665 870.589 -95.2641 870.366 -97.6817C867.131 -97.6979 863.913 -97.5711 860.68 -97.5434L860.597 -89.1867C854.447 -89.1267 848.079 -89.0276 841.936 -89.1452C841.929 -85.9831 841.823 -82.2104 841.949 -79.0991C846.897 -78.7349 855.537 -79.076 860.87 -79.0668C860.88 -76.5178 860.766 -71.7563 860.986 -69.3341C863.696 -69.2396 867.545 -69.2995 870.311 -69.3894L870.299 -60.0024C877.39 -59.8503 884.506 -60.0324 891.599 -59.9655C893.556 -59.9471 896.841 -60.1476 898.626 -59.5783C899.074 -58.154 898.909 -53.3764 898.756 -51.7862C898.577 -49.9217 891.18 -50.65 889.564 -50.4725C889.216 -45.204 889.448 -37.9972 889.401 -32.5305C892.211 -32.6411 895.023 -32.7103 897.835 -32.7379C898.427 -32.3185 899.176 -31.7492 899.774 -31.3759C901.82 -31.3874 907.913 -30.6937 909.209 -31.1293C912.665 -32.2908 914.903 -31.5395 918.191 -32.0258C918.037 -28.3867 918.096 -25.5658 918.885 -22.005C921.347 -21.9866 925.489 -21.8529 927.829 -22.1064C928.085 -24.4042 927.897 -29.6727 927.854 -32.0558C924.896 -32.1987 921.172 -32.0742 918.191 -32.0258C918.047 -41.3114 918.455 -50.9427 918.195 -60.1684C915.297 -60.3181 911.612 -60.2329 908.656 -60.2467C908.472 -62.8118 908.577 -66.6998 908.573 -69.3686C914.928 -69.4032 921.283 -69.4032 927.637 -69.3709C927.823 -66.8335 927.697 -62.6851 927.731 -59.9655C933.905 -59.9171 940.08 -59.9218 946.254 -59.9748C946.457 -63.365 946.729 -75.937 946.124 -78.9285C943.424 -79.212 940.446 -78.6888 937.7 -78.8801C931.168 -79.3295 924.759 -79.4332 918.226 -79.5761C917.975 -84.976 918.201 -92.5607 918.201 -98.1404C922.906 -97.8615 927.687 -98.281 932.393 -97.873C933.817 -97.7509 935.159 -97.6725 936.59 -97.7186C936.651 -95.6098 936.01 -90.1915 937.227 -88.7695C938.165 -87.6725 944.906 -87.843 945.962 -88.3961C946.618 -88.7395 946.445 -97.0157 946.446 -97.9721C944.394 -98.1196 938.671 -98.2326 936.749 -98.0205C936.801 -101.987 936.761 -105.419 937.356 -109.341C937.604 -110.975 937.673 -115.638 937.196 -117.175C936.09 -117.719 928.983 -117.668 928.149 -117.401C927.5 -116.147 927.671 -109.811 927.631 -107.903C924.663 -107.903 921.114 -107.981 918.204 -107.76C918.144 -105.084 917.937 -100.828 918.118 -98.2833C914.938 -98.4123 911.842 -98.2786 908.581 -98.4469C908.487 -101.487 908.533 -104.806 908.514 -107.871C905.488 -107.97 902.124 -107.924 899.075 -107.947C899.036 -110.987 899.069 -114.093 899.069 -117.14C902.06 -117.214 916.061 -116.838 917.82 -117.546C918.51 -119.148 918.215 -124.672 918.189 -126.677C914.87 -126.728 911.936 -126.606 908.548 -126.781C908.366 -129.498 908.402 -133.656 908.49 -136.38C910.408 -136.546 912.871 -136.375 914.855 -136.483C919.171 -136.719 923.354 -136.765 927.677 -136.725C927.69 -133.547 927.653 -130.182 927.801 -127.025C930.999 -127.055 934.03 -127.226 937.317 -127.226C937.558 -132.96 937.365 -140.24 937.368 -146.069C940.169 -146.207 943.501 -146.156 946.326 -146.172C945.842 -149.164 946.096 -160.701 946.119 -164.359C941.82 -164.407 937.526 -164.213 933.223 -164.29C929.253 -164.359 922.227 -165.363 918.472 -164.527C917.74 -163.089 918.006 -157.484 918.018 -155.596C914.898 -155.603 911.743 -155.647 908.628 -155.527C908.421 -152.99 908.517 -148.758 908.498 -146.092C905.188 -146.025 902.391 -146.013 899.088 -146.156L899.05 -155.571C892.825 -155.817 886.274 -155.414 879.951 -155.617C879.864 -158.528 879.894 -161.632 879.873 -164.559C881.669 -164.552 888.388 -164.239 889.34 -164.962C889.841 -167.154 889.612 -180.929 889.562 -183.925ZM937.644 -22.6457C942.954 -22.6342 948.421 -22.5443 953.691 -23.1689C957.204 -23.5837 960.366 -23.5515 963.89 -23.5238L964.745 -23.6275C965.819 -25.0495 964.878 -39.7258 965.235 -42.5582C965.36 -43.5654 965.229 -49.0713 965.093 -50.083C964.622 -50.5878 963.101 -50.6546 962.375 -50.6569C954.014 -50.6892 945.6 -50.567 937.24 -50.6799C936.635 -49.0482 936.906 -46.8634 936.751 -45.1441C936.208 -39.1219 936.337 -33.3602 937.234 -27.3703C937.464 -25.8377 937.359 -24.2221 937.644 -22.6457ZM974.779 -22.0811C977.851 -22.0742 980.921 -22.088 983.993 -22.1272C984.235 -24.8951 984.072 -29.1196 984.021 -31.9958C981.02 -32.0742 978.02 -32.1042 975.021 -32.088C974.756 -29.7649 974.708 -24.5264 974.779 -22.0811Z" fill="#9E2184"/> -<path d="M1164.85 -79.4632C1167.61 -79.2535 1171.36 -79.4816 1174.47 -79.3088C1174.58 -76.1859 1174.49 -72.5606 1174.48 -69.4009L1183.4 -69.3894C1183.54 -67.0502 1183.56 -62.4731 1183.22 -60.2052L1174.5 -60.1891C1174.41 -57.0225 1174.47 -53.6599 1174.47 -50.4771C1176.21 -50.431 1181.9 -50.8113 1183.01 -50.1891C1183.87 -48.1748 1183.49 -35.0219 1183.17 -32.1134C1178.06 -31.8737 1170 -31.9152 1164.87 -32.1065C1164.8 -35.3146 1164.91 -38.4513 1164.79 -41.7032C1160.93 -41.9083 1149.1 -41.8691 1145.47 -41.5926C1145.39 -38.4236 1145.44 -35.0473 1145.44 -31.8645L1155.11 -31.8C1155.32 -25.5474 1155.14 -18.8061 1155.18 -12.489C1158.39 -12.4521 1161.6 -12.4659 1164.82 -12.5304L1164.83 -22.0903C1167.87 -22.2171 1171.35 -22.1387 1174.43 -22.1295C1174.48 -19.0135 1174.27 -15.9114 1174.38 -12.7402C1171.19 -12.6849 1168 -12.6641 1164.82 -12.678C1164.69 -9.78788 1164.8 -6.19028 1164.82 -3.2495C1163.07 -3.54681 1156.58 -3.71964 1155.19 -2.51659C1153.97 -1.46336 1149.04 -1.9243 1147.11 -1.97961C1146.87 0.825188 1146.85 3.81207 1146.87 6.63531C1152.91 6.64223 1158.79 6.40025 1164.8 6.39103C1164.62 8.03197 1164.52 14.1025 1164.82 15.5821C1162.66 15.2364 1158.97 15.3309 1156.76 15.3055C1153.36 15.2664 1156.37 22.2634 1154.61 24.6073C1153.09 25.1581 1147.76 24.8608 1145.9 24.817C1145.28 19.2673 1146.73 12.1089 1146.59 6.43019C1143.14 6.37488 1139.69 6.37719 1136.24 6.43941C1136.08 10.415 1136.59 21.2263 1135.91 24.5266C1135.03 25.2618 1128.52 24.9046 1126.98 24.8769C1127.11 16.0384 1126.96 6.99023 1126.91 -1.86668L1123.59 -1.91508C1121.3 -3.51683 1120.14 -3.24258 1117.32 -3.21723C1117.35 -6.38157 1117.34 -9.54358 1117.31 -12.7056C1114.71 -12.8301 1111.37 -12.754 1108.73 -12.7586L1107.77 -14.8513C1105.82 -14.5102 1100.85 -14.4226 1098.49 -14.2544C1098.24 -19.055 1099.42 -38.3038 1097.77 -41.3206C1095.82 -42.0927 1082.47 -41.6525 1079.04 -41.7654C1079.03 -44.6578 1079.06 -47.5479 1079.13 -50.438C1083.81 -50.7076 1093.66 -50.0323 1097.7 -50.6477C1098.52 -51.7862 1098.21 -58.1932 1098.19 -59.9494H1126.3C1126.41 -62.0951 1126.12 -67.3659 1126.79 -68.9884C1128.18 -69.5554 1143.94 -69.6683 1145.17 -68.9653C1145.95 -67.3728 1145.47 -53.4525 1145.5 -50.5025C1147.77 -50.3481 1150.94 -50.4518 1153.3 -50.4449C1157.04 -50.431 1161.05 -50.3066 1164.77 -50.4357C1164.91 -53.4802 1164.83 -57.0732 1164.83 -60.1614C1161.79 -60.2721 1158.41 -60.226 1155.35 -60.2444C1155.31 -63.2474 1155.3 -66.2504 1155.32 -69.2534C1157.74 -69.4862 1162.15 -69.3802 1164.75 -69.4194C1164.91 -72.4777 1164.83 -76.3426 1164.85 -79.4632ZM1136.27 -50.544C1130.7 -50.6869 1125.13 -50.7145 1119.56 -50.6293C1117.4 -50.6062 1108.98 -50.862 1107.68 -50.1729C1106.34 -47.4557 1108.07 -27.0431 1108.13 -22.1871L1124.14 -22.1433L1136.23 -22.1087C1136.38 -30.3549 1136.67 -42.3831 1136.27 -50.544ZM1126.79 -2.3299C1129.84 -2.38752 1132.88 -2.40598 1135.92 -2.38293C1136.47 -3.26102 1136.26 -11.014 1136.25 -12.7033C1133.48 -12.7102 1129.98 -12.6296 1127.3 -12.8808C1126.14 -11.5026 1126.66 -4.46404 1126.79 -2.3299ZM1107.87 -14.9458C1107.87 -15.8216 1107.98 -17.6307 1107.68 -18.3521L1107.3 -18.6333C1107.29 -17.5063 1107.19 -16.3447 1107.5 -15.28L1107.87 -14.9458Z" fill="#9E2184"/> -<path d="M1032.02 -50.3112L1040.85 -50.3089C1040.82 -44.0194 1041.25 -38.0872 1041.17 -31.8553C1037.17 -31.9198 1025.54 -32.4891 1022.29 -32.1365C1022 -26.4139 1022.18 -18.8315 1022.15 -12.9891C1024.79 -12.9868 1028.02 -13.0698 1030.61 -12.9614C1030.74 -9.73718 1030.94 -6.1972 1030.91 -2.99138C1037.46 -3.03056 1044.02 -3.02363 1050.58 -2.97062C1050.55 -6.11191 1050.58 -9.2532 1050.67 -12.3922C1053.71 -12.4752 1056.75 -12.5051 1059.78 -12.4821C1060.08 -10.4171 1059.95 -4.91809 1059.68 -2.88996C1056.62 -2.83696 1053.56 -2.83927 1050.5 -2.89688L1050.52 6.87961C1048.04 6.26656 1035.1 6.39794 1031.84 6.39794C1031.62 9.54153 1031.62 12.5007 1031.61 15.6512C1028.82 15.695 1026.04 15.6881 1023.25 15.6328C1023.32 12.3025 1023.35 9.88723 1023.07 6.53622C1022.8 3.30274 1022.32 0.062336 1022.34 -3.15501C1018.94 -2.98907 1015.74 -3.17806 1012.35 -3.27255C1009.32 -3.35552 1006.35 -3.22185 1003.33 -3.50533C1003.21 -9.67728 1003.36 -16.029 1003.43 -22.2148C1005.37 -22.2217 1011.15 -21.9382 1012.42 -22.6066C1013 -23.8511 1013.44 -32.2217 1011.65 -32.6274C1009.66 -33.0791 1005.66 -32.7034 1003.35 -32.7564C1003.3 -35.7456 1003.27 -38.7348 1003.25 -41.7239C1007.16 -41.7539 1011.29 -41.7746 1015.16 -41.7124C1018.76 -41.6548 1028.77 -40.4817 1031.66 -41.4405C1032.27 -42.9362 1031.97 -48.3177 1032.02 -50.3112Z" fill="#9E2184"/> -<path d="M785.156 -12.3945C786.514 -12.5512 792.769 -12.5973 793.865 -12.3807C794.776 -10.9426 793.965 3.84664 793.426 6.04762C792.666 6.67449 786.241 6.42096 784.582 6.43709C784.379 12.2772 784.85 19.0576 784.411 24.7547C782.704 25.0083 777.867 24.8746 775.987 24.8585C776.039 18.7764 773.947 -8.78074 775.611 -11.4334C777.258 -12.3991 782.258 -11.9405 784.826 -12.3415L785.156 -12.3945Z" fill="#9E2184"/> -<path d="M746.8 -12.4798C749.874 -12.3853 753.101 -12.4521 756.189 -12.4728C756.16 -9.33156 756.167 -6.19027 756.208 -3.05128L765.588 -2.97754C765.528 2.19187 765.507 7.35899 765.524 12.5284C765.56 15.3286 765.883 22.2565 765.431 24.7432C763.614 25.029 758.764 25.1212 757.065 24.4459C756.342 23.2521 756.794 17.6955 756.618 15.9924C756.29 12.8349 755.869 9.63831 755.931 6.46245C753.85 6.32186 748.581 6.81509 747.212 6.05223C746.389 4.05177 746.754 -9.55742 746.8 -12.4798Z" fill="#9E2184"/> -<path d="M1088.63 6.50395C1094.04 6.22278 1102.51 6.94644 1107.46 6.4325C1107.5 9.44011 1107.45 12.5468 1107.44 15.5637C1105.3 15.5222 1099.61 14.946 1098.37 15.8656C1097.45 17.2622 1097.79 21.9915 1097.79 23.9873L1097.64 24.5197C1096.53 25.1328 1081.63 24.8446 1079.11 24.8124C1079.09 18.97 1078.98 12.6874 1079.16 6.88193C1082.37 6.63763 1085.34 7.08934 1088.63 6.50395Z" fill="#9E2184"/> -<path d="M1061.1 6.97179C1062.64 6.83351 1068.1 6.74362 1069.45 7.22761C1070.08 8.76022 1069.64 22.2588 1069.62 24.8262C1063.51 24.9414 1057.11 24.8423 1050.99 24.84C1041.54 22.9617 1042.13 26.1099 1042.59 15.1857C1044.35 15.1696 1048.88 15.566 1050.09 14.9829C1051.14 13.872 1050.73 9.08518 1050.72 7.19764C1053.78 7.16999 1058.17 7.28753 1061.1 6.97179Z" fill="#9E2184"/> -<path d="M937.087 15.6328C943.257 15.6812 949.428 15.6858 955.598 15.6512C958.124 15.6489 962.878 15.5268 965.213 15.8195C965.261 17.6102 965.531 23.3881 965.038 24.8377C964.621 24.9852 964.798 24.9921 964.512 24.9391C959.44 25.1489 953.664 24.8953 948.502 24.9691C945.852 25.006 939.574 25.1466 937.151 24.9207C937.221 21.9131 937.126 18.6612 937.087 15.6328Z" fill="#9E2184"/> -<path d="M879.942 -2.98908C882.9 -3.11584 886.41 -3.03286 889.411 -3.03517C889.435 0.424171 889.701 12.8995 889.26 15.642L879.953 15.6812C879.9 12.6252 879.275 -0.629083 879.942 -2.98908Z" fill="#9E2184"/> -<path d="M1003.38 6.65836C1006.28 6.47629 1009.59 6.57539 1012.48 6.65144C1012.59 8.99531 1012.45 23.07 1011.96 24.8354C1011.7 24.87 1011.43 24.8999 1011.17 24.9253C1009.73 25.0613 1004.33 25.4692 1003.93 24.6072C1002.74 22.0905 1003.19 9.10363 1003.38 6.65836Z" fill="#9E2184"/> -<path d="M946.396 -3.05129C949.596 -3.12734 952.797 -3.12506 955.996 -3.04439C956.04 -0.389393 956.148 3.53318 955.888 6.11213C953.108 6.22967 949.313 6.18358 946.542 6.06604C946.291 3.70143 946.39 -0.536871 946.396 -3.05129Z" fill="#9E2184"/> -<path d="M1107.88 -2.98907C1110.95 -3.07435 1114.02 -3.05129 1117.1 -2.91761C1117.1 -0.311012 1117.21 3.91808 1116.81 6.32187C1114.1 6.4855 1110.41 6.39331 1107.63 6.40022C1107.61 4.4251 1107.44 -1.33661 1107.88 -2.98907Z" fill="#9E2184"/> -<path d="M1164.81 15.5821C1167.83 15.619 1171.42 15.5729 1174.39 15.7204C1174.35 18.7234 1174.27 21.8394 1174.29 24.8354C1171.25 24.8516 1167.83 24.9391 1164.83 24.8124C1164.77 21.7356 1164.77 18.6589 1164.81 15.5821Z" fill="#9E2184"/> -<path d="M1107.6 15.6167C1110.64 15.6813 1113.86 15.6282 1116.91 15.6305C1117.08 18.675 1117 21.7172 1116.89 24.7617C1115.05 24.9968 1109.66 24.8562 1107.67 24.8424C1107.53 21.95 1107.6 18.5506 1107.6 15.6167Z" fill="#9E2184"/> -<path d="M1164.81 -3.24954C1167.87 -3.19423 1171.32 -3.2311 1174.34 -3.04211C1174.31 -1.18684 1174.39 4.46655 1174.04 5.93925C1171.35 5.96229 1167.48 5.88393 1164.87 6.05448C1164.89 2.95237 1164.87 -0.147433 1164.81 -3.24954Z" fill="#9E2184"/> -<path d="M728.088 6.91189C731.213 6.87502 734.339 6.87731 737.464 6.92571C737.646 8.76715 737.432 14.2223 736.911 16.0016C734.373 15.9947 731.613 16.1283 729.133 15.672C728.364 15.5061 728.496 13.6324 728.413 13.0101C728.08 10.5072 727.08 9.47701 728.088 6.91189Z" fill="#9E2184"/> -<path d="M804.108 6.67684C807.037 6.59157 809.969 6.58694 812.899 6.663C812.957 8.94925 813.227 14.1832 812.437 16.0892C810.562 16.0984 808.458 15.9025 806.598 15.7965C803.553 15.6259 803.582 13.2867 803.783 10.9405C803.911 9.45629 803.824 8.19563 804.108 6.67684Z" fill="#9E2184"/> -<path d="M-16.4382 -183.925C-19.9999 -184.108 -33.0334 -183.6 -35.551 -184.262C-36.0864 -185.216 -36.0557 -191.393 -35.6153 -192.6C-34.3613 -193.225 -10.4712 -192.958 -7.15333 -192.967C-7.43473 -190.646 -7.3573 -186.147 -7.23492 -183.78C-4.2704 -183.644 -0.527588 -183.732 2.51091 -183.707C2.5494 -180.586 2.51252 -177.396 2.51067 -174.271C-0.704369 -174.303 -3.9194 -174.299 -7.13422 -174.257C-7.27249 -172.105 -7.8164 -166.52 -6.78321 -165.013C-5.38311 -164.015 0.310844 -164.543 2.50952 -164.58C2.77248 -167.525 2.61923 -171.201 2.56991 -174.227L26.9459 -174.234C30.7837 -174.234 36.8337 -174.393 40.4544 -174.008C40.5936 -171.222 40.4214 -167.352 40.3603 -164.522C42.3974 -164.587 48.4865 -164.237 49.86 -164.799C50.4823 -166.776 50.2426 -180.724 50.2357 -183.766C54.6538 -183.919 65.1263 -183.384 68.876 -183.895C68.8829 -180.934 68.9843 -177.189 68.717 -174.31C65.7578 -174.186 62.2316 -174.257 59.2401 -174.255C59.0742 -171.086 59.1664 -167.737 59.2078 -164.557C62.4413 -164.52 75.8154 -165.041 77.7975 -163.953C78.8461 -161.911 78.1409 -158.032 78.6133 -155.529C69.5905 -155.887 59.9753 -155.573 50.9317 -155.442C48.929 -155.412 50.8257 -148.23 49.5996 -146.43C48.0439 -145.787 42.3076 -146.101 40.3477 -146.135L40.3518 -136.686C42.5588 -136.493 46.1518 -136.61 48.4496 -136.615C51.9458 -136.622 55.8707 -136.566 59.3346 -136.769C59.413 -133.886 59.1502 -129.233 59.4314 -126.702C53.8103 -126.368 46.2624 -126.573 40.5039 -126.585C40.3172 -123.639 40.3891 -120.298 40.3926 -117.313C42.7501 -117.094 47.4678 -117.276 49.9776 -117.313C50.0698 -114.209 50.0651 -111.102 49.9637 -107.995C47.3041 -107.769 43.3723 -107.928 40.4532 -107.809C40.2209 -105.202 40.3304 -100.749 40.3168 -98.009C45.9743 -98.0251 53.9163 -98.281 59.3876 -97.9399C59.6642 -88.5598 60.6805 -88.8916 50.904 -89.3895C50.5906 -88.4998 49.0511 -82.0444 49.0972 -81.3461C49.2954 -78.3155 57.4079 -80.6478 59.0304 -79.3894C59.7587 -77.7485 59.3116 -71.807 59.4291 -69.3664L68.8829 -69.3871C69.2701 -64.1324 68.6525 -56.2135 68.6893 -50.4633C71.8629 -50.438 75.1378 -50.5025 78.3229 -50.5232C78.6802 -53.2566 78.5303 -59.9079 78.5027 -62.8625C78.4497 -68.2947 78.6317 -74.1716 78.452 -79.5577C75.4052 -79.613 72.1994 -79.5231 69.1019 -79.5577C69.0189 -88.9332 69.0143 -98.3063 69.088 -107.682C72.2339 -107.739 75.3822 -107.739 78.5304 -107.679C78.7124 -103.386 78.1823 -100.162 77.5854 -96.0224C77.3826 -94.6303 77.4725 -90.4819 77.4771 -88.9124C84.1446 -88.6981 90.7659 -89.265 97.5809 -88.5759C97.7676 -91.6066 97.6984 -94.9369 97.6938 -97.9998C103.695 -98.1865 110.185 -98.0758 116.2 -98.032C116.295 -88.4906 116.293 -78.9469 116.189 -69.4032C125.286 -69.175 135.311 -69.3963 144.488 -69.3802C144.756 -65.7918 144.613 -54.1623 144.414 -50.7468C141.305 -50.514 138.183 -50.5509 135.067 -50.5854C135.21 -53.6368 135.2 -57.0777 135.145 -60.1315C132.488 -60.3135 128.542 -60.2398 125.848 -60.1983C125.717 -57.1262 125.627 -53.57 125.797 -50.5255C122.939 -50.7399 119.425 -50.4979 116.327 -50.65C116.376 -53.8281 116.383 -57.004 116.355 -60.1822C113.933 -60.4311 109.312 -60.2144 106.707 -60.1591C106.627 -56.9141 106.763 -53.7913 106.41 -50.5578C103.262 -50.5393 100.406 -50.0784 97.2836 -49.629C97.2145 -52.5444 97.5832 -55.1556 97.65 -58.0065C97.7353 -61.6433 97.6915 -65.4023 97.6846 -69.0483C100.183 -69.2673 104.345 -69.1543 106.97 -69.152C107.221 -73.0078 106.8 -76.0799 106.548 -79.9149C102.985 -79.9356 100.877 -79.8596 97.3158 -80.3413C94.9973 -80.1362 89.7058 -81.2654 87.9588 -80.2882C87.1545 -77.9398 87.3642 -51.3806 88.4128 -50.1153C90.4548 -49.2902 94.9697 -49.5322 97.2836 -49.629C97.2606 -47.1745 97.1591 -44.1231 97.249 -41.7239C92.0981 -41.7331 82.8401 -41.9913 78.051 -41.5418C77.9173 -38.3199 77.9173 -35.2731 77.9265 -32.0465C81.1162 -32.065 84.3889 -32.1226 87.567 -31.9982C87.7353 -27.8336 87.3204 -23.7912 87.3596 -19.6381C87.4333 -11.71 87.1752 -3.7957 86.9332 4.12552C86.818 7.92595 86.977 11.8393 86.8641 15.6582L78.3667 15.6282C77.7583 7.08705 78.8645 -3.73344 78.5488 -12.7102C75.9975 -12.701 71.3536 -12.8301 68.9659 -12.6272C68.8737 -9.74408 69.0258 -5.46428 68.6732 -2.81389L59.1894 -2.80005C59.0972 -6.12111 59.2171 -9.56891 59.1041 -12.7909C56.4837 -12.7678 42.1831 -12.9384 40.7733 -12.3622C40.0363 -10.7489 40.3571 -5.38361 40.3115 -3.26561C37.5205 -3.51451 33.9459 -3.44539 31.1496 -3.27945L31.069 9.2189C31.0614 10.7262 30.9485 14.25 31.0865 15.6328C24.8228 15.4715 18.5048 15.7481 12.2194 15.566C12.1512 13.4503 11.6382 8.66576 12.6937 7.1631C14.0701 6.18591 19.584 6.61458 21.7954 6.60767C22.0466 0.530212 21.8816 -6.55208 21.8765 -12.7033C18.7138 -12.7494 15.3941 -12.6871 12.2187 -12.6756C12.4328 -15.727 12.4112 -19.1034 12.4476 -22.1894C6.26386 -22.1848 -0.995209 -21.9981 -7.07982 -22.3162C-7.33149 -19.463 -7.31029 -15.356 -7.27733 -12.4728L12.1634 -12.5005C12.1556 -9.45367 12.091 -6.40918 11.9698 -3.36699C10.0505 -3.34856 4.69391 -3.67584 3.28297 -3.12964C2.01978 -1.81827 2.58212 3.73141 2.35027 6.40486C-0.742622 6.43481 -3.83551 6.43713 -6.92841 6.4164C-6.98901 3.23822 -6.94199 -0.0252075 -6.9874 -3.23103C-9.19483 -3.55138 -14.2193 -3.34859 -16.5539 -3.27483C-16.367 -6.18565 -16.4163 -9.81783 -16.4756 -12.7355C-21.1691 -12.8139 -25.8992 -12.6595 -30.5973 -12.7309C-32.1733 -12.754 -33.7985 -12.7794 -35.3606 -12.5742C-36.0497 -11.3228 -35.7022 -5.00102 -35.8292 -2.85767C-37.3547 -2.79083 -41.1811 -2.54886 -42.4964 -2.84155C-46.4086 -3.71272 -48.6234 -4.08607 -52.6239 -4.04459C-53.3561 -3.37624 -53.7232 -2.89687 -54.3552 -2.12248C-54.4375 -0.0897522 -54.9715 4.59569 -54.0867 6.04073C-52.9226 6.95338 -47.0535 6.60307 -44.9654 6.70448C-44.7377 8.99533 -44.6769 22.8304 -45.3496 24.5174C-46.97 25.1835 -79.2797 24.8447 -83.5099 24.8124C-83.2712 19.1913 -83.4378 12.397 -83.4343 6.69063C-80.1838 6.5224 -76.9268 6.51781 -73.6758 6.68144C-73.4848 9.52312 -73.6477 13.0101 -73.5009 16.0684C-70.6821 16.179 -66.9296 16.1675 -64.1312 16.05C-63.8692 13.0401 -64.016 8.80174 -64.0273 5.66968C-64.066 -0.377823 -64.0664 -6.42763 -64.0284 -12.4751C-62.086 -12.4636 -56.8187 -12.2931 -55.3082 -12.5904C-53.3658 -12.9729 -55.3167 -19.7418 -54.224 -21.7492C-52.6064 -22.4567 -47.1593 -22.1226 -44.915 -22.1341C-44.6896 -24.5724 -44.2549 -29.9262 -44.2706 -32.0926C-40.3586 -32.0327 -40.0332 -30.7052 -35.5019 -30.5785C-32.3862 -32.201 -29.7605 -31.846 -26.2555 -31.8553C-26.1958 -28.6333 -26.2474 -25.4183 -26.1783 -22.1871C-23.4661 -21.9843 -19.4463 -22.0695 -16.6325 -22.0511C-16.3606 -25.1163 -16.4631 -29.2556 -16.4836 -32.3439L-26.0333 -32.2793C-26.2122 -38.2623 -26.0006 -44.3536 -26.2576 -50.3135L-35.4789 -50.2951C-35.5542 -53.3442 -35.5093 -56.5753 -35.5151 -59.6383C-38.6623 -59.8157 -41.4146 -59.4677 -44.8668 -59.7765C-45.08 -50.9035 -44.9207 -41.3506 -44.9152 -32.4153C-47.3969 -32.4199 -48.0977 -32.4568 -50.4006 -31.5764C-53.4006 -32.625 -58.7057 -32.4222 -61.773 -32.0396C-62.2769 -31.9774 -63.0151 -32.1917 -63.2971 -32.6043C-64.4046 -34.2222 -64.0731 -39.5229 -64.0697 -41.5764C-66.588 -41.7377 -71.0626 -41.7769 -73.5528 -41.5787C-73.4984 -44.8422 -73.4869 -48.1056 -73.5187 -51.3667C-76.4359 -51.346 -80.6445 -51.1916 -83.4609 -51.3667L-83.4452 -59.9217L-73.7385 -60.0024C-73.7431 -57.2345 -73.8026 -54.2822 -73.7501 -51.5304C-67.5438 -51.6664 -60.635 -51.4221 -54.6315 -51.671C-54.5988 -54.432 -54.5506 -57.1538 -54.6318 -59.9171C-60.9747 -59.9702 -67.2444 -60.3136 -73.5629 -60.2052C-73.538 -63.1898 -73.4401 -66.6192 -73.5698 -69.5623L-92.8799 -69.6199L-92.6992 -78.3754C-88.1398 -78.3615 -84.1198 -78.3615 -79.5565 -78.7994C-77.8167 -78.9654 -75.4283 -78.7603 -73.5986 -78.9262C-73.2628 -88.5114 -73.5364 -99.3065 -73.4894 -109.014C-76.3608 -108.802 -80.7169 -108.756 -83.5805 -108.977L-83.4493 -117.145C-80.6192 -117.428 -76.9441 -117.338 -74.0381 -117.297C-73.9017 -120.261 -73.8759 -123.225 -73.9605 -126.188C-77.137 -126.112 -80.3147 -126.094 -83.492 -126.128C-83.4632 -132.6 -83.695 -140.012 -83.4334 -146.352C-80.5726 -146.421 -76.4253 -146.592 -73.7049 -146.066L-73.7918 -126.37C-71.7904 -126.354 -65.7705 -126.11 -64.3356 -126.758C-63.3843 -128.551 -64.9994 -136.048 -63.396 -136.198C-57.7156 -136.73 -51.3524 -136.518 -45.6349 -136.334C-44.4568 -136.294 -45.1007 -127.527 -45.0777 -126.368C-46.4927 -126.477 -48.0717 -126.463 -49.4923 -126.407C-54.316 -126.223 -59.2552 -126.583 -64.0616 -126.465C-64.1494 -119.302 -64.1526 -112.137 -64.0715 -104.971C-64.0411 -103.052 -64.1291 -99.7974 -63.9844 -98.0067L-46.0876 -97.9491C-46.0871 -100.715 -46.2176 -104.819 -46.0525 -107.477C-43.2399 -107.804 -38.5602 -107.668 -35.6033 -107.636C-35.5971 -104.43 -35.6349 -101.224 -35.7169 -98.0182C-29.9024 -98.009 -22.2585 -98.2441 -16.6286 -97.9583C-16.562 -94.6879 -16.2175 -82.1113 -17.0077 -79.7951C-17.7895 -79.0599 -21.1541 -78.917 -22.374 -78.6381C-23.5911 -78.3592 -24.8347 -77.8776 -26.0349 -77.7116C-26.0538 -75.0105 -26.0045 -72.2956 -26.3325 -69.6153C-29.1152 -69.6037 -32.863 -69.6959 -35.5662 -69.5323C-35.498 -72.7727 -35.4775 -76.0154 -35.5044 -79.2581C-25.3099 -79.4056 -25.5931 -77.5641 -26.1677 -88.622C-26.1755 -88.7879 -26.1873 -88.9516 -26.2023 -89.1175C-29.023 -89.0945 -32.7328 -88.9815 -35.5021 -89.1313C-35.5019 -91.6665 -35.4107 -95.2641 -35.6338 -97.6817C-38.8688 -97.6979 -42.0869 -97.5711 -45.3199 -97.5434L-45.4033 -89.1867C-51.5534 -89.1267 -57.921 -89.0276 -64.0641 -89.1452C-64.0708 -85.9831 -64.1768 -82.2104 -64.0505 -79.0991C-59.1031 -78.7349 -50.4635 -79.076 -45.13 -79.0668C-45.1201 -76.5178 -45.2339 -71.7563 -45.0136 -69.3341C-42.3044 -69.2396 -38.4549 -69.2995 -35.6888 -69.3894L-35.7013 -60.0024C-28.6097 -59.8503 -21.4938 -60.0324 -14.4011 -59.9655C-12.444 -59.9471 -9.15934 -60.1476 -7.37367 -59.5783C-6.92564 -58.154 -7.0911 -53.3764 -7.2439 -51.7862C-7.42321 -49.9217 -14.8201 -50.65 -16.4359 -50.4725C-16.7839 -45.204 -16.5519 -37.9972 -16.5986 -32.5305C-13.7885 -32.6411 -10.9768 -32.7103 -8.16463 -32.7379C-7.57324 -32.3185 -6.82446 -31.7492 -6.2257 -31.3759C-4.18006 -31.3874 1.91308 -30.6937 3.20878 -31.1293C6.66534 -32.2908 8.90343 -31.5395 12.1906 -32.0258C12.0369 -28.3867 12.0956 -25.5658 12.8848 -22.005C15.3473 -21.9866 19.4889 -21.8529 21.8288 -22.1064C22.0846 -24.4042 21.8975 -29.6727 21.8539 -32.0558C18.8956 -32.1987 15.1717 -32.0742 12.1906 -32.0258C12.0472 -41.3114 12.4554 -50.9427 12.1945 -60.1684C9.29706 -60.3181 5.61209 -60.2329 2.65587 -60.2467C2.47242 -62.8118 2.57729 -66.6998 2.57291 -69.3686C8.92762 -69.4032 15.2826 -69.4032 21.6373 -69.3709C21.823 -66.8335 21.697 -62.6851 21.7306 -59.9655C27.9051 -59.9171 34.0798 -59.9218 40.2543 -59.9748C40.4569 -63.365 40.7289 -75.937 40.1241 -78.9285C37.4237 -79.212 34.4463 -78.6888 31.6995 -78.8801C25.1676 -79.3295 18.7589 -79.4332 12.2263 -79.5761C11.9751 -84.976 12.2005 -92.5607 12.2012 -98.1404C16.9058 -97.8615 21.6873 -98.281 26.3932 -97.873C27.8168 -97.7509 29.1591 -97.6725 30.5898 -97.7186C30.6514 -95.6098 30.0104 -90.1915 31.2273 -88.7695C32.1653 -87.6725 38.9059 -87.843 39.9621 -88.3961C40.6176 -88.7395 40.4449 -97.0157 40.4458 -97.9721C38.394 -98.1196 32.6707 -98.2326 30.7491 -98.0205C30.8009 -101.987 30.7608 -105.419 31.3559 -109.341C31.6037 -110.975 31.6733 -115.638 31.1955 -117.175C30.0899 -117.719 22.9834 -117.668 22.1491 -117.401C21.4997 -116.147 21.6714 -109.811 21.6313 -107.903C18.6631 -107.903 15.1136 -107.981 12.204 -107.76C12.1443 -105.084 11.9369 -100.828 12.118 -98.2833C8.93753 -98.4123 5.84164 -98.2786 2.58143 -98.4469C2.48694 -101.487 2.53327 -104.806 2.51437 -107.871C-0.511909 -107.97 -3.87561 -107.924 -6.92494 -107.947C-6.96366 -110.987 -6.9314 -114.093 -6.9314 -117.14C-3.94015 -117.214 10.0608 -116.838 11.8205 -117.546C12.5105 -119.148 12.2148 -124.672 12.1888 -126.677C8.86977 -126.728 5.93613 -126.606 2.54847 -126.781C2.36617 -129.498 2.40235 -133.656 2.4897 -136.38C4.40789 -136.546 6.87138 -136.375 8.8548 -136.483C13.1712 -136.719 17.3538 -136.765 21.6769 -136.725C21.6898 -133.547 21.6527 -130.182 21.8007 -127.025C24.9994 -127.055 28.0298 -127.226 31.3167 -127.226C31.5583 -132.96 31.3649 -140.24 31.3681 -146.069C34.1695 -146.207 37.5014 -146.156 40.3264 -146.172C39.8418 -149.164 40.0957 -160.701 40.1186 -164.359C35.8201 -164.407 31.5265 -164.213 27.2227 -164.29C23.2526 -164.359 16.2268 -165.363 12.4722 -164.527C11.7405 -163.089 12.006 -157.484 12.0177 -155.596C8.8979 -155.603 5.743 -155.647 2.62799 -155.527C2.42126 -152.99 2.51691 -148.758 2.49824 -146.092C-0.812218 -146.025 -3.60941 -146.013 -6.91249 -146.156L-6.95029 -155.571C-13.1746 -155.817 -19.7256 -155.414 -26.0495 -155.617C-26.1357 -158.528 -26.1057 -161.632 -26.1267 -164.559C-24.3313 -164.552 -17.612 -164.239 -16.6602 -164.962C-16.1589 -167.154 -16.388 -180.929 -16.4382 -183.925ZM31.6438 -22.6457C36.9536 -22.6342 42.4205 -22.5443 47.6913 -23.1689C51.2037 -23.5837 54.3657 -23.5515 57.8896 -23.5238L58.7446 -23.6275C59.8186 -25.0495 58.8783 -39.7258 59.2355 -42.5582C59.36 -43.5654 59.2286 -49.0713 59.0926 -50.083C58.6225 -50.5878 57.1014 -50.6546 56.3754 -50.6569C48.014 -50.6892 39.6002 -50.567 31.2398 -50.6799C30.6345 -49.0482 30.9058 -46.8634 30.7509 -45.1441C30.208 -39.1219 30.3375 -33.3602 31.234 -27.3703C31.4635 -25.8377 31.3589 -24.2221 31.6438 -22.6457ZM68.7792 -22.0811C71.8514 -22.0742 74.9212 -22.088 77.9933 -22.1272C78.2353 -24.8951 78.0717 -29.1196 78.021 -31.9958C75.0203 -32.0742 72.0196 -32.1042 69.0212 -32.088C68.7562 -29.7649 68.7078 -24.5264 68.7792 -22.0811Z" fill="#9E2184"/> -<path d="M258.854 -79.4632C261.606 -79.2535 265.355 -79.4816 268.473 -79.3088C268.582 -76.1859 268.485 -72.5606 268.478 -69.4009L277.397 -69.3894C277.542 -67.0502 277.556 -62.4731 277.217 -60.2052L268.499 -60.1891C268.414 -57.0225 268.469 -53.6599 268.471 -50.4771C270.209 -50.431 275.895 -50.8113 277.012 -50.1891C277.865 -48.1748 277.489 -35.0219 277.169 -32.1134C272.062 -31.8737 263.998 -31.9152 258.865 -32.1065C258.798 -35.3146 258.909 -38.4513 258.789 -41.7032C254.931 -41.9083 243.101 -41.8691 239.469 -41.5926C239.391 -38.4236 239.444 -35.0473 239.441 -31.8645L249.11 -31.8C249.319 -25.5474 249.137 -18.8061 249.176 -12.489C252.389 -12.4521 255.604 -12.4659 258.819 -12.5304L258.826 -22.0903C261.871 -22.2171 265.348 -22.1387 268.427 -22.1295C268.483 -19.0135 268.266 -15.9114 268.381 -12.7402C265.194 -12.6849 262.004 -12.6641 258.817 -12.678C258.685 -9.78788 258.796 -6.19028 258.815 -3.2495C257.068 -3.54681 250.582 -3.71964 249.188 -2.51659C247.966 -1.46336 243.037 -1.9243 241.105 -1.97961C240.866 0.825188 240.85 3.81207 240.868 6.63531C246.911 6.64223 252.788 6.40025 258.803 6.39103C258.621 8.03197 258.52 14.1025 258.815 15.5821C256.657 15.2364 252.97 15.3309 250.762 15.3055C247.358 15.2664 250.372 22.2634 248.605 24.6073C247.093 25.1581 241.762 24.8608 239.9 24.817C239.28 19.2673 240.725 12.1089 240.594 6.43019C237.144 6.37488 233.691 6.37719 230.241 6.43941C230.077 10.415 230.587 21.2263 229.914 24.5266C229.033 25.2618 222.518 24.9046 220.981 24.8769C221.112 16.0384 220.955 6.99023 220.907 -1.86668L217.593 -1.91508C215.304 -3.51683 214.14 -3.24258 211.322 -3.21723C211.345 -6.38157 211.34 -9.54358 211.306 -12.7056C208.713 -12.8301 205.371 -12.754 202.732 -12.7586L201.774 -14.8513C199.817 -14.5102 194.848 -14.4226 192.493 -14.2544C192.237 -19.055 193.419 -38.3038 191.774 -41.3206C189.821 -42.0927 176.468 -41.6525 173.043 -41.7654C173.027 -44.6578 173.057 -47.5479 173.131 -50.438C177.807 -50.7076 187.662 -50.0323 191.704 -50.6477C192.518 -51.7862 192.207 -58.1932 192.191 -59.9494H220.301C220.412 -62.0951 220.119 -67.3659 220.79 -68.9884C222.179 -69.5554 237.939 -69.6683 239.172 -68.9653C239.948 -67.3728 239.469 -53.4525 239.501 -50.5025C241.767 -50.3481 244.936 -50.4518 247.296 -50.4449C251.041 -50.431 255.046 -50.3066 258.768 -50.4357C258.909 -53.4802 258.828 -57.0732 258.828 -60.1614C255.791 -60.2721 252.408 -60.226 249.352 -60.2444C249.31 -63.2474 249.299 -66.2504 249.322 -69.2534C251.737 -69.4862 256.148 -69.3802 258.75 -69.4194C258.911 -72.4777 258.831 -76.3426 258.854 -79.4632ZM230.269 -50.544C224.698 -50.6869 219.128 -50.7145 213.557 -50.6293C211.398 -50.6062 202.984 -50.862 201.681 -50.1729C200.34 -47.4557 202.069 -27.0431 202.126 -22.1871L218.137 -22.1433L230.225 -22.1087C230.384 -30.3549 230.672 -42.3831 230.269 -50.544ZM220.794 -2.3299C223.836 -2.38752 226.878 -2.40598 229.921 -2.38293C230.467 -3.26102 230.257 -11.014 230.248 -12.7033C227.478 -12.7102 223.979 -12.6296 221.299 -12.8808C220.142 -11.5026 220.663 -4.46404 220.794 -2.3299ZM201.866 -14.9458C201.87 -15.8216 201.983 -17.6307 201.679 -18.3521L201.299 -18.6333C201.287 -17.5063 201.186 -16.3447 201.497 -15.28L201.866 -14.9458Z" fill="#9E2184"/> -<path d="M126.016 -50.3112L134.848 -50.3089C134.822 -44.0194 135.249 -38.0872 135.175 -31.8553C131.172 -31.9198 119.535 -32.4891 116.293 -32.1365C116 -26.4139 116.182 -18.8315 116.154 -12.9891C118.786 -12.9868 122.024 -13.0698 124.613 -12.9614C124.742 -9.73718 124.935 -6.1972 124.905 -2.99138C131.464 -3.03056 138.024 -3.02363 144.583 -2.97062C144.546 -6.11191 144.576 -9.2532 144.675 -12.3922C147.71 -12.4752 150.745 -12.5051 153.781 -12.4821C154.085 -10.4171 153.949 -4.91809 153.677 -2.88996C150.619 -2.83696 147.558 -2.83927 144.5 -2.89688L144.52 6.87961C142.036 6.26656 129.102 6.39794 125.843 6.39794C125.615 9.54153 125.624 12.5007 125.61 15.6512C122.824 15.695 120.038 15.6881 117.251 15.6328C117.323 12.3025 117.346 9.88723 117.069 6.53622C116.8 3.30274 116.323 0.062336 116.336 -3.15501C112.937 -2.98907 109.74 -3.17806 106.346 -3.27255C103.32 -3.35552 100.347 -3.22185 97.3274 -3.50533C97.2098 -9.67728 97.355 -16.029 97.4288 -22.2148C99.367 -22.2217 105.154 -21.9382 106.419 -22.6066C107 -23.8511 107.438 -32.2217 105.647 -32.6274C103.661 -33.0791 99.6574 -32.7034 97.3527 -32.7564C97.302 -35.7456 97.2675 -38.7348 97.249 -41.7239C101.16 -41.7539 105.288 -41.7746 109.16 -41.7124C112.764 -41.6548 122.769 -40.4817 125.659 -41.4405C126.272 -42.9362 125.97 -48.3177 126.016 -50.3112Z" fill="#9E2184"/> -<path d="M182.626 6.50395C188.04 6.22278 196.507 6.94644 201.462 6.4325C201.504 9.44011 201.451 12.5468 201.437 15.5637C199.298 15.5222 193.608 14.946 192.368 15.8656C191.451 17.2622 191.789 21.9915 191.794 23.9873L191.642 24.5197C190.526 25.1328 175.633 24.8446 173.108 24.8124C173.091 18.97 172.978 12.6874 173.163 6.88193C176.366 6.63763 179.337 7.08934 182.626 6.50395Z" fill="#9E2184"/> -<path d="M155.104 6.97179C156.643 6.83351 162.101 6.74362 163.447 7.22761C164.083 8.76022 163.643 22.2588 163.615 24.8262C157.515 24.9414 151.112 24.8423 144.989 24.84C135.537 22.9617 136.129 26.1099 136.588 15.1857C138.353 15.1696 142.88 15.566 144.087 14.9829C145.138 13.872 144.733 9.08518 144.721 7.19764C147.784 7.16999 152.168 7.28753 155.104 6.97179Z" fill="#9E2184"/> -<path d="M31.0869 15.6328C37.257 15.6812 43.4281 15.6858 49.5977 15.6512C52.1236 15.6489 56.8782 15.5268 59.2129 15.8195C59.2613 17.6102 59.5309 23.3881 59.0377 24.8377C58.6205 24.9852 58.798 24.9921 58.5122 24.9391C53.4396 25.1489 47.6641 24.8953 42.5016 24.9691C39.8519 25.006 33.5741 25.1466 31.1514 24.9207C31.2213 21.9131 31.1263 18.6612 31.0869 15.6328Z" fill="#9E2184"/> -<path d="M97.3832 6.65836C100.278 6.47629 103.585 6.57539 106.482 6.65144C106.586 8.99531 106.448 23.07 105.959 24.8354C105.696 24.87 105.431 24.8999 105.166 24.9253C103.733 25.0613 98.3327 25.4692 97.9271 24.6072C96.7425 22.0905 97.1896 9.10363 97.3832 6.65836Z" fill="#9E2184"/> -<path d="M40.3965 -3.05129C43.5961 -3.12734 46.7973 -3.12506 49.9962 -3.04439C50.04 -0.389393 50.1483 3.53318 49.8879 6.11213C47.1084 6.22967 43.3126 6.18358 40.5419 6.06604C40.2914 3.70143 40.3902 -0.536871 40.3965 -3.05129Z" fill="#9E2184"/> -<path d="M201.878 -2.98907C204.95 -3.07435 208.024 -3.05129 211.096 -2.91761C211.096 -0.311012 211.212 3.91808 210.806 6.32187C208.098 6.4855 204.413 6.39331 201.629 6.40022C201.608 4.4251 201.438 -1.33661 201.878 -2.98907Z" fill="#9E2184"/> -<path d="M258.814 15.5821C261.829 15.619 265.415 15.5729 268.386 15.7204C268.351 18.7234 268.271 21.8394 268.287 24.8354C265.254 24.8516 261.829 24.9391 258.831 24.8124C258.773 21.7356 258.766 18.6589 258.814 15.5821Z" fill="#9E2184"/> -<path d="M201.601 15.6167C204.639 15.6813 207.861 15.6282 210.915 15.6305C211.083 18.675 211.004 21.7172 210.894 24.7617C209.055 24.9968 203.659 24.8562 201.668 24.8424C201.528 21.95 201.601 18.5506 201.601 15.6167Z" fill="#9E2184"/> -<path d="M258.814 -3.24954C261.873 -3.19423 265.323 -3.2311 268.34 -3.04211C268.31 -1.18684 268.388 4.46655 268.04 5.93925C265.351 5.96229 261.481 5.88393 258.872 6.05448C258.886 2.95237 258.865 -0.147433 258.814 -3.24954Z" fill="#9E2184"/> -<path d="M-35.4382 272.075C-38.9999 271.892 -52.0334 272.4 -54.551 271.738C-55.0864 270.784 -55.0557 264.607 -54.6153 263.4C-53.3613 262.775 -29.4712 263.042 -26.1533 263.033C-26.4347 265.354 -26.3573 269.853 -26.2349 272.22C-23.2704 272.356 -19.5276 272.268 -16.4891 272.293C-16.4506 275.414 -16.4875 278.604 -16.4893 281.729C-19.7044 281.697 -22.9194 281.701 -26.1342 281.743C-26.2725 283.895 -26.8164 289.48 -25.7832 290.987C-24.3831 291.985 -18.6892 291.457 -16.4905 291.42C-16.2275 288.475 -16.3808 284.799 -16.4301 281.773L7.9459 281.766C11.7837 281.766 17.8337 281.607 21.4544 281.992C21.5936 284.778 21.4214 288.648 21.3603 291.478C23.3974 291.413 29.4865 291.763 30.86 291.201C31.4823 289.224 31.2426 275.276 31.2357 272.234C35.6538 272.081 46.1263 272.616 49.876 272.104C49.8829 275.066 49.9843 278.811 49.717 281.69C46.7578 281.814 43.2316 281.743 40.2401 281.745C40.0742 284.914 40.1664 288.263 40.2078 291.443C43.4413 291.48 56.8154 290.959 58.7975 292.047C59.8461 294.089 59.1409 297.968 59.6133 300.471C50.5905 300.113 40.9753 300.427 31.9317 300.558C29.929 300.588 31.8257 307.77 30.5996 309.57C29.0439 310.213 23.3076 309.899 21.3477 309.864L21.3518 319.314C23.5588 319.507 27.1518 319.39 29.4496 319.385C32.9458 319.378 36.8707 319.434 40.3346 319.231C40.413 322.114 40.1502 326.767 40.4314 329.298C34.8103 329.632 27.2624 329.427 21.5039 329.415C21.3172 332.361 21.3891 335.702 21.3926 338.687C23.7501 338.906 28.4678 338.724 30.9776 338.687C31.0698 341.791 31.0651 344.898 30.9637 348.005C28.3041 348.231 24.3723 348.072 21.4532 348.191C21.2209 350.798 21.3304 355.251 21.3168 357.991C26.9743 357.975 34.9163 357.719 40.3876 358.06C40.6642 367.44 41.6805 367.108 31.904 366.611C31.5906 367.5 30.0511 373.956 30.0972 374.654C30.2954 377.685 38.4079 375.352 40.0304 376.611C40.7587 378.251 40.3116 384.193 40.4291 386.634L49.8829 386.613C50.2701 391.868 49.6525 399.786 49.6893 405.537C52.8629 405.562 56.1378 405.497 59.3229 405.477C59.6802 402.743 59.5303 396.092 59.5027 393.137C59.4497 387.705 59.6317 381.828 59.452 376.442C56.4052 376.387 53.1994 376.477 50.1019 376.442C50.0189 367.067 50.0143 357.694 50.088 348.318C53.2339 348.261 56.3822 348.261 59.5304 348.321C59.7124 352.614 59.1823 355.838 58.5854 359.978C58.3826 361.37 58.4725 365.518 58.4771 367.088C65.1446 367.302 71.7659 366.735 78.5809 367.424C78.7676 364.393 78.6984 361.063 78.6938 358C84.6952 357.814 91.1852 357.924 97.2005 357.968C97.295 367.509 97.2926 377.053 97.1889 386.597C106.286 386.825 116.311 386.604 125.488 386.62C125.756 390.208 125.613 401.838 125.414 405.253C122.305 405.486 119.183 405.449 116.067 405.415C116.21 402.363 116.2 398.922 116.145 395.869C113.488 395.686 109.542 395.76 106.848 395.802C106.717 398.874 106.627 402.43 106.797 405.474C103.939 405.26 100.425 405.502 97.3272 405.35C97.3756 402.172 97.3826 398.996 97.3549 395.818C94.9327 395.569 90.3117 395.786 87.7074 395.841C87.6268 399.086 87.7628 402.209 87.4102 405.442C84.262 405.461 81.4064 405.922 78.2836 406.371C78.2145 403.456 78.5832 400.844 78.65 397.993C78.7353 394.357 78.6915 390.598 78.6846 386.952C81.1829 386.733 85.3451 386.846 87.9702 386.848C88.2214 382.992 87.7997 379.92 87.5484 376.085C83.9854 376.064 81.8766 376.14 78.3158 375.659C75.9973 375.864 70.7058 374.735 68.9588 375.712C68.1545 378.06 68.3642 404.619 69.4128 405.885C71.4548 406.71 75.9697 406.468 78.2836 406.371C78.2606 408.825 78.1591 411.877 78.249 414.276C73.0981 414.267 63.8401 414.009 59.051 414.458C58.9173 417.68 58.9173 420.727 58.9265 423.953C62.1162 423.935 65.3889 423.877 68.567 424.002C68.7353 428.166 68.3204 432.209 68.3596 436.362C68.4333 444.29 68.1752 452.204 67.9332 460.126C67.818 463.926 67.977 467.839 67.8641 471.658L59.3667 471.628C58.7583 463.087 59.8645 452.267 59.5488 443.29C56.9975 443.299 52.3536 443.17 49.9659 443.373C49.8737 446.256 50.0258 450.536 49.6732 453.186L40.1894 453.2C40.0972 449.879 40.2171 446.431 40.1041 443.209C37.4837 443.232 23.1831 443.062 21.7733 443.638C21.0363 445.251 21.3571 450.616 21.3115 452.734C18.5205 452.485 14.9459 452.555 12.1496 452.721L12.069 465.219C12.0614 466.726 11.9485 470.25 12.0865 471.633C5.82284 471.471 -0.495247 471.748 -6.78059 471.566C-6.84881 469.45 -7.36184 464.666 -6.30629 463.163C-4.92993 462.186 0.584038 462.615 2.79539 462.608C3.04659 456.53 2.88158 449.448 2.8765 443.297C-0.286217 443.251 -3.60588 443.313 -6.78128 443.324C-6.56718 440.273 -6.58884 436.897 -6.55243 433.811C-12.7361 433.815 -19.9952 434.002 -26.0798 433.684C-26.3315 436.537 -26.3103 440.644 -26.2773 443.527L-6.8366 443.5C-6.84444 446.546 -6.90897 449.591 -7.03019 452.633C-8.94953 452.651 -14.3061 452.324 -15.717 452.87C-16.9802 454.182 -16.4179 459.731 -16.6497 462.405C-19.7426 462.435 -22.8355 462.437 -25.9284 462.416C-25.989 459.238 -25.942 455.975 -25.9874 452.769C-28.1948 452.449 -33.2193 452.651 -35.5539 452.725C-35.367 449.814 -35.4163 446.182 -35.4756 443.264C-40.1691 443.186 -44.8992 443.34 -49.5973 443.269C-51.1733 443.246 -52.7985 443.221 -54.3606 443.426C-55.0497 444.677 -54.7022 450.999 -54.8292 453.142C-56.3547 453.209 -60.1811 453.451 -61.4964 453.158C-65.4086 452.287 -67.6234 451.914 -71.6239 451.955C-72.3561 452.624 -72.7232 453.103 -73.3552 453.878C-73.4375 455.91 -73.9715 460.596 -73.0867 462.041C-71.9226 462.953 -66.0535 462.603 -63.9654 462.704C-63.7377 464.995 -63.6769 478.83 -64.3496 480.517C-65.97 481.183 -98.2797 480.845 -102.51 480.812C-102.271 475.191 -102.438 468.397 -102.434 462.691C-99.1838 462.522 -95.9268 462.518 -92.6758 462.681C-92.4848 465.523 -92.6477 469.01 -92.5009 472.068C-89.6821 472.179 -85.9296 472.168 -83.1312 472.05C-82.8692 469.04 -83.016 464.802 -83.0273 461.67C-83.066 455.622 -83.0664 449.572 -83.0284 443.525C-81.086 443.536 -75.8187 443.707 -74.3082 443.41C-72.3658 443.027 -74.3167 436.258 -73.224 434.251C-71.6064 433.543 -66.1593 433.877 -63.915 433.866C-63.6896 431.428 -63.2549 426.074 -63.2706 423.907C-59.3586 423.967 -59.0332 425.295 -54.5019 425.422C-51.3862 423.799 -48.7605 424.154 -45.2555 424.145C-45.1958 427.367 -45.2474 430.582 -45.1783 433.813C-42.4661 434.016 -38.4463 433.93 -35.6325 433.949C-35.3606 430.884 -35.4631 426.744 -35.4836 423.656L-45.0333 423.721C-45.2122 417.738 -45.0006 411.646 -45.2576 405.686L-54.4789 405.705C-54.5542 402.656 -54.5093 399.425 -54.5151 396.362C-57.6623 396.184 -60.4146 396.532 -63.8668 396.223C-64.08 405.096 -63.9207 414.649 -63.9152 423.585C-66.3969 423.58 -67.0977 423.543 -69.4006 424.424C-72.4006 423.375 -77.7057 423.578 -80.773 423.96C-81.2769 424.023 -82.0151 423.808 -82.2971 423.396C-83.4046 421.778 -83.0731 416.477 -83.0697 414.424C-85.588 414.262 -90.0626 414.223 -92.5528 414.421C-92.4984 411.158 -92.4869 407.894 -92.5187 404.633C-95.4359 404.654 -99.6445 404.808 -102.461 404.633L-102.445 396.078L-92.7385 395.998C-92.7431 398.766 -92.8026 401.718 -92.7501 404.47C-86.5438 404.334 -79.635 404.578 -73.6315 404.329C-73.5988 401.568 -73.5506 398.846 -73.6318 396.083C-79.9747 396.03 -86.2444 395.686 -92.5629 395.795C-92.538 392.81 -92.4401 389.381 -92.5698 386.438L-111.88 386.38L-111.699 377.625C-107.14 377.638 -103.12 377.638 -98.5565 377.201C-96.8167 377.035 -94.4283 377.24 -92.5986 377.074C-92.2628 367.489 -92.5364 356.693 -92.4894 346.986C-95.3608 347.198 -99.7169 347.244 -102.58 347.023L-102.449 338.855C-99.6192 338.572 -95.9441 338.662 -93.0381 338.703C-92.9017 335.739 -92.8759 332.775 -92.9605 329.812C-96.137 329.888 -99.3147 329.906 -102.492 329.871C-102.463 323.4 -102.695 315.988 -102.433 309.648C-99.5726 309.579 -95.4253 309.408 -92.7049 309.934L-92.7918 329.629C-90.7904 329.646 -84.7705 329.89 -83.3356 329.242C-82.3843 327.449 -83.9994 319.952 -82.396 319.802C-76.7156 319.27 -70.3524 319.482 -64.6349 319.666C-63.4568 319.706 -64.1007 328.473 -64.0777 329.632C-65.4927 329.523 -67.0717 329.537 -68.4923 329.593C-73.316 329.777 -78.2552 329.417 -83.0616 329.535C-83.1494 336.698 -83.1526 343.863 -83.0715 351.029C-83.0411 352.948 -83.1291 356.203 -82.9844 357.993L-65.0876 358.051C-65.0871 355.285 -65.2176 351.181 -65.0525 348.523C-62.2399 348.196 -57.5602 348.332 -54.6033 348.364C-54.5971 351.57 -54.6349 354.776 -54.7169 357.982C-48.9024 357.991 -41.2585 357.756 -35.6286 358.042C-35.562 361.312 -35.2175 373.889 -36.0077 376.205C-36.7895 376.94 -40.1541 377.083 -41.374 377.362C-42.5911 377.641 -43.8347 378.122 -45.0349 378.288C-45.0538 380.989 -45.0045 383.704 -45.3325 386.385C-48.1152 386.396 -51.863 386.304 -54.5662 386.468C-54.498 383.227 -54.4775 379.985 -54.5044 376.742C-44.3099 376.594 -44.5931 378.436 -45.1677 367.378C-45.1755 367.212 -45.1873 367.048 -45.2023 366.882C-48.023 366.906 -51.7328 367.018 -54.5021 366.869C-54.5019 364.333 -54.4107 360.736 -54.6338 358.318C-57.8688 358.302 -61.0869 358.429 -64.3199 358.457L-64.4033 366.813C-70.5534 366.873 -76.921 366.972 -83.0641 366.855C-83.0708 370.017 -83.1768 373.79 -83.0505 376.901C-78.1031 377.265 -69.4635 376.924 -64.13 376.933C-64.1201 379.482 -64.2339 384.244 -64.0136 386.666C-61.3044 386.76 -57.4549 386.7 -54.6888 386.611L-54.7013 395.998C-47.6097 396.15 -40.4938 395.968 -33.4011 396.034C-31.444 396.053 -28.1593 395.852 -26.3737 396.422C-25.9256 397.846 -26.0911 402.624 -26.2439 404.214C-26.4232 406.078 -33.8201 405.35 -35.4359 405.527C-35.7839 410.796 -35.5519 418.003 -35.5986 423.469C-32.7885 423.359 -29.9768 423.29 -27.1646 423.262C-26.5732 423.681 -25.8245 424.251 -25.2257 424.624C-23.1801 424.613 -17.0869 425.306 -15.7912 424.871C-12.3347 423.709 -10.0966 424.46 -6.8094 423.974C-6.96312 427.613 -6.90436 430.434 -6.11523 433.995C-3.65268 434.013 0.488853 434.147 2.8288 433.894C3.08463 431.596 2.89749 426.327 2.85393 423.944C-0.10437 423.801 -3.82829 423.926 -6.8094 423.974C-6.95275 414.689 -6.5446 405.057 -6.80549 395.832C-9.70294 395.682 -13.3879 395.767 -16.3441 395.753C-16.5276 393.188 -16.4227 389.3 -16.4271 386.631C-10.0724 386.597 -3.71743 386.597 2.63729 386.629C2.82304 389.167 2.69698 393.315 2.73062 396.034C8.90511 396.083 15.0798 396.078 21.2543 396.025C21.4569 392.635 21.7289 380.063 21.1241 377.071C18.4237 376.788 15.4463 377.311 12.6995 377.12C6.16759 376.67 -0.241051 376.567 -6.77368 376.424C-7.02489 371.024 -6.7995 363.439 -6.79881 357.86C-2.09425 358.138 2.6873 357.719 7.39324 358.127C8.81685 358.249 10.1591 358.327 11.5898 358.281C11.6514 360.39 11.0104 365.808 12.2273 367.23C13.1653 368.328 19.9059 368.157 20.9621 367.604C21.6176 367.26 21.4449 358.984 21.4458 358.028C19.394 357.88 13.6707 357.767 11.7491 357.979C11.8009 354.013 11.7608 350.581 12.3559 346.659C12.6037 345.025 12.6733 340.362 12.1955 338.825C11.0899 338.281 3.98344 338.332 3.14915 338.599C2.49969 339.853 2.67139 346.189 2.63129 348.097C-0.336914 348.097 -3.88637 348.019 -6.79604 348.24C-6.85573 350.916 -7.06315 355.172 -6.882 357.717C-10.0625 357.588 -13.1584 357.721 -16.4186 357.553C-16.5131 354.513 -16.4667 351.194 -16.4856 348.129C-19.5119 348.03 -22.8756 348.076 -25.9249 348.053C-25.9637 345.013 -25.9314 341.907 -25.9314 338.86C-22.9401 338.786 -8.93916 339.162 -7.17953 338.454C-6.48951 336.852 -6.7852 331.328 -6.81124 329.323C-10.1302 329.272 -13.0639 329.394 -16.4515 329.219C-16.6338 326.502 -16.5976 322.344 -16.5103 319.62C-14.5921 319.454 -12.1286 319.625 -10.1452 319.517C-5.82876 319.281 -1.6462 319.235 2.67693 319.275C2.68983 322.453 2.65273 325.818 2.80069 328.975C5.99936 328.945 9.02979 328.774 12.3167 328.774C12.5583 323.04 12.3649 315.76 12.3681 309.931C15.1695 309.793 18.5014 309.844 21.3264 309.828C20.8418 306.836 21.0957 295.299 21.1186 291.641C16.8201 291.593 12.5265 291.787 8.2227 291.71C4.25265 291.641 -2.7732 290.636 -6.52777 291.473C-7.25951 292.911 -6.994 298.516 -6.98225 300.404C-10.1021 300.397 -13.257 300.353 -16.372 300.473C-16.5787 303.01 -16.4831 307.242 -16.5018 309.908C-19.8122 309.975 -22.6094 309.987 -25.9125 309.844L-25.9503 300.429C-32.1746 300.183 -38.7256 300.586 -45.0495 300.383C-45.1357 297.472 -45.1057 294.368 -45.1267 291.441C-43.3313 291.448 -36.612 291.761 -35.6602 291.038C-35.1589 288.846 -35.388 275.071 -35.4382 272.075ZM12.6438 433.354C17.9536 433.366 23.4205 433.456 28.6913 432.831C32.2037 432.416 35.3657 432.449 38.8896 432.476L39.7446 432.372C40.8186 430.95 39.8783 416.274 40.2355 413.442C40.36 412.435 40.2286 406.929 40.0926 405.917C39.6225 405.412 38.1014 405.345 37.3754 405.343C29.014 405.311 20.6002 405.433 12.2398 405.32C11.6345 406.952 11.9058 409.137 11.7509 410.856C11.208 416.878 11.3375 422.64 12.234 428.63C12.4635 430.162 12.3589 431.778 12.6438 433.354ZM49.7792 433.919C52.8514 433.926 55.9212 433.912 58.9933 433.873C59.2353 431.105 59.0717 426.88 59.021 424.004C56.0203 423.926 53.0196 423.896 50.0212 423.912C49.7562 426.235 49.7078 431.474 49.7792 433.919Z" fill="#9E2184"/> -<path d="M21.2809 414.223L30.8926 414.159C30.9825 416.212 30.9894 420.646 30.6552 422.545L21.1428 422.769C21.1055 420.821 20.9437 415.933 21.2809 414.223Z" fill="#9E2184"/> -<path d="M192.087 224.994C193.469 214.075 190.957 215.113 201.847 214.718C201.49 217.366 201.478 222.028 201.312 224.958C204.836 225.123 209.524 225.137 213.036 225.036C221.531 224.793 220.526 224.66 220.448 232.867L220.393 243.43C217.316 243.307 214.447 243.54 211.259 243.288C211.165 241.216 211.522 235.823 210.99 234.309C210.093 233.685 202.598 233.594 201.766 234.144C201.056 235.802 201.375 243.517 201.596 245.713C202.061 250.355 201.073 258.56 201.971 262.754C203.403 263.964 217.185 262.114 219.724 263.713C220.596 265.045 220.248 270.12 220.227 272.061C217.233 272.079 214.237 272.065 211.241 272.024C211.024 274.547 211.054 279.36 211.135 281.959C213.599 282.107 217.447 281.978 220.017 281.971C219.759 284.428 219.819 286.407 219.492 289.498C219.061 293.561 213.824 290.45 212.555 292.211C211.137 294.176 211.333 308.353 211.354 310.024C214.343 310.116 217.521 310.06 220.526 310.051C220.464 314.195 220.441 318.339 220.46 322.485C220.457 324.518 220.358 327.742 220.483 329.659L192.107 329.682C192.165 327.597 191.743 321.298 192.575 320.109C193.976 319.18 199.213 319.533 201.384 319.514C201.593 316.659 201.501 312.782 201.506 309.844L192.094 309.867C189.1 309.869 185.661 309.802 182.709 310.005C182.349 315.244 182.619 324.354 182.601 329.8C185.59 329.606 189.008 329.786 192.107 329.682C191.794 335.115 192.029 342.46 191.898 348.24C189.724 348.072 185.382 348.323 182.764 348.251C182.559 345.546 182.665 341.342 182.656 338.521C180.107 338.431 175.673 338.438 173.181 338.562L173.17 329.473C171.934 329.429 164.184 329.832 163.769 328.933C162.907 327.064 164.267 321.344 163.124 319.643C161.526 319.037 147.924 319.493 144.603 319.251L144.571 309.977C141.632 309.816 138.074 309.894 135.085 309.892C135.039 306.813 134.951 303.746 135.103 300.671L154.013 300.683C154.135 297.998 154.128 294.236 153.965 291.577C151.904 291.362 147.041 291.528 144.61 291.478L144.575 262.835L134.983 262.844C134.739 268.366 135.327 276.585 134.688 281.731C131.658 281.75 128.629 281.733 125.601 281.683C125.889 276.622 125.82 271.325 125.594 266.262C125.44 262.789 125.059 259.323 125.228 255.84C125.258 255.253 125.26 254.407 125.7 253.964C126.991 252.667 141.625 253.358 144.61 253.215C144.698 250.046 144.629 246.552 144.631 243.359C141.402 243.365 138.362 243.46 135.135 243.225C135.048 240.203 135.066 237.022 135.027 233.982C132.504 233.749 128.136 233.867 125.571 233.968C125.804 231.554 125.61 227.502 125.548 225.001C131.881 224.991 138.217 225.02 144.55 225.089C144.725 227.827 144.656 231.453 144.665 234.226C147.537 234.344 150.969 234.261 153.884 234.263C153.843 237.44 153.868 240.677 153.863 243.861C156.917 243.99 160.388 243.888 163.479 243.858C163.513 246.619 163.61 251.003 163.225 253.646C160.517 253.667 157.938 253.678 155.23 253.84C155.302 257.078 155.527 260.27 155.594 263.533C158.178 263.566 160.759 263.637 163.338 263.743C163.594 266.345 163.444 269.618 163.4 272.28L173.142 272.261C173.373 266.287 173.218 259.399 173.218 253.356L181.234 253.393C181.296 250.254 181.179 247.587 180.992 244.455C178.286 244.441 175.583 244.402 172.877 244.338C172.713 241.91 172.63 227.203 173.19 225.398C174.739 224.699 189.146 225.035 192.087 224.994ZM172.854 308.749C172.833 306.631 172.421 301.773 173.458 300.314C174.891 299.36 180.704 299.818 182.923 299.793L182.932 299.355C182.969 297.82 183.08 296.659 183.393 295.22C183.949 292.658 183.834 283.688 182.589 281.828C181.13 280.95 175.232 281.275 173.091 281.284C171.58 285.732 175.06 291.916 169.685 291.775C167.749 291.724 165.781 291.791 163.84 291.775C163.336 294.515 163.518 306.905 163.548 310.305C165.564 310.353 171.116 310.754 172.552 309.89C172.849 309.337 172.891 309.364 172.854 308.749ZM192.006 291.411C194.078 291.441 199.692 291.625 201.591 291.415C202.216 288.242 202.057 275.575 201.861 272.051C198.623 272.022 195.385 272.04 192.149 272.104C191.833 273.828 191.826 289.36 192.006 291.411Z" fill="#9E2184"/> -<path d="M68.6825 24.151C74.6447 23.9874 81.6256 24.0218 87.6362 24.1053C87.6431 26.9675 87.5463 30.8496 87.7445 33.6259C90.8997 33.7552 94.1447 33.7179 97.3113 33.7187C97.0416 36.1395 97.2353 40.152 97.1799 42.7784C94.0387 42.7537 90.8651 42.692 87.7284 42.8095C87.6915 45.7339 87.574 49.2815 87.6892 52.188C86.1635 52.1502 79.632 51.887 78.6203 52.5364C77.9012 54.527 78.3622 67.849 78.2054 71.2344C76.9678 71.36 69.7564 71.189 69.39 71.7296C68.3414 73.2798 68.7124 87.9277 68.883 90.6228C71.9874 90.6753 75.0895 90.6788 78.1916 90.6334C78.2538 93.8752 78.2838 97.1176 78.2769 100.36C76.689 100.096 68.0464 100.107 65.9122 100.118C61.5633 100.14 54.3658 99.6177 50.3326 100.071C49.6573 101.239 49.6988 108.478 49.897 110.016C47.9725 110.056 42.2661 109.682 41.017 110.382C40.0951 111.516 40.4546 117.353 40.4062 119.514C37.3618 119.679 34.1629 119.583 31.1045 119.548C30.9409 122.47 31.0262 126.36 30.9686 129.4C26.91 129.603 16.2789 129.63 12.5177 129.365C12.0604 124.705 12.4151 114.949 12.3534 109.768L3.18325 109.842C3.04266 106.825 3.10926 103.215 3.0869 100.152C-0.0898781 100.222 -3.51925 100.394 -6.66538 100.203C-6.87718 97.6594 -6.77347 93.4191 -6.78499 90.7447C4.77141 91.8224 2.98343 91.1837 2.85253 81.033C-0.0995502 80.8534 -3.78475 80.9737 -6.80181 81.003C-6.72438 77.9021 -6.54254 74.4895 -6.86727 71.442C-10.0583 71.4019 -13.0344 71.6043 -16.2828 71.4201C-16.5525 68.5784 -16.4324 65.1574 -16.4107 62.2668C-14.443 62.2677 -8.98666 62.5985 -7.51765 61.9744C-6.35632 60.8269 -6.93111 54.8614 -6.78315 52.4553C-3.67113 52.2396 -0.179756 52.5429 2.84906 52.2207L2.78477 62.2947C5.71402 62.4459 9.19133 62.3387 12.1393 62.3037C12.4326 59.7298 12.3439 55.011 12.2165 52.3576C14.7823 52.3795 19.0213 52.4807 21.4447 52.2417C21.4297 55.7303 21.4693 59.2189 21.5631 62.7063C27.5415 62.9469 34.0407 62.4132 40.1735 62.3788C40.2772 59.9691 39.8577 54.432 40.5422 52.6102C42.2662 51.8015 55.9629 52.3186 59.1019 52.1864C59.0927 54.9077 58.9797 59.7918 59.4315 62.3164C61.9574 62.3542 66.2395 62.5966 68.5719 62.4067C68.9775 60.3671 68.7954 54.5196 68.7516 52.2841C66.0321 52.0845 61.9297 52.1924 59.1019 52.1864L59.1411 43.2317C62.31 42.9932 65.8293 43.2458 68.5626 42.9946C68.9429 36.8346 68.2953 29.9342 68.6825 24.151ZM12.5919 100.345L40.3878 100.387C40.881 99.4251 40.8856 74.9892 40.6782 71.6748C34.4579 71.5656 28.1522 71.7697 21.933 71.7331C19.2398 71.7172 14.8726 71.9246 12.3536 71.4932C11.0291 73.3146 12.1457 82.6675 12.2962 85.4905C12.5624 90.4847 12.5315 95.3612 12.5919 100.345ZM21.4979 119.567C24.5293 119.645 27.7144 119.474 30.6897 119.668C31.0677 119.368 31.2751 119.342 31.2244 118.624C31.0561 116.31 31.7222 112.038 30.692 110.154C30.3901 109.91 29.9614 109.57 29.565 109.579C26.9077 109.641 24.2527 109.801 21.5866 109.79C21.39 112.078 21.2527 117.318 21.4979 119.567ZM49.6895 90.9334L59.2586 90.8908C59.6458 89.0676 59.4845 82.9788 59.3623 80.9196C56.2302 80.971 53.0982 80.9839 49.9661 80.9583C49.5674 82.9489 49.6849 88.6514 49.6895 90.9334Z" fill="#9E2184"/> -<path d="M21.5317 81.2385C24.6856 81.1961 27.8384 81.1908 30.9912 81.2224C31.0489 83.4485 31.3093 88.7083 30.7193 90.6308C28.0159 90.7663 24.0058 90.7239 21.3171 90.6099C21.1721 88.9205 21.0742 82.773 21.5317 81.2385Z" fill="#9E2184"/> -<path d="M239.854 376.537C242.606 376.747 246.355 376.518 249.473 376.691C249.582 379.814 249.485 383.439 249.478 386.599L258.397 386.611C258.542 388.95 258.556 393.527 258.217 395.795L249.499 395.811C249.414 398.978 249.469 402.34 249.471 405.523C251.209 405.569 256.895 405.189 258.012 405.811C258.865 407.825 258.489 420.978 258.169 423.887C253.062 424.126 244.998 424.085 239.865 423.894C239.798 420.685 239.909 417.549 239.789 414.297C235.931 414.092 224.101 414.131 220.469 414.407C220.391 417.576 220.444 420.953 220.441 424.136L230.11 424.2C230.319 430.453 230.137 437.194 230.176 443.511C233.389 443.548 236.604 443.534 239.819 443.47L239.826 433.91C242.871 433.783 246.348 433.861 249.427 433.871C249.483 436.986 249.266 440.089 249.381 443.26C246.194 443.315 243.004 443.336 239.817 443.322C239.685 446.212 239.796 449.81 239.815 452.751C238.068 452.453 231.582 452.28 230.188 453.483C228.966 454.537 224.037 454.076 222.105 454.02C221.866 456.825 221.85 459.812 221.868 462.635C227.911 462.642 233.788 462.4 239.803 462.391C239.621 464.032 239.52 470.103 239.815 471.582C237.657 471.236 233.97 471.331 231.762 471.306C228.358 471.266 231.372 478.263 229.605 480.607C228.093 481.158 222.762 480.861 220.9 480.817C220.28 475.267 221.725 468.109 221.594 462.43C218.144 462.375 214.691 462.377 211.241 462.439C211.077 466.415 211.587 477.226 210.914 480.527C210.033 481.262 203.518 480.905 201.981 480.877C202.112 472.038 201.955 462.99 201.907 454.133L198.593 454.085C196.304 452.483 195.14 452.757 192.322 452.783C192.345 449.618 192.34 446.456 192.306 443.294C189.713 443.17 186.371 443.246 183.732 443.241L182.774 441.149C180.817 441.49 175.848 441.577 173.493 441.746C173.237 436.945 174.419 417.696 172.774 414.679C170.821 413.907 157.468 414.347 154.043 414.235C154.027 411.342 154.057 408.452 154.131 405.562C158.807 405.292 168.662 405.968 172.704 405.352C173.518 404.214 173.207 397.807 173.191 396.051H201.301C201.412 393.905 201.119 388.634 201.79 387.012C203.179 386.445 218.939 386.332 220.172 387.035C220.948 388.627 220.469 402.548 220.501 405.498C222.767 405.652 225.936 405.548 228.296 405.555C232.041 405.569 236.046 405.693 239.768 405.564C239.909 402.52 239.828 398.927 239.828 395.839C236.791 395.728 233.408 395.774 230.352 395.756C230.31 392.753 230.299 389.75 230.322 386.747C232.737 386.514 237.148 386.62 239.75 386.581C239.911 383.522 239.831 379.657 239.854 376.537ZM211.269 405.456C205.698 405.313 200.128 405.285 194.557 405.371C192.398 405.394 183.984 405.138 182.681 405.827C181.34 408.544 183.069 428.957 183.126 433.813L199.137 433.857L211.225 433.891C211.384 425.645 211.672 413.617 211.269 405.456ZM201.794 453.67C204.836 453.612 207.878 453.594 210.921 453.617C211.467 452.739 211.257 444.986 211.248 443.297C208.478 443.29 204.979 443.37 202.299 443.119C201.142 444.497 201.663 451.536 201.794 453.67ZM182.866 441.054C182.87 440.178 182.983 438.369 182.679 437.648L182.299 437.367C182.287 438.494 182.186 439.655 182.497 440.72L182.866 441.054Z" fill="#9E2184"/> -<path d="M192.244 414.732C195.063 414.613 198.63 414.571 201.412 414.707C201.426 416.576 201.672 422.525 200.986 423.96C197.932 424.096 195.146 424.209 192.106 423.868C192.039 421.762 191.781 416.532 192.244 414.732Z" fill="#9E2184"/> -<path d="M182.299 437.367L182.68 437.648C182.984 438.369 182.871 440.178 182.866 441.054L182.497 440.72C182.186 439.655 182.288 438.494 182.299 437.367Z" fill="#9E2184"/> -<path d="M-45.7894 100.624C-48.0814 100.501 -52.491 100.898 -54.1886 100.119C-55.3861 98.7212 -55.8895 56.0986 -54.4286 52.7554C-52.9552 51.9949 -46.8512 52.1737 -44.9482 52.2848C-44.8466 55.2876 -45.4675 69.6877 -44.7629 71.1118C-43.6018 71.6525 -36.4054 72.0876 -35.6495 70.9205C-34.5297 69.1913 -35.2063 64.6001 -35.1669 62.3365C-32.897 62.2318 -27.855 62.3848 -26.1314 62.1696C-26.1309 65.2362 -25.8378 89.3983 -26.5753 90.3976C-28.1192 90.9093 -31.0968 90.6986 -32.7862 90.6565L-35.3192 90.6945C-35.5002 92.6691 -35.8489 98.9061 -35.1213 100.55C-33.1508 101.74 -26.8364 99.7724 -26.384 101.928C-25.9387 104.049 -26.4059 107.686 -26.1168 110.184C-20.1622 110.256 -14.2069 110.279 -8.25183 110.253C-4.7819 110.256 -0.249256 110.383 3.14993 110.215C3.09922 112.616 2.65327 114.481 2.4705 116.863C2.21883 120.145 2.96255 126.515 1.52742 129.448C0.14875 129.878 -5.03518 129.643 -6.77983 129.611C-6.79527 127.869 -6.56479 120.706 -7.23431 119.765C-8.60283 119.328 -16.5307 118.709 -16.5489 121.168C-16.5683 123.807 -16.4404 126.707 -16.5298 129.409C-19.5038 129.451 -22.5444 129.394 -25.4902 129.457C-25.5776 132.903 -24.7239 135.699 -24.5137 139.108C-21.661 138.832 -19.3436 138.825 -16.4793 139.032C-16.4726 144.846 -16.6923 152.513 -16.4335 158.203C-13.289 158.304 -10.0506 158.248 -6.89599 158.231C-7.00039 160.612 -7.10847 165.456 -6.93723 167.743C-4.3062 167.86 0.175491 167.917 2.77495 167.701C2.94872 164.548 2.89064 161.311 2.88142 158.147C5.96717 158.212 9.05384 158.229 12.1403 158.196C12.1868 164.562 12.1949 170.929 12.1642 177.295C12.1585 179.961 12.019 184.174 12.1765 186.733C14.9907 186.745 18.8266 186.66 21.5563 186.857C21.465 190.088 21.3192 193.491 21.3696 196.708C23.303 196.755 29.2215 197.266 30.3715 196.099C31.7244 194.726 31.9249 188.786 31.941 186.771C34.6283 186.756 37.3709 186.701 40.0535 186.828C39.8945 193.16 40.5928 198.795 40.1849 205.411C37.0505 205.675 34.0406 205.306 31.109 205.543C31.0237 207.181 31.192 213.796 30.5697 214.64C29.3782 215.082 22.6623 215.076 21.4796 214.51C20.9529 212.896 21.3035 199.332 21.3367 196.793C15.3528 196.708 10.0156 196.646 3.99943 196.251C0.723778 196.037 -3.36335 196.332 -6.77752 196.191C-6.80287 193.035 -6.80724 189.878 -6.79088 186.722C-4.61779 186.756 1.04758 187.258 2.43893 186.209C3.3986 184.711 2.8934 179.436 2.84962 177.192C-8.27834 176.95 -6.87548 175.37 -7.01422 186.476C-8.47147 186.377 -14.8559 186.195 -15.805 186.912C-16.6142 188.87 -16.1025 195.63 -17.3095 195.738C-21.9919 196.16 -30.986 195.945 -35.5886 195.958C-35.5704 201.722 -35.3672 208.984 -35.6592 214.62C-38.3598 214.959 -42.3034 214.877 -45.0902 214.862C-45.0791 212.031 -44.9558 208.209 -45.1068 205.459C-48.1944 205.451 -51.4714 205.499 -54.5426 205.424C-54.6491 202.628 -54.5009 198.782 -54.7307 196.22C-57.7911 196.179 -60.8522 196.192 -63.9121 196.26C-63.819 193.298 -63.745 189.687 -63.852 186.726C-60.0142 186.711 -51.6277 186.474 -48.0826 186.79C-47.9489 189.752 -48.0194 192.631 -48.0667 195.592C-44.0388 195.819 -39.6403 195.766 -35.579 195.79C-35.5594 190.041 -35.2826 182.242 -35.5209 176.631C-31.8438 176.648 -28.0546 176.629 -24.3872 176.767C-21.6103 176.872 -19.0728 177.411 -16.2263 177.295C-16.2353 174.235 -16.1454 170.478 -16.2961 167.473C-22.6868 167.384 -29.0781 167.375 -35.469 167.445C-35.4836 165.783 -35.8429 159.132 -35.1415 158.314C-32.7675 157.314 -27.8288 158.749 -26.3466 157.601C-25.6117 155.466 -25.9594 151.209 -25.9209 148.737C-30.9449 148.764 -40.3739 149.079 -45.1596 148.692C-45.3262 145.612 -45.1755 141.982 -45.1132 138.854C-46.9621 138.861 -53.7404 139.18 -54.7616 138.339C-55.2163 136.495 -55.8174 129.179 -52.6853 129.446C-50.2296 129.655 -47.6136 129.66 -45.1335 129.637C-45.2116 131.914 -45.3234 136.809 -45.1531 138.971C-43.0429 138.979 -37.0819 139.413 -35.7239 138.539C-34.6884 137.07 -35.1355 131.79 -35.1581 129.619C-32.1367 129.611 -28.9286 129.651 -25.9256 129.546C-25.9154 127.468 -25.6792 121.216 -26.3664 119.682C-27.3298 119.303 -33.935 119.376 -34.9516 119.609C-36.1757 120.826 -35.2996 127.525 -35.283 129.586C-37.9498 129.313 -42.2951 129.427 -45.1047 129.427C-45.1236 126.262 -44.8337 123.985 -44.5942 120.869C-44.4633 119.168 -44.7742 116.489 -44.7447 114.679C-44.6675 109.97 -45.8374 105.232 -45.7894 100.624Z" fill="#9E2184"/> -<path d="M163.723 158.19C172.863 158.432 182.64 158.128 191.897 158.231C192.144 160.893 191.946 164.71 191.863 167.439C189.906 167.548 184.366 167.275 183.163 167.972C182.236 169.112 182.575 175.167 182.534 177.265C188.768 177.369 195.159 176.83 201.427 177.336L201.411 186.736L211.197 186.812C211.344 192.994 211.162 199.659 211.215 205.928L230.314 205.7L230.33 214.735C221.45 214.332 210.976 214.626 201.962 214.638C201.997 211.834 202.033 199.063 201.437 196.716C200.593 195.929 193.84 196.216 192.167 196.219C192.128 192.977 192.22 189.773 192.13 186.521C189.185 186.355 185.742 186.496 182.656 186.386C182.58 183.424 182.649 180.206 182.658 177.224L163.672 177.303C163.709 180.32 163.601 183.366 163.527 186.384C161.478 186.397 156.428 186.283 154.691 186.789C153.64 187.88 154.483 191.607 154.276 193.019C153.76 196.559 154.366 202.168 153.736 205.517L152.51 205.508C146.668 205.583 140.826 205.547 134.986 205.399C134.773 208.416 134.854 211.801 134.684 214.951C131.711 214.909 128.454 214.865 125.513 215.176C125.46 217.494 125.214 222.953 125.483 224.987C123.063 224.756 117.894 224.932 115.276 224.95C115.17 221.927 115.292 218.345 115.329 215.28C113.34 215.339 108.491 215.037 107.145 215.929C106.195 217.245 106.58 222.581 106.548 224.775C103.485 224.861 100.452 224.805 97.3684 224.943C97.373 222.072 96.9144 208.485 97.5804 206.812C98.5369 204.419 122.13 207.484 125.227 205.635C125.921 203.308 125.85 189.506 125.428 186.88C124.571 186.098 117.924 186.351 116.172 186.339C116.018 183.711 116.076 180.332 116.053 177.649C118.744 177.801 133.204 177.044 134.366 178.044C134.833 178.448 134.967 179.173 135.006 179.758C135.158 182.008 134.695 184.476 134.571 186.738C134.386 190.113 134.444 193.53 134.527 196.908C137.191 197.064 141.66 196.928 144.37 196.8C144.882 191.818 144.545 182.829 144.644 177.403C150.604 177.11 157.638 177.31 163.727 177.249C163.766 170.896 163.766 164.543 163.723 158.19Z" fill="#9E2184"/> -<path d="M154.062 71.3865C155.444 71.5381 162.909 71.0654 163.26 72.1316C164.345 75.4524 162.702 87.9247 163.889 90.2778C165.306 90.8648 171.294 90.7675 172.872 90.4974C172.644 92.2856 172.884 97.2985 172.531 99.2584C172.372 99.4117 172.213 99.5647 172.054 99.718C170.24 100.358 165.804 100.022 163.608 100.132C163.543 102.893 163.679 106.963 163.446 109.53C158.443 109.902 107.548 109.405 107.145 109.926C106.255 111.075 106.576 117.76 106.749 119.416C112.697 119.493 119.526 119.543 125.453 119.349C125.622 122.683 125.288 126.478 125.553 129.559C123.995 129.286 118.046 129.368 116.115 129.365C115.951 130.852 116.023 132.707 115.79 134.112C114.619 141.174 116.087 148.262 116.009 155.363C115.926 162.682 115.744 170.034 115.753 177.382C110.759 177.268 106.179 177.371 101.261 178.185C100.298 178.344 98.1982 178.232 97.1842 178.209C96.6426 166.73 93.824 168.153 106.364 167.811C106.509 162.766 106.246 157.241 106.417 152.126C106.592 146.861 107.924 134.545 106.942 129.78C105.559 129.132 99.3022 129.41 97.3824 129.434C97.3939 127.369 97.8894 122.008 97.0298 120.754C95.6654 119.801 90.413 120.226 88.2881 120.229C88.4932 118.205 88.454 112.794 88.2973 110.745C90.0166 110.676 95.1376 110.903 96.366 110.611C98.4495 110.114 96.5688 103.53 97.6106 100.879C99.5788 99.4177 121.913 101.192 125.099 100.054C125.894 98.9339 125.573 92.4986 125.566 90.7021L134.953 90.658C134.806 93.5435 134.907 97.4896 134.986 100.411C137.041 100.644 142.285 100.415 144.529 100.369C144.711 97.4534 144.617 93.5795 144.624 90.5935C147.302 90.7583 151.266 90.6571 153.999 90.6124C154.393 86.183 154.078 76.286 154.062 71.3865Z" fill="#9E2184"/> -<path d="M87.7167 319.39C90.1551 319.576 94.8336 319.36 97.3734 319.286C96.9655 324.336 97.2305 333.658 97.1637 339.116C99.7726 339.132 104.306 339.298 106.765 339.118C106.823 335.979 106.839 332.842 106.811 329.703C110.416 329.676 114.105 329.609 117.703 329.703C117.77 332.732 117.606 337.074 117.823 339.865C122.492 340.031 127.168 339.941 131.828 339.597C133.935 339.436 136.088 339.106 138.171 338.98C140.155 338.86 142.338 339.014 144.348 338.913C144.318 341.837 144.242 345.168 144.348 348.083C141.262 348.06 138.03 348.085 134.956 347.996C134.908 351.337 134.898 354.679 134.928 358.019C138.153 358.194 141.554 358.085 144.797 358.037C144.811 354.741 144.281 351.31 144.364 348.334C146.307 348.32 151.808 348.141 153.451 348.613C154.142 349.413 153.88 352.119 153.866 353.246C153.847 354.884 152.746 357.184 152.064 358.726L145.44 358.715C145.375 362.126 145.018 364.746 144.783 368.085C144.599 370.674 144.643 374.197 144.61 376.848C141.497 376.901 138.222 376.995 135.117 376.823C134.903 373.476 135.097 370.261 134.984 366.97C132.271 366.958 128.374 367.037 125.737 366.772C125.737 364.329 125.822 361.109 125.673 358.731C123.937 358.731 122.135 358.754 120.411 358.576C118.636 358.394 116.329 357.694 114.601 357.638C108.908 357.452 103.015 357.588 97.3319 357.774L97.3642 348.526C93.3978 348.592 91.1069 348.325 87.136 348.023C84.6815 347.839 81.2313 347.975 78.6916 347.892C78.6962 344.981 78.7561 341.796 78.6501 338.91C72.8607 339.016 65.3083 339.199 59.5788 339.005C59.3691 335.96 59.4705 332.709 59.4982 329.643L49.9291 329.648C49.9083 326.228 50.0351 322.729 49.9498 319.323C53.0865 319.298 56.2232 319.314 59.3576 319.369C59.5143 322.42 59.3806 326.421 59.4129 329.602C68.0509 329.929 78.8437 329.673 87.6222 329.62C87.8458 326.714 87.7467 322.363 87.7167 319.39Z" fill="#9E2184"/> -<path d="M87.7714 129.637L97.3681 129.57C97.4396 133.817 97.6032 154.323 96.4463 157.633C95.4737 158.285 89.3962 158.003 87.564 158.013C87.322 161.181 87.647 164.388 87.269 167.616C84.266 167.718 81.2584 167.639 78.2646 167.378C78.1148 170.244 78.2277 174.167 78.2254 177.113C80.1521 177.135 85.8171 176.818 87.2944 177.464C88.0918 179.515 87.8798 193.503 86.8887 196.039C86.0614 196.713 70.9057 196.49 68.631 196.506C68.7094 194.379 68.8753 178.524 68.419 177.632L67.6976 177.57C65.0173 177.685 62.3369 177.759 59.6542 177.792C59.6058 175.548 60.2097 169.364 59.3316 168.094C58.0271 167.14 51.899 167.606 49.8778 167.633C49.9193 164.453 49.9192 161.273 49.8801 158.094C46.9116 158.052 43.3785 158.538 40.5023 157.994C39.3453 157.776 39.5459 150.656 40.1889 149.631C41.9796 149.029 56.4945 148.723 58.6817 149.118C59.4307 150.303 59.1334 156.384 59.1311 158.298C65.2316 158.385 71.6893 158.245 77.8451 158.267C77.9005 156.097 77.4902 149.23 78.3314 148.093C79.7995 147.172 84.9413 147.644 87.2552 147.467L87.5801 147.441C88.0618 144.406 87.7138 133.492 87.7714 129.637Z" fill="#9E2184"/> -<path d="M107.016 405.689L115.848 405.691C115.822 411.981 116.249 417.913 116.175 424.145C112.172 424.08 100.535 423.511 97.2927 423.864C97 429.586 97.182 437.169 97.1544 443.011C99.7863 443.013 103.024 442.93 105.613 443.039C105.742 446.263 105.935 449.803 105.905 453.009C112.464 452.969 119.024 452.976 125.583 453.029C125.546 449.888 125.576 446.747 125.675 443.608C128.71 443.525 131.745 443.495 134.781 443.518C135.085 445.583 134.949 451.082 134.677 453.11C131.619 453.163 128.558 453.161 125.5 453.103L125.52 462.88C123.036 462.267 110.102 462.398 106.843 462.398C106.615 465.542 106.624 468.501 106.61 471.651C103.824 471.695 101.038 471.688 98.2514 471.633C98.3228 468.303 98.3459 465.887 98.0693 462.536C97.7997 459.303 97.3226 456.062 97.3364 452.845C93.937 453.011 90.7404 452.822 87.3456 452.727C84.3196 452.644 81.3465 452.778 78.3274 452.495C78.2098 446.323 78.355 439.971 78.4288 433.785C80.367 433.778 86.1541 434.062 87.4194 433.393C88.0001 432.149 88.438 423.778 86.6473 423.373C84.6607 422.921 80.6574 423.297 78.3527 423.244C78.302 420.254 78.2675 417.265 78.249 414.276C82.1601 414.246 86.2878 414.225 90.1596 414.288C93.7642 414.345 103.769 415.518 106.659 414.56C107.272 413.064 106.97 407.682 107.016 405.689Z" fill="#9E2184"/> -<path d="M230.377 348.374C233.539 348.268 236.517 348.307 239.683 348.353C239.849 351.395 239.778 354.893 239.778 357.977C241.981 357.959 257.155 357.521 258.084 358.369C258.729 359.846 258.612 365.152 258.135 366.537C257.328 367.159 249.425 366.917 247.81 366.908C245.148 366.947 242.486 366.929 239.824 366.848C239.78 370.04 239.759 373.232 239.757 376.426C236.623 376.484 233.486 376.486 230.349 376.428V366.859C228.206 366.788 223.182 366.693 221.243 367.048C219.457 367.373 221.296 373.656 220.103 376.004C218.872 376.954 195.756 376.456 192.112 376.518C191.861 379.561 192.036 383.061 191.822 386.329C188.775 386.394 185.724 386.399 182.674 386.339C182.55 379.987 182.642 373.402 182.658 367.035C185.016 367.256 189.632 367.134 192.091 367.127C192.391 361.704 192.133 353.99 192.114 348.369C194.836 348.346 209.238 348.014 210.865 348.735C211.531 350.395 211.193 355.67 211.147 357.698C207.959 357.599 204.788 357.645 201.603 357.671C201.28 359.849 201.315 364.88 201.43 367.166C204.687 367.205 207.941 367.198 211.197 367.15C211.301 364.186 211.227 360.883 211.218 357.892C213.405 358.032 228.266 358.102 229.916 357.68C230.649 356.541 230.365 350.328 230.377 348.374Z" fill="#9E2184"/> -<path d="M78.482 205.984C80.8443 205.874 84.9374 205.807 87.302 205.99C87.703 211.977 87.2098 219.006 87.3642 225.135C90.63 224.994 93.9003 225.041 97.1684 225.054C97.1776 228.012 97.1177 231.272 97.2076 234.204C100.229 234.23 103.919 234.159 106.885 234.31C106.88 236.865 106.754 241.117 106.963 243.536L116.067 243.538C115.991 249.567 116.118 256.682 115.788 262.612C112.794 262.706 109.798 262.757 106.8 262.759C106.816 259.436 106.885 255.969 106.839 252.66L97.3182 252.545C97.3182 249.565 97.3735 246.375 97.2951 243.413C90.8858 243.496 83.8196 243.881 77.5509 243.685C77.4979 245.711 77.2582 250.798 77.4886 252.653C72.688 252.713 64.5248 252.462 60.0952 252.805C60.0675 249.871 59.9868 246.649 60.1505 243.734C65.9445 243.651 71.7408 243.632 77.5347 243.676C77.4057 241.146 76.7857 233.428 78.074 231.602C78.8231 230.543 78.4635 226.858 78.5188 225.435C78.4819 219.962 78.1662 211.314 78.482 205.984Z" fill="#9E2184"/> -<path d="M135.106 119.481C138.291 119.352 141.437 119.443 144.624 119.501C144.633 128.67 144.327 139.682 144.642 148.699C146.809 148.729 152.128 149.192 153.578 148.155C154.513 146.731 154.039 141.151 154.124 138.894C157.86 138.812 169.533 138.612 172.764 139.099L172.723 148.409C170.828 148.996 164.145 148.177 163.808 149.378C163.184 151.59 163.486 155.534 163.516 157.975C160.872 157.972 156.694 157.858 154.228 158.135C154.122 160.322 154.426 165.971 153.49 167.28C152.02 168.252 147.03 167.695 144.645 167.868C144.612 164.665 144.67 161.152 144.564 157.986C141.545 157.93 138.023 158.049 135.11 157.908C135.143 151.724 135.272 145 135.103 138.837C132.531 138.815 128.072 138.933 125.689 138.694C125.673 135.787 125.726 132.422 125.553 129.559C128.272 129.629 132.255 129.722 134.944 129.553C134.967 126.889 134.854 121.955 135.106 119.481Z" fill="#9E2184"/> -<path d="M201.149 119.46C202.269 119.515 210.552 119.827 210.854 119.084C212.071 116.108 210.299 102.468 211.799 100.575C213.145 100.116 218.695 100.042 219.946 100.664C221.755 101.565 219.568 116.507 220.594 119.205C220.727 119.555 221.02 119.552 221.34 119.68C223.417 119.664 228.314 119.115 229.762 120.162C230.651 121.466 230.163 127.315 230.154 129.541C223.15 129.287 215.217 129.536 208.125 129.427C204.489 129.371 195.339 129.225 192.057 129.602C192.05 125.845 192.022 122.019 192.082 118.268C192.133 115.271 192.37 112.761 192.264 109.738C189.363 109.475 185.809 109.722 182.665 109.54C182.624 107.747 182.306 101.612 183.007 100.39C188.561 100.168 195.931 100.249 201.527 100.401C201.854 103.731 201.31 106.898 201.163 110.215C201.027 113.288 201.071 116.386 201.149 119.46Z" fill="#9E2184"/> -<path d="M230.38 214.923C233.457 214.954 236.568 214.814 239.619 215.13C239.896 220.009 239.714 224.93 239.64 229.814C239.622 231.156 239.58 232.392 239.94 233.699C241.608 235.138 254.814 233.454 257.854 234.548C258.963 235.816 258.317 250.21 258.227 252.823C255.176 252.989 252.12 252.941 249.078 252.678C240.219 252.761 229.37 253.019 220.603 252.681C220.394 249.59 220.626 246.695 220.477 243.678C223.701 243.669 227.128 243.713 230.331 243.568C230.488 234.371 230.587 224.096 230.38 214.923Z" fill="#9E2184"/> -<path d="M97.387 43.0875C99.392 42.9231 105.089 42.9105 107.037 43.1354C107.223 49.5104 106.917 56.0299 107.094 62.3261C108.648 62.3307 114.836 61.8296 115.566 62.6761C116.981 64.3125 116.103 70.2277 115.253 72.1915C113.34 72.2102 109.016 71.9078 107.777 72.9272C107.193 73.9753 107.484 79.9643 107.41 82.0424C107.408 91.7749 107.73 91.4887 97.3593 90.4857C97.3708 87.7624 97.5114 83.4967 97.3224 80.9009C94.1005 80.9726 90.8901 81.0735 87.6681 80.9991C87.6681 78.3955 87.5321 74.1546 87.7004 71.6833C90.1042 71.5656 95.7368 72.1417 97.0136 70.9852C97.8433 69.4213 97.3455 64.2387 97.274 62.1606C94.1696 62.0908 90.7518 62.1956 87.728 62.0571C87.6197 58.7579 87.6635 55.4881 87.6888 52.188C89.8921 52.5012 94.921 52.3871 97.3201 52.3657C97.4354 49.3099 97.3916 46.1538 97.387 43.0875Z" fill="#9E2184"/> -<path d="M211.264 52.1181C211.204 50.4074 210.724 44.3938 211.734 43.2958C213.663 42.7802 228.24 42.8298 230.001 43.3255C230.432 46.0554 229.959 49.5994 230.236 52.3537C233.22 52.3717 247.371 52.0336 249.028 52.7395C249.715 53.9278 249.8 61.693 248.982 61.8515C246.35 62.3616 242.607 62.0283 239.837 62.0905C239.738 65.5005 240.13 78.4964 239.408 80.6336C238.141 81.3462 232.181 81.0104 230.365 81.0159C230.363 78.083 230.466 74.4061 230.333 71.5349C228.41 71.5031 222.1 71.7661 220.876 71.0302C219.579 68.6895 221.231 56.427 220.402 53.1875C219.975 51.5215 213.029 52.238 211.264 52.1181Z" fill="#9E2184"/> -<path d="M106.8 262.759C106.717 264.188 106.71 265.737 106.712 267.175C106.731 275.225 106.489 283.388 106.724 291.429C109.775 291.521 123.124 291.07 125.104 291.865C125.89 293.499 125.507 307.133 125.468 309.89C122.568 309.802 119.321 310.024 116.251 309.966C116.263 306.82 116.256 303.672 116.226 300.526C111.84 300.111 102.451 300.422 97.5972 300.374C97.634 294.091 97.2883 288.058 97.3298 281.724C94.4121 281.597 90.7592 281.729 87.7193 281.687C87.5464 278.79 87.664 275.154 87.7077 272.245C90.7154 272.16 94.0042 272.236 97.0348 272.252C97.2353 269.242 97.1593 265.889 97.1501 262.842C100.077 262.895 103.93 262.953 106.8 262.759Z" fill="#9E2184"/> -<path d="M12.2538 252.738C17.0713 252.717 22.8105 252.441 27.5397 252.736C38.3302 253.411 49.0125 253.208 59.826 253.19C59.9136 257.062 59.6163 259.804 59.1808 263.662C58.9295 265.891 59.3928 269.512 58.593 271.602C56.9659 272.333 52.3358 272.061 50.3492 272.04C49.8444 271.69 50.0864 264.63 50.0934 263.508C45.5324 263.185 36.0947 263.515 31.2364 263.533C31.082 266.29 31.0659 269.281 31.0036 272.058L21.427 272.072C21.2702 269.173 21.3219 265.661 21.2926 262.713C18.273 262.505 15.394 262.955 12.0891 262.563C12.0033 260.837 11.7673 254.063 12.2538 252.738Z" fill="#9E2184"/> -<path d="M173.094 24.0927L182.658 24.1033C182.727 27.5903 182.923 50.2938 182.264 51.8427C180.722 52.4745 174.924 52.1426 173.002 52.1016C172.72 55.3818 173.018 58.6365 172.686 62.0643C170.162 62.2102 165.553 62.2544 163.066 62.0096C162.875 55.7729 163.124 49.1158 162.995 42.7899C160.104 42.6742 157.062 42.7574 154.161 42.7862C154.246 41.6968 153.734 34.2336 154.599 33.8794C157.869 32.5371 169.964 34.6863 172.672 33.2273C173.416 31.8523 173.114 26.1142 173.094 24.0927Z" fill="#9E2184"/> -<path d="M78.2763 100.36C80.4657 100.661 85.8979 99.8254 87.1816 101.05C87.8407 103.136 87.9352 115.141 87.8315 118.06C87.7163 121.32 86.746 125.598 87.6448 129.406L68.7717 129.433L68.7648 119.943C67.2967 119.374 52.8763 119.826 49.9701 119.671C49.901 116.412 49.9747 113.492 50.0047 110.257C59.4677 110.264 69.2765 110.412 78.7119 110.285C78.7326 106.5 78.6681 104.161 78.2763 100.36Z" fill="#9E2184"/> -<path d="M153.977 386.597C154.426 380.95 153.972 374.82 154.057 369.136C154.069 368.51 154.315 368.079 154.67 367.602C155.166 367.281 155.629 367.046 156.235 367.035C161.79 366.942 167.397 367.191 172.949 367.005C172.94 372.976 172.9 380.383 172.679 386.325C170.605 386.433 165.403 386.046 164.087 386.839C163.216 387.91 163.548 393.725 163.49 395.767C158.114 395.991 150.033 395.85 144.65 395.746C144.541 392.727 144.597 389.745 144.631 386.724C147.268 386.505 151.276 386.599 153.977 386.597Z" fill="#9E2184"/> -<path d="M201.503 80.768C202.054 76.2837 202.268 72.684 201.902 68.1961C201.831 67.3222 201.748 63.0945 202.236 62.5692C203.695 62.15 209.572 62.0873 210.846 62.7287C211.513 63.9712 211.162 78.5236 211.141 81.1123C213.879 81.3238 218.062 81.1842 220.897 81.2024C223.414 81.2187 228.051 81.3222 230.365 81.0159C230.245 83.3706 230.685 88.1215 229.929 90.0139C228.749 90.5202 195.281 90.6585 192.522 90.2766C191.902 89.1088 191.851 83.2181 192.296 82.0305C192.987 80.1856 199.77 82.1485 201.503 80.768Z" fill="#9E2184"/> -<path d="M250.282 281.846C252.255 281.786 256.505 281.443 258.153 282.153C258.865 283.478 258.381 315.495 258.19 319.54C254.283 319.606 252.386 319.47 248.616 319.086C245.684 319.097 242.755 319.083 239.824 319.049C239.803 313.059 239.708 306.852 239.828 300.883C242.691 300.646 246.242 300.791 249.227 300.708C249.519 295.769 248.886 287.398 249.519 282.353C249.554 282.07 249.946 281.994 250.282 281.846Z" fill="#9E2184"/> -<path d="M201.732 148.736C204.843 148.693 207.957 148.691 211.071 148.732C211.28 151.654 210.995 155.079 211.124 158.196C213.246 158.223 218.625 157.846 219.962 158.776C220.815 160.099 220.43 165.495 220.448 167.656C222.838 167.735 225.221 167.575 227.605 167.615C231.055 167.672 230.483 170.408 230.329 172.849C230.236 174.318 230.213 175.719 229.967 177.181C225.821 177.605 215.735 177.299 211.267 177.283L211.216 167.664C208.144 167.564 204.666 167.633 201.566 167.627C201.419 165.044 201.177 150.661 201.732 148.736Z" fill="#9E2184"/> -<path d="M242.861 177.198C245.147 177.199 257.093 176.826 258.144 177.566C258.833 179.386 258.452 184.31 258.174 186.318C244.488 187.105 251.264 184.916 248.828 195.427C248.713 195.925 241.465 195.674 240.575 195.966C240.126 196.114 237.553 196.448 236.809 196.461C231.409 196.5 226.012 196.474 220.612 196.384C220.377 193.774 220.464 189.453 220.522 186.779C226.689 186.575 233.606 186.702 239.764 186.8C239.821 183.652 239.847 180.504 239.84 177.357C240.766 177.268 241.914 177.245 242.861 177.198Z" fill="#9E2184"/> -<path d="M125.884 24.1766C131.826 23.9435 138.618 24.0919 144.626 24.0991C144.64 27.08 144.73 30.3117 144.497 33.2654C141.531 33.3937 138.067 33.2741 135.006 33.3281C134.852 36.205 134.935 39.8453 134.93 42.7819C132.872 42.7459 127.329 42.5579 125.585 43.0179C125.354 45.6321 125.541 49.2666 125.368 52.185C122.365 52.2505 119.362 52.2468 116.359 52.1737L116.322 51.7042C116.182 49.6849 115.935 34.8042 116.733 33.8947C118.514 33.219 123.335 33.5774 125.43 33.6414C125.686 31.2205 125.241 25.91 125.884 24.1766Z" fill="#9E2184"/> -<path d="M163.626 462.504C169.04 462.223 177.507 462.946 182.462 462.432C182.504 465.44 182.451 468.547 182.437 471.564C180.298 471.522 174.608 470.946 173.368 471.866C172.451 473.262 172.789 477.991 172.794 479.987L172.642 480.52C171.526 481.133 156.633 480.845 154.108 480.812C154.091 474.97 153.978 468.687 154.163 462.882C157.366 462.638 160.337 463.089 163.626 462.504Z" fill="#9E2184"/> -<path d="M69.1622 291.464C72.1997 291.397 75.2373 291.448 78.2703 291.616C78.4086 297.663 78.2887 304.027 78.2542 310.093L87.4821 310.102C87.655 313.144 87.3738 316.223 87.6043 319.194C85.0737 319.113 80.1947 319.47 78.1366 318.666C77.5397 318.392 70.6833 318.323 69.4272 318.231C69.3972 315.465 69.4157 312.697 69.4779 309.931C66.5786 309.756 62.686 309.908 59.5931 309.825L59.5654 300.63C62.5777 300.724 65.6613 300.669 68.6805 300.653C68.7957 298.625 68.4085 292.775 69.1622 291.464Z" fill="#9E2184"/> -<path d="M136.104 462.972C137.643 462.834 143.101 462.744 144.447 463.228C145.083 464.76 144.643 478.259 144.615 480.826C138.515 480.941 132.112 480.842 125.989 480.84C116.537 478.962 117.129 482.11 117.588 471.186C119.353 471.17 123.88 471.566 125.087 470.983C126.138 469.872 125.733 465.085 125.721 463.198C128.784 463.17 133.168 463.288 136.104 462.972Z" fill="#9E2184"/> -<path d="M125.511 415.027C127.205 414.444 141.794 414.615 144.576 414.744C144.772 417.71 144.686 421.174 144.673 424.188C146.74 424.198 152.216 423.845 153.539 424.776C154.447 426.104 153.988 431.667 154.08 433.838C148.15 433.834 140.964 434.043 135.161 433.76C135.05 430.476 135.016 427.187 135.057 423.9L125.597 423.967C125.5 420.987 125.47 418.007 125.511 415.027Z" fill="#9E2184"/> -<path d="M11.7622 23.0588L11.9781 23.0221C12.6294 23.8924 12.1215 48.6563 12.2766 52.1884C9.1685 52.2036 6.0604 52.1963 2.9523 52.1661C3.08897 49.6498 3.00531 46.3412 3.00439 43.7669L2.75755 43.1444C1.45471 42.4889 -4.68244 42.8254 -6.79169 42.712C-6.84055 39.7164 -6.84401 36.7201 -6.8016 33.7241C-3.98136 33.4445 -1.40886 33.748 1.4236 33.596C3.3759 33.7694 3.06545 31.0288 2.87946 29.6922C1.82714 22.1226 5.32866 23.5895 11.7622 23.0588Z" fill="#9E2184"/> -<path d="M154.08 433.838C156.903 433.847 160.805 433.746 163.541 433.912C163.536 437.065 163.483 440.344 163.536 443.488L172.808 443.534C172.829 447.217 174.287 454.576 169.406 453.785C167.502 453.479 165.17 453.735 163.207 453.43L161.199 452.045C155.239 451.884 150.473 452.824 144.615 452.73C144.608 449.814 144.52 446.445 144.631 443.566C155.617 443.481 154.414 445.203 154.08 433.838Z" fill="#9E2184"/> -<path d="M230.559 148.79C233.264 148.762 247.132 149.076 248.996 150.056C249.704 151.444 249.261 156.554 249.469 158.6C254.357 158.706 258.913 156.772 258.406 163.113C258.286 164.612 259.038 165.712 258.418 167.488C256.263 167.626 241.409 167.83 240.158 167.276C239.104 165.473 240.381 161.146 239.632 158.836C236.244 155.989 229.261 162.152 230.268 153.131C230.427 151.712 230.042 150.262 230.559 148.79Z" fill="#9E2184"/> -<path d="M163.974 186.527C166.281 186.905 171.356 186.137 172.467 187.046C172.838 189.585 172.672 195.455 172.64 198.201C172.578 203.687 172.67 209.414 172.52 214.88C169.699 215.013 166.055 214.918 163.17 214.924C160.135 214.937 157.12 214.981 154.087 214.829C153.939 212.285 154.073 208.549 154.094 205.92L163.177 205.905C163.338 204.749 163.486 203.456 163.46 202.288C163.34 196.955 164.082 191.86 163.974 186.527Z" fill="#9E2184"/> -<path d="M40.4569 129.599C49.1364 129.778 60.0306 129.772 68.6847 129.582C68.4681 132.756 68.7193 136.153 68.4911 139.477C64.7759 139.555 60.646 139.243 56.8686 139.132L40.1942 138.806C40.102 136.624 39.8876 131.48 40.4569 129.599Z" fill="#9E2184"/> -<path d="M232.152 264.093L239.619 263.893C239.653 270.252 239.907 276.26 239.773 282.644C235.5 282.764 232.315 282.121 228.119 282.109C225.475 282.132 222.829 282.081 220.19 281.964C220.285 278.744 220.269 275.389 220.299 272.157C222.336 272.22 228.688 272.505 230.273 271.872C231.956 269.936 229.084 265.306 232.152 264.093Z" fill="#9E2184"/> -<path d="M144.138 42.9934C146.848 43.0015 151.54 43.1582 154.092 42.9524C154.08 45.957 154.126 49.1617 154.046 52.1493C150.916 52.2108 147.786 52.2348 144.656 52.2216C144.571 55.3851 144.435 58.9585 144.493 62.1002C141.9 61.7882 137.802 61.9666 135 61.8861C135.016 55.8292 135.163 48.9582 134.977 42.9729L144.138 42.9934Z" fill="#9E2184"/> -<path d="M12.0869 471.633C18.257 471.681 24.4281 471.686 30.5977 471.651C33.1236 471.649 37.8782 471.527 40.2129 471.819C40.2613 473.61 40.5309 479.388 40.0377 480.838C39.6205 480.985 39.798 480.992 39.5122 480.939C34.4396 481.149 28.6641 480.895 23.5016 480.969C20.8519 481.006 14.5741 481.147 12.1514 480.921C12.2213 477.913 12.1263 474.661 12.0869 471.633Z" fill="#9E2184"/> -<path d="M130.568 62.1975C132.091 62.2261 133.354 62.2221 134.873 62.1537L134.921 80.9701L125.511 80.992L125.44 90.4347L120.955 90.4617C119.399 90.4691 117.846 90.4488 116.292 90.4009C115.211 78.8145 116.062 81.7968 125.313 81.0648C125.267 79.8733 125.255 78.7288 125.366 77.5391C125.838 72.4893 125.737 67.4464 125.735 62.3756C127.247 62.2627 129.033 62.2473 130.568 62.1975Z" fill="#9E2184"/> -<path d="M77.5645 252.784L97.1612 252.704V262.759C90.7011 262.628 84.0199 262.93 77.576 262.611C77.5967 259.337 77.5921 256.062 77.5645 252.784Z" fill="#9E2184"/> -<path d="M163.702 119.722C169.775 119.546 176.558 119.596 182.64 119.689C182.649 121.216 182.794 128.753 182.391 129.427C176.187 129.224 169.51 129.716 163.32 129.352C163.253 127.316 162.773 121.053 163.702 119.722Z" fill="#9E2184"/> -<path d="M50.1404 215.121C52.9244 215.14 66.824 214.507 68.0985 215.705C68.6608 217.592 68.5779 223.113 68.0755 224.948C63.4131 225.485 55.4665 224.908 50.6889 224.793C49.3683 224.762 49.6541 216.452 50.1404 215.121Z" fill="#9E2184"/> -<path d="M40.6736 167.937C43.5913 167.836 46.7626 167.885 49.6988 167.879L49.6849 178.197L59.549 178.026C59.5743 180.076 59.8371 184.555 59.0742 186.437C58.959 186.721 58.5211 186.752 58.1316 186.867C54.0431 186.884 53.7343 188.05 48.9128 187.384C49.2585 185.339 49.3623 180.539 49.4683 178.247C47.2258 178.253 44.0039 178.636 41.9896 177.898C41.5978 176.869 41.2936 174.81 41.1691 173.66C40.9801 171.916 39.8762 169.466 40.6736 167.937Z" fill="#9E2184"/> -<path d="M182.723 129.574C185.166 129.733 189.321 129.595 191.893 129.591C192.02 135.85 192.004 142.11 191.847 148.367C189.95 149.089 184.832 148.784 182.693 148.685C182.442 143.739 182.594 134.573 182.723 129.574Z" fill="#9E2184"/> -<path d="M192.97 24.1378C198.008 23.9449 204.823 24.0488 209.939 24.177C210.209 24.254 210.856 24.3423 210.912 24.6792C211.177 26.2644 211.986 32.6635 210.356 33.3271C206.775 33.5213 195.33 33.5973 192.124 33.2459C192.055 30.7187 191.9 27.8315 192.098 25.3117C192.156 24.5609 192.481 24.4571 192.97 24.1378Z" fill="#9E2184"/> -<path d="M230.319 129.616C233.447 129.763 247.876 129.068 249.319 130.177C249.932 132.024 249.547 136.502 249.457 138.613C247.867 139.189 233.073 138.842 230.342 138.812L230.319 129.616Z" fill="#9E2184"/> -<path d="M40.4402 329.415C42.9316 329.782 47.299 329.655 49.9286 329.648C49.7051 334.974 49.8065 342.725 49.8664 348.122C46.8519 348.141 43.3856 348.233 40.4172 348.053C40.2028 342.326 40.4241 335.221 40.4402 329.415Z" fill="#9E2184"/> -<path d="M3.31561 214.936C4.59195 214.916 11.8552 214.532 12.0006 215.545C12.4284 218.523 12.1435 231.252 11.2758 233.756C9.74338 234.268 5.00034 234.547 4.0833 233.902C2.10219 232.508 2.64218 216.112 3.31561 214.936Z" fill="#9E2184"/> -<path d="M220.482 329.659C224.244 329.701 228.005 329.71 231.768 329.687C234.082 329.682 237.399 329.588 239.616 329.895C239.731 332.748 239.634 335.753 239.593 338.618C234.375 338.187 226.313 338.638 220.6 338.456L220.482 329.659Z" fill="#9E2184"/> -<path d="M78.3832 462.658C81.2779 462.476 84.5851 462.575 87.4821 462.651C87.5858 464.995 87.4475 479.07 86.959 480.835C86.6962 480.87 86.4312 480.9 86.1662 480.925C84.7326 481.061 79.3327 481.469 78.9271 480.607C77.7425 478.09 78.1896 465.104 78.3832 462.658Z" fill="#9E2184"/> -<path d="M50.033 196.688L68.5535 196.68C68.542 198.488 68.7724 204.352 68.0511 205.477C62.7872 205.567 55.0619 205.79 49.9086 205.442C49.8487 203.315 49.6527 198.567 50.033 196.688Z" fill="#9E2184"/> -<path d="M172.951 355.502C174.67 355.477 180.035 355.318 181.37 355.689C181.48 355.947 181.589 356.101 181.598 356.352C183.059 361.612 182.345 361.87 182.515 366.988C179.408 366.887 176.074 366.972 172.948 367.005C172.946 363.216 172.886 359.277 172.951 355.502Z" fill="#9E2184"/> -<path d="M220.602 300.321C223.442 300.097 227.203 300.136 230.102 300.194C230.437 302.552 230.201 307.362 230.118 309.897C226.922 309.998 223.723 310.049 220.526 310.051C220.672 306.716 220.487 303.563 220.602 300.321Z" fill="#9E2184"/> -<path d="M22.2791 167.762C24.9507 167.613 28.3571 167.745 31.0305 167.859C31.2379 170.272 31.0997 173.396 31.0559 175.854C31.042 176.732 30.989 176.864 30.5004 177.308C27.4306 177.36 24.3584 177.353 21.2902 177.284C21.2575 174.851 21.0019 170.551 21.4773 168.184C21.5373 167.885 21.8747 167.888 22.2791 167.762Z" fill="#9E2184"/> -<path d="M68.7282 348.129C71.9755 348.088 75.2228 348.072 78.4701 348.079C78.4909 351.148 78.5577 354.617 78.3688 357.65C75.3312 357.406 72.1876 357.892 68.7858 357.544C68.6775 354.518 68.5969 351.139 68.7282 348.129Z" fill="#9E2184"/> -<path d="M21.6382 24.0825L31.0217 24.0941C31.054 26.2823 31.2499 32.0676 30.7498 33.9572L30.4594 33.995C19.9705 35.292 21.5515 33.3459 21.6382 24.0825Z" fill="#9E2184"/> -<path d="M246.523 90.2859C247.367 90.1211 248.482 90.0386 249.275 90.3986C249.83 91.6189 249.501 98.1372 249.459 99.9552C247.3 100.011 244.917 99.957 242.739 99.9545C241.776 99.9499 240.785 99.9114 239.819 99.8865C239.738 96.821 239.74 93.754 239.823 90.6885C242.234 90.5341 244.048 90.78 246.523 90.2859Z" fill="#9E2184"/> -<path d="M21.4595 225.057C24.6492 224.974 27.8435 224.978 31.0332 225.066C31.3282 227.148 31.3074 232.16 31.0239 234.258C27.7905 234.296 24.5547 234.29 21.3203 234.239C21.2615 232.172 21.0442 226.878 21.4595 225.057Z" fill="#9E2184"/> -<path d="M241.689 110.124C244.431 110.089 246.941 110.167 249.679 110.267C249.746 112.459 250.029 116.65 249.506 118.815C249.377 119.344 248.794 119.368 248.386 119.438C246.303 119.433 242.06 119.716 240.264 119.244C239.483 117.527 239.492 112.692 240.045 110.767C240.686 110.067 240.486 110.29 241.689 110.124Z" fill="#9E2184"/> -<path d="M68.8275 272.273C71.948 272.151 75.1123 272.236 78.2398 272.28C78.279 274.704 78.4219 279.468 78.1361 281.74C74.9856 281.773 71.8328 281.766 68.68 281.717C68.6154 279.256 68.4449 274.575 68.8275 272.273Z" fill="#9E2184"/> -<path d="M165.896 338.756C168.242 338.671 170.59 338.8 172.973 338.719C172.978 340.69 173.114 346.228 172.819 347.843C172.164 348.327 172.155 348.159 171.155 348.198C168.599 348.219 165.845 348.129 163.275 348.085C163.25 346.15 163.036 340.768 163.526 339.136C164.128 338.733 165.121 338.791 165.896 338.756Z" fill="#9E2184"/> -<path d="M172.942 81.2247L182.607 81.2342C183.015 92.8242 183.81 90.1496 172.872 90.4974C172.882 87.7901 172.727 83.7845 172.942 81.2247Z" fill="#9E2184"/> -<path d="M2.93709 138.888C5.99057 138.832 9.04474 138.831 12.0985 138.884C12.2607 141.989 12.1538 145.428 12.1141 148.566L2.85251 148.536C2.92373 145.57 2.73175 141.647 2.93709 138.888Z" fill="#9E2184"/> -<path d="M97.4382 309.892C100.132 309.874 104.391 309.731 106.982 310.074C106.943 312.759 107.111 316.737 106.855 319.238C103.963 319.24 100.197 319.136 97.3736 319.286C97.3621 316.152 97.3276 313.024 97.4382 309.892Z" fill="#9E2184"/> -<path d="M134.99 81.0662C138.247 81.2282 141.416 81.1662 144.649 81.2533L144.624 90.5935C142.732 90.3156 137.189 90.4409 135.018 90.4465C135.009 87.3522 135.046 84.1501 134.99 81.0662Z" fill="#9E2184"/> -<path d="M2.85211 148.536C2.55388 149.968 2.70922 156.382 2.83759 158.026C-0.32928 158 -3.4579 157.944 -6.6227 158.088C-7.12051 157.435 -6.83518 150.044 -6.78863 148.776C-4.4095 148.646 0.930459 148.876 2.85211 148.536Z" fill="#9E2184"/> -<path d="M249.487 443.442C251.942 443.594 255.867 443.46 258.427 443.451C258.482 446.131 258.664 450.755 258.155 453.239C256.572 453.755 251.19 453.49 249.379 453.066L249.487 443.442Z" fill="#9E2184"/> -<path d="M230.861 24.1371C233.837 24.0848 236.812 24.0539 239.79 24.0447C239.833 26.6415 239.988 29.9815 239.688 32.5799C239.619 33.1574 239.382 33.1897 238.983 33.4412C236.081 33.5337 233.175 33.5469 230.271 33.4809C230.177 31.6226 229.866 25.2424 230.861 24.1371Z" fill="#9E2184"/> -<path d="M116.29 424.186C119.104 424.29 122.614 424.177 125.481 424.165C125.521 426.853 125.647 431.109 125.359 433.67C123.884 433.979 118.072 433.834 116.35 433.815C116.191 430.639 116.265 427.374 116.29 424.186Z" fill="#9E2184"/> -<path d="M21.3965 452.949C24.5961 452.873 27.7973 452.875 30.9962 452.956C31.04 455.611 31.1483 459.533 30.8879 462.112C28.1084 462.23 24.3126 462.184 21.5419 462.066C21.2914 459.701 21.3902 455.463 21.3965 452.949Z" fill="#9E2184"/> -<path d="M97.385 24.1128C100.499 24.0522 103.753 24.0995 106.88 24.0995C106.924 27.0029 107.025 30.4661 106.797 33.3151C103.73 33.4974 100.432 33.486 97.3389 33.5244L97.385 24.1128Z" fill="#9E2184"/> -<path d="M182.878 453.011C185.95 452.926 189.024 452.949 192.096 453.082C192.096 455.689 192.212 459.918 191.806 462.322C189.098 462.485 185.413 462.393 182.629 462.4C182.608 460.425 182.438 454.663 182.878 453.011Z" fill="#9E2184"/> -<path d="M-2.06631 262.699C-0.678198 262.607 1.25566 262.653 2.68687 262.646C2.68295 265.67 2.7461 269.014 2.53177 271.996C1.18399 272.068 -0.633952 272.019 -2.01815 272.022L-6.81742 271.996C-6.89325 269.042 -6.82942 265.817 -6.82849 262.842L-2.06631 262.699Z" fill="#9E2184"/> -<path d="M239.814 471.582C242.829 471.619 246.415 471.573 249.386 471.72C249.351 474.723 249.271 477.839 249.287 480.835C246.254 480.852 242.829 480.939 239.831 480.812C239.773 477.736 239.766 474.659 239.814 471.582Z" fill="#9E2184"/> -<path d="M50.0441 24.1224C53.1554 24.0454 56.4211 24.0981 59.5463 24.1056C59.5463 27.1769 59.4725 30.2478 59.325 33.3156L49.8896 33.2845C49.8436 31.3506 49.6407 25.7657 50.0441 24.1224Z" fill="#9E2184"/> -<path d="M22.1266 43.0851C24.2854 43.0384 29.1483 42.5567 30.6325 43.5383C31.6789 45.0181 31.0589 50.0276 30.9598 52.161C27.9107 52.252 24.5988 52.193 21.5297 52.1926C21.5025 49.5719 21.4433 46.7671 21.5481 44.1497C21.579 43.3748 21.6376 43.4903 22.1266 43.0851Z" fill="#9E2184"/> -<path d="M40.4357 309.876L49.8526 309.878C49.9287 312.794 49.6107 316.412 49.8066 319.083C46.8819 318.982 43.388 319.081 40.4196 319.088C40.2329 316.02 40.2375 312.944 40.4357 309.876Z" fill="#9E2184"/> -<path d="M-6.77863 300.634L2.66115 300.692C2.69296 303.734 2.66575 306.776 2.58001 309.816C-0.545833 309.869 -3.67237 309.876 -6.79845 309.837C-6.85307 306.836 -6.78946 303.649 -6.77863 300.634Z" fill="#9E2184"/> -<path d="M182.601 471.617C185.639 471.681 188.861 471.628 191.915 471.631C192.083 474.675 192.004 477.717 191.894 480.762C190.055 480.997 184.659 480.856 182.668 480.842C182.528 477.95 182.601 474.551 182.601 471.617Z" fill="#9E2184"/> -<path d="M239.814 452.75C242.873 452.806 246.323 452.769 249.34 452.958C249.31 454.813 249.388 460.467 249.04 461.939C246.351 461.962 242.481 461.884 239.872 462.055C239.886 458.952 239.865 455.853 239.814 452.75Z" fill="#9E2184"/> -<path d="M249.482 338.867C252.465 338.818 255.452 338.825 258.434 338.885C258.478 340.743 258.881 346.903 257.952 347.972C256.231 348.085 250.305 348.5 249.247 347.569C248.833 345.979 248.975 340.441 249.482 338.867Z" fill="#9E2184"/> -<path d="M12.2031 148.627C13.7671 148.819 19.6217 148.72 21.5749 148.745C21.5878 151.006 21.698 155.737 21.3726 157.793C20.0642 158.112 13.9291 157.989 12.3022 157.982C12.341 154.863 12.308 151.744 12.2031 148.627Z" fill="#9E2184"/> -<path d="M154.401 225.088C157.187 225.013 160.642 224.974 163.391 225.143C163.562 227.147 163.726 232.412 163.2 234.19L153.988 234.162C153.991 232.228 153.689 226.175 154.401 225.088Z" fill="#9E2184"/> -<path d="M249.934 262.895C252.654 262.851 255.675 262.775 258.36 263.049C258.492 264.84 258.84 271.132 257.95 272.259C255.712 272.215 251.356 272.812 250.031 272.031C248.86 270.616 248.784 264.294 249.934 262.895Z" fill="#9E2184"/> -<path d="M144.493 62.1002C147.535 62.2166 150.988 62.117 153.924 62.3309C153.901 64.4833 153.735 69.3471 153.938 71.3448C151.082 71.3667 147.399 71.4821 144.622 71.3005C144.608 68.3056 144.648 65.0779 144.493 62.1002Z" fill="#9E2184"/> -<path d="M183.021 196.519C186.028 196.478 189.036 196.463 192.043 196.474C191.76 199.4 192.336 201.965 191.746 205.39C189.861 205.613 185.424 206.117 183.696 205.45C182.002 204.796 182.276 197.66 183.021 196.519Z" fill="#9E2184"/> -<path d="M78.4701 81.2397C81.4431 81.1155 84.5383 81.2489 87.599 81.127C87.4215 83.9353 87.834 87.7297 87.3039 90.4091L78.2742 90.435C78.318 88.2236 78.076 83.1277 78.4701 81.2397Z" fill="#9E2184"/> -<path d="M107.435 366.873C110.06 366.735 113.386 366.806 116.062 366.793C116.126 368.41 116.564 375 115.347 375.758C113.603 375.737 107.733 376.534 106.981 374.981C106.223 373.412 106.525 369.59 106.636 367.733C106.668 367.187 107.048 367.101 107.435 366.873Z" fill="#9E2184"/> -<path d="M125.686 310.143C127.795 310.323 132.566 310.134 134.949 310.116C134.785 313.096 135.094 316.189 134.785 319.166C132.925 319.461 127.507 319.245 125.502 319.164C125.702 316.119 125.677 313.19 125.686 310.143Z" fill="#9E2184"/> -<path d="M125.489 234.211C125.493 236.921 125.599 240.604 125.263 243.217C122.428 243.391 119.029 243.335 116.146 243.348C116.265 240.521 116.194 237.153 116.231 234.263C119.284 234.206 122.426 234.228 125.489 234.211Z" fill="#9E2184"/> -<path d="M144.555 329.655C147.565 329.586 150.796 329.664 153.825 329.689C153.848 332.013 153.963 336.461 153.631 338.629L144.546 338.636C144.357 336.191 144.445 332.107 144.555 329.655Z" fill="#9E2184"/> -<path d="M249.061 205.878C253.113 205.938 259.197 204.297 258.547 210.039C258.363 211.685 258.812 213.221 258.169 214.899C256.229 214.891 251.467 215.417 250.269 214.689C249.503 213.745 248.95 207.236 249.061 205.878Z" fill="#9E2184"/> -<path d="M-55.4382 725.075C-58.9999 724.892 -72.0334 725.4 -74.551 724.738C-75.0864 723.784 -75.0557 717.607 -74.6153 716.4C-73.3613 715.775 -49.4712 716.042 -46.1533 716.033C-46.4347 718.354 -46.3573 722.853 -46.2349 725.22C-43.2704 725.356 -39.5276 725.268 -36.4891 725.293C-36.4506 728.414 -36.4875 731.604 -36.4893 734.729C-39.7044 734.697 -42.9194 734.701 -46.1342 734.743C-46.2725 736.895 -46.8164 742.48 -45.7832 743.987C-44.3831 744.985 -38.6892 744.457 -36.4905 744.42C-36.2275 741.475 -36.3808 737.799 -36.4301 734.773L-12.0541 734.766C-8.21634 734.766 -2.16629 734.607 1.45438 734.992C1.59358 737.778 1.4214 741.648 1.36032 744.478C3.39743 744.413 9.48645 744.763 10.86 744.201C11.4823 742.224 11.2426 728.276 11.2357 725.234C15.6538 725.081 26.1263 725.616 29.876 725.104C29.8829 728.066 29.9843 731.811 29.717 734.69C26.7578 734.814 23.2316 734.743 20.2401 734.745C20.0742 737.914 20.1664 741.263 20.2078 744.443C23.4413 744.48 36.8154 743.959 38.7975 745.047C39.8461 747.089 39.1409 750.968 39.6133 753.471C30.5905 753.113 20.9753 753.427 11.9317 753.558C9.92896 753.588 11.8257 760.77 10.5996 762.57C9.04395 763.213 3.30757 762.899 1.34766 762.864L1.35179 772.314C3.55876 772.507 7.15179 772.39 9.44957 772.385C12.9458 772.378 16.8707 772.434 20.3346 772.231C20.413 775.114 20.1502 779.767 20.4314 782.298C14.8103 782.632 7.26241 782.427 1.50392 782.415C1.31723 785.361 1.38913 788.702 1.39259 791.687C3.75006 791.906 8.46777 791.724 10.9776 791.687C11.0698 794.791 11.0651 797.898 10.9637 801.005C8.30414 801.231 4.37233 801.072 1.45322 801.191C1.2209 803.798 1.33037 808.251 1.31677 810.991C6.97432 810.975 14.9163 810.719 20.3876 811.06C20.6642 820.44 21.6805 820.108 11.904 819.611C11.5906 820.5 10.0511 826.956 10.0972 827.654C10.2954 830.685 18.4079 828.352 20.0304 829.611C20.7587 831.251 20.3116 837.193 20.4291 839.634L29.8829 839.613C30.2701 844.868 29.6525 852.786 29.6893 858.537C32.8629 858.562 36.1378 858.497 39.3229 858.477C39.6802 855.743 39.5303 849.092 39.5027 846.137C39.4497 840.705 39.6317 834.828 39.452 829.442C36.4052 829.387 33.1994 829.477 30.1019 829.442C30.0189 820.067 30.0143 810.694 30.088 801.318C33.2339 801.261 36.3822 801.261 39.5304 801.321C39.7124 805.614 39.1823 808.838 38.5854 812.978C38.3826 814.37 38.4725 818.518 38.4771 820.088C45.1446 820.302 51.7659 819.735 58.5809 820.424C58.7676 817.393 58.6984 814.063 58.6938 811C64.6952 810.814 71.1852 810.924 77.2005 810.968C77.295 820.509 77.2926 830.053 77.1889 839.597C86.2855 839.825 96.3109 839.604 105.488 839.62C105.756 843.208 105.613 854.838 105.414 858.253C102.305 858.486 99.1826 858.449 96.0666 858.415C96.2095 855.363 96.2003 851.922 96.145 848.869C93.4877 848.686 89.5421 848.76 86.8479 848.802C86.7165 851.874 86.6266 855.43 86.7972 858.474C83.9394 858.26 80.4247 858.502 77.3272 858.35C77.3756 855.172 77.3826 851.996 77.3549 848.818C74.9327 848.569 70.3117 848.786 67.7074 848.841C67.6268 852.086 67.7628 855.209 67.4102 858.442C64.262 858.461 61.4064 858.922 58.2836 859.371C58.2145 856.456 58.5832 853.844 58.65 850.993C58.7353 847.357 58.6915 843.598 58.6846 839.952C61.1829 839.733 65.3451 839.846 67.9702 839.848C68.2214 835.992 67.7997 832.92 67.5484 829.085C63.9854 829.064 61.8766 829.14 58.3158 828.659C55.9973 828.864 50.7058 827.735 48.9588 828.712C48.1545 831.06 48.3642 857.619 49.4128 858.885C51.4548 859.71 55.9697 859.468 58.2836 859.371C58.2606 861.825 58.1591 864.877 58.249 867.276C53.0981 867.267 43.8401 867.009 39.051 867.458C38.9173 870.68 38.9173 873.727 38.9265 876.953C42.1162 876.935 45.3889 876.877 48.567 877.002C48.7353 881.166 48.3204 885.209 48.3596 889.362C48.4333 897.29 48.1752 905.204 47.9332 913.126C47.818 916.926 47.977 920.839 47.8641 924.658L39.3667 924.628C38.7583 916.087 39.8645 905.267 39.5488 896.29C36.9975 896.299 32.3536 896.17 29.9659 896.373C29.8737 899.256 30.0258 903.536 29.6732 906.186L20.1894 906.2C20.0972 902.879 20.2171 899.431 20.1041 896.209C17.4837 896.232 3.18309 896.062 1.77332 896.638C1.03629 898.251 1.35712 903.616 1.31148 905.734C-1.47949 905.485 -5.05408 905.555 -7.85036 905.721L-7.93102 918.219C-7.93862 919.726 -8.05154 923.25 -7.91348 924.633C-14.1772 924.471 -20.4952 924.748 -26.7806 924.566C-26.8488 922.45 -27.3618 917.666 -26.3063 916.163C-24.9299 915.186 -19.416 915.615 -17.2046 915.608C-16.9534 909.53 -17.1184 902.448 -17.1235 896.297C-20.2862 896.251 -23.6059 896.313 -26.7813 896.324C-26.5672 893.273 -26.5888 889.897 -26.5524 886.811C-32.7361 886.815 -39.9952 887.002 -46.0798 886.684C-46.3315 889.537 -46.3103 893.644 -46.2773 896.527L-26.8366 896.5C-26.8444 899.546 -26.909 902.591 -27.0302 905.633C-28.9495 905.651 -34.3061 905.324 -35.717 905.87C-36.9802 907.182 -36.4179 912.731 -36.6497 915.405C-39.7426 915.435 -42.8355 915.437 -45.9284 915.416C-45.989 912.238 -45.942 908.975 -45.9874 905.769C-48.1948 905.449 -53.2193 905.651 -55.5539 905.725C-55.367 902.814 -55.4163 899.182 -55.4756 896.264C-60.1691 896.186 -64.8992 896.34 -69.5973 896.269C-71.1733 896.246 -72.7985 896.221 -74.3606 896.426C-75.0497 897.677 -74.7022 903.999 -74.8292 906.142C-76.3547 906.209 -80.1811 906.451 -81.4964 906.158C-85.4086 905.287 -87.6234 904.914 -91.6239 904.955C-92.3561 905.624 -92.7232 906.103 -93.3552 906.878C-93.4375 908.91 -93.9715 913.596 -93.0867 915.041C-91.9226 915.953 -86.0535 915.603 -83.9654 915.704C-83.7377 917.995 -83.6769 931.83 -84.3496 933.517C-85.97 934.183 -118.28 933.845 -122.51 933.812C-122.271 928.191 -122.438 921.397 -122.434 915.691C-119.184 915.522 -115.927 915.518 -112.676 915.681C-112.485 918.523 -112.648 922.01 -112.501 925.068C-109.682 925.179 -105.93 925.168 -103.131 925.05C-102.869 922.04 -103.016 917.802 -103.027 914.67C-103.066 908.622 -103.066 902.572 -103.028 896.525C-101.086 896.536 -95.8187 896.707 -94.3082 896.41C-92.3658 896.027 -94.3167 889.258 -93.224 887.251C-91.6064 886.543 -86.1593 886.877 -83.915 886.866C-83.6896 884.428 -83.2549 879.074 -83.2706 876.907C-79.3586 876.967 -79.0332 878.295 -74.5019 878.422C-71.3862 876.799 -68.7605 877.154 -65.2555 877.145C-65.1958 880.367 -65.2474 883.582 -65.1783 886.813C-62.4661 887.016 -58.4463 886.93 -55.6325 886.949C-55.3606 883.884 -55.4631 879.744 -55.4836 876.656L-65.0333 876.721C-65.2122 870.738 -65.0006 864.646 -65.2576 858.686L-74.4789 858.705C-74.5542 855.656 -74.5093 852.425 -74.5151 849.362C-77.6623 849.184 -80.4146 849.532 -83.8668 849.223C-84.08 858.096 -83.9207 867.649 -83.9152 876.585C-86.3969 876.58 -87.0977 876.543 -89.4006 877.424C-92.4006 876.375 -97.7057 876.578 -100.773 876.96C-101.277 877.023 -102.015 876.808 -102.297 876.396C-103.405 874.778 -103.073 869.477 -103.07 867.424C-105.588 867.262 -110.063 867.223 -112.553 867.421C-112.498 864.158 -112.487 860.894 -112.519 857.633C-115.436 857.654 -119.645 857.808 -122.461 857.633L-122.445 849.078L-112.739 848.998C-112.743 851.766 -112.803 854.718 -112.75 857.47C-106.544 857.334 -99.635 857.578 -93.6315 857.329C-93.5988 854.568 -93.5506 851.846 -93.6318 849.083C-99.9747 849.03 -106.244 848.686 -112.563 848.795C-112.538 845.81 -112.44 842.381 -112.57 839.438L-131.88 839.38L-131.699 830.625C-127.14 830.638 -123.12 830.638 -118.556 830.201C-116.817 830.035 -114.428 830.24 -112.599 830.074C-112.263 820.489 -112.536 809.693 -112.489 799.986C-115.361 800.198 -119.717 800.244 -122.58 800.023L-122.449 791.855C-119.619 791.572 -115.944 791.662 -113.038 791.703C-112.902 788.739 -112.876 785.775 -112.96 782.812C-116.137 782.888 -119.315 782.906 -122.492 782.871C-122.463 776.4 -122.695 768.988 -122.433 762.648C-119.573 762.579 -115.425 762.408 -112.705 762.934L-112.792 782.629C-110.79 782.646 -104.771 782.89 -103.336 782.242C-102.384 780.449 -103.999 772.952 -102.396 772.802C-96.7156 772.27 -90.3524 772.482 -84.6349 772.666C-83.4568 772.706 -84.1007 781.473 -84.0777 782.632C-85.4927 782.523 -87.0717 782.537 -88.4923 782.593C-93.316 782.777 -98.2552 782.417 -103.062 782.535C-103.149 789.698 -103.153 796.863 -103.072 804.029C-103.041 805.948 -103.129 809.203 -102.984 810.993L-85.0876 811.051C-85.0871 808.285 -85.2176 804.181 -85.0525 801.523C-82.2399 801.196 -77.5602 801.332 -74.6033 801.364C-74.5971 804.57 -74.6349 807.776 -74.7169 810.982C-68.9024 810.991 -61.2585 810.756 -55.6286 811.042C-55.562 814.312 -55.2175 826.889 -56.0077 829.205C-56.7895 829.94 -60.1541 830.083 -61.374 830.362C-62.5911 830.641 -63.8347 831.122 -65.0349 831.288C-65.0538 833.989 -65.0045 836.704 -65.3325 839.385C-68.1152 839.396 -71.863 839.304 -74.5662 839.468C-74.498 836.227 -74.4775 832.985 -74.5044 829.742C-64.3099 829.594 -64.5931 831.436 -65.1677 820.378C-65.1755 820.212 -65.1873 820.048 -65.2023 819.882C-68.023 819.906 -71.7328 820.018 -74.5021 819.869C-74.5019 817.333 -74.4107 813.736 -74.6338 811.318C-77.8688 811.302 -81.0869 811.429 -84.3199 811.457L-84.4033 819.813C-90.5534 819.873 -96.921 819.972 -103.064 819.855C-103.071 823.017 -103.177 826.79 -103.051 829.901C-98.1031 830.265 -89.4635 829.924 -84.13 829.933C-84.1201 832.482 -84.2339 837.244 -84.0136 839.666C-81.3044 839.76 -77.4549 839.7 -74.6888 839.611L-74.7013 848.998C-67.6097 849.15 -60.4938 848.968 -53.4011 849.034C-51.444 849.053 -48.1593 848.852 -46.3737 849.422C-45.9256 850.846 -46.0911 855.624 -46.2439 857.214C-46.4232 859.078 -53.8201 858.35 -55.4359 858.527C-55.7839 863.796 -55.5519 871.003 -55.5986 876.469C-52.7885 876.359 -49.9768 876.29 -47.1646 876.262C-46.5732 876.681 -45.8245 877.251 -45.2257 877.624C-43.1801 877.613 -37.0869 878.306 -35.7912 877.871C-32.3347 876.709 -30.0966 877.46 -26.8094 876.974C-26.9631 880.613 -26.9044 883.434 -26.1152 886.995C-23.6527 887.013 -19.5111 887.147 -17.1712 886.894C-16.9154 884.596 -17.1025 879.327 -17.1461 876.944C-20.1044 876.801 -23.8283 876.926 -26.8094 876.974C-26.9528 867.689 -26.5446 858.057 -26.8055 848.832C-29.7029 848.682 -33.3879 848.767 -36.3441 848.753C-36.5276 846.188 -36.4227 842.3 -36.4271 839.631C-30.0724 839.597 -23.7174 839.597 -17.3627 839.629C-17.177 842.167 -17.303 846.315 -17.2694 849.034C-11.0949 849.083 -4.92017 849.078 1.25432 849.025C1.45689 845.635 1.72887 833.063 1.12411 830.071C-1.57629 829.788 -4.55373 830.311 -7.30046 830.12C-13.8324 829.67 -20.2411 829.567 -26.7737 829.424C-27.0249 824.024 -26.7995 816.439 -26.7988 810.86C-22.0942 811.138 -17.3127 810.719 -12.6068 811.127C-11.1832 811.249 -9.8409 811.327 -8.41016 811.281C-8.34862 813.39 -8.98956 818.808 -7.77267 820.23C-6.83467 821.328 -0.0941467 821.157 0.962097 820.604C1.61755 820.26 1.44493 811.984 1.44585 811.028C-0.606018 810.88 -6.32927 810.767 -8.25092 810.979C-8.19906 807.013 -8.23915 803.581 -7.64408 799.659C-7.39632 798.025 -7.32674 793.362 -7.8045 791.825C-8.91006 791.281 -16.0166 791.332 -16.8509 791.599C-17.5003 792.853 -17.3286 799.189 -17.3687 801.097C-20.3369 801.097 -23.8864 801.019 -26.796 801.24C-26.8557 803.916 -27.0631 808.172 -26.882 810.717C-30.0625 810.588 -33.1584 810.721 -36.4186 810.553C-36.5131 807.513 -36.4667 804.194 -36.4856 801.129C-39.5119 801.03 -42.8756 801.076 -45.9249 801.053C-45.9637 798.013 -45.9314 794.907 -45.9314 791.86C-42.9401 791.786 -28.9392 792.162 -27.1795 791.454C-26.4895 789.852 -26.7852 784.328 -26.8112 782.323C-30.1302 782.272 -33.0639 782.394 -36.4515 782.219C-36.6338 779.502 -36.5976 775.344 -36.5103 772.62C-34.5921 772.454 -32.1286 772.625 -30.1452 772.517C-25.8288 772.281 -21.6462 772.235 -17.3231 772.275C-17.3102 775.453 -17.3473 778.818 -17.1993 781.975C-14.0006 781.945 -10.9702 781.774 -7.68327 781.774C-7.44174 776.04 -7.63509 768.76 -7.63187 762.931C-4.83052 762.793 -1.49864 762.844 1.32645 762.828C0.841766 759.836 1.09575 748.299 1.11858 744.641C-3.1799 744.593 -7.47353 744.787 -11.7773 744.71C-15.7474 744.641 -22.7732 743.636 -26.5278 744.473C-27.2595 745.911 -26.994 751.516 -26.9823 753.404C-30.1021 753.397 -33.257 753.353 -36.372 753.473C-36.5787 756.01 -36.4831 760.242 -36.5018 762.908C-39.8122 762.975 -42.6094 762.987 -45.9125 762.844L-45.9503 753.429C-52.1746 753.183 -58.7256 753.586 -65.0495 753.383C-65.1357 750.472 -65.1057 747.368 -65.1267 744.441C-63.3313 744.448 -56.612 744.761 -55.6602 744.038C-55.1589 741.846 -55.388 728.071 -55.4382 725.075ZM-7.35622 886.354C-2.04645 886.366 3.4205 886.456 8.69131 885.831C12.2037 885.416 15.3657 885.449 18.8896 885.476L19.7446 885.372C20.8186 883.95 19.8783 869.274 20.2355 866.442C20.36 865.435 20.2286 859.929 20.0926 858.917C19.6225 858.412 18.1014 858.345 17.3754 858.343C9.01399 858.311 0.600235 858.433 -7.76025 858.32C-8.36546 859.952 -8.09418 862.137 -8.24906 863.856C-8.79205 869.878 -8.66254 875.64 -7.76601 881.63C-7.53646 883.162 -7.64108 884.778 -7.35622 886.354ZM29.7792 886.919C32.8514 886.926 35.9212 886.912 38.9933 886.873C39.2353 884.105 39.0717 879.88 39.021 877.004C36.0203 876.926 33.0196 876.896 30.0212 876.912C29.7562 879.235 29.7078 884.474 29.7792 886.919Z" fill="#9E2184"/> -<path d="M172.087 677.994C173.469 667.075 170.957 668.113 181.847 667.718C181.49 670.366 181.478 675.028 181.312 677.958C184.836 678.123 189.524 678.137 193.036 678.036C201.531 677.793 200.526 677.66 200.448 685.867L200.393 696.43C197.316 696.307 194.447 696.54 191.259 696.288C191.165 694.216 191.522 688.823 190.99 687.309C190.093 686.685 182.598 686.594 181.766 687.144C181.056 688.802 181.375 696.517 181.596 698.713C182.061 703.355 181.073 711.56 181.971 715.754C183.403 716.964 197.185 715.114 199.724 716.713C200.596 718.045 200.248 723.12 200.227 725.061C197.233 725.079 194.237 725.065 191.241 725.024C191.024 727.547 191.054 732.36 191.135 734.959C193.599 735.107 197.447 734.978 200.017 734.971C199.759 737.428 199.819 739.407 199.492 742.498C199.061 746.561 193.824 743.45 192.555 745.211C191.137 747.176 191.333 761.353 191.354 763.024C194.343 763.116 197.521 763.06 200.526 763.051C200.464 767.195 200.441 771.339 200.46 775.485C200.457 777.518 200.358 780.742 200.483 782.659L172.107 782.682C172.165 780.597 171.743 774.298 172.575 773.109C173.976 772.18 179.213 772.533 181.384 772.514C181.593 769.659 181.501 765.782 181.506 762.844L172.094 762.867C169.1 762.869 165.661 762.802 162.709 763.005C162.349 768.244 162.619 777.354 162.601 782.8C165.59 782.606 169.008 782.786 172.107 782.682C171.794 788.115 172.029 795.46 171.898 801.24C169.724 801.072 165.382 801.323 162.764 801.251C162.559 798.546 162.665 794.342 162.656 791.521C160.107 791.431 155.673 791.438 153.181 791.562L153.17 782.473C151.934 782.429 144.184 782.832 143.769 781.933C142.907 780.064 144.267 774.344 143.124 772.643C141.526 772.037 127.924 772.493 124.603 772.251L124.571 762.977C121.632 762.816 118.074 762.894 115.085 762.892C115.039 759.813 114.951 756.746 115.103 753.671L134.013 753.683C134.135 750.998 134.128 747.236 133.965 744.577C131.904 744.362 127.041 744.528 124.61 744.478L124.575 715.835L114.983 715.844C114.739 721.366 115.327 729.585 114.688 734.731C111.658 734.75 108.629 734.733 105.601 734.683C105.889 729.622 105.82 724.325 105.594 719.262C105.44 715.789 105.059 712.323 105.228 708.84C105.258 708.253 105.26 707.407 105.7 706.964C106.991 705.667 121.625 706.358 124.61 706.215C124.698 703.046 124.629 699.552 124.631 696.359C121.402 696.365 118.362 696.46 115.135 696.225C115.048 693.203 115.066 690.022 115.027 686.982C112.504 686.749 108.136 686.867 105.571 686.968C105.804 684.554 105.61 680.502 105.548 678.001C111.881 677.991 118.217 678.02 124.55 678.089C124.725 680.827 124.656 684.453 124.665 687.226C127.537 687.344 130.969 687.261 133.884 687.263C133.843 690.44 133.868 693.677 133.863 696.861C136.917 696.99 140.388 696.888 143.479 696.858C143.513 699.619 143.61 704.003 143.225 706.646C140.517 706.667 137.938 706.678 135.23 706.84C135.302 710.078 135.527 713.27 135.594 716.533C138.178 716.566 140.759 716.637 143.338 716.743C143.594 719.345 143.444 722.618 143.4 725.28L153.142 725.261C153.373 719.287 153.218 712.399 153.218 706.356L161.234 706.393C161.296 703.254 161.179 700.587 160.992 697.455C158.286 697.441 155.583 697.402 152.877 697.338C152.713 694.91 152.63 680.203 153.19 678.398C154.739 677.699 169.146 678.035 172.087 677.994ZM152.854 761.749C152.833 759.631 152.421 754.773 153.458 753.314C154.891 752.36 160.704 752.818 162.923 752.793L162.932 752.355C162.969 750.82 163.08 749.659 163.393 748.22C163.949 745.658 163.834 736.688 162.589 734.828C161.13 733.95 155.232 734.275 153.091 734.284C151.58 738.732 155.06 744.916 149.685 744.775C147.749 744.724 145.781 744.791 143.84 744.775C143.336 747.515 143.518 759.905 143.548 763.305C145.564 763.353 151.116 763.754 152.552 762.89C152.849 762.337 152.891 762.364 152.854 761.749ZM172.006 744.411C174.078 744.441 179.692 744.625 181.591 744.415C182.216 741.242 182.057 728.575 181.861 725.051C178.623 725.022 175.385 725.04 172.149 725.104C171.833 726.828 171.826 742.36 172.006 744.411Z" fill="#9E2184"/> -<path d="M48.6825 477.151C54.6447 476.987 61.6256 477.022 67.6362 477.105C67.6431 479.968 67.5463 483.85 67.7445 486.626C70.8997 486.755 74.1447 486.718 77.3113 486.719C77.0416 489.14 77.2353 493.152 77.1799 495.778C74.0387 495.754 70.8651 495.692 67.7284 495.81C67.6915 498.734 67.574 502.282 67.6892 505.188C66.1635 505.15 59.632 504.887 58.6203 505.536C57.9012 507.527 58.3622 520.849 58.2054 524.234C56.9678 524.36 49.7564 524.189 49.39 524.73C48.3414 526.28 48.7124 540.928 48.883 543.623C51.9874 543.675 55.0895 543.679 58.1916 543.633C58.2538 546.875 58.2838 550.118 58.2769 553.36C56.689 553.096 48.0464 553.107 45.9122 553.118C41.5633 553.14 34.3658 552.618 30.3326 553.071C29.6573 554.239 29.6988 561.478 29.897 563.016C27.9725 563.056 22.2661 562.682 21.017 563.382C20.0951 564.516 20.4546 570.353 20.4062 572.514C17.3618 572.679 14.1629 572.583 11.1045 572.548C10.9409 575.47 11.0262 579.36 10.9686 582.4C6.91001 582.603 -3.72105 582.63 -7.4823 582.365C-7.93955 577.705 -7.58487 567.949 -7.64663 562.768L-16.8168 562.842C-16.9573 559.825 -16.8907 556.215 -16.9131 553.152C-20.0899 553.222 -23.5193 553.394 -26.6654 553.203C-26.8772 550.659 -26.7735 546.419 -26.785 543.745C-15.2286 544.822 -17.0166 544.184 -17.1475 534.033C-20.0996 533.853 -23.7847 533.974 -26.8018 534.003C-26.7244 530.902 -26.5425 527.49 -26.8673 524.442C-30.0583 524.402 -33.0344 524.604 -36.2828 524.42C-36.5525 521.578 -36.4324 518.157 -36.4107 515.267C-34.443 515.268 -28.9867 515.599 -27.5177 514.974C-26.3563 513.827 -26.9311 507.861 -26.7831 505.455C-23.6711 505.24 -20.1798 505.543 -17.1509 505.221L-17.2152 515.295C-14.286 515.446 -10.8087 515.339 -7.86074 515.304C-7.56735 512.73 -7.65608 508.011 -7.78353 505.358C-5.21772 505.38 -0.978703 505.481 1.44468 505.242C1.4297 508.73 1.46933 512.219 1.56313 515.706C7.54149 515.947 14.0407 515.413 20.1735 515.379C20.2772 512.969 19.8577 507.432 20.5422 505.61C22.2662 504.802 35.9629 505.319 39.1019 505.186C39.0927 507.908 38.9797 512.792 39.4315 515.316C41.9574 515.354 46.2395 515.597 48.5719 515.407C48.9775 513.367 48.7954 507.52 48.7516 505.284C46.0321 505.085 41.9297 505.192 39.1019 505.186L39.1411 496.232C42.31 495.993 45.8293 496.246 48.5626 495.995C48.9429 489.835 48.2953 482.934 48.6825 477.151ZM-7.4081 553.345L20.3878 553.387C20.881 552.425 20.8856 527.989 20.6782 524.675C14.4579 524.566 8.15223 524.77 1.93303 524.733C-0.760227 524.717 -5.12738 524.925 -7.64641 524.493C-8.97091 526.315 -7.85428 535.667 -7.70378 538.491C-7.43759 543.485 -7.46848 548.361 -7.4081 553.345ZM1.49791 572.567C4.52926 572.645 7.71435 572.474 10.6897 572.668C11.0677 572.368 11.2751 572.342 11.2244 571.624C11.0561 569.31 11.7222 565.038 10.692 563.154C10.3901 562.91 9.96142 562.57 9.56501 562.579C6.90771 562.641 4.2527 562.801 1.58664 562.79C1.39005 565.079 1.25269 570.318 1.49791 572.567ZM29.6895 543.933L39.2586 543.891C39.6458 542.068 39.4845 535.979 39.3623 533.92C36.2302 533.971 33.0982 533.984 29.9661 533.958C29.5674 535.949 29.6849 541.651 29.6895 543.933Z" fill="#9E2184"/> -<path d="M1.53166 534.239C4.68563 534.196 7.83844 534.191 10.9912 534.222C11.0489 536.449 11.3093 541.708 10.7193 543.631C8.01591 543.766 4.00575 543.724 1.3171 543.61C1.17214 541.921 1.07418 535.773 1.53166 534.239Z" fill="#9E2184"/> -<path d="M-65.7894 553.624C-68.0814 553.501 -72.491 553.898 -74.1886 553.119C-75.3861 551.721 -75.8895 509.099 -74.4286 505.755C-72.9552 504.995 -66.8512 505.174 -64.9482 505.285C-64.8466 508.288 -65.4675 522.688 -64.7629 524.112C-63.6018 524.652 -56.4054 525.088 -55.6495 523.92C-54.5297 522.191 -55.2063 517.6 -55.1669 515.336C-52.897 515.232 -47.855 515.385 -46.1314 515.17C-46.1309 518.236 -45.8378 542.398 -46.5753 543.398C-48.1192 543.909 -51.0968 543.699 -52.7862 543.656L-55.3192 543.694C-55.5002 545.669 -55.8489 551.906 -55.1213 553.55C-53.1508 554.74 -46.8364 552.772 -46.384 554.927C-45.9387 557.049 -46.4059 560.686 -46.1168 563.184C-40.1622 563.256 -34.2069 563.279 -28.2518 563.253C-24.7819 563.256 -20.2493 563.383 -16.8501 563.215C-16.9008 565.616 -17.3467 567.481 -17.5295 569.863C-17.7812 573.145 -17.0375 579.515 -18.4726 582.448C-19.8512 582.878 -25.0352 582.643 -26.7798 582.611C-26.7953 580.869 -26.5648 573.706 -27.2343 572.765C-28.6028 572.328 -36.5307 571.709 -36.5489 574.168C-36.5683 576.807 -36.4404 579.707 -36.5298 582.409C-39.5038 582.451 -42.5444 582.394 -45.4902 582.457C-45.5776 585.903 -44.7239 588.699 -44.5137 592.108C-41.661 591.832 -39.3436 591.825 -36.4793 592.032C-36.4726 597.846 -36.6923 605.513 -36.4335 611.203C-33.289 611.304 -30.0506 611.248 -26.896 611.231C-27.0004 613.612 -27.1085 618.456 -26.9372 620.743C-24.3062 620.86 -19.8245 620.917 -17.2251 620.701C-17.0513 617.548 -17.1094 614.311 -17.1186 611.147C-14.0328 611.212 -10.9462 611.228 -7.85973 611.196C-7.81317 617.562 -7.8051 623.929 -7.83575 630.295C-7.84151 632.961 -7.98096 637.174 -7.82355 639.733C-5.00929 639.745 -1.17336 639.66 1.55631 639.857C1.46505 643.088 1.31916 646.491 1.36964 649.708C3.30303 649.755 9.22148 650.266 10.3715 649.099C11.7244 647.726 11.9249 641.786 11.941 639.771C14.6283 639.756 17.3709 639.701 20.0535 639.828C19.8945 646.16 20.5928 651.795 20.1849 658.411C17.0505 658.675 14.0406 658.306 11.109 658.543C11.0237 660.181 11.192 666.796 10.5697 667.64C9.3782 668.082 2.66233 668.076 1.47956 667.51C0.952942 665.896 1.30349 652.332 1.33668 649.793C-4.64722 649.708 -9.98441 649.646 -16.0006 649.251C-19.2762 649.037 -23.3634 649.332 -26.7775 649.191C-26.8029 646.035 -26.8072 642.878 -26.7909 639.722C-24.6178 639.756 -18.9524 640.258 -17.5611 639.209C-16.6014 637.71 -17.1066 632.436 -17.1504 630.192C-28.2783 629.95 -26.8755 628.37 -27.0142 639.476C-28.4715 639.377 -34.8559 639.194 -35.805 639.912C-36.6142 641.87 -36.1025 648.63 -37.3095 648.738C-41.9919 649.16 -50.986 648.945 -55.5886 648.958C-55.5704 654.722 -55.3672 661.984 -55.6592 667.62C-58.3598 667.959 -62.3034 667.877 -65.0902 667.862C-65.0791 665.031 -64.9558 661.209 -65.1068 658.459C-68.1944 658.451 -71.4714 658.499 -74.5426 658.424C-74.6491 655.628 -74.5009 651.782 -74.7307 649.22C-77.7911 649.179 -80.8522 649.192 -83.9121 649.26C-83.819 646.298 -83.745 642.687 -83.852 639.726C-80.0142 639.71 -71.6277 639.474 -68.0826 639.79C-67.9489 642.752 -68.0194 645.631 -68.0667 648.592C-64.0388 648.819 -59.6403 648.766 -55.579 648.79C-55.5594 643.041 -55.2826 635.242 -55.5209 629.631C-51.8438 629.648 -48.0546 629.629 -44.3872 629.767C-41.6103 629.872 -39.0728 630.411 -36.2263 630.295C-36.2353 627.235 -36.1454 623.478 -36.2961 620.473C-42.6868 620.384 -49.0781 620.375 -55.469 620.445C-55.4836 618.783 -55.8429 612.132 -55.1415 611.314C-52.7675 610.314 -47.8288 611.749 -46.3466 610.601C-45.6117 608.466 -45.9594 604.209 -45.9209 601.737C-50.9449 601.764 -60.3739 602.079 -65.1596 601.692C-65.3262 598.612 -65.1755 594.982 -65.1132 591.854C-66.9621 591.861 -73.7404 592.18 -74.7616 591.339C-75.2163 589.495 -75.8174 582.179 -72.6853 582.446C-70.2296 582.655 -67.6136 582.66 -65.1335 582.637C-65.2116 584.914 -65.3234 589.809 -65.1531 591.971C-63.0429 591.979 -57.0819 592.413 -55.7239 591.539C-54.6884 590.07 -55.1355 584.79 -55.1581 582.619C-52.1367 582.611 -48.9286 582.651 -45.9256 582.546C-45.9154 580.468 -45.6792 574.216 -46.3664 572.682C-47.3298 572.303 -53.935 572.376 -54.9516 572.609C-56.1757 573.826 -55.2996 580.525 -55.283 582.586C-57.9498 582.313 -62.2951 582.427 -65.1047 582.427C-65.1236 579.262 -64.8337 576.985 -64.5942 573.869C-64.4633 572.168 -64.7742 569.489 -64.7447 567.679C-64.6675 562.97 -65.8374 558.232 -65.7894 553.624Z" fill="#9E2184"/> -<path d="M143.723 611.19C152.863 611.432 162.64 611.128 171.897 611.231C172.144 613.893 171.946 617.71 171.863 620.439C169.906 620.548 164.366 620.275 163.163 620.972C162.236 622.112 162.575 628.167 162.534 630.265C168.768 630.369 175.159 629.83 181.427 630.336L181.411 639.736L191.197 639.812C191.344 645.994 191.162 652.659 191.215 658.928L210.314 658.7L210.33 667.735C201.45 667.332 190.976 667.626 181.962 667.638C181.997 664.834 182.033 652.063 181.437 649.716C180.593 648.929 173.84 649.216 172.167 649.218C172.128 645.977 172.22 642.773 172.13 639.521C169.185 639.355 165.742 639.496 162.656 639.386C162.58 636.424 162.649 633.206 162.658 630.224L143.672 630.303C143.709 633.32 143.601 636.366 143.527 639.384C141.478 639.397 136.428 639.282 134.691 639.789C133.64 640.88 134.483 644.607 134.276 646.019C133.76 649.559 134.366 655.168 133.736 658.517L132.51 658.507C126.668 658.583 120.826 658.547 114.986 658.399C114.773 661.416 114.854 664.801 114.684 667.951C111.711 667.909 108.454 667.865 105.513 668.176C105.46 670.493 105.214 675.953 105.483 677.987C103.063 677.756 97.8939 677.932 95.2758 677.95C95.1698 674.927 95.292 671.345 95.3288 668.28C93.3399 668.339 88.4908 668.037 87.1449 668.929C86.1954 670.245 86.5802 675.581 86.548 677.775C83.485 677.861 80.4521 677.805 77.3684 677.943C77.373 675.072 76.9144 661.484 77.5804 659.812C78.5369 657.419 102.13 660.484 105.227 658.634C105.921 656.308 105.85 642.506 105.428 639.88C104.571 639.098 97.9239 639.35 96.1723 639.339C96.0179 636.711 96.0756 633.332 96.0525 630.649C98.7444 630.801 113.204 630.044 114.366 631.044C114.833 631.448 114.967 632.173 115.006 632.758C115.158 635.008 114.695 637.476 114.571 639.738C114.386 643.113 114.444 646.53 114.527 649.908C117.191 650.064 121.66 649.928 124.37 649.8C124.882 644.818 124.545 635.829 124.644 630.403C130.604 630.11 137.638 630.31 143.727 630.249C143.766 623.896 143.766 617.543 143.723 611.19Z" fill="#9E2184"/> -<path d="M134.062 524.386C135.444 524.538 142.909 524.065 143.26 525.132C144.345 528.452 142.702 540.925 143.889 543.278C145.306 543.865 151.294 543.768 152.872 543.497C152.644 545.286 152.884 550.299 152.531 552.258C152.372 552.412 152.213 552.565 152.054 552.718C150.24 553.358 145.804 553.022 143.608 553.132C143.543 555.893 143.679 559.963 143.446 562.53C138.443 562.902 87.5484 562.405 87.1451 562.926C86.2554 564.075 86.5758 570.76 86.7486 572.416C92.697 572.493 99.5258 572.543 105.453 572.349C105.622 575.683 105.288 579.478 105.553 582.559C103.995 582.286 98.0462 582.368 96.1149 582.365C95.9512 583.852 96.0227 585.707 95.7899 587.112C94.6192 594.174 96.0872 601.262 96.0089 608.363C95.9259 615.682 95.7438 623.034 95.7531 630.382C90.7588 630.268 86.1794 630.371 81.2612 631.185C80.2978 631.344 78.1982 631.232 77.1842 631.209C76.6426 619.73 73.824 621.153 86.3638 620.811C86.509 615.766 86.2462 610.241 86.4168 605.126C86.5919 599.861 87.924 587.545 86.9422 582.78C85.5594 582.132 79.3022 582.41 77.3824 582.434C77.3939 580.369 77.8894 575.008 77.0298 573.754C75.6654 572.801 70.413 573.226 68.2881 573.229C68.4932 571.205 68.454 565.794 68.2973 563.745C70.0166 563.676 75.1376 563.903 76.366 563.611C78.4495 563.114 76.5688 556.53 77.6106 553.879C79.5788 552.418 101.913 554.192 105.099 553.054C105.894 551.934 105.573 545.499 105.566 543.702L114.953 543.658C114.806 546.544 114.907 550.49 114.986 553.411C117.041 553.644 122.285 553.415 124.529 553.369C124.711 550.453 124.617 546.579 124.624 543.594C127.302 543.758 131.266 543.657 133.999 543.612C134.393 539.183 134.078 529.286 134.062 524.386Z" fill="#9E2184"/> -<path d="M67.7714 582.637L77.3681 582.57C77.4396 586.817 77.6032 607.323 76.4463 610.633C75.4737 611.285 69.3962 611.003 67.564 611.013C67.322 614.181 67.647 617.388 67.269 620.616C64.266 620.718 61.2584 620.639 58.2646 620.378C58.1148 623.244 58.2277 627.167 58.2254 630.113C60.1521 630.135 65.8171 629.818 67.2944 630.464C68.0918 632.515 67.8798 646.503 66.8887 649.039C66.0614 649.713 50.9057 649.49 48.631 649.506C48.7094 647.379 48.8753 631.524 48.419 630.632L47.6976 630.57C45.0173 630.685 42.3369 630.759 39.6542 630.792C39.6058 628.548 40.2097 622.364 39.3316 621.094C38.0271 620.14 31.899 620.606 29.8778 620.633C29.9193 617.453 29.9192 614.273 29.8801 611.094C26.9116 611.052 23.3785 611.538 20.5023 610.994C19.3453 610.776 19.5459 603.656 20.1889 602.631C21.9796 602.029 36.4945 601.723 38.6817 602.118C39.4307 603.303 39.1334 609.384 39.1311 611.298C45.2316 611.385 51.6893 611.245 57.8451 611.267C57.9005 609.097 57.4902 602.23 58.3314 601.093C59.7995 600.172 64.9413 600.644 67.2552 600.467L67.5801 600.441C68.0618 597.406 67.7138 586.492 67.7714 582.637Z" fill="#9E2184"/> -<path d="M58.482 658.984C60.8443 658.874 64.9374 658.807 67.302 658.99C67.703 664.977 67.2098 672.006 67.3642 678.135C70.63 677.994 73.9003 678.041 77.1684 678.054C77.1776 681.012 77.1177 684.272 77.2076 687.204C80.229 687.23 83.9188 687.159 86.8849 687.31C86.8803 689.865 86.7536 694.117 86.9633 696.536L96.0668 696.538C95.9907 702.567 96.1175 709.682 95.7879 715.612C92.7942 715.706 89.7981 715.757 86.7997 715.759C86.8158 712.436 86.8849 708.969 86.8388 705.66L77.3182 705.545C77.3182 702.565 77.3735 699.375 77.2951 696.413C70.8858 696.496 63.8196 696.881 57.5509 696.685C57.4979 698.711 57.2582 703.798 57.4886 705.653C52.688 705.713 44.5248 705.462 40.0952 705.805C40.0675 702.871 39.9868 699.649 40.1505 696.734C45.9445 696.651 51.7408 696.632 57.5347 696.676C57.4057 694.146 56.7857 686.428 58.074 684.602C58.8231 683.543 58.4635 679.858 58.5188 678.435C58.4819 672.962 58.1662 664.314 58.482 658.984Z" fill="#9E2184"/> -<path d="M115.106 572.481C118.291 572.352 121.437 572.443 124.624 572.501C124.633 581.67 124.327 592.682 124.642 601.699C126.809 601.729 132.128 602.192 133.578 601.155C134.513 599.731 134.039 594.151 134.124 591.894C137.86 591.812 149.533 591.612 152.764 592.099L152.723 601.409C150.828 601.996 144.145 601.177 143.808 602.378C143.184 604.59 143.486 608.534 143.516 610.975C140.872 610.972 136.694 610.858 134.228 611.135C134.122 613.322 134.426 618.971 133.49 620.28C132.02 621.252 127.03 620.695 124.645 620.868C124.612 617.665 124.67 614.152 124.564 610.986C121.545 610.93 118.023 611.049 115.11 610.908C115.143 604.724 115.272 598 115.103 591.837C112.531 591.815 108.072 591.933 105.689 591.694C105.673 588.787 105.726 585.422 105.553 582.559C108.272 582.629 112.255 582.722 114.944 582.553C114.967 579.889 114.854 574.955 115.106 572.481Z" fill="#9E2184"/> -<path d="M181.149 572.46C182.269 572.515 190.552 572.827 190.854 572.084C192.071 569.108 190.299 555.468 191.799 553.575C193.145 553.116 198.695 553.042 199.946 553.664C201.755 554.565 199.568 569.507 200.594 572.205C200.727 572.555 201.02 572.552 201.34 572.68C203.417 572.664 208.314 572.115 209.762 573.162C210.651 574.466 210.163 580.315 210.154 582.541C203.15 582.287 195.217 582.536 188.125 582.427C184.489 582.371 175.339 582.225 172.057 582.602C172.05 578.845 172.022 575.019 172.082 571.268C172.133 568.271 172.37 565.761 172.264 562.738C169.363 562.475 165.809 562.722 162.665 562.54C162.624 560.747 162.306 554.612 163.007 553.39C168.561 553.168 175.931 553.249 181.527 553.401C181.854 556.731 181.31 559.898 181.163 563.215C181.027 566.288 181.071 569.386 181.149 572.46Z" fill="#9E2184"/> -<path d="M210.38 667.923C213.457 667.954 216.568 667.814 219.619 668.13C219.896 673.009 219.714 677.93 219.64 682.814C219.622 684.156 219.58 685.392 219.94 686.699C221.608 688.138 234.814 686.454 237.854 687.548C238.963 688.816 238.317 703.21 238.227 705.823C235.176 705.989 232.12 705.941 229.078 705.678C220.219 705.761 209.37 706.019 200.603 705.681C200.394 702.59 200.626 699.695 200.477 696.678C203.701 696.669 207.128 696.713 210.331 696.568C210.488 687.371 210.587 677.096 210.38 667.923Z" fill="#9E2184"/> -<path d="M77.387 496.087C79.392 495.923 85.0892 495.91 87.0367 496.135C87.2234 502.51 86.9168 509.03 87.0943 515.326C88.6477 515.331 94.8357 514.83 95.5663 515.676C96.9814 517.312 96.1033 523.228 95.2529 525.192C93.34 525.21 89.0164 524.908 87.7765 525.927C87.1934 526.975 87.4838 532.964 87.4101 535.042C87.4078 544.775 87.7304 544.489 77.3593 543.486C77.3708 540.762 77.5114 536.497 77.3224 533.901C74.1005 533.973 70.8901 534.074 67.6681 533.999C67.6681 531.395 67.5321 527.155 67.7004 524.683C70.1042 524.566 75.7368 525.142 77.0136 523.985C77.8433 522.421 77.3455 517.239 77.274 515.161C74.1696 515.091 70.7518 515.196 67.728 515.057C67.6197 511.758 67.6635 508.488 67.6888 505.188C69.8921 505.501 74.921 505.387 77.3201 505.366C77.4354 502.31 77.3916 499.154 77.387 496.087Z" fill="#9E2184"/> -<path d="M191.264 505.118C191.204 503.407 190.724 497.394 191.734 496.296C193.663 495.78 208.24 495.83 210.001 496.326C210.432 499.055 209.959 502.599 210.236 505.354C213.22 505.372 227.371 505.034 229.028 505.739C229.715 506.928 229.8 514.693 228.982 514.852C226.35 515.362 222.607 515.028 219.837 515.091C219.738 518.501 220.13 531.496 219.408 533.634C218.141 534.346 212.181 534.01 210.365 534.016C210.363 531.083 210.466 527.406 210.333 524.535C208.41 524.503 202.1 524.766 200.876 524.03C199.579 521.69 201.231 509.427 200.402 506.188C199.975 504.521 193.029 505.238 191.264 505.118Z" fill="#9E2184"/> -<path d="M86.7998 715.759C86.7168 717.188 86.7099 718.737 86.7122 720.175C86.7307 728.225 86.4886 736.388 86.7237 744.429C89.7751 744.521 103.124 744.07 105.104 744.865C105.89 746.499 105.507 760.133 105.468 762.89C102.568 762.802 99.3212 763.023 96.2513 762.966C96.2628 759.82 96.2559 756.672 96.226 753.526C91.8402 753.111 82.4508 753.422 77.5972 753.374C77.634 747.091 77.2883 741.057 77.3298 734.724C74.4121 734.597 70.7592 734.729 67.7193 734.687C67.5464 731.79 67.664 728.154 67.7077 725.245C70.7154 725.16 74.0042 725.236 77.0348 725.252C77.2353 722.242 77.1593 718.889 77.1501 715.842C80.077 715.895 83.9305 715.953 86.7998 715.759Z" fill="#9E2184"/> -<path d="M-7.74615 705.738C-2.92867 705.717 2.81047 705.441 7.53969 705.736C18.3302 706.411 29.0125 706.208 39.826 706.19C39.9136 710.062 39.6163 712.804 39.1808 716.662C38.9295 718.891 39.3928 722.512 38.593 724.602C36.9659 725.333 32.3358 725.061 30.3492 725.04C29.8444 724.69 30.0864 717.63 30.0934 716.508C25.5324 716.185 16.0947 716.515 11.2364 716.533C11.082 719.29 11.0659 722.281 11.0036 725.058L1.42696 725.072C1.27024 722.173 1.32187 718.661 1.2926 715.713C-1.727 715.505 -4.60601 715.955 -7.91093 715.563C-7.99667 713.837 -8.23267 707.063 -7.74615 705.738Z" fill="#9E2184"/> -<path d="M153.094 477.093L162.658 477.103C162.727 480.59 162.923 503.294 162.264 504.843C160.722 505.474 154.924 505.143 153.002 505.102C152.72 508.382 153.018 511.636 152.686 515.064C150.162 515.21 145.553 515.254 143.066 515.01C142.875 508.773 143.124 502.116 142.995 495.79C140.104 495.674 137.062 495.757 134.161 495.786C134.246 494.697 133.734 487.234 134.599 486.879C137.869 485.537 149.964 487.686 152.672 486.227C153.416 484.852 153.114 479.114 153.094 477.093Z" fill="#9E2184"/> -<path d="M58.2763 553.36C60.4657 553.661 65.8979 552.825 67.1816 554.05C67.8407 556.136 67.9352 568.141 67.8315 571.06C67.7163 574.32 66.746 578.598 67.6448 582.406L48.7717 582.433L48.7648 572.943C47.2967 572.374 32.8763 572.826 29.9701 572.671C29.901 569.412 29.9747 566.492 30.0047 563.257C39.4677 563.264 49.2765 563.412 58.7119 563.285C58.7326 559.5 58.6681 557.161 58.2763 553.36Z" fill="#9E2184"/> -<path d="M181.503 533.768C182.054 529.284 182.268 525.684 181.902 521.196C181.831 520.322 181.748 516.094 182.236 515.569C183.695 515.15 189.572 515.087 190.846 515.729C191.513 516.971 191.162 531.524 191.141 534.112C193.879 534.324 198.062 534.184 200.897 534.202C203.414 534.219 208.051 534.322 210.365 534.016C210.245 536.371 210.685 541.121 209.929 543.014C208.749 543.52 175.281 543.658 172.522 543.277C171.902 542.109 171.851 536.218 172.296 535.03C172.987 533.186 179.77 535.148 181.503 533.768Z" fill="#9E2184"/> -<path d="M230.282 734.846C232.255 734.786 236.505 734.443 238.153 735.153C238.865 736.478 238.381 768.495 238.19 772.54C234.283 772.606 232.386 772.47 228.616 772.086C225.684 772.097 222.755 772.083 219.824 772.049C219.803 766.059 219.708 759.852 219.828 753.883C222.691 753.646 226.242 753.791 229.227 753.708C229.519 748.769 228.886 740.398 229.519 735.353C229.554 735.07 229.946 734.994 230.282 734.846Z" fill="#9E2184"/> -<path d="M181.732 601.736C184.843 601.693 187.957 601.691 191.071 601.732C191.28 604.654 190.995 608.079 191.124 611.196C193.246 611.223 198.625 610.846 199.962 611.776C200.815 613.099 200.43 618.495 200.448 620.656C202.838 620.735 205.221 620.575 207.605 620.615C211.055 620.672 210.483 623.408 210.329 625.849C210.236 627.318 210.213 628.719 209.967 630.181C205.821 630.605 195.735 630.299 191.267 630.283L191.216 620.664C188.144 620.564 184.666 620.633 181.566 620.627C181.419 618.044 181.177 603.661 181.732 601.736Z" fill="#9E2184"/> -<path d="M222.861 630.198C225.147 630.199 237.093 629.826 238.144 630.566C238.833 632.386 238.452 637.31 238.174 639.319C224.488 640.105 231.264 637.916 228.828 648.427C228.713 648.925 221.465 648.674 220.575 648.966C220.126 649.114 217.553 649.448 216.809 649.461C211.409 649.5 206.012 649.474 200.612 649.385C200.377 646.774 200.464 642.453 200.522 639.779C206.689 639.575 213.606 639.702 219.764 639.8C219.821 636.652 219.847 633.505 219.84 630.357C220.766 630.268 221.914 630.245 222.861 630.198Z" fill="#9E2184"/> -<path d="M105.884 477.177C111.826 476.943 118.618 477.092 124.626 477.099C124.64 480.08 124.73 483.312 124.497 486.265C121.531 486.394 118.067 486.274 115.006 486.328C114.852 489.205 114.935 492.845 114.93 495.782C112.872 495.746 107.329 495.558 105.585 496.018C105.354 498.632 105.541 502.267 105.368 505.185C102.365 505.25 99.3622 505.247 96.3591 505.174L96.3223 504.704C96.1817 502.685 95.9351 487.804 96.7325 486.895C98.514 486.219 103.335 486.577 105.43 486.641C105.686 484.22 105.241 478.91 105.884 477.177Z" fill="#9E2184"/> -<path d="M49.1622 744.464C52.1997 744.397 55.2373 744.448 58.2703 744.616C58.4086 750.663 58.2887 757.027 58.2542 763.093L67.4821 763.102C67.655 766.144 67.3738 769.223 67.6043 772.194C65.0737 772.113 60.1947 772.47 58.1366 771.666C57.5397 771.392 50.6833 771.323 49.4272 771.23C49.3972 768.465 49.4157 765.697 49.4779 762.931C46.5786 762.756 42.686 762.908 39.5931 762.825L39.5654 753.63C42.5777 753.724 45.6613 753.669 48.6805 753.653C48.7957 751.624 48.4085 745.775 49.1622 744.464Z" fill="#9E2184"/> -<path d="M210.559 601.79C213.264 601.762 227.132 602.076 228.996 603.056C229.704 604.444 229.261 609.554 229.469 611.6C234.357 611.706 238.913 609.772 238.406 616.113C238.286 617.612 239.038 618.712 238.418 620.488C236.263 620.626 221.409 620.83 220.158 620.276C219.104 618.473 220.381 614.146 219.632 611.836C216.244 608.989 209.261 615.152 210.268 606.131C210.427 604.712 210.042 603.262 210.559 601.79Z" fill="#9E2184"/> -<path d="M143.974 639.527C146.281 639.905 151.356 639.137 152.467 640.046C152.838 642.585 152.672 648.455 152.64 651.202C152.578 656.687 152.67 662.415 152.52 667.88C149.699 668.013 146.055 667.918 143.17 667.925C140.135 667.937 137.12 667.981 134.087 667.829C133.939 665.285 134.073 661.549 134.094 658.92L143.177 658.905C143.338 657.749 143.486 656.456 143.46 655.288C143.34 649.955 144.082 644.86 143.974 639.527Z" fill="#9E2184"/> -<path d="M20.4569 582.599C29.1364 582.778 40.0306 582.772 48.6847 582.582C48.4681 585.756 48.7193 589.153 48.4911 592.477C44.7759 592.555 40.646 592.243 36.8686 592.132L20.1942 591.806C20.102 589.624 19.8876 584.48 20.4569 582.599Z" fill="#9E2184"/> -<path d="M212.152 717.093L219.619 716.893C219.653 723.251 219.907 729.26 219.773 735.644C215.5 735.764 212.315 735.121 208.119 735.109C205.475 735.132 202.829 735.081 200.19 734.964C200.285 731.744 200.269 728.389 200.299 725.157C202.336 725.22 208.688 725.505 210.273 724.872C211.956 722.936 209.084 718.306 212.152 717.093Z" fill="#9E2184"/> -<path d="M124.138 495.993C126.848 496.001 131.54 496.158 134.092 495.952C134.08 498.957 134.126 502.162 134.046 505.149C130.916 505.211 127.786 505.235 124.656 505.222C124.571 508.385 124.435 511.958 124.493 515.1C121.9 514.788 117.802 514.967 115 514.886C115.016 508.829 115.163 501.958 114.977 495.973L124.138 495.993Z" fill="#9E2184"/> -<path d="M110.568 515.197C112.091 515.226 113.354 515.222 114.873 515.154L114.921 533.97L105.511 533.992L105.44 543.435L100.955 543.462C99.3991 543.469 97.8457 543.449 96.2924 543.401C95.2115 531.815 96.0619 534.797 105.313 534.065C105.267 532.873 105.255 531.729 105.366 530.539C105.838 525.489 105.737 520.446 105.735 515.376C107.247 515.263 109.033 515.247 110.568 515.197Z" fill="#9E2184"/> -<path d="M57.5645 705.784L77.1612 705.704V715.759C70.7011 715.628 64.0199 715.93 57.576 715.611C57.5967 712.337 57.5921 709.062 57.5645 705.784Z" fill="#9E2184"/> -<path d="M143.702 572.722C149.775 572.546 156.558 572.596 162.64 572.689C162.649 574.216 162.794 581.753 162.391 582.427C156.187 582.224 149.51 582.716 143.32 582.352C143.253 580.316 142.773 574.053 143.702 572.722Z" fill="#9E2184"/> -<path d="M30.1404 668.121C32.9244 668.14 46.824 667.507 48.0985 668.705C48.6608 670.592 48.5779 676.113 48.0755 677.948C43.4131 678.485 35.4665 677.908 30.6889 677.793C29.3683 677.762 29.6541 669.452 30.1404 668.121Z" fill="#9E2184"/> -<path d="M20.6736 620.937C23.5913 620.836 26.7626 620.885 29.6988 620.879L29.6849 631.197L39.549 631.026C39.5743 633.076 39.8371 637.555 39.0742 639.437C38.959 639.721 38.5211 639.752 38.1316 639.867C34.0431 639.884 33.7343 641.05 28.9128 640.384C29.2585 638.339 29.3623 633.539 29.4683 631.247C27.2258 631.253 24.0039 631.636 21.9896 630.898C21.5978 629.869 21.2936 627.81 21.1691 626.66C20.9801 624.916 19.8762 622.466 20.6736 620.937Z" fill="#9E2184"/> -<path d="M162.723 582.574C165.166 582.733 169.321 582.595 171.893 582.591C172.02 588.85 172.004 595.11 171.847 601.367C169.95 602.089 164.832 601.784 162.693 601.685C162.442 596.739 162.594 587.573 162.723 582.574Z" fill="#9E2184"/> -<path d="M172.97 477.138C178.008 476.945 184.823 477.049 189.939 477.177C190.209 477.254 190.856 477.342 190.912 477.679C191.177 479.264 191.986 485.663 190.356 486.327C186.775 486.521 175.33 486.597 172.124 486.246C172.055 483.719 171.9 480.831 172.098 478.312C172.156 477.561 172.481 477.457 172.97 477.138Z" fill="#9E2184"/> -<path d="M210.319 582.616C213.447 582.763 227.876 582.068 229.319 583.177C229.932 585.024 229.547 589.502 229.457 591.613C227.867 592.189 213.073 591.842 210.342 591.812L210.319 582.616Z" fill="#9E2184"/> -<path d="M30.033 649.688L48.5535 649.68C48.542 651.488 48.7724 657.352 48.0511 658.477C42.7872 658.567 35.0619 658.79 29.9086 658.442C29.8487 656.315 29.6527 651.567 30.033 649.688Z" fill="#9E2184"/> -<path d="M200.602 753.321C203.442 753.097 207.203 753.136 210.102 753.194C210.437 755.552 210.201 760.362 210.118 762.897C206.922 762.998 203.723 763.049 200.526 763.051C200.672 759.716 200.487 756.563 200.602 753.321Z" fill="#9E2184"/> -<path d="M2.27915 620.762C4.95074 620.613 8.35708 620.746 11.0305 620.859C11.2379 623.272 11.0997 626.396 11.0559 628.854C11.042 629.732 10.989 629.864 10.5004 630.308C7.43059 630.36 4.35845 630.353 1.29022 630.284C1.25749 627.851 1.00189 623.551 1.47735 621.184C1.53727 620.885 1.87468 620.888 2.27915 620.762Z" fill="#9E2184"/> -<path d="M1.6382 477.082L11.0217 477.094C11.054 479.282 11.2499 485.068 10.7498 486.957L10.4594 486.995C-0.029464 488.292 1.55155 486.346 1.6382 477.082Z" fill="#9E2184"/> -<path d="M226.523 543.286C227.367 543.121 228.482 543.039 229.275 543.399C229.83 544.619 229.501 551.137 229.459 552.955C227.3 553.011 224.917 552.957 222.739 552.954C221.776 552.95 220.785 552.911 219.819 552.887C219.738 549.821 219.74 546.754 219.823 543.688C222.234 543.534 224.048 543.78 226.523 543.286Z" fill="#9E2184"/> -<path d="M1.45947 678.057C4.64916 677.974 7.84347 677.978 11.0332 678.066C11.3282 680.148 11.3074 685.16 11.0239 687.258C7.79045 687.296 4.55467 687.29 1.32027 687.239C1.2615 685.172 1.04417 679.878 1.45947 678.057Z" fill="#9E2184"/> -<path d="M221.689 563.124C224.431 563.089 226.941 563.167 229.679 563.267C229.746 565.459 230.029 569.65 229.506 571.815C229.377 572.344 228.794 572.368 228.386 572.438C226.303 572.433 222.06 572.716 220.264 572.244C219.483 570.527 219.492 565.692 220.045 563.767C220.686 563.067 220.486 563.29 221.689 563.124Z" fill="#9E2184"/> -<path d="M48.8275 725.273C51.948 725.151 55.1123 725.236 58.2398 725.28C58.279 727.704 58.4219 732.468 58.1361 734.74C54.9856 734.773 51.8328 734.766 48.68 734.717C48.6154 732.256 48.4449 727.575 48.8275 725.273Z" fill="#9E2184"/> -<path d="M152.942 534.225L162.607 534.234C163.015 545.824 163.81 543.15 152.872 543.497C152.882 540.79 152.727 536.785 152.942 534.225Z" fill="#9E2184"/> -<path d="M77.4382 762.892C80.1324 762.874 84.3914 762.731 86.9819 763.074C86.9427 765.759 87.111 769.737 86.8551 772.238C83.9628 772.24 80.1969 772.136 77.3736 772.286C77.3621 769.152 77.3276 766.024 77.4382 762.892Z" fill="#9E2184"/> -<path d="M114.99 534.066C118.247 534.228 121.416 534.166 124.649 534.253L124.624 543.594C122.732 543.316 117.189 543.441 115.018 543.446C115.009 540.352 115.046 537.15 114.99 534.066Z" fill="#9E2184"/> -<path d="M210.861 477.137C213.837 477.085 216.812 477.054 219.79 477.045C219.833 479.642 219.988 482.981 219.688 485.58C219.619 486.157 219.382 486.19 218.983 486.441C216.081 486.534 213.175 486.547 210.271 486.481C210.177 484.623 209.866 478.242 210.861 477.137Z" fill="#9E2184"/> -<path d="M77.385 477.113C80.4986 477.052 83.7528 477.099 86.8803 477.099C86.9241 480.003 87.0255 483.466 86.7973 486.315C83.7298 486.497 80.4318 486.486 77.3389 486.524L77.385 477.113Z" fill="#9E2184"/> -<path d="M30.0441 477.122C33.1554 477.045 36.4211 477.098 39.5463 477.106C39.5463 480.177 39.4725 483.248 39.325 486.316L29.8896 486.285C29.8436 484.351 29.6407 478.766 30.0441 477.122Z" fill="#9E2184"/> -<path d="M2.12661 496.085C4.28541 496.038 9.14831 495.557 10.6325 496.538C11.6789 498.018 11.0589 503.028 10.9598 505.161C7.91067 505.252 4.59884 505.193 1.52969 505.193C1.50249 502.572 1.44326 499.767 1.54813 497.15C1.57901 496.375 1.63755 496.49 2.12661 496.085Z" fill="#9E2184"/> -<path d="M20.4357 762.876L29.8526 762.878C29.9287 765.794 29.6107 769.412 29.8066 772.083C26.8819 771.982 23.388 772.081 20.4196 772.088C20.2329 769.02 20.2375 765.944 20.4357 762.876Z" fill="#9E2184"/> -<path d="M-7.79688 601.627C-6.23291 601.819 -0.378316 601.72 1.57491 601.745C1.58781 604.006 1.69798 608.737 1.37256 610.793C0.0641861 611.112 -6.07088 610.989 -7.69776 610.982C-7.65904 607.863 -7.69201 604.744 -7.79688 601.627Z" fill="#9E2184"/> -<path d="M134.401 678.088C137.187 678.013 140.642 677.974 143.391 678.143C143.562 680.147 143.726 685.412 143.2 687.19L133.988 687.162C133.991 685.228 133.689 679.175 134.401 678.088Z" fill="#9E2184"/> -<path d="M229.934 715.895C232.654 715.851 235.675 715.775 238.36 716.049C238.492 717.84 238.84 724.132 237.95 725.259C235.712 725.215 231.356 725.812 230.031 725.031C228.86 723.616 228.784 717.294 229.934 715.895Z" fill="#9E2184"/> -<path d="M124.493 515.1C127.535 515.217 130.988 515.117 133.924 515.331C133.901 517.483 133.735 522.347 133.938 524.345C131.082 524.367 127.399 524.482 124.622 524.301C124.608 521.306 124.648 518.078 124.493 515.1Z" fill="#9E2184"/> -<path d="M163.021 649.519C166.028 649.478 169.036 649.463 172.043 649.474C171.76 652.4 172.336 654.965 171.746 658.39C169.861 658.613 165.424 659.117 163.696 658.45C162.002 657.796 162.276 650.66 163.021 649.519Z" fill="#9E2184"/> -<path d="M58.4701 534.24C61.4431 534.115 64.5383 534.249 67.599 534.127C67.4215 536.935 67.834 540.73 67.3039 543.409L58.2742 543.435C58.318 541.224 58.076 536.128 58.4701 534.24Z" fill="#9E2184"/> -<path d="M105.686 763.143C107.795 763.323 112.566 763.134 114.949 763.116C114.785 766.096 115.094 769.189 114.785 772.166C112.925 772.461 107.507 772.245 105.502 772.164C105.702 769.119 105.677 766.19 105.686 763.143Z" fill="#9E2184"/> -<path d="M105.489 687.211C105.493 689.921 105.599 693.604 105.263 696.217C102.428 696.391 99.0287 696.335 96.1455 696.348C96.2654 693.521 96.1939 690.153 96.2308 687.263C99.2845 687.206 102.426 687.228 105.489 687.211Z" fill="#9E2184"/> -<path d="M229.061 658.878C233.113 658.938 239.197 657.297 238.547 663.039C238.363 664.685 238.812 666.221 238.169 667.899C236.229 667.891 231.467 668.417 230.269 667.689C229.503 666.745 228.95 660.236 229.061 658.878Z" fill="#9E2184"/> -<path d="M841.562 731.075C838 730.892 824.967 731.4 822.449 730.738C821.914 729.784 821.944 723.607 822.385 722.4C823.639 721.775 847.529 722.042 850.847 722.033C850.565 724.354 850.643 728.853 850.765 731.22C853.73 731.356 857.472 731.268 860.511 731.293C860.549 734.414 860.513 737.604 860.511 740.729C857.296 740.697 854.081 740.701 850.866 740.743C850.728 742.895 850.184 748.48 851.217 749.987C852.617 750.985 858.311 750.457 860.51 750.42C860.772 747.475 860.619 743.799 860.57 740.773L884.946 740.766C888.784 740.766 894.834 740.607 898.454 740.992C898.594 743.778 898.421 747.648 898.36 750.478C900.397 750.413 906.486 750.763 907.86 750.201C908.482 748.224 908.243 734.276 908.236 731.234C912.654 731.081 923.126 731.616 926.876 731.104C926.883 734.066 926.984 737.811 926.717 740.69C923.758 740.814 920.232 740.743 917.24 740.745C917.074 743.914 917.166 747.263 917.208 750.443C920.441 750.48 933.815 749.959 935.797 751.047C936.846 753.089 936.141 756.968 936.613 759.471C927.59 759.113 917.975 759.427 908.932 759.558C906.929 759.588 908.826 766.77 907.6 768.57C906.044 769.213 900.308 768.899 898.348 768.864L898.352 778.314C900.559 778.507 904.152 778.39 906.45 778.385C909.946 778.378 913.871 778.434 917.335 778.231C917.413 781.114 917.15 785.767 917.431 788.298C911.81 788.632 904.262 788.427 898.504 788.415C898.317 791.361 898.389 794.702 898.393 797.687C900.75 797.906 905.468 797.724 907.978 797.687C908.07 800.791 908.065 803.898 907.964 807.005C905.304 807.231 901.372 807.072 898.453 807.191C898.221 809.798 898.33 814.251 898.317 816.991C903.974 816.975 911.916 816.719 917.388 817.06C917.664 826.44 918.681 826.108 908.904 825.611C908.591 826.5 907.051 832.956 907.097 833.654C907.295 836.685 915.408 834.352 917.03 835.611C917.759 837.251 917.312 843.193 917.429 845.634L926.883 845.613C927.27 850.868 926.652 858.786 926.689 864.537C929.863 864.562 933.138 864.497 936.323 864.477C936.68 861.743 936.53 855.092 936.503 852.137C936.45 846.705 936.632 840.828 936.452 835.442C933.405 835.387 930.199 835.477 927.102 835.442C927.019 826.067 927.014 816.694 927.088 807.318C930.234 807.261 933.382 807.261 936.53 807.321C936.712 811.614 936.182 814.838 935.585 818.978C935.383 820.37 935.472 824.518 935.477 826.088C942.145 826.302 948.766 825.735 955.581 826.424C955.768 823.393 955.698 820.063 955.694 817C961.695 816.814 968.185 816.924 974.2 816.968C974.295 826.509 974.293 836.053 974.189 845.597C983.286 845.825 993.311 845.604 1002.49 845.62C1002.76 849.208 1002.61 860.838 1002.41 864.253C999.305 864.486 996.183 864.449 993.067 864.415C993.21 861.363 993.2 857.922 993.145 854.869C990.488 854.686 986.542 854.76 983.848 854.802C983.717 857.874 983.627 861.43 983.797 864.474C980.939 864.26 977.425 864.502 974.327 864.35C974.376 861.172 974.383 857.996 974.355 854.818C971.933 854.569 967.312 854.786 964.707 854.841C964.627 858.086 964.763 861.209 964.41 864.442C961.262 864.461 958.406 864.922 955.284 865.371C955.214 862.456 955.583 859.844 955.65 856.993C955.735 853.357 955.692 849.598 955.685 845.952C958.183 845.733 962.345 845.846 964.97 845.848C965.221 841.992 964.8 838.92 964.548 835.085C960.985 835.064 958.877 835.14 955.316 834.659C952.997 834.864 947.706 833.735 945.959 834.712C945.154 837.06 945.364 863.619 946.413 864.885C948.455 865.71 952.97 865.468 955.284 865.371C955.261 867.825 955.159 870.877 955.249 873.276C950.098 873.267 940.84 873.009 936.051 873.458C935.917 876.68 935.917 879.727 935.926 882.953C939.116 882.935 942.389 882.877 945.567 883.002C945.735 887.166 945.32 891.209 945.36 895.362C945.433 903.29 945.175 911.204 944.933 919.126C944.818 922.926 944.977 926.839 944.864 930.658L936.367 930.628C935.758 922.087 936.865 911.267 936.549 902.29C933.997 902.299 929.354 902.17 926.966 902.373C926.874 905.256 927.026 909.536 926.673 912.186L917.189 912.2C917.097 908.879 917.217 905.431 917.104 902.209C914.484 902.232 900.183 902.062 898.773 902.638C898.036 904.251 898.357 909.616 898.311 911.734C895.521 911.485 891.946 911.555 889.15 911.721L889.069 924.219C889.061 925.726 888.948 929.25 889.087 930.633C882.823 930.471 876.505 930.748 870.219 930.566C870.151 928.45 869.638 923.666 870.694 922.163C872.07 921.186 877.584 921.615 879.795 921.608C880.047 915.53 879.882 908.448 879.877 902.297C876.714 902.251 873.394 902.313 870.219 902.324C870.433 899.273 870.411 895.897 870.448 892.811C864.264 892.815 857.005 893.002 850.92 892.684C850.669 895.537 850.69 899.644 850.723 902.527L870.163 902.5C870.156 905.546 870.091 908.591 869.97 911.633C868.05 911.651 862.694 911.324 861.283 911.87C860.02 913.182 860.582 918.731 860.35 921.405C857.257 921.435 854.164 921.437 851.072 921.416C851.011 918.238 851.058 914.975 851.013 911.769C848.805 911.449 843.781 911.651 841.446 911.725C841.633 908.814 841.584 905.182 841.524 902.264C836.831 902.186 832.101 902.34 827.403 902.269C825.827 902.246 824.201 902.221 822.639 902.426C821.95 903.677 822.298 909.999 822.171 912.142C820.645 912.209 816.819 912.451 815.504 912.158C811.591 911.287 809.377 910.914 805.376 910.955C804.644 911.624 804.277 912.103 803.645 912.878C803.563 914.91 803.029 919.596 803.913 921.041C805.077 921.953 810.947 921.603 813.035 921.704C813.262 923.995 813.323 937.83 812.65 939.517C811.03 940.183 778.72 939.845 774.49 939.812C774.729 934.191 774.562 927.397 774.566 921.691C777.816 921.522 781.073 921.518 784.324 921.681C784.515 924.523 784.352 928.01 784.499 931.068C787.318 931.179 791.07 931.168 793.869 931.05C794.131 928.04 793.984 923.802 793.973 920.67C793.934 914.622 793.934 908.572 793.972 902.525C795.914 902.536 801.181 902.707 802.692 902.41C804.634 902.027 802.683 895.258 803.776 893.251C805.394 892.543 810.841 892.877 813.085 892.866C813.31 890.428 813.745 885.074 813.729 882.907C817.641 882.967 817.967 884.295 822.498 884.422C825.614 882.799 828.24 883.154 831.744 883.145C831.804 886.367 831.753 889.582 831.822 892.813C834.534 893.016 838.554 892.93 841.367 892.949C841.639 889.884 841.537 885.744 841.516 882.656L831.967 882.721C831.788 876.738 831.999 870.646 831.742 864.686L822.521 864.705C822.446 861.656 822.491 858.425 822.485 855.362C819.338 855.184 816.585 855.532 813.133 855.223C812.92 864.096 813.079 873.649 813.085 882.585C810.603 882.58 809.902 882.543 807.599 883.424C804.599 882.375 799.294 882.578 796.227 882.96C795.723 883.023 794.985 882.808 794.703 882.396C793.595 880.778 793.927 875.477 793.93 873.424C791.412 873.262 786.937 873.223 784.447 873.421C784.502 870.158 784.513 866.894 784.481 863.633C781.564 863.654 777.355 863.808 774.539 863.633L774.555 855.078L784.261 854.998C784.257 857.766 784.197 860.718 784.25 863.47C790.456 863.334 797.365 863.578 803.368 863.329C803.401 860.568 803.449 857.846 803.368 855.083C797.025 855.03 790.756 854.686 784.437 854.795C784.462 851.81 784.56 848.381 784.43 845.438L765.12 845.38L765.301 836.625C769.86 836.638 773.88 836.638 778.444 836.201C780.183 836.035 782.572 836.24 784.401 836.074C784.737 826.489 784.464 815.693 784.511 805.986C781.639 806.198 777.283 806.244 774.42 806.023L774.551 797.855C777.381 797.572 781.056 797.662 783.962 797.703C784.098 794.739 784.124 791.775 784.04 788.812C780.863 788.888 777.685 788.906 774.508 788.871C774.537 782.4 774.305 774.988 774.567 768.648C777.427 768.579 781.575 768.408 784.295 768.934L784.208 788.629C786.21 788.646 792.229 788.89 793.664 788.242C794.616 786.449 793.001 778.952 794.604 778.802C800.284 778.27 806.648 778.482 812.365 778.666C813.543 778.706 812.899 787.473 812.922 788.632C811.507 788.523 809.928 788.537 808.508 788.593C803.684 788.777 798.745 788.417 793.938 788.535C793.851 795.698 793.847 802.863 793.928 810.029C793.959 811.948 793.871 815.203 794.016 816.993L811.912 817.051C811.913 814.285 811.782 810.181 811.947 807.523C814.76 807.196 819.44 807.332 822.397 807.364C822.403 810.57 822.365 813.776 822.283 816.982C828.098 816.991 835.742 816.756 841.371 817.042C841.438 820.312 841.783 832.889 840.992 835.205C840.211 835.94 836.846 836.083 835.626 836.362C834.409 836.641 833.165 837.122 831.965 837.288C831.946 839.989 831.995 842.704 831.668 845.385C828.885 845.396 825.137 845.304 822.434 845.468C822.502 842.227 822.523 838.985 822.496 835.742C832.69 835.594 832.407 837.436 831.832 826.378C831.824 826.212 831.813 826.048 831.798 825.882C828.977 825.906 825.267 826.018 822.498 825.869C822.498 823.333 822.589 819.736 822.366 817.318C819.131 817.302 815.913 817.429 812.68 817.457L812.597 825.813C806.447 825.873 800.079 825.972 793.936 825.855C793.929 829.017 793.823 832.79 793.949 835.901C798.897 836.265 807.537 835.924 812.87 835.933C812.88 838.482 812.766 843.244 812.986 845.666C815.696 845.76 819.545 845.7 822.311 845.611L822.299 854.998C829.39 855.15 836.506 854.968 843.599 855.034C845.556 855.053 848.841 854.852 850.626 855.422C851.074 856.846 850.909 861.624 850.756 863.214C850.577 865.078 843.18 864.35 841.564 864.527C841.216 869.796 841.448 877.003 841.401 882.469C844.211 882.359 847.023 882.29 849.835 882.262C850.427 882.681 851.176 883.251 851.774 883.624C853.82 883.613 859.913 884.306 861.209 883.871C864.665 882.709 866.903 883.46 870.191 882.974C870.037 886.613 870.096 889.434 870.885 892.995C873.347 893.013 877.489 893.147 879.829 892.894C880.085 890.596 879.897 885.327 879.854 882.944C876.896 882.801 873.172 882.926 870.191 882.974C870.047 873.689 870.455 864.057 870.195 854.832C867.297 854.682 863.612 854.767 860.656 854.753C860.472 852.188 860.577 848.3 860.573 845.631C866.928 845.597 873.283 845.597 879.637 845.629C879.823 848.167 879.697 852.315 879.731 855.034C885.905 855.083 892.08 855.078 898.254 855.025C898.457 851.635 898.729 839.063 898.124 836.071C895.424 835.788 892.446 836.311 889.7 836.12C883.168 835.67 876.759 835.567 870.226 835.424C869.975 830.024 870.201 822.439 870.201 816.86C874.906 817.138 879.687 816.719 884.393 817.127C885.817 817.249 887.159 817.327 888.59 817.281C888.651 819.39 888.01 824.808 889.227 826.23C890.165 827.328 896.906 827.157 897.962 826.604C898.618 826.26 898.445 817.984 898.446 817.028C896.394 816.88 890.671 816.767 888.749 816.979C888.801 813.013 888.761 809.581 889.356 805.659C889.604 804.025 889.673 799.362 889.196 797.825C888.09 797.281 880.983 797.332 880.149 797.599C879.5 798.853 879.671 805.189 879.631 807.097C876.663 807.097 873.114 807.019 870.204 807.24C870.144 809.916 869.937 814.172 870.118 816.717C866.938 816.588 863.842 816.721 860.581 816.553C860.487 813.513 860.533 810.194 860.514 807.129C857.488 807.03 854.124 807.076 851.075 807.053C851.036 804.013 851.069 800.907 851.069 797.86C854.06 797.786 868.061 798.162 869.82 797.454C870.51 795.852 870.215 790.328 870.189 788.323C866.87 788.272 863.936 788.394 860.548 788.219C860.366 785.502 860.402 781.344 860.49 778.62C862.408 778.454 864.871 778.625 866.855 778.517C871.171 778.281 875.354 778.235 879.677 778.275C879.69 781.453 879.653 784.818 879.801 787.975C882.999 787.945 886.03 787.774 889.317 787.774C889.558 782.04 889.365 774.76 889.368 768.931C892.169 768.793 895.501 768.844 898.326 768.828C897.842 765.836 898.096 754.299 898.119 750.641C893.82 750.593 889.526 750.787 885.223 750.71C881.253 750.641 874.227 749.636 870.472 750.473C869.74 751.911 870.006 757.516 870.018 759.404C866.898 759.397 863.743 759.353 860.628 759.473C860.421 762.01 860.517 766.242 860.498 768.908C857.188 768.975 854.391 768.987 851.088 768.844L851.05 759.429C844.825 759.183 838.274 759.586 831.951 759.383C831.864 756.472 831.894 753.368 831.873 750.441C833.669 750.448 840.388 750.761 841.34 750.038C841.841 747.846 841.612 734.071 841.562 731.075ZM889.644 892.354C894.954 892.366 900.421 892.456 905.691 891.831C909.204 891.416 912.366 891.449 915.89 891.476L916.745 891.372C917.819 889.95 916.878 875.274 917.235 872.442C917.36 871.435 917.229 865.929 917.093 864.917C916.622 864.412 915.101 864.345 914.375 864.343C906.014 864.311 897.6 864.433 889.24 864.32C888.635 865.952 888.906 868.137 888.751 869.856C888.208 875.878 888.337 881.64 889.234 887.63C889.464 889.162 889.359 890.778 889.644 892.354ZM926.779 892.919C929.851 892.926 932.921 892.912 935.993 892.873C936.235 890.105 936.072 885.88 936.021 883.004C933.02 882.926 930.02 882.896 927.021 882.912C926.756 885.235 926.708 890.474 926.779 892.919Z" fill="#9E2184"/> -<path d="M1069.09 683.994C1070.47 673.075 1067.96 674.113 1078.85 673.718C1078.49 676.366 1078.48 681.028 1078.31 683.958C1081.84 684.123 1086.52 684.137 1090.04 684.036C1098.53 683.793 1097.53 683.66 1097.45 691.867L1097.39 702.43C1094.32 702.307 1091.45 702.54 1088.26 702.288C1088.16 700.216 1088.52 694.823 1087.99 693.309C1087.09 692.685 1079.6 692.594 1078.77 693.144C1078.06 694.802 1078.37 702.517 1078.6 704.713C1079.06 709.355 1078.07 717.56 1078.97 721.754C1080.4 722.964 1094.18 721.114 1096.72 722.713C1097.6 724.045 1097.25 729.12 1097.23 731.061C1094.23 731.079 1091.24 731.065 1088.24 731.024C1088.02 733.547 1088.05 738.36 1088.13 740.959C1090.6 741.107 1094.45 740.978 1097.02 740.971C1096.76 743.428 1096.82 745.407 1096.49 748.498C1096.06 752.561 1090.82 749.45 1089.55 751.211C1088.14 753.176 1088.33 767.353 1088.35 769.024C1091.34 769.116 1094.52 769.06 1097.53 769.051C1097.46 773.195 1097.44 777.339 1097.46 781.485C1097.46 783.518 1097.36 786.742 1097.48 788.659L1069.11 788.682C1069.16 786.597 1068.74 780.298 1069.58 779.109C1070.98 778.18 1076.21 778.533 1078.38 778.514C1078.59 775.659 1078.5 771.782 1078.51 768.844L1069.09 768.867C1066.1 768.869 1062.66 768.802 1059.71 769.005C1059.35 774.244 1059.62 783.354 1059.6 788.8C1062.59 788.606 1066.01 788.786 1069.11 788.682C1068.79 794.115 1069.03 801.46 1068.9 807.24C1066.72 807.072 1062.38 807.323 1059.76 807.251C1059.56 804.546 1059.67 800.342 1059.66 797.521C1057.11 797.431 1052.67 797.438 1050.18 797.562L1050.17 788.473C1048.93 788.429 1041.18 788.832 1040.77 787.933C1039.91 786.064 1041.27 780.344 1040.12 778.643C1038.53 778.037 1024.92 778.493 1021.6 778.251L1021.57 768.977C1018.63 768.816 1015.07 768.894 1012.08 768.892C1012.04 765.813 1011.95 762.746 1012.1 759.671L1031.01 759.683C1031.14 756.998 1031.13 753.236 1030.96 750.577C1028.9 750.362 1024.04 750.528 1021.61 750.478L1021.58 721.835L1011.98 721.844C1011.74 727.366 1012.33 735.585 1011.69 740.731C1008.66 740.75 1005.63 740.733 1002.6 740.683C1002.89 735.622 1002.82 730.325 1002.59 725.262C1002.44 721.789 1002.06 718.323 1002.23 714.84C1002.26 714.253 1002.26 713.407 1002.7 712.964C1003.99 711.667 1018.63 712.358 1021.61 712.215C1021.7 709.046 1021.63 705.552 1021.63 702.359C1018.4 702.365 1015.36 702.46 1012.14 702.225C1012.05 699.203 1012.07 696.022 1012.03 692.982C1009.5 692.749 1005.14 692.867 1002.57 692.968C1002.8 690.554 1002.61 686.502 1002.55 684.001C1008.88 683.991 1015.22 684.02 1021.55 684.089C1021.73 686.827 1021.66 690.453 1021.67 693.226C1024.54 693.344 1027.97 693.261 1030.88 693.263C1030.84 696.44 1030.87 699.677 1030.86 702.861C1033.92 702.99 1037.39 702.888 1040.48 702.858C1040.51 705.619 1040.61 710.003 1040.23 712.646C1037.52 712.667 1034.94 712.678 1032.23 712.84C1032.3 716.078 1032.53 719.27 1032.59 722.533C1035.18 722.566 1037.76 722.637 1040.34 722.743C1040.59 725.345 1040.44 728.618 1040.4 731.28L1050.14 731.261C1050.37 725.287 1050.22 718.399 1050.22 712.356L1058.23 712.393C1058.3 709.254 1058.18 706.587 1057.99 703.455C1055.29 703.441 1052.58 703.402 1049.88 703.338C1049.71 700.91 1049.63 686.203 1050.19 684.398C1051.74 683.699 1066.15 684.035 1069.09 683.994ZM1049.85 767.749C1049.83 765.631 1049.42 760.773 1050.46 759.314C1051.89 758.36 1057.7 758.818 1059.92 758.793L1059.93 758.355C1059.97 756.82 1060.08 755.659 1060.39 754.22C1060.95 751.658 1060.83 742.688 1059.59 740.828C1058.13 739.95 1052.23 740.275 1050.09 740.284C1048.58 744.732 1052.06 750.916 1046.69 750.775C1044.75 750.724 1042.78 750.791 1040.84 750.775C1040.34 753.515 1040.52 765.905 1040.55 769.305C1042.56 769.353 1048.12 769.754 1049.55 768.89C1049.85 768.337 1049.89 768.364 1049.85 767.749ZM1069.01 750.411C1071.08 750.441 1076.69 750.625 1078.59 750.415C1079.22 747.242 1079.06 734.575 1078.86 731.051C1075.62 731.022 1072.38 731.04 1069.15 731.104C1068.83 732.828 1068.83 748.36 1069.01 750.411Z" fill="#9E2184"/> -<path d="M945.682 483.151C951.645 482.987 958.626 483.022 964.636 483.105C964.643 485.968 964.546 489.85 964.745 492.626C967.9 492.755 971.145 492.718 974.311 492.719C974.042 495.14 974.235 499.152 974.18 501.778C971.039 501.754 967.865 501.692 964.728 501.81C964.692 504.734 964.574 508.282 964.689 511.188C963.164 511.15 956.632 510.887 955.62 511.536C954.901 513.527 955.362 526.849 955.205 530.234C953.968 530.36 946.756 530.189 946.39 530.73C945.341 532.28 945.712 546.928 945.883 549.623C948.987 549.675 952.09 549.679 955.192 549.633C955.254 552.875 955.284 556.118 955.277 559.36C953.689 559.096 945.046 559.107 942.912 559.118C938.563 559.14 931.366 558.618 927.333 559.071C926.657 560.239 926.699 567.478 926.897 569.016C924.973 569.056 919.266 568.682 918.017 569.382C917.095 570.516 917.455 576.353 917.406 578.514C914.362 578.679 911.163 578.583 908.105 578.548C907.941 581.47 908.026 585.36 907.969 588.4C903.91 588.603 893.279 588.63 889.518 588.365C889.06 583.705 889.415 573.949 889.353 568.768L880.183 568.842C880.043 565.825 880.109 562.215 880.087 559.152C876.91 559.222 873.481 559.394 870.335 559.203C870.123 556.659 870.227 552.419 870.215 549.745C881.771 550.822 879.983 550.184 879.853 540.033C876.9 539.853 873.215 539.974 870.198 540.003C870.276 536.902 870.457 533.49 870.133 530.442C866.942 530.402 863.966 530.604 860.717 530.42C860.448 527.578 860.568 524.157 860.589 521.267C862.557 521.268 868.013 521.599 869.482 520.974C870.644 519.827 870.069 513.861 870.217 511.455C873.329 511.24 876.82 511.543 879.849 511.221L879.785 521.295C882.714 521.446 886.191 521.339 889.139 521.304C889.433 518.73 889.344 514.011 889.216 511.358C891.782 511.38 896.021 511.481 898.445 511.242C898.43 514.73 898.469 518.219 898.563 521.706C904.541 521.947 911.041 521.413 917.173 521.379C917.277 518.969 916.858 513.432 917.542 511.61C919.266 510.802 932.963 511.319 936.102 511.186C936.093 513.908 935.98 518.792 936.431 521.316C938.957 521.354 943.24 521.597 945.572 521.407C945.977 519.367 945.795 513.52 945.752 511.284C943.032 511.085 938.93 511.192 936.102 511.186L936.141 502.232C939.31 501.993 942.829 502.246 945.563 501.995C945.943 495.835 945.295 488.934 945.682 483.151ZM889.592 559.345L917.388 559.387C917.881 558.425 917.886 533.989 917.678 530.675C911.458 530.566 905.152 530.77 898.933 530.733C896.24 530.717 891.873 530.925 889.354 530.493C888.029 532.315 889.146 541.667 889.296 544.491C889.562 549.485 889.532 554.361 889.592 559.345ZM898.498 578.567C901.529 578.645 904.714 578.474 907.69 578.668C908.068 578.368 908.275 578.342 908.224 577.624C908.056 575.31 908.722 571.038 907.692 569.154C907.39 568.91 906.961 568.57 906.565 568.579C903.908 568.641 901.253 568.801 898.587 568.79C898.39 571.079 898.253 576.318 898.498 578.567ZM926.69 549.933L936.259 549.891C936.646 548.068 936.484 541.979 936.362 539.92C933.23 539.971 930.098 539.984 926.966 539.958C926.567 541.949 926.685 547.651 926.69 549.933Z" fill="#9E2184"/> -<path d="M898.532 540.239C901.686 540.196 904.838 540.191 907.991 540.222C908.049 542.449 908.309 547.708 907.719 549.631C905.016 549.766 901.006 549.724 898.317 549.61C898.172 547.921 898.074 541.773 898.532 540.239Z" fill="#9E2184"/> -<path d="M831.211 559.624C828.919 559.501 824.509 559.898 822.811 559.119C821.614 557.721 821.111 515.099 822.571 511.755C824.045 510.995 830.149 511.174 832.052 511.285C832.153 514.288 831.533 528.688 832.237 530.112C833.398 530.652 840.595 531.088 841.351 529.92C842.47 528.191 841.794 523.6 841.833 521.336C844.103 521.232 849.145 521.385 850.869 521.17C850.869 524.236 851.162 548.398 850.425 549.398C848.881 549.909 845.903 549.699 844.214 549.656L841.681 549.694C841.5 551.669 841.151 557.906 841.879 559.55C843.849 560.74 850.164 558.772 850.616 560.927C851.061 563.049 850.594 566.686 850.883 569.184C856.838 569.256 862.793 569.279 868.748 569.253C872.218 569.256 876.751 569.383 880.15 569.215C880.099 571.616 879.653 573.481 879.471 575.863C879.219 579.145 879.963 585.515 878.527 588.448C877.149 588.878 871.965 588.643 870.22 588.611C870.205 586.869 870.435 579.706 869.766 578.765C868.397 578.328 860.469 577.709 860.451 580.168C860.432 582.807 860.56 585.707 860.47 588.409C857.496 588.451 854.456 588.394 851.51 588.457C851.422 591.903 852.276 594.699 852.486 598.108C855.339 597.832 857.656 597.825 860.521 598.032C860.527 603.846 860.308 611.513 860.567 617.203C863.711 617.304 866.949 617.248 870.104 617.231C870 619.612 869.892 624.456 870.063 626.743C872.694 626.86 877.175 626.917 879.775 626.701C879.949 623.548 879.891 620.311 879.881 617.147C882.967 617.212 886.054 617.228 889.14 617.196C889.187 623.562 889.195 629.929 889.164 636.295C889.158 638.961 889.019 643.174 889.176 645.733C891.991 645.745 895.827 645.66 898.556 645.857C898.465 649.088 898.319 652.491 898.37 655.708C900.303 655.755 906.221 656.266 907.372 655.099C908.724 653.726 908.925 647.786 908.941 645.771C911.628 645.756 914.371 645.701 917.054 645.828C916.894 652.16 917.593 657.795 917.185 664.411C914.05 664.675 911.041 664.306 908.109 664.543C908.024 666.181 908.192 672.796 907.57 673.64C906.378 674.082 899.662 674.076 898.48 673.51C897.953 671.896 898.303 658.332 898.337 655.793C892.353 655.708 887.016 655.646 880.999 655.251C877.724 655.037 873.637 655.332 870.222 655.191C870.197 652.035 870.193 648.878 870.209 645.722C872.382 645.756 878.048 646.258 879.439 645.209C880.399 643.71 879.893 638.436 879.85 636.192C868.722 635.95 870.125 634.37 869.986 645.476C868.529 645.377 862.144 645.194 861.195 645.912C860.386 647.87 860.897 654.63 859.691 654.738C855.008 655.16 846.014 654.945 841.411 654.958C841.43 660.722 841.633 667.984 841.341 673.62C838.64 673.959 834.697 673.877 831.91 673.862C831.921 671.031 832.044 667.209 831.893 664.459C828.806 664.451 825.529 664.499 822.457 664.424C822.351 661.628 822.499 657.782 822.269 655.22C819.209 655.179 816.148 655.192 813.088 655.26C813.181 652.298 813.255 648.687 813.148 645.726C816.986 645.71 825.372 645.474 828.917 645.79C829.051 648.752 828.981 651.631 828.933 654.592C832.961 654.819 837.36 654.766 841.421 654.79C841.441 649.041 841.717 641.242 841.479 635.631C845.156 635.648 848.945 635.629 852.613 635.767C855.39 635.872 857.927 636.411 860.774 636.295C860.765 633.235 860.855 629.478 860.704 626.473C854.313 626.384 847.922 626.375 841.531 626.445C841.516 624.783 841.157 618.132 841.858 617.314C844.233 616.314 849.171 617.749 850.653 616.601C851.388 614.466 851.041 610.209 851.079 607.737C846.055 607.764 836.626 608.079 831.84 607.692C831.674 604.612 831.825 600.982 831.887 597.854C830.038 597.861 823.26 598.18 822.238 597.339C821.784 595.495 821.183 588.179 824.315 588.446C826.77 588.655 829.386 588.66 831.866 588.637C831.788 590.914 831.677 595.809 831.847 597.971C833.957 597.979 839.918 598.413 841.276 597.539C842.312 596.07 841.864 590.79 841.842 588.619C844.863 588.611 848.071 588.651 851.074 588.546C851.085 586.468 851.321 580.216 850.634 578.682C849.67 578.303 843.065 578.376 842.048 578.609C840.824 579.826 841.7 586.525 841.717 588.586C839.05 588.313 834.705 588.427 831.895 588.427C831.876 585.262 832.166 582.985 832.406 579.869C832.537 578.168 832.226 575.489 832.255 573.679C832.332 568.97 831.163 564.232 831.211 559.624Z" fill="#9E2184"/> -<path d="M765.109 521.292C770.502 521.272 779.064 521.513 784.286 521.149C784.259 523.175 783.84 528.409 784.783 529.777C786.001 530.655 791.788 530.248 793.902 530.339C793.969 532.553 793.555 538.542 794.469 539.788C795.879 540.682 801.363 540.285 803.311 540.131C803.391 536.944 803.417 533.756 803.39 530.568C805.649 530.523 810.713 530.202 812.661 530.898C813.831 532.344 812.974 553.657 813.145 557.292C813.344 561.515 804.07 557.097 803.56 560.218C803.328 561.641 803.177 567.922 803.682 568.893C804.638 569.456 811.126 569.149 813.029 569.312C813.262 571.5 813.113 586.755 812.378 588.027C809.823 589.354 797.939 587.633 794.609 588.614C793.542 588.929 793.907 596.722 793.962 597.809C791.848 597.819 786.396 597.54 784.692 598.034C783.617 599.438 784.612 604.833 784.135 606.586C783.46 609.066 777.369 606.607 774.878 608.01C774.169 609.171 774.351 616.566 774.325 618.519C773.028 618.48 769.628 618.818 768.747 618.266C768.66 617.959 768.473 617.186 768.254 617.144C765.591 616.627 758.218 616.977 755.688 616.854C755.52 610.686 755.683 604.066 755.629 597.826C752.416 597.793 749.28 597.75 746.068 597.853C745.83 600.537 746.052 604.487 745.904 607.491C742.742 607.7 739.63 607.441 736.503 607.705C736.566 604.431 736.594 601.157 736.587 597.883C733.711 597.719 730.034 597.825 727.094 597.84C727.115 594.761 727.104 591.682 727.061 588.603C735.94 588.794 746.746 588.771 755.621 588.553C755.693 585.219 755.699 581.885 755.64 578.552C752.9 578.372 749.163 578.517 746.213 578.422C746.139 576.244 746.601 570.767 745.708 569.402C744.395 568.459 738.769 569.016 736.57 569.051L736.601 568.767C738.128 553.585 734.485 561.29 727.694 558.582C726.404 558.067 727.105 551.97 727.117 550.868C727.112 550.48 727.137 550.198 727.419 550.037C729.776 548.685 745.359 550.992 746.064 548.71C746.803 546.317 745.245 532.41 746.807 530.622C748.587 530.08 753.692 530.211 755.633 530.4C755.792 539.604 755.239 550.712 755.689 559.566C757.306 559.576 763.215 559.225 764.195 559.958C765.532 562.537 764.708 574.682 764.892 578.481C768.873 578.543 772.855 578.554 776.837 578.516C778.749 578.51 782.166 578.61 783.894 578.329C785.896 575.925 782.513 569.97 785.968 569.645C787.806 569.471 791.899 570.159 793.68 569.311C794.409 567.362 794.422 551.987 793.705 550.171C790.418 548.631 775.536 551.421 774.375 548.798C773.654 547.167 775.391 542.998 773.608 542.028C771.785 541.036 766.594 542.998 765.485 540.903C764.621 539.272 765.1 524.28 765.109 521.292ZM774.164 597.935C774.55 596.22 774.885 589.983 774.152 588.655C772.653 588.167 767.061 588.342 765.238 588.351C764.868 589.74 764.645 596.637 765.117 597.703C766.509 598.201 772.467 598.05 774.164 597.935Z" fill="#9E2184"/> -<path d="M708.421 750.404C710.503 750.409 715.778 750.017 717.108 750.982C718.065 752.446 717.55 757.456 717.604 759.653L728.873 759.639C730.917 759.639 734.656 759.544 736.544 759.908C736.546 762.729 736.626 765.951 736.41 768.733C730.793 769.067 723.42 768.881 717.663 768.869L717.608 788.473L726.984 788.408C727.015 791.6 727.045 794.329 726.827 797.507C723.792 797.385 720.611 797.47 717.636 797.293C717.522 803.474 717.339 810.881 717.532 816.996L728.684 816.975C731.117 816.979 734.119 817.065 736.506 816.899C736.725 814.089 736.591 810.245 736.559 807.339C745.704 807.3 755.907 807.06 764.973 807.35C765.037 810.356 764.915 813.55 764.847 816.571C758.607 816.661 752.385 816.565 746.151 816.615C745.887 819.226 745.981 823.223 745.978 825.963C741.77 825.633 731.62 825.889 727.085 825.995C727.039 829.381 727.035 832.767 727.072 836.152L736.524 836.173C736.549 839.3 736.534 842.43 736.48 845.558C734.369 845.253 729.395 845.389 727.087 845.419C726.836 848.005 727.017 852.285 727.063 855.018C730.214 855.078 733.365 855.08 736.516 855.027C736.621 851.888 736.586 848.759 736.573 845.62C739.666 845.615 742.915 845.664 745.994 845.599C745.991 848.332 745.878 852.343 746.166 854.998C749.333 855.104 752.485 855.06 755.655 855.037C755.652 857.869 755.736 861.499 755.546 864.255C757.813 864.511 762.499 864.454 764.906 864.396C764.917 867.187 765.015 870.506 764.917 873.253C759.403 873.324 751.609 873.566 746.234 873.251C746.196 870.248 746.194 867.245 746.228 864.239C741.606 864.219 738.656 864.338 734.093 865.009C730.977 865.465 727.301 865.223 724.075 866.035C722.615 866.242 720.214 866.083 718.681 866.042C718.953 858.565 717.825 851.379 717.399 843.983C717.074 838.325 717.631 831.709 717.308 825.917C712.105 825.82 703.841 825.719 698.74 825.993C698.772 823.043 698.845 819.614 698.682 816.673C696.169 816.601 692.253 816.595 689.755 816.756C689.751 813.661 689.794 810.411 689.706 807.33C695.273 807.33 702.743 807.565 708.149 807.304C708.172 803.027 708.47 801.619 709.058 797.466C709.269 795.979 709.146 790.443 709.142 788.62L698.726 788.669C698.707 791.704 698.754 794.615 698.462 797.636C695.964 797.636 691.898 797.509 689.527 797.671C689.49 800.865 689.484 804.059 689.509 807.254C686.566 806.956 682.861 807.237 679.727 807.076C680.234 800.519 679.728 794.573 680.145 788.77C686.239 788.491 692.801 789.003 698.685 788.724C698.646 785.26 698.456 780.289 698.702 776.945C700.464 776.892 707.143 776.873 708.247 776.26C708.604 774.573 708.558 767.279 708.515 765.142C708.425 760.662 708.746 754.764 708.421 750.404Z" fill="#9E2184"/> -<path d="M813.286 674.107C817.92 673.57 826.715 674.048 831.911 673.862C831.558 679.333 831.76 687.694 831.728 693.315C834.697 693.359 837.88 693.281 840.866 693.264C841.037 690.56 840.947 686.906 840.952 684.132C844.453 683.863 867.901 683.592 869.703 684.482C870.323 684.789 870.432 685.323 870.583 685.953C871.413 689.433 870.85 695.62 870.87 699.306C870.888 702.529 871.192 705.933 870.891 709.129C870.815 709.938 870.719 710.588 870.272 711.273C868.757 712.065 862.927 711.653 860.589 711.819C860.337 715.018 860.651 718.33 860.322 721.77C857.214 721.84 854.009 721.817 850.893 721.833C851.322 717.219 851.066 707.511 851.071 702.508C854.241 702.522 857.405 702.563 860.573 702.44C860.742 700.905 861.057 693.885 860.281 693.098C858.619 692.725 852.886 692.584 851.282 693.435C851.054 693.702 850.679 694.139 850.674 694.494C850.636 697.068 850.832 699.819 850.876 702.392C846.455 702.196 836.138 702.141 831.964 702.461L831.943 693.451C829.923 693.41 823.635 693.729 822.028 695.168C821.093 696.005 821.83 700.671 821.91 702.506C824.194 702.674 829.599 702.692 831.853 702.457C831.698 705.46 831.842 708.581 831.678 711.727C825.604 711.883 819.046 711.568 813.068 711.84C813.016 706.013 813.244 699.607 813.239 693.649L812.971 693.075C811.811 692.481 805.113 692.842 803.502 692.957C803.288 697.338 803.557 704.195 803.585 708.763C806.237 708.576 808.991 708.648 811.651 708.707C811.571 711.952 812.196 712.886 812.373 715.907C812.443 717.106 811.524 719.821 811.542 721.339C811.573 723.888 812.316 726.467 812.321 728.938C812.338 736.115 812.062 743.186 812.378 750.369C808.752 749.961 798.183 750.259 793.981 750.226C794.16 747.908 793.975 743.241 793.95 740.75C796.966 740.842 800.274 740.768 803.313 740.756C803.462 737.802 803.455 734.004 803.332 731.063C800.483 730.945 796.979 731.049 794.08 731.061C794.146 728.067 794.078 724.831 794.069 721.817C791.297 721.662 787.268 721.775 784.422 721.764C784.385 718.71 784.395 715.654 784.453 712.598C786.337 712.625 792.322 712.835 793.797 712.526C794.404 710.952 794.303 695.099 793.978 692.924C792.794 692.228 786.834 692.586 784.788 692.419L784.485 692.392C784.061 687.896 784.309 678.628 784.356 673.876C787.408 674.131 790.844 674.068 793.942 674.077C793.926 677.398 793.935 680.719 793.969 684.04L813.2 684.029C813.412 681.442 813.282 676.822 813.286 674.107Z" fill="#9E2184"/> -<path d="M1040.72 617.19C1049.86 617.432 1059.64 617.128 1068.9 617.231C1069.14 619.893 1068.95 623.71 1068.86 626.439C1066.91 626.548 1061.37 626.275 1060.16 626.972C1059.24 628.112 1059.58 634.167 1059.53 636.265C1065.77 636.369 1072.16 635.83 1078.43 636.336L1078.41 645.736L1088.2 645.812C1088.34 651.994 1088.16 658.659 1088.22 664.928L1107.31 664.7L1107.33 673.735C1098.45 673.332 1087.98 673.626 1078.96 673.638C1079 670.834 1079.03 658.063 1078.44 655.716C1077.59 654.929 1070.84 655.216 1069.17 655.218C1069.13 651.977 1069.22 648.773 1069.13 645.521C1066.19 645.355 1062.74 645.496 1059.66 645.386C1059.58 642.424 1059.65 639.206 1059.66 636.224L1040.67 636.303C1040.71 639.32 1040.6 642.366 1040.53 645.384C1038.48 645.397 1033.43 645.282 1031.69 645.789C1030.64 646.88 1031.48 650.607 1031.28 652.019C1030.76 655.559 1031.37 661.168 1030.74 664.517L1029.51 664.507C1023.67 664.583 1017.83 664.547 1011.99 664.399C1011.77 667.416 1011.85 670.801 1011.68 673.951C1008.71 673.909 1005.45 673.865 1002.51 674.176C1002.46 676.493 1002.21 681.953 1002.48 683.987C1000.06 683.756 994.894 683.932 992.276 683.95C992.17 680.927 992.292 677.345 992.329 674.28C990.34 674.339 985.491 674.037 984.145 674.929C983.196 676.245 983.581 681.581 983.548 683.775C980.486 683.861 977.453 683.805 974.369 683.943C974.374 681.072 973.915 667.484 974.581 665.812C975.537 663.419 999.13 666.484 1002.23 664.634C1002.92 662.308 1002.85 648.506 1002.43 645.88C1001.57 645.098 994.924 645.35 993.173 645.339C993.018 642.711 993.076 639.332 993.053 636.649C995.745 636.801 1010.2 636.044 1011.37 637.044C1011.83 637.448 1011.97 638.173 1012.01 638.758C1012.16 641.008 1011.7 643.476 1011.57 645.738C1011.39 649.113 1011.44 652.53 1011.53 655.908C1014.19 656.064 1018.66 655.928 1021.37 655.8C1021.88 650.818 1021.55 641.829 1021.64 636.403C1027.6 636.11 1034.64 636.31 1040.73 636.249C1040.77 629.896 1040.77 623.543 1040.72 617.19Z" fill="#9E2184"/> -<path d="M1031.06 530.386C1032.44 530.538 1039.91 530.065 1040.26 531.132C1041.35 534.452 1039.7 546.925 1040.89 549.278C1042.31 549.865 1048.29 549.768 1049.87 549.497C1049.64 551.286 1049.88 556.299 1049.53 558.258C1049.37 558.412 1049.21 558.565 1049.05 558.718C1047.24 559.358 1042.8 559.022 1040.61 559.132C1040.54 561.893 1040.68 565.963 1040.45 568.53C1035.44 568.902 984.549 568.405 984.146 568.926C983.256 570.075 983.576 576.76 983.749 578.416C989.698 578.493 996.526 578.543 1002.45 578.349C1002.62 581.683 1002.29 585.478 1002.55 588.559C1001 588.286 995.047 588.368 993.115 588.365C992.952 589.852 993.023 591.707 992.79 593.112C991.62 600.174 993.088 607.262 993.009 614.363C992.926 621.682 992.744 629.034 992.754 636.382C987.759 636.268 983.18 636.371 978.262 637.185C977.298 637.344 975.199 637.232 974.185 637.209C973.643 625.73 970.824 627.153 983.364 626.811C983.509 621.766 983.247 616.241 983.417 611.126C983.592 605.861 984.925 593.545 983.943 588.78C982.56 588.132 976.303 588.41 974.383 588.434C974.394 586.369 974.89 581.008 974.03 579.754C972.666 578.801 967.413 579.226 965.289 579.229C965.494 577.205 965.455 571.794 965.298 569.745C967.017 569.676 972.138 569.903 973.367 569.611C975.45 569.114 973.569 562.53 974.611 559.879C976.579 558.418 998.914 560.192 1002.1 559.054C1002.89 557.934 1002.57 551.499 1002.57 549.702L1011.95 549.658C1011.81 552.544 1011.91 556.49 1011.99 559.411C1014.04 559.644 1019.29 559.415 1021.53 559.369C1021.71 556.453 1021.62 552.579 1021.62 549.594C1024.3 549.758 1028.27 549.657 1031 549.612C1031.39 545.183 1031.08 535.286 1031.06 530.386Z" fill="#9E2184"/> -<path d="M964.772 588.637L974.369 588.57C974.44 592.817 974.604 613.323 973.447 616.633C972.474 617.285 966.397 617.003 964.564 617.013C964.322 620.181 964.647 623.388 964.27 626.616C961.266 626.718 958.259 626.639 955.265 626.378C955.115 629.244 955.228 633.167 955.226 636.113C957.153 636.135 962.818 635.818 964.295 636.464C965.092 638.515 964.88 652.503 963.889 655.039C963.062 655.713 947.906 655.49 945.632 655.506C945.71 653.379 945.876 637.524 945.419 636.632L944.698 636.57C942.018 636.685 939.337 636.759 936.655 636.792C936.606 634.548 937.21 628.364 936.332 627.094C935.028 626.14 928.899 626.606 926.878 626.633C926.92 623.453 926.92 620.273 926.881 617.094C923.912 617.052 920.379 617.538 917.503 616.994C916.346 616.776 916.546 609.656 917.189 608.631C918.98 608.029 933.495 607.723 935.682 608.118C936.431 609.303 936.134 615.384 936.132 617.298C942.232 617.385 948.69 617.245 954.846 617.267C954.901 615.097 954.491 608.23 955.332 607.093C956.8 606.172 961.942 606.644 964.256 606.467L964.581 606.441C965.062 603.406 964.714 592.492 964.772 588.637Z" fill="#9E2184"/> -<path d="M955.482 664.984C957.844 664.874 961.937 664.807 964.302 664.99C964.703 670.977 964.21 678.006 964.364 684.135C967.63 683.994 970.9 684.041 974.168 684.054C974.178 687.012 974.118 690.272 974.208 693.204C977.229 693.23 980.919 693.159 983.885 693.31C983.88 695.865 983.754 700.117 983.963 702.536L993.067 702.538C992.991 708.567 993.118 715.682 992.788 721.612C989.794 721.706 986.798 721.757 983.8 721.759C983.816 718.436 983.885 714.969 983.839 711.66L974.318 711.545C974.318 708.565 974.373 705.375 974.295 702.413C967.886 702.496 960.82 702.881 954.551 702.685C954.498 704.711 954.258 709.798 954.489 711.653C949.688 711.713 941.525 711.462 937.095 711.805C937.068 708.871 936.987 705.649 937.15 702.734C942.944 702.651 948.741 702.632 954.535 702.676C954.406 700.146 953.786 692.428 955.074 690.602C955.823 689.543 955.464 685.858 955.519 684.435C955.482 678.962 955.166 670.314 955.482 664.984Z" fill="#9E2184"/> -<path d="M851.078 483.105L860.57 483.083L860.522 501.673L860.494 521.089C857.468 521.003 854.121 521.073 851.07 521.075L851.097 511.247L841.692 511.161C841.688 509.917 842.28 502.271 841.062 501.987C836.486 500.921 816.706 502.901 813.731 501.228C813.031 499.73 813.369 485.723 813.396 483.127C816.461 483.027 819.871 483.093 822.962 483.086C822.947 484.72 822.652 491.468 823.39 492.476C824.729 492.869 830.392 493.143 831.589 492.034C832.575 491.121 831.989 488.379 831.978 487.033C831.968 485.767 832.017 484.403 832.081 483.091L841.612 483.092L841.649 492.471C852.816 493.94 851.148 492.751 851.078 483.105Z" fill="#9E2184"/> -<path d="M765.097 702.28C771.507 702.247 777.917 702.388 784.319 702.702C784.348 705.958 784.357 709.215 784.345 712.471C781.87 712.059 777.175 711.953 774.551 712.171C774.496 715.087 774.364 719.106 774.568 722.001C777.729 722.003 781.115 722.04 784.266 721.84L784.243 731.091C780.969 731.045 777.826 731.008 774.554 731.095C774.527 732.96 774.306 739.226 774.485 740.747C771.956 740.69 767.37 740.6 764.922 740.793L764.894 759.408C760.34 759.425 750.335 759.703 746.232 759.319C746.179 757.265 745.694 752.287 746.784 750.89C748.13 750.028 753.673 750.494 755.85 750.427C756.038 744.852 755.987 739.272 756.082 733.697C756.124 731.243 754.98 723.974 756.489 722.268C758.913 721.217 763.08 723.554 765 721.459C765.242 720.736 765.197 720.298 765.205 719.544L765.097 702.28Z" fill="#9E2184"/> -<path d="M1012.11 578.481C1015.29 578.352 1018.44 578.443 1021.62 578.501C1021.63 587.67 1021.33 598.682 1021.64 607.699C1023.81 607.729 1029.13 608.192 1030.58 607.155C1031.51 605.731 1031.04 600.151 1031.12 597.894C1034.86 597.812 1046.53 597.612 1049.76 598.099L1049.72 607.409C1047.83 607.996 1041.14 607.177 1040.81 608.378C1040.18 610.59 1040.49 614.534 1040.52 616.975C1037.87 616.972 1033.69 616.858 1031.23 617.135C1031.12 619.322 1031.43 624.971 1030.49 626.28C1029.02 627.252 1024.03 626.695 1021.64 626.868C1021.61 623.665 1021.67 620.152 1021.56 616.986C1018.54 616.93 1015.02 617.049 1012.11 616.908C1012.14 610.724 1012.27 604 1012.1 597.837C1009.53 597.815 1005.07 597.933 1002.69 597.694C1002.67 594.787 1002.73 591.422 1002.55 588.559C1005.27 588.629 1009.25 588.722 1011.94 588.553C1011.97 585.889 1011.85 580.955 1012.11 578.481Z" fill="#9E2184"/> -<path d="M679.881 711.713C683.04 711.664 686.257 711.685 689.421 711.674L689.556 721.95C692.003 722.1 695.914 722.029 698.347 721.918C698.11 727.38 698.74 734.9 698.814 740.775C700.871 740.83 706.048 740.487 707.574 741.015C708.995 742.361 708.08 747.871 708.342 750.187C705.481 750.197 691.462 749.932 689.704 750.653C689.465 751.752 690.089 757.189 690.155 758.908C692.687 759.282 696.508 758.726 698.718 759.445C698.76 762.589 698.752 765.732 698.693 768.876C692.618 768.876 686.117 769.035 680.089 768.835L680.107 740.934C683.082 740.641 686.523 740.927 689.663 740.796C689.838 737.924 689.719 734.006 689.707 731.049C686.501 731.042 683.315 731.056 680.111 730.913C680.04 727.673 680.087 724.363 680.027 721.114C679.981 718.675 679.032 713.812 679.881 711.713Z" fill="#9E2184"/> -<path d="M774.536 645.751C777.628 645.839 781.06 645.737 784.227 645.78C784.399 648.452 784.272 652.658 784.286 655.458C787.49 655.535 790.655 655.446 793.915 655.555C793.962 658.517 793.959 661.48 793.906 664.442C790.699 664.538 787.49 664.513 784.284 664.367C784.127 667.142 784.24 670.891 784.249 673.741C781.263 673.549 777.345 673.583 774.542 673.213C774.531 675.859 774.497 690.908 773.986 692.563C772.867 693.356 766.669 693.094 764.885 693.09C764.875 695.566 764.749 699.858 765.025 702.178C763.264 702.251 756.65 702.012 755.698 702.54C755.677 705.866 755.581 709.187 755.41 712.506C752.816 712.755 748.864 712.639 746.25 712.561C746.113 706.223 746.217 699.594 746.237 693.232C751.926 693.344 758.855 693.336 764.496 693.199C764.775 689.615 765.079 686.238 765.616 682.646C765.905 680.713 764.424 673.52 765.422 672.109C766.664 671.41 772.921 671.783 774.476 672.08C774.834 663.967 774.474 654.105 774.536 645.751Z" fill="#9E2184"/> -<path d="M1078.15 578.46C1079.27 578.515 1087.55 578.827 1087.85 578.084C1089.07 575.108 1087.3 561.468 1088.8 559.575C1090.14 559.116 1095.69 559.042 1096.95 559.664C1098.76 560.565 1096.57 575.507 1097.59 578.205C1097.73 578.555 1098.02 578.552 1098.34 578.68C1100.42 578.664 1105.31 578.115 1106.76 579.162C1107.65 580.466 1107.16 586.315 1107.15 588.541C1100.15 588.287 1092.22 588.536 1085.13 588.427C1081.49 588.371 1072.34 588.225 1069.06 588.602C1069.05 584.845 1069.02 581.019 1069.08 577.268C1069.13 574.271 1069.37 571.761 1069.26 568.738C1066.36 568.475 1062.81 568.722 1059.67 568.54C1059.62 566.747 1059.31 560.612 1060.01 559.39C1065.56 559.168 1072.93 559.249 1078.53 559.401C1078.85 562.731 1078.31 565.898 1078.16 569.215C1078.03 572.288 1078.07 575.386 1078.15 578.46Z" fill="#9E2184"/> -<path d="M1107.38 673.923C1110.46 673.954 1113.57 673.814 1116.62 674.13C1116.9 679.009 1116.71 683.93 1116.64 688.814C1116.62 690.156 1116.58 691.392 1116.94 692.699C1118.61 694.138 1131.81 692.454 1134.85 693.548C1135.96 694.816 1135.32 709.21 1135.23 711.823C1132.18 711.989 1129.12 711.941 1126.08 711.678C1117.22 711.761 1106.37 712.019 1097.6 711.681C1097.39 708.59 1097.63 705.695 1097.48 702.678C1100.7 702.669 1104.13 702.713 1107.33 702.568C1107.49 693.371 1107.59 683.096 1107.38 673.923Z" fill="#9E2184"/> -<path d="M974.387 502.087C976.392 501.923 982.089 501.91 984.037 502.135C984.223 508.51 983.917 515.03 984.094 521.326C985.648 521.331 991.836 520.83 992.566 521.676C993.981 523.312 993.103 529.228 992.253 531.192C990.34 531.21 986.016 530.908 984.777 531.927C984.193 532.975 984.484 538.964 984.41 541.042C984.408 550.775 984.73 550.489 974.359 549.486C974.371 546.762 974.511 542.497 974.322 539.901C971.1 539.973 967.89 540.074 964.668 539.999C964.668 537.395 964.532 533.155 964.7 530.683C967.104 530.566 972.737 531.142 974.014 529.985C974.843 528.421 974.345 523.239 974.274 521.161C971.17 521.091 967.752 521.196 964.728 521.057C964.62 517.758 964.663 514.488 964.689 511.188C966.892 511.501 971.921 511.387 974.32 511.366C974.435 508.31 974.392 505.154 974.387 502.087Z" fill="#9E2184"/> -<path d="M1088.26 511.118C1088.2 509.407 1087.72 503.394 1088.73 502.296C1090.66 501.78 1105.24 501.83 1107 502.326C1107.43 505.055 1106.96 508.599 1107.24 511.354C1110.22 511.372 1124.37 511.034 1126.03 511.739C1126.72 512.928 1126.8 520.693 1125.98 520.852C1123.35 521.362 1119.61 521.028 1116.84 521.091C1116.74 524.501 1117.13 537.496 1116.41 539.634C1115.14 540.346 1109.18 540.01 1107.36 540.016C1107.36 537.083 1107.47 533.406 1107.33 530.535C1105.41 530.503 1099.1 530.766 1097.88 530.03C1096.58 527.69 1098.23 515.427 1097.4 512.188C1096.98 510.521 1090.03 511.238 1088.26 511.118Z" fill="#9E2184"/> -<path d="M983.799 721.759C983.716 723.188 983.709 724.737 983.712 726.175C983.73 734.225 983.488 742.388 983.723 750.429C986.775 750.521 1000.12 750.07 1002.1 750.865C1002.89 752.499 1002.51 766.133 1002.47 768.89C999.568 768.802 996.321 769.023 993.251 768.966C993.262 765.82 993.255 762.672 993.225 759.526C988.84 759.111 979.45 759.422 974.597 759.374C974.634 753.091 974.288 747.057 974.329 740.724C971.412 740.597 967.759 740.729 964.719 740.687C964.546 737.79 964.663 734.154 964.707 731.245C967.715 731.16 971.004 731.236 974.034 731.252C974.235 728.242 974.159 724.889 974.15 721.842C977.077 721.895 980.93 721.953 983.799 721.759Z" fill="#9E2184"/> -<path d="M774.554 483.12C784.49 482.969 794.735 483.085 804.696 483.097C804.763 486.336 804.815 490.025 804.554 493.231C795.274 493.037 783.382 493.588 774.406 492.967C774.26 498.953 774.481 504.96 774.264 511.019C771.797 511.307 768.512 511.212 765.97 511.21C765.743 511.22 765.487 511.313 765.255 511.377C764.632 512.624 764.883 519.441 765.03 521.101C759.14 521.122 752.024 521.318 746.238 521.039C746.13 519.381 745.834 513.038 746.574 511.81C748.656 511.014 761.637 511.423 765.085 511.29C765.255 505.153 764.982 498.849 765.229 492.711C768.229 492.654 771.369 492.737 774.381 492.779C774.392 489.82 774.267 485.97 774.554 483.12Z" fill="#9E2184"/> -<path d="M889.253 711.738C894.071 711.717 899.81 711.441 904.539 711.736C915.33 712.411 926.012 712.208 936.826 712.19C936.913 716.062 936.616 718.804 936.18 722.662C935.929 724.891 936.392 728.512 935.593 730.602C933.965 731.333 929.335 731.061 927.349 731.04C926.844 730.69 927.086 723.63 927.093 722.508C922.532 722.185 913.094 722.515 908.236 722.533C908.082 725.29 908.065 728.281 908.003 731.058L898.426 731.072C898.27 728.173 898.321 724.661 898.292 721.713C895.273 721.505 892.394 721.955 889.089 721.563C889.003 719.837 888.767 713.063 889.253 711.738Z" fill="#9E2184"/> -<path d="M1050.09 483.093L1059.66 483.103C1059.73 486.59 1059.92 509.294 1059.26 510.843C1057.72 511.474 1051.92 511.143 1050 511.102C1049.72 514.382 1050.02 517.636 1049.69 521.064C1047.16 521.21 1042.55 521.254 1040.07 521.01C1039.87 514.773 1040.12 508.116 1039.99 501.79C1037.1 501.674 1034.06 501.757 1031.16 501.786C1031.25 500.697 1030.73 493.234 1031.6 492.879C1034.87 491.537 1046.96 493.686 1049.67 492.227C1050.42 490.852 1050.11 485.114 1050.09 483.093Z" fill="#9E2184"/> -<path d="M955.277 559.36C957.466 559.661 962.898 558.825 964.182 560.05C964.841 562.136 964.936 574.141 964.832 577.06C964.717 580.32 963.746 584.598 964.645 588.406L945.772 588.433L945.765 578.943C944.297 578.374 929.877 578.826 926.971 578.671C926.901 575.412 926.975 572.492 927.005 569.257C936.468 569.264 946.277 569.412 955.712 569.285C955.733 565.5 955.669 563.161 955.277 559.36Z" fill="#9E2184"/> -<path d="M813.609 617.043C816.459 617.017 819.393 617.113 822.249 617.172C822.259 620.204 822.2 623.632 822.407 626.622C825.383 626.758 829.018 626.648 832.07 626.704C834.57 626.75 839.049 626.895 841.379 626.631C841.404 629.532 841.371 632.474 841.364 635.379C837.078 635.533 832.844 635.688 828.556 635.531C825.03 635.402 816.905 634.415 813.601 635.02C813.114 635.678 813.162 635.711 813.056 636.498C812.881 638.911 812.735 643.033 812.957 645.454C807.09 645.072 800.364 645.729 794.06 645.296C793.905 643.201 793.347 638.238 794.524 636.694C795.907 635.794 801.039 636.134 803.234 636.092C803.597 633.74 803.537 629.876 803.558 627.372C806.028 627.252 809.151 627.377 811.52 627.312C815.241 627.209 811.558 619.503 813.609 617.043Z" fill="#9E2184"/> -<path d="M691.08 492.391L707.106 492.333C709.132 492.323 714.288 492.167 716.085 492.561C717.264 493.707 717.383 509.439 716.709 510.678C716.062 511.129 715.444 511.029 714.629 511.043C706.554 511.146 696.765 511.428 688.799 511.078C688.921 505.367 688.441 498.515 688.396 492.511L691.08 492.391Z" fill="#9E2184"/> -<path d="M698.553 521.324C707.901 521.117 717.339 521.389 726.696 521.282C729.948 521.245 733.27 521.255 736.516 521.366C736.545 523.498 736.966 528.431 735.965 529.895C734.644 530.799 728.485 530.351 726.287 530.356C724.176 530.393 719.547 530.045 717.945 530.646C716.657 531.961 717.214 537.402 717.086 539.911C712.83 540.24 702.68 540.135 698.307 539.97C698.173 537.35 697.862 522.982 698.553 521.324Z" fill="#9E2184"/> -<path d="M1078.5 539.768C1079.05 535.284 1079.27 531.684 1078.9 527.196C1078.83 526.322 1078.75 522.094 1079.24 521.569C1080.7 521.15 1086.57 521.087 1087.85 521.729C1088.51 522.971 1088.16 537.524 1088.14 540.112C1090.88 540.324 1095.06 540.184 1097.9 540.202C1100.41 540.219 1105.05 540.322 1107.37 540.016C1107.25 542.371 1107.69 547.121 1106.93 549.014C1105.75 549.52 1072.28 549.658 1069.52 549.277C1068.9 548.109 1068.85 542.218 1069.3 541.03C1069.99 539.186 1076.77 541.148 1078.5 539.768Z" fill="#9E2184"/> -<path d="M755.879 626.733C758.523 626.587 762.163 626.688 764.882 626.685L764.921 636.059C767.787 636.124 771.47 635.923 774.367 635.828C774.336 639.03 774.346 642.232 774.399 645.434C771.532 645.336 767.801 645.362 764.927 645.456C764.67 650.57 765.316 659.74 764.603 664.346C763.111 664.75 757.435 664.642 755.655 664.638C755.553 658.27 755.781 651.855 755.589 645.485C752.82 645.247 749.247 645.342 746.403 645.346C746.543 642.419 746.62 639.585 746.483 636.656C747.784 636.622 750.147 636.461 751.388 636.696C758.418 638.026 754.537 630.888 755.879 626.733Z" fill="#9E2184"/> -<path d="M1127.28 740.846C1129.26 740.786 1133.51 740.443 1135.15 741.153C1135.87 742.478 1135.38 774.495 1135.19 778.54C1131.28 778.606 1129.39 778.47 1125.62 778.086C1122.68 778.097 1119.76 778.083 1116.82 778.049C1116.8 772.059 1116.71 765.852 1116.83 759.883C1119.69 759.646 1123.24 759.791 1126.23 759.708C1126.52 754.769 1125.89 746.398 1126.52 741.353C1126.55 741.07 1126.95 740.994 1127.28 740.846Z" fill="#9E2184"/> -<path d="M1078.73 607.736C1081.84 607.693 1084.96 607.691 1088.07 607.732C1088.28 610.654 1087.99 614.079 1088.12 617.196C1090.25 617.223 1095.63 616.846 1096.96 617.776C1097.81 619.099 1097.43 624.495 1097.45 626.656C1099.84 626.735 1102.22 626.575 1104.6 626.615C1108.05 626.672 1107.48 629.408 1107.33 631.849C1107.24 633.318 1107.21 634.719 1106.97 636.181C1102.82 636.605 1092.74 636.299 1088.27 636.283L1088.22 626.664C1085.14 626.564 1081.67 626.633 1078.57 626.627C1078.42 624.044 1078.18 609.661 1078.73 607.736Z" fill="#9E2184"/> -<path d="M1119.86 636.198C1122.15 636.199 1134.09 635.826 1135.14 636.566C1135.83 638.386 1135.45 643.31 1135.17 645.319C1121.49 646.105 1128.26 643.916 1125.83 654.427C1125.71 654.925 1118.46 654.674 1117.57 654.966C1117.13 655.114 1114.55 655.448 1113.81 655.461C1108.41 655.5 1103.01 655.474 1097.61 655.385C1097.38 652.774 1097.46 648.453 1097.52 645.779C1103.69 645.575 1110.61 645.702 1116.76 645.8C1116.82 642.652 1116.85 639.505 1116.84 636.357C1117.77 636.268 1118.91 636.245 1119.86 636.198Z" fill="#9E2184"/> -<path d="M1002.88 483.177C1008.83 482.943 1015.62 483.092 1021.63 483.099C1021.64 486.08 1021.73 489.312 1021.5 492.265C1018.53 492.394 1015.07 492.274 1012.01 492.328C1011.85 495.205 1011.94 498.845 1011.93 501.782C1009.87 501.746 1004.33 501.558 1002.59 502.018C1002.35 504.632 1002.54 508.267 1002.37 511.185C999.366 511.25 996.363 511.247 993.36 511.174L993.323 510.704C993.182 508.685 992.936 493.804 993.733 492.895C995.515 492.219 1000.34 492.577 1002.43 492.641C1002.69 490.22 1002.24 484.91 1002.88 483.177Z" fill="#9E2184"/> -<path d="M946.162 750.464C949.2 750.397 952.237 750.448 955.27 750.616C955.409 756.663 955.289 763.027 955.254 769.093L964.482 769.102C964.655 772.144 964.374 775.223 964.604 778.194C962.074 778.113 957.195 778.47 955.137 777.666C954.54 777.392 947.683 777.323 946.427 777.23C946.397 774.465 946.416 771.697 946.478 768.931C943.579 768.756 939.686 768.908 936.593 768.825L936.565 759.63C939.578 759.724 942.661 759.669 945.68 759.653C945.796 757.624 945.409 751.775 946.162 750.464Z" fill="#9E2184"/> -<path d="M717.41 569.261C721.498 569.136 725.64 569.276 729.73 569.242C731.85 569.224 734.503 569.35 736.57 569.051C736.541 571.539 736.601 576.093 736.353 578.451C734.193 578.528 728.722 578.277 727.427 579.209C726.6 580.484 726.953 586.776 727.061 588.603C725.259 588.238 710.505 588.388 708.258 588.556C708.27 586.397 707.974 580.896 708.575 579.194C709.071 577.79 714.655 579.301 716.92 578.357C717.757 577.211 717.402 571.278 717.41 569.261Z" fill="#9E2184"/> -<path d="M689.695 549.664C692.217 549.657 706.929 549.232 708.054 550.209C708.576 552.3 708.232 556.627 708.134 558.935C705.644 559.049 701.469 558.68 699.339 559.281C697.661 561.394 700.104 567.924 697.866 568.641C691.916 568.839 686.041 568.683 680.094 568.515C680.101 558.243 677.706 556.907 689.359 558.945C689.49 556.445 688.991 551.624 689.695 549.664Z" fill="#9E2184"/> -<path d="M888.762 482.059L888.978 482.022C889.629 482.892 889.122 507.656 889.277 511.188C886.169 511.204 883.06 511.196 879.952 511.166C880.089 508.65 880.005 505.341 880.004 502.767L879.758 502.144C878.455 501.489 872.318 501.825 870.208 501.712C870.159 498.716 870.156 495.72 870.198 492.724C873.019 492.445 875.591 492.748 878.424 492.596C880.376 492.769 880.065 490.029 879.879 488.692C878.827 481.123 882.329 482.59 888.762 482.059Z" fill="#9E2184"/> -<path d="M793.962 597.809C799.041 597.919 808.492 597.497 812.982 598C813.024 600.115 813.367 605.485 812.635 607.208C811.06 608.303 805.424 606.823 803.866 607.98C803.107 608.543 803.384 615.368 803.308 616.471C802.408 616.461 799.07 616.39 798.407 616.595C795.961 617.353 796.857 617.661 794.078 617.679C793.965 619.794 794.255 624.608 793.423 626.037C792.008 627.23 786.428 626.637 784.231 626.589C784.167 623.622 784.848 623.098 784.768 620.582C784.734 619.529 784.447 619.542 784.845 618.414C785.859 618.166 792.461 617.632 793.916 617.529C794.35 611.852 793.944 603.748 793.962 597.809Z" fill="#9E2184"/> -<path d="M1107.56 607.79C1110.26 607.762 1124.13 608.076 1126 609.056C1126.7 610.444 1126.26 615.554 1126.47 617.6C1131.36 617.706 1135.91 615.772 1135.41 622.113C1135.29 623.612 1136.04 624.712 1135.42 626.488C1133.26 626.626 1118.41 626.83 1117.16 626.276C1116.1 624.473 1117.38 620.146 1116.63 617.836C1113.24 614.989 1106.26 621.152 1107.27 612.131C1107.43 610.712 1107.04 609.262 1107.56 607.79Z" fill="#9E2184"/> -<path d="M1040.97 645.527C1043.28 645.905 1048.36 645.137 1049.47 646.046C1049.84 648.585 1049.67 654.455 1049.64 657.202C1049.58 662.687 1049.67 668.415 1049.52 673.88C1046.7 674.013 1043.06 673.918 1040.17 673.925C1037.13 673.937 1034.12 673.981 1031.09 673.829C1030.94 671.285 1031.07 667.549 1031.09 664.92L1040.18 664.905C1040.34 663.749 1040.49 662.456 1040.46 661.288C1040.34 655.955 1041.08 650.86 1040.97 645.527Z" fill="#9E2184"/> -<path d="M726.157 482.121C729.602 482.496 733.294 482.935 736.734 483.15C736.603 486.687 736.827 510.64 736.246 511.476C733.625 511.809 728.8 512.395 726.358 512.564C726.413 502.585 726.202 492.136 726.157 482.121Z" fill="#9E2184"/> -<path d="M806.114 510.608C807.367 510.558 811.678 510.279 812.434 510.704C813.714 511.424 813.019 519.499 812.546 520.711C811.589 521.51 794.045 521.139 791.667 521.14L784.428 521.111C784.386 517.728 784.4 514.345 784.468 510.963C791.183 511.047 799.179 510.647 806.114 510.608Z" fill="#9E2184"/> -<path d="M917.457 588.599C926.136 588.778 937.031 588.772 945.685 588.582C945.468 591.756 945.719 595.153 945.491 598.477C941.776 598.555 937.646 598.243 933.869 598.132L917.194 597.806C917.102 595.624 916.888 590.48 917.457 588.599Z" fill="#9E2184"/> -<path d="M1109.15 723.093L1116.62 722.893C1116.65 729.251 1116.91 735.26 1116.77 741.644C1112.5 741.764 1109.32 741.121 1105.12 741.109C1102.48 741.132 1099.83 741.081 1097.19 740.964C1097.28 737.744 1097.27 734.389 1097.3 731.157C1099.34 731.22 1105.69 731.505 1107.27 730.872C1108.96 728.936 1106.08 724.306 1109.15 723.093Z" fill="#9E2184"/> -<path d="M1021.14 501.993C1023.85 502.001 1028.54 502.158 1031.09 501.952C1031.08 504.957 1031.13 508.162 1031.05 511.149C1027.92 511.211 1024.79 511.235 1021.66 511.222C1021.57 514.385 1021.43 517.958 1021.49 521.1C1018.9 520.788 1014.8 520.967 1012 520.886C1012.02 514.829 1012.16 507.958 1011.98 501.973L1021.14 501.993Z" fill="#9E2184"/> -<path d="M774.485 740.747C777.782 740.803 781.079 740.8 784.376 740.734C784.138 743.559 784.246 747.486 784.312 750.363C786.503 750.671 791.507 750.459 793.912 750.411C793.905 752.766 793.996 757.203 793.762 759.385L781.453 759.42C779.601 759.427 776.207 759.367 774.457 759.581C774.743 754.827 774.581 745.619 774.485 740.747Z" fill="#9E2184"/> -<path d="M1007.57 521.197C1009.09 521.226 1010.35 521.222 1011.87 521.154L1011.92 539.97L1002.51 539.992L1002.44 549.435L997.955 549.462C996.4 549.469 994.846 549.449 993.293 549.401C992.212 537.815 993.062 540.797 1002.31 540.065C1002.27 538.873 1002.26 537.729 1002.37 536.539C1002.84 531.489 1002.74 526.446 1002.74 521.376C1004.25 521.263 1006.03 521.247 1007.57 521.197Z" fill="#9E2184"/> -<path d="M812.402 750.482C815.672 750.503 819.005 750.452 822.281 750.436L822.313 765.444C822.315 767.56 822.43 772.485 822.02 774.377C820.069 774.426 815.731 774.654 814.081 774.304C813.643 773.774 813.496 773.405 813.514 772.66C813.635 767.514 813.441 762.289 812.854 757.177C812.575 754.741 812.28 752.928 812.402 750.482Z" fill="#9E2184"/> -<path d="M954.564 711.784L974.161 711.704V721.759C967.701 721.628 961.02 721.93 954.576 721.611C954.597 718.337 954.592 715.062 954.564 711.784Z" fill="#9E2184"/> -<path d="M1040.7 578.722C1046.78 578.546 1053.56 578.596 1059.64 578.689C1059.65 580.216 1059.79 587.753 1059.39 588.427C1053.19 588.224 1046.51 588.716 1040.32 588.352C1040.25 586.316 1039.77 580.053 1040.7 578.722Z" fill="#9E2184"/> -<path d="M927.141 674.121C929.925 674.14 943.825 673.507 945.099 674.705C945.661 676.592 945.578 682.113 945.076 683.948C940.414 684.485 932.467 683.908 927.689 683.793C926.369 683.762 926.655 675.452 927.141 674.121Z" fill="#9E2184"/> -<path d="M727.094 597.84C727.001 601.054 727.053 604.388 726.972 607.655C720.933 607.42 714.596 607.774 708.357 607.52C708.13 605.081 708.292 600.56 708.28 597.914C714.142 597.786 721.451 598.17 727.094 597.84Z" fill="#9E2184"/> -<path d="M917.674 626.937C920.591 626.836 923.763 626.885 926.699 626.879L926.685 637.197L936.549 637.026C936.574 639.076 936.837 643.555 936.074 645.437C935.959 645.721 935.521 645.752 935.132 645.867C931.043 645.884 930.734 647.05 925.913 646.384C926.259 644.339 926.362 639.539 926.468 637.247C924.226 637.253 921.004 637.636 918.99 636.898C918.598 635.869 918.294 633.81 918.169 632.66C917.98 630.916 916.876 628.466 917.674 626.937Z" fill="#9E2184"/> -<path d="M1059.72 588.574C1062.17 588.733 1066.32 588.595 1068.89 588.591C1069.02 594.85 1069 601.11 1068.85 607.367C1066.95 608.089 1061.83 607.784 1059.69 607.685C1059.44 602.739 1059.59 593.573 1059.72 588.574Z" fill="#9E2184"/> -<path d="M1069.97 483.138C1075.01 482.945 1081.82 483.049 1086.94 483.177C1087.21 483.254 1087.86 483.342 1087.91 483.679C1088.18 485.264 1088.99 491.663 1087.36 492.327C1083.77 492.521 1072.33 492.597 1069.12 492.246C1069.05 489.719 1068.9 486.831 1069.1 484.312C1069.16 483.561 1069.48 483.457 1069.97 483.138Z" fill="#9E2184"/> -<path d="M1107.32 588.616C1110.45 588.763 1124.88 588.068 1126.32 589.177C1126.93 591.024 1126.55 595.502 1126.46 597.613C1124.87 598.189 1110.07 597.842 1107.34 597.812L1107.32 588.616Z" fill="#9E2184"/> -<path d="M880.316 673.936C881.592 673.916 888.855 673.532 889.001 674.545C889.428 677.523 889.143 690.252 888.276 692.756C886.743 693.268 882 693.547 881.083 692.902C879.102 691.508 879.642 675.112 880.316 673.936Z" fill="#9E2184"/> -<path d="M927.033 655.688L945.553 655.68C945.542 657.488 945.772 663.352 945.051 664.477C939.787 664.567 932.062 664.79 926.909 664.442C926.849 662.315 926.653 657.567 927.033 655.688Z" fill="#9E2184"/> -<path d="M1097.6 759.321C1100.44 759.097 1104.2 759.136 1107.1 759.194C1107.44 761.552 1107.2 766.362 1107.12 768.897C1103.92 768.998 1100.72 769.049 1097.53 769.051C1097.67 765.716 1097.49 762.563 1097.6 759.321Z" fill="#9E2184"/> -<path d="M899.279 626.762C901.951 626.613 905.357 626.746 908.031 626.859C908.238 629.272 908.1 632.396 908.056 634.854C908.042 635.732 907.989 635.864 907.5 636.308C904.431 636.36 901.358 636.353 898.29 636.284C898.257 633.851 898.002 629.551 898.477 627.184C898.537 626.885 898.875 626.888 899.279 626.762Z" fill="#9E2184"/> -<path d="M898.638 483.082L908.021 483.094C908.054 485.282 908.249 491.068 907.749 492.957L907.459 492.995C896.97 494.292 898.551 492.346 898.638 483.082Z" fill="#9E2184"/> -<path d="M1123.52 549.286C1124.37 549.121 1125.48 549.039 1126.27 549.399C1126.83 550.619 1126.5 557.137 1126.46 558.955C1124.3 559.011 1121.92 558.957 1119.74 558.954C1118.78 558.95 1117.78 558.911 1116.82 558.887C1116.74 555.821 1116.74 552.754 1116.82 549.688C1119.23 549.534 1121.05 549.78 1123.52 549.286Z" fill="#9E2184"/> -<path d="M898.459 684.057C901.649 683.974 904.843 683.978 908.033 684.066C908.328 686.148 908.307 691.16 908.024 693.258C904.79 693.296 901.555 693.29 898.32 693.239C898.262 691.172 898.044 685.878 898.459 684.057Z" fill="#9E2184"/> -<path d="M1118.69 569.124C1121.43 569.089 1123.94 569.167 1126.68 569.267C1126.75 571.459 1127.03 575.65 1126.51 577.815C1126.38 578.344 1125.79 578.368 1125.39 578.438C1123.3 578.433 1119.06 578.716 1117.26 578.244C1116.48 576.527 1116.49 571.692 1117.04 569.767C1117.69 569.067 1117.49 569.29 1118.69 569.124Z" fill="#9E2184"/> -<path d="M945.827 731.273C948.948 731.151 952.112 731.236 955.24 731.28C955.279 733.704 955.422 738.468 955.136 740.74C951.986 740.773 948.833 740.766 945.68 740.717C945.615 738.256 945.445 733.575 945.827 731.273Z" fill="#9E2184"/> -<path d="M869.916 540.13C870.406 540.563 870.065 548.182 870.181 549.629L861.041 549.651C859.993 548.796 860.244 541.905 861.183 540.565C862.557 539.683 867.861 540.191 869.916 540.13Z" fill="#9E2184"/> -<path d="M784.423 731.167C787.549 731.282 790.821 731.243 793.961 731.25C793.924 734.414 793.905 737.578 793.906 740.743L784.375 740.734L784.423 731.167Z" fill="#9E2184"/> -<path d="M1049.94 540.225L1059.61 540.234C1060.02 551.824 1060.81 549.15 1049.87 549.497C1049.88 546.79 1049.73 542.785 1049.94 540.225Z" fill="#9E2184"/> -<path d="M879.937 597.888C882.99 597.832 886.044 597.831 889.098 597.884C889.26 600.989 889.153 604.429 889.114 607.566L879.852 607.536C879.923 604.571 879.731 600.647 879.937 597.888Z" fill="#9E2184"/> -<path d="M1011.99 540.066C1015.25 540.228 1018.42 540.166 1021.65 540.253L1021.62 549.594C1019.73 549.316 1014.19 549.441 1012.02 549.446C1012.01 546.352 1012.05 543.15 1011.99 540.066Z" fill="#9E2184"/> -<path d="M879.853 607.536C879.554 608.968 879.71 615.382 879.838 617.026C876.671 617 873.543 616.944 870.378 617.088C869.88 616.435 870.165 609.044 870.212 607.776C872.591 607.646 877.931 607.876 879.853 607.536Z" fill="#9E2184"/> -<path d="M1107.86 483.137C1110.84 483.085 1113.81 483.054 1116.79 483.045C1116.83 485.642 1116.99 488.981 1116.69 491.58C1116.62 492.157 1116.38 492.19 1115.98 492.441C1113.08 492.534 1110.17 492.547 1107.27 492.481C1107.18 490.623 1106.87 484.242 1107.86 483.137Z" fill="#9E2184"/> -<path d="M823.109 740.84C825.752 740.731 829.196 740.706 831.803 740.888C831.763 742.72 832.034 748.961 831.524 750.22L830.846 750.229C828.075 750.243 825.23 750.213 822.468 750.358C822.453 747.599 822.241 744.734 822.341 741.978C822.367 741.271 822.67 741.148 823.109 740.84Z" fill="#9E2184"/> -<path d="M974.385 483.113C977.499 483.052 980.753 483.099 983.88 483.099C983.924 486.003 984.025 489.466 983.797 492.315C980.73 492.497 977.432 492.486 974.339 492.524L974.385 483.113Z" fill="#9E2184"/> -<path d="M874.933 721.699C876.321 721.607 878.255 721.653 879.686 721.646C879.682 724.67 879.746 728.014 879.531 730.996C878.183 731.068 876.366 731.019 874.981 731.022L870.182 730.996C870.106 728.042 870.17 724.817 870.171 721.842L874.933 721.699Z" fill="#9E2184"/> -<path d="M727.975 740.849C730.626 740.724 733.774 740.793 736.471 740.796C736.484 742.409 736.824 749.422 735.828 750.194C732.919 750.27 730.009 750.247 727.102 750.13C726.998 747.88 726.842 743.605 727.218 741.337C727.272 741.012 727.56 741.012 727.975 740.849Z" fill="#9E2184"/> -<path d="M927.045 483.122C930.156 483.045 933.422 483.098 936.547 483.106C936.547 486.177 936.473 489.248 936.326 492.316L926.89 492.285C926.844 490.351 926.641 484.766 927.045 483.122Z" fill="#9E2184"/> -<path d="M899.126 502.085C901.285 502.038 906.148 501.557 907.632 502.538C908.678 504.018 908.058 509.028 907.959 511.161C904.91 511.252 901.598 511.193 898.529 511.193C898.502 508.572 898.443 505.767 898.548 503.15C898.579 502.375 898.637 502.49 899.126 502.085Z" fill="#9E2184"/> -<path d="M860.569 664.83L870 664.829C870.061 667.352 870.193 671.414 869.892 673.843C866.771 673.928 863.647 673.94 860.525 673.876C860.343 671.156 860.337 667.554 860.569 664.83Z" fill="#9E2184"/> -<path d="M870.222 759.634L879.662 759.692C879.693 762.734 879.666 765.776 879.581 768.816C876.455 768.869 873.328 768.876 870.202 768.837C870.147 765.836 870.211 762.649 870.222 759.634Z" fill="#9E2184"/> -<path d="M813.026 655.445C812.92 658.505 813.06 661.329 812.754 664.431C809.63 664.491 806.506 664.494 803.382 664.441C803.346 662.442 803.167 657.183 803.572 655.486L813.026 655.445Z" fill="#9E2184"/> -<path d="M889.203 607.627C890.767 607.819 896.622 607.72 898.575 607.745C898.588 610.006 898.698 614.737 898.373 616.793C897.064 617.112 890.929 616.989 889.302 616.982C889.341 613.863 889.308 610.744 889.203 607.627Z" fill="#9E2184"/> -<path d="M1031.4 684.088C1034.19 684.013 1037.64 683.974 1040.39 684.143C1040.56 686.147 1040.73 691.412 1040.2 693.19L1030.99 693.162C1030.99 691.228 1030.69 685.175 1031.4 684.088Z" fill="#9E2184"/> -<path d="M1126.93 721.895C1129.65 721.851 1132.68 721.775 1135.36 722.049C1135.49 723.84 1135.84 730.132 1134.95 731.259C1132.71 731.215 1128.36 731.812 1127.03 731.031C1125.86 729.616 1125.78 723.294 1126.93 721.895Z" fill="#9E2184"/> -<path d="M1021.49 521.1C1024.53 521.217 1027.99 521.117 1030.92 521.331C1030.9 523.483 1030.73 528.347 1030.94 530.345C1028.08 530.367 1024.4 530.482 1021.62 530.301C1021.61 527.306 1021.65 524.078 1021.49 521.1Z" fill="#9E2184"/> -<path d="M727.094 607.751L736.49 607.735C736.286 609.758 736.366 614.387 736.316 616.67C734.677 617.15 729.009 616.97 727.091 616.956C727.148 613.935 727.099 610.783 727.094 607.751Z" fill="#9E2184"/> -<path d="M1060.02 655.519C1063.03 655.478 1066.04 655.463 1069.04 655.474C1068.76 658.4 1069.34 660.965 1068.75 664.39C1066.86 664.613 1062.42 665.117 1060.7 664.45C1059 663.796 1059.28 656.66 1060.02 655.519Z" fill="#9E2184"/> -<path d="M955.47 540.24C958.443 540.115 961.538 540.249 964.599 540.127C964.421 542.935 964.834 546.73 964.304 549.409L955.274 549.435C955.318 547.224 955.076 542.128 955.47 540.24Z" fill="#9E2184"/> -<path d="M1002.49 693.211C1002.49 695.921 1002.6 699.604 1002.26 702.217C999.428 702.391 996.028 702.335 993.145 702.348C993.265 699.521 993.193 696.153 993.23 693.263C996.284 693.206 999.425 693.228 1002.49 693.211Z" fill="#9E2184"/> -<path d="M1126.06 664.878C1130.11 664.938 1136.2 663.297 1135.55 669.039C1135.36 670.685 1135.81 672.221 1135.17 673.899C1133.23 673.891 1128.47 674.417 1127.27 673.689C1126.5 672.745 1125.95 666.236 1126.06 664.878Z" fill="#9E2184"/> -<path d="M765.119 759.657C768.01 759.667 771.638 759.766 774.457 759.581C774.261 761.098 774.356 766.429 774.353 768.247C771.707 768.079 767.819 768.203 765.077 768.215C765.194 765.573 765.116 762.34 765.119 759.657Z" fill="#9E2184"/> -<path d="M680.078 597.61L691.091 597.891C693.139 597.956 696.913 598.171 698.798 597.883C698.74 604.113 698.728 610.343 698.76 616.573C698.762 619.261 698.608 624.234 698.811 626.713C702.158 626.909 705.82 626.741 709.2 626.75C711.738 626.756 714.862 626.893 717.331 626.593C717.38 623.46 717.398 620.327 717.387 617.194C720.618 617.151 723.849 617.16 727.08 617.22C726.811 619.089 727.035 624.573 727.08 626.733C733.078 626.883 740.264 626.44 746.064 626.876C746.135 629.74 745.926 633.947 746.143 636.522C745.007 636.445 743.467 636.319 742.333 636.43C737.309 636.92 732.357 636.89 727.313 636.923C727.246 639.716 727.087 642.978 727.121 645.734C731.112 645.798 735.105 645.815 739.097 645.786C740.85 645.78 744.429 645.833 746.019 645.617C746.011 651.783 745.84 658.761 746.03 664.859L755.55 664.893C755.529 667.74 755.571 671.059 755.388 673.873C752.004 673.964 739.009 673.608 736.926 674.347C736.192 675.359 736.521 682.236 736.54 684.008L745.99 684.049C746.022 687.035 746.03 690.022 746.015 693.008C740.417 692.946 732.313 692.722 726.891 693.04L726.875 702.637C729.847 702.646 733.611 702.552 736.519 702.704C736.548 704.799 736.999 709.864 735.919 711.277C734.58 712.146 729.227 711.717 727.085 711.805C727.011 715.087 726.819 719.132 726.961 722.349C730.918 722.379 734.883 722.42 738.84 722.513C740.811 722.559 743.444 722.31 745.32 722.63C746.422 723.942 746.248 738.83 745.578 740.468C744.056 740.989 738.522 740.685 736.538 740.743C736.588 737.592 736.712 734.195 736.518 731.068C732.654 731.024 710.725 731.393 708.833 730.602C706.935 728.394 709.769 721.478 707.074 721.457C704.552 721.436 701.366 721.644 698.699 721.598L698.709 711.768C701.515 711.872 704.512 711.745 707.249 711.957C707.251 708.751 707.301 705.4 707.226 702.208C704.278 702.259 701.221 702.272 698.284 702.381C698.288 704.979 698.174 708.98 698.35 711.464C695.464 711.473 692.578 711.466 689.692 711.446C689.797 705.451 689.676 699.487 689.74 693.511C692.447 693.814 695.273 693.442 698.06 693.672C698.043 690.914 698.113 687.515 697.813 684.844L697.77 684.448L697.741 684.21C695.05 684.367 692.44 684.28 689.748 684.228C689.512 687.057 689.555 690.353 689.528 693.23C682.685 693.168 675.843 693.156 669 693.196V684.042L689.843 684.041C690.142 680.705 690.213 678.299 690.228 674.965C687.089 674.707 682.808 674.821 679.567 674.826C679.944 668.026 680.405 662.031 680.126 655.126C679.994 651.863 679.6 648.546 679.62 645.362L689.468 645.319C689.396 648.708 689.371 652.098 689.393 655.487L700.461 655.496C702.467 655.502 705.45 655.632 707.362 655.363C708.55 654.315 708.037 652.491 708.402 651.054C708.799 649.496 709.619 646.471 708.669 645.002C705.326 645.634 693.748 645.362 689.736 645.345C689.882 642.82 689.78 639.571 689.761 636.986C686.581 637.133 683.259 637.059 680.063 637.034L680.086 626.682L689.454 626.68C689.666 620.867 689.591 613.44 689.492 607.611L680.073 607.541L680.078 597.61ZM717.179 683.984C713.933 684 710.268 683.934 707.057 684.054C706.829 686.55 706.531 700.019 707.197 701.807C708.732 702.418 714.242 702.094 716.389 702.195C716.829 701.981 717.1 701.975 717.137 701.601C717.628 696.592 717.323 688.97 717.336 684.04C720.259 684.027 724.13 684.125 726.977 683.96C727.11 680.58 727.043 677.247 727.001 673.865L717.445 673.854C716.955 675.672 717.152 681.852 717.179 683.984ZM698.942 664.472C698.489 665.905 698.343 672.357 698.734 673.698C699.541 674.361 706.432 674.084 707.957 674.07C708.667 672.663 708.254 666.338 708.222 664.404L698.942 664.472ZM736.526 655.252C733.391 655.185 730.255 655.165 727.119 655.192C726.59 657.063 726.835 662.761 726.883 664.933C729.988 664.914 733.305 664.955 736.391 664.863C736.692 662.446 736.555 657.828 736.526 655.252ZM709.69 646.465C712.5 646.325 715.058 646.307 717.87 646.307C717.902 642.552 717.84 638.538 717.956 634.816C715.723 634.707 710.994 635.119 709.577 633.916C709.601 637.316 709.408 643.327 709.69 646.465Z" fill="#9E2184"/> -<path d="M698.946 588.659C702.024 588.664 705.102 588.646 708.179 588.606L708.197 597.825C705.086 597.805 701.898 597.738 698.797 597.883C699.03 594.74 698.742 591.677 698.946 588.659Z" fill="#9E2184"/> -<path d="M1195.42 291.404C1197.5 291.409 1202.78 291.017 1204.11 291.982C1205.06 293.446 1204.55 298.456 1204.6 300.653L1215.87 300.639C1217.92 300.639 1221.66 300.544 1223.54 300.908C1223.55 303.729 1223.63 306.951 1223.41 309.733C1217.79 310.067 1210.42 309.881 1204.66 309.869L1204.61 329.473L1213.98 329.408C1214.01 332.6 1214.04 335.329 1213.83 338.507C1210.79 338.385 1207.61 338.47 1204.64 338.293C1204.52 344.474 1204.34 351.881 1204.53 357.996L1215.68 357.975C1218.12 357.979 1221.12 358.065 1223.51 357.899C1223.73 355.089 1223.59 351.245 1223.56 348.339C1232.7 348.3 1242.91 348.06 1251.97 348.35C1252.04 351.356 1251.92 354.55 1251.85 357.572C1245.61 357.661 1239.38 357.565 1233.15 357.615C1232.89 360.227 1232.98 364.223 1232.98 366.963C1228.77 366.634 1218.62 366.889 1214.08 366.995C1214.04 370.381 1214.03 373.767 1214.07 377.152L1223.52 377.173C1223.55 380.3 1223.53 383.43 1223.48 386.558C1221.37 386.253 1216.4 386.389 1214.09 386.419C1213.84 389.005 1214.02 393.285 1214.06 396.018C1217.21 396.078 1220.37 396.081 1223.52 396.028C1223.62 392.889 1223.59 389.759 1223.57 386.62C1226.67 386.615 1229.92 386.664 1232.99 386.599C1232.99 389.332 1232.88 393.343 1233.17 395.998C1236.33 396.104 1239.49 396.06 1242.65 396.037C1242.65 398.869 1242.74 402.499 1242.55 405.256C1244.81 405.511 1249.5 405.454 1251.91 405.396C1251.92 408.187 1252.01 411.506 1251.92 414.253C1246.4 414.324 1238.61 414.566 1233.23 414.251C1233.2 411.248 1233.19 408.245 1233.23 405.239C1228.61 405.219 1225.66 405.338 1221.09 406.009C1217.98 406.465 1214.3 406.223 1211.08 407.035C1209.62 407.242 1207.21 407.083 1205.68 407.042C1205.95 399.565 1204.83 392.379 1204.4 384.983C1204.07 379.325 1204.63 372.709 1204.31 366.917C1199.1 366.82 1190.84 366.719 1185.74 366.993C1185.77 364.043 1185.85 360.614 1185.68 357.673C1183.17 357.602 1179.25 357.595 1176.75 357.756C1176.75 354.661 1176.79 351.411 1176.71 348.33C1182.27 348.33 1189.74 348.565 1195.15 348.304C1195.17 344.027 1195.47 342.619 1196.06 338.466C1196.27 336.979 1196.15 331.443 1196.14 329.62L1185.73 329.669C1185.71 332.704 1185.75 335.615 1185.46 338.636C1182.96 338.636 1178.9 338.509 1176.53 338.671C1176.49 341.865 1176.48 345.059 1176.51 348.254C1173.57 347.956 1169.86 348.238 1166.73 348.076C1167.23 341.519 1166.73 335.573 1167.15 329.77C1173.24 329.491 1179.8 330.003 1185.68 329.724C1185.65 326.26 1185.46 321.289 1185.7 317.945C1187.46 317.892 1194.14 317.873 1195.25 317.26C1195.6 315.573 1195.56 308.279 1195.52 306.142C1195.43 301.662 1195.75 295.764 1195.42 291.404Z" fill="#9E2184"/> -<path d="M1166.88 252.713C1170.04 252.664 1173.26 252.685 1176.42 252.674L1176.56 262.95C1179 263.1 1182.91 263.029 1185.35 262.918C1185.11 268.38 1185.74 275.9 1185.81 281.775C1187.87 281.83 1193.05 281.487 1194.57 282.015C1196 283.361 1195.08 288.871 1195.34 291.187C1192.48 291.197 1178.46 290.932 1176.7 291.653C1176.47 292.752 1177.09 298.189 1177.16 299.908C1179.69 300.282 1183.51 299.726 1185.72 300.445C1185.76 303.589 1185.75 306.732 1185.69 309.876C1179.62 309.876 1173.12 310.035 1167.09 309.835L1167.11 281.934C1170.08 281.641 1173.52 281.927 1176.66 281.796C1176.84 278.924 1176.72 275.006 1176.71 272.049C1173.5 272.042 1170.31 272.056 1167.11 271.913C1167.04 268.673 1167.09 265.363 1167.03 262.114C1166.98 259.675 1166.03 254.812 1166.88 252.713Z" fill="#9E2184"/> -<path d="M1178.08 33.3913L1194.11 33.3325C1196.13 33.3234 1201.29 33.1667 1203.08 33.5606C1204.26 34.7065 1204.38 50.439 1203.71 51.6784C1203.06 52.129 1202.44 52.0292 1201.63 52.0428C1193.55 52.146 1183.76 52.4279 1175.8 52.0776C1175.92 46.3668 1175.44 39.5145 1175.4 33.5114L1178.08 33.3913Z" fill="#9E2184"/> -<path d="M1185.55 62.3238C1194.9 62.1166 1204.34 62.3892 1213.7 62.2818C1216.95 62.2447 1220.27 62.2546 1223.52 62.3657C1223.54 64.4985 1223.97 69.4312 1222.96 70.8951C1221.64 71.799 1215.49 71.351 1213.29 71.3561C1211.18 71.3927 1206.55 71.0447 1204.95 71.6465C1203.66 72.9608 1204.21 78.4022 1204.09 80.9106C1199.83 81.2402 1189.68 81.1346 1185.31 80.9698C1185.17 78.3496 1184.86 63.9818 1185.55 62.3238Z" fill="#9E2184"/> -<path d="M1172.7 405.594C1174.01 405.553 1175.31 405.539 1176.61 405.553C1176.37 410.715 1176.9 419.164 1176.23 423.907C1174.4 423.967 1168.48 423.661 1167.3 424.253C1166.62 426.295 1166.89 440.206 1166.82 443.58L1162.22 443.506C1160.61 442.877 1159.88 442.677 1158.17 442.308L1158.33 424.539C1158.34 421.61 1158 408.132 1158.84 406.067C1160.4 405.428 1170.22 405.67 1172.7 405.594Z" fill="#9E2184"/> -<path d="M1167.25 376.947C1170.02 376.848 1173.95 377.27 1176.46 376.896L1176.45 386.583C1180.22 386.809 1191.94 386.17 1194.6 387C1194.79 387.217 1195.01 387.505 1195.04 387.8C1196.24 398.63 1194.15 396.198 1185.92 396.387C1185.97 399.162 1185.79 402.591 1185.72 405.412C1183.78 405.232 1179.04 405.415 1176.73 405.368C1176.74 402.193 1176.73 399.017 1176.7 395.841C1173.61 395.617 1170.39 395.859 1167.11 395.62C1167.05 393.347 1166.9 378.457 1167.25 376.947Z" fill="#9E2184"/> -<path d="M1185.8 443.52C1188.87 443.615 1192.1 443.548 1195.19 443.527C1195.16 446.668 1195.17 449.81 1195.21 452.949L1204.59 453.022C1204.53 458.192 1204.51 463.359 1204.52 468.528C1204.56 471.329 1204.88 478.257 1204.43 480.743C1202.61 481.029 1197.76 481.121 1196.07 480.446C1195.34 479.252 1195.79 473.696 1195.62 471.992C1195.29 468.835 1194.87 465.638 1194.93 462.462C1192.85 462.322 1187.58 462.815 1186.21 462.052C1185.39 460.052 1185.75 446.443 1185.8 443.52Z" fill="#9E2184"/> -<path d="M1204.41 110.261C1208.5 110.136 1212.64 110.276 1216.73 110.242C1218.85 110.224 1221.5 110.35 1223.57 110.051C1223.54 112.539 1223.6 117.093 1223.35 119.451C1221.19 119.528 1215.72 119.277 1214.43 120.209C1213.6 121.484 1213.95 127.776 1214.06 129.603C1212.26 129.238 1197.5 129.388 1195.26 129.556C1195.27 127.397 1194.97 121.896 1195.58 120.194C1196.07 118.79 1201.66 120.301 1203.92 119.357C1204.76 118.211 1204.4 112.278 1204.41 110.261Z" fill="#9E2184"/> -<path d="M1176.7 90.6641C1179.22 90.6569 1193.93 90.2324 1195.05 91.2094C1195.58 93.2999 1195.23 97.627 1195.13 99.9351C1192.64 100.049 1188.47 99.6805 1186.34 100.281C1184.66 102.394 1187.1 108.924 1184.87 109.641C1178.92 109.839 1173.04 109.683 1167.09 109.515C1167.1 99.2426 1164.71 97.9075 1176.36 99.9446C1176.49 97.4447 1175.99 92.6235 1176.7 90.6641Z" fill="#9E2184"/> -<path d="M1214.09 138.84C1214 142.054 1214.05 145.388 1213.97 148.655C1207.93 148.42 1201.6 148.774 1195.36 148.52C1195.13 146.081 1195.29 141.56 1195.28 138.914C1201.14 138.786 1208.45 139.17 1214.09 138.84Z" fill="#9E2184"/> -<path d="M1195.58 414.557C1198.6 414.516 1201.54 414.454 1204.56 414.583C1204.68 416.383 1204.9 422.718 1204.12 423.949C1201.55 424.189 1197.84 424.122 1195.17 424.136C1195.19 422.428 1194.84 415.541 1195.58 414.557Z" fill="#9E2184"/> -<path d="M1195.2 433.827C1198.34 433.824 1201.48 433.848 1204.62 433.898C1204.64 436.998 1204.69 440.086 1204.57 443.184C1202.67 443.502 1197.31 443.364 1195.22 443.352C1195.27 440.178 1195.27 437.003 1195.2 433.827Z" fill="#9E2184"/> -<path d="M1185.91 424.38C1188.91 424.034 1191.97 424.255 1195 424.152C1195.1 427.369 1195.15 430.589 1195.13 433.806L1185.88 433.836C1185.96 430.655 1185.85 427.523 1185.91 424.38Z" fill="#9E2184"/> -<path d="M1176.7 433.88C1179.76 433.85 1182.82 433.834 1185.88 433.836C1185.65 435.394 1185.76 441.531 1185.75 443.419C1182.73 443.479 1179.71 443.513 1176.7 443.52C1176.62 440.319 1176.49 437.072 1176.7 433.88Z" fill="#9E2184"/> -<path d="M1176.27 443.894C1176.87 444.129 1176.5 451.713 1176.1 452.817C1174.65 453.511 1169.2 453.211 1167.35 453.186C1166.83 452.402 1167.06 445.382 1167.07 443.974C1170.09 443.99 1173.26 444.062 1176.27 443.894Z" fill="#9E2184"/> -<path d="M1167.13 358.032C1169.85 357.848 1173.75 357.968 1176.56 357.979C1176.55 360.547 1176.68 364.232 1176.93 366.788C1173.56 366.935 1170.44 367.083 1167.07 366.749C1167.06 363.873 1166.99 360.897 1167.13 358.032Z" fill="#9E2184"/> -<path d="M1167.09 462.912C1170.21 462.875 1173.34 462.877 1176.46 462.926C1176.65 464.767 1176.43 470.222 1175.91 472.002C1173.37 471.995 1170.61 472.128 1168.13 471.672C1167.36 471.506 1167.5 469.632 1167.41 469.01C1167.08 466.507 1166.08 465.477 1167.09 462.912Z" fill="#9E2184"/> -<path d="M1185.74 366.993C1185.75 369.823 1185.81 372.773 1185.62 375.587C1180.01 375.41 1181.52 375.901 1176.63 376.809C1176.62 372.854 1177.93 370.381 1177.67 367.048C1180.36 367.069 1183.05 367.051 1185.74 366.993Z" fill="#9E2184"/> -<path d="M1167.08 138.61L1178.09 138.891C1180.14 138.956 1183.91 139.171 1185.8 138.883C1185.74 145.113 1185.73 151.343 1185.76 157.573C1185.76 160.261 1185.61 165.234 1185.81 167.713C1189.16 167.909 1192.82 167.741 1196.2 167.75C1198.74 167.756 1201.86 167.893 1204.33 167.593C1204.38 164.46 1204.4 161.327 1204.39 158.194C1207.62 158.151 1210.85 158.16 1214.08 158.22C1213.81 160.089 1214.04 165.573 1214.08 167.733C1220.08 167.883 1227.26 167.44 1233.06 167.876C1233.14 170.74 1232.93 174.947 1233.14 177.522C1232.01 177.445 1230.47 177.319 1229.33 177.43C1224.31 177.92 1219.36 177.89 1214.31 177.923C1214.25 180.716 1214.09 183.978 1214.12 186.734C1218.11 186.798 1222.1 186.815 1226.1 186.786C1227.85 186.78 1231.43 186.833 1233.02 186.617C1233.01 192.783 1232.84 199.761 1233.03 205.859L1242.55 205.893C1242.53 208.74 1242.57 212.059 1242.39 214.873C1239 214.964 1226.01 214.608 1223.93 215.347C1223.19 216.359 1223.52 223.236 1223.54 225.008L1232.99 225.049C1233.02 228.035 1233.03 231.022 1233.01 234.008C1227.42 233.946 1219.31 233.722 1213.89 234.04L1213.87 243.637C1216.85 243.646 1220.61 243.552 1223.52 243.704C1223.55 245.799 1224 250.864 1222.92 252.277C1221.58 253.146 1216.23 252.717 1214.09 252.805C1214.01 256.087 1213.82 260.132 1213.96 263.349C1217.92 263.379 1221.88 263.42 1225.84 263.513C1227.81 263.559 1230.44 263.31 1232.32 263.63C1233.42 264.942 1233.25 279.83 1232.58 281.468C1231.06 281.989 1225.52 281.685 1223.54 281.743C1223.59 278.592 1223.71 275.195 1223.52 272.068C1219.65 272.024 1197.72 272.393 1195.83 271.602C1193.94 269.394 1196.77 262.478 1194.07 262.457C1191.55 262.436 1188.37 262.644 1185.7 262.598L1185.71 252.768C1188.52 252.872 1191.51 252.745 1194.25 252.957C1194.25 249.751 1194.3 246.4 1194.23 243.208C1191.28 243.259 1188.22 243.272 1185.28 243.381C1185.29 245.979 1185.17 249.98 1185.35 252.464C1182.46 252.473 1179.58 252.466 1176.69 252.446C1176.8 246.451 1176.68 240.487 1176.74 234.511C1179.45 234.814 1182.27 234.442 1185.06 234.672C1185.04 231.914 1185.11 228.515 1184.81 225.844L1184.77 225.448L1184.74 225.21C1182.05 225.367 1179.44 225.28 1176.75 225.228C1176.51 228.057 1176.56 231.353 1176.53 234.23C1169.69 234.168 1162.84 234.156 1156 234.196V225.042L1176.84 225.041C1177.14 221.705 1177.21 219.299 1177.23 215.965C1174.09 215.707 1169.81 215.821 1166.57 215.826C1166.94 209.026 1167.41 203.031 1167.13 196.126C1166.99 192.863 1166.6 189.546 1166.62 186.362L1176.47 186.319C1176.4 189.708 1176.37 193.098 1176.39 196.487L1187.46 196.496C1189.47 196.502 1192.45 196.632 1194.36 196.363C1195.55 195.315 1195.04 193.491 1195.4 192.054C1195.8 190.496 1196.62 187.471 1195.67 186.002C1192.33 186.634 1180.75 186.362 1176.74 186.345C1176.88 183.82 1176.78 180.571 1176.76 177.986C1173.58 178.133 1170.26 178.059 1167.06 178.034L1167.09 167.682L1176.45 167.68C1176.67 161.867 1176.59 154.44 1176.49 148.611L1167.07 148.541L1167.08 138.61ZM1204.18 224.984C1200.93 225 1197.27 224.934 1194.06 225.054C1193.83 227.55 1193.53 241.019 1194.2 242.807C1195.73 243.418 1201.24 243.094 1203.39 243.195C1203.83 242.981 1204.1 242.975 1204.14 242.601C1204.63 237.592 1204.32 229.97 1204.34 225.04C1207.26 225.027 1211.13 225.125 1213.98 224.96C1214.11 221.58 1214.04 218.247 1214 214.865L1204.44 214.854C1203.95 216.672 1204.15 222.852 1204.18 224.984ZM1185.94 205.472C1185.49 206.905 1185.34 213.357 1185.73 214.698C1186.54 215.361 1193.43 215.084 1194.96 215.07C1195.67 213.663 1195.25 207.338 1195.22 205.404L1185.94 205.472ZM1223.53 196.252C1220.39 196.185 1217.25 196.165 1214.12 196.192C1213.59 198.063 1213.83 203.761 1213.88 205.933C1216.99 205.914 1220.3 205.955 1223.39 205.863C1223.69 203.446 1223.56 198.828 1223.53 196.252ZM1196.69 187.465C1199.5 187.325 1202.06 187.307 1204.87 187.307C1204.9 183.552 1204.84 179.538 1204.96 175.816C1202.72 175.707 1197.99 176.119 1196.58 174.916C1196.6 178.316 1196.41 184.327 1196.69 187.465Z" fill="#9E2184"/> -<path d="M1185.95 129.659C1189.02 129.664 1192.1 129.646 1195.18 129.606L1195.2 138.825C1192.09 138.806 1188.9 138.738 1185.8 138.883C1186.03 135.74 1185.74 132.677 1185.95 129.659Z" fill="#9E2184"/> -<path d="M438.562 -183.925C435 -184.108 421.967 -183.6 419.449 -184.262C418.914 -185.216 418.944 -191.393 419.385 -192.6C420.639 -193.225 444.529 -192.958 447.847 -192.967C447.565 -190.646 447.643 -186.147 447.765 -183.78C450.73 -183.644 454.472 -183.732 457.511 -183.707C457.549 -180.586 457.513 -177.396 457.511 -174.271C454.296 -174.303 451.081 -174.299 447.866 -174.257C447.728 -172.105 447.184 -166.52 448.217 -165.013C449.617 -164.015 455.311 -164.543 457.51 -164.58C457.772 -167.525 457.619 -171.201 457.57 -174.227L481.946 -174.234C485.784 -174.234 491.834 -174.393 495.454 -174.008C495.594 -171.222 495.421 -167.352 495.36 -164.522C497.397 -164.587 503.486 -164.237 504.86 -164.799C505.482 -166.776 505.243 -180.724 505.236 -183.766C509.654 -183.919 520.126 -183.384 523.876 -183.895C523.883 -180.934 523.984 -177.189 523.717 -174.31C520.758 -174.186 517.232 -174.257 514.24 -174.255C514.074 -171.086 514.166 -167.737 514.208 -164.557C517.441 -164.52 530.815 -165.041 532.797 -163.953C533.846 -161.911 533.141 -158.032 533.613 -155.529C524.59 -155.887 514.975 -155.573 505.932 -155.442C503.929 -155.412 505.826 -148.23 504.6 -146.43C503.044 -145.787 497.308 -146.101 495.348 -146.135L495.352 -136.686C497.559 -136.493 501.152 -136.61 503.45 -136.615C506.946 -136.622 510.871 -136.566 514.335 -136.769C514.413 -133.886 514.15 -129.233 514.431 -126.702C508.81 -126.368 501.262 -126.573 495.504 -126.585C495.317 -123.639 495.389 -120.298 495.393 -117.313C497.75 -117.094 502.468 -117.276 504.978 -117.313C505.07 -114.209 505.065 -111.102 504.964 -107.995C502.304 -107.769 498.372 -107.928 495.453 -107.809C495.221 -105.202 495.33 -100.749 495.317 -98.009C500.974 -98.0251 508.916 -98.281 514.388 -97.9399C514.664 -88.5598 515.681 -88.8916 505.904 -89.3895C505.591 -88.4998 504.051 -82.0444 504.097 -81.3461C504.295 -78.3155 512.408 -80.6478 514.03 -79.3894C514.759 -77.7485 514.312 -71.807 514.429 -69.3664L523.883 -69.3871C524.27 -64.1324 523.652 -56.2135 523.689 -50.4633C526.863 -50.438 530.138 -50.5025 533.323 -50.5232C533.68 -53.2566 533.53 -59.9079 533.503 -62.8625C533.45 -68.2947 533.632 -74.1716 533.452 -79.5577C530.405 -79.613 527.199 -79.5231 524.102 -79.5577C524.019 -88.9332 524.014 -98.3063 524.088 -107.682C527.234 -107.739 530.382 -107.739 533.53 -107.679C533.712 -103.386 533.182 -100.162 532.585 -96.0224C532.383 -94.6303 532.472 -90.4819 532.477 -88.9124C539.145 -88.6981 545.766 -89.265 552.581 -88.5759C552.768 -91.6066 552.698 -94.9369 552.694 -97.9998C558.695 -98.1865 565.185 -98.0758 571.2 -98.032C571.295 -88.4906 571.293 -78.9469 571.189 -69.4032C580.286 -69.175 590.311 -69.3963 599.488 -69.3802C599.756 -65.7918 599.613 -54.1623 599.414 -50.7468C596.305 -50.514 593.183 -50.5509 590.067 -50.5854C590.21 -53.6368 590.2 -57.0777 590.145 -60.1315C587.488 -60.3135 583.542 -60.2398 580.848 -60.1983C580.717 -57.1262 580.627 -53.57 580.797 -50.5255C577.939 -50.7399 574.425 -50.4979 571.327 -50.65C571.376 -53.8281 571.383 -57.004 571.355 -60.1822C568.933 -60.4311 564.312 -60.2144 561.707 -60.1591C561.627 -56.9141 561.763 -53.7913 561.41 -50.5578C558.262 -50.5393 555.406 -50.0784 552.284 -49.629C552.214 -52.5444 552.583 -55.1556 552.65 -58.0065C552.735 -61.6433 552.692 -65.4023 552.685 -69.0483C555.183 -69.2673 559.345 -69.1543 561.97 -69.152C562.221 -73.0078 561.8 -76.0799 561.548 -79.9149C557.985 -79.9356 555.877 -79.8596 552.316 -80.3413C549.997 -80.1362 544.706 -81.2654 542.959 -80.2882C542.154 -77.9398 542.364 -51.3806 543.413 -50.1153C545.455 -49.2902 549.97 -49.5322 552.284 -49.629C552.261 -47.1745 552.159 -44.1231 552.249 -41.7239C547.098 -41.7331 537.84 -41.9913 533.051 -41.5418C532.917 -38.3199 532.917 -35.2731 532.926 -32.0465C536.116 -32.065 539.389 -32.1226 542.567 -31.9982C542.735 -27.8336 542.32 -23.7912 542.36 -19.6381C542.433 -11.71 542.175 -3.7957 541.933 4.12552C541.818 7.92595 541.977 11.8393 541.864 15.6582L533.367 15.6282C532.758 7.08705 533.865 -3.73344 533.549 -12.7102C530.997 -12.701 526.354 -12.8301 523.966 -12.6272C523.874 -9.74408 524.026 -5.46428 523.673 -2.81389L514.189 -2.80005C514.097 -6.12111 514.217 -9.56891 514.104 -12.7909C511.484 -12.7678 497.183 -12.9384 495.773 -12.3622C495.036 -10.7489 495.357 -5.38361 495.311 -3.26561C492.521 -3.51451 488.946 -3.44539 486.15 -3.27945L486.069 9.2189C486.061 10.7262 485.948 14.25 486.087 15.6328C479.823 15.4715 473.505 15.7481 467.219 15.566C467.151 13.4503 466.638 8.66576 467.694 7.1631C469.07 6.18591 474.584 6.61458 476.795 6.60767C477.047 0.530212 476.882 -6.55208 476.877 -12.7033C473.714 -12.7494 470.394 -12.6871 467.219 -12.6756C467.433 -15.727 467.411 -19.1034 467.448 -22.1894C461.264 -22.1848 454.005 -21.9981 447.92 -22.3162C447.669 -19.463 447.69 -15.356 447.723 -12.4728L467.163 -12.5005C467.156 -9.45367 467.091 -6.40918 466.97 -3.36699C465.05 -3.34856 459.694 -3.67584 458.283 -3.12964C457.02 -1.81827 457.582 3.73141 457.35 6.40486C454.257 6.43481 451.164 6.43713 448.072 6.4164C448.011 3.23822 448.058 -0.0252075 448.013 -3.23103C445.805 -3.55138 440.781 -3.34859 438.446 -3.27483C438.633 -6.18565 438.584 -9.81783 438.524 -12.7355C433.831 -12.8139 429.101 -12.6595 424.403 -12.7309C422.827 -12.754 421.201 -12.7794 419.639 -12.5742C418.95 -11.3228 419.298 -5.00102 419.171 -2.85767C417.645 -2.79083 413.819 -2.54886 412.504 -2.84155C408.591 -3.71272 406.377 -4.08607 402.376 -4.04459C401.644 -3.37624 401.277 -2.89687 400.645 -2.12248C400.563 -0.0897522 400.029 4.59569 400.913 6.04073C402.077 6.95338 407.947 6.60307 410.035 6.70448C410.262 8.99533 410.323 22.8304 409.65 24.5174C408.03 25.1835 375.72 24.8447 371.49 24.8124C371.729 19.1913 371.562 12.397 371.566 6.69063C374.816 6.5224 378.073 6.51781 381.324 6.68144C381.515 9.52312 381.352 13.0101 381.499 16.0684C384.318 16.179 388.07 16.1675 390.869 16.05C391.131 13.0401 390.984 8.80174 390.973 5.66968C390.934 -0.377823 390.934 -6.42763 390.972 -12.4751C392.914 -12.4636 398.181 -12.2931 399.692 -12.5904C401.634 -12.9729 399.683 -19.7418 400.776 -21.7492C402.394 -22.4567 407.841 -22.1226 410.085 -22.1341C410.31 -24.5724 410.745 -29.9262 410.729 -32.0926C414.641 -32.0327 414.967 -30.7052 419.498 -30.5785C422.614 -32.201 425.24 -31.846 428.744 -31.8553C428.804 -28.6333 428.753 -25.4183 428.822 -22.1871C431.534 -21.9843 435.554 -22.0695 438.367 -22.0511C438.639 -25.1163 438.537 -29.2556 438.516 -32.3439L428.967 -32.2793C428.788 -38.2623 428.999 -44.3536 428.742 -50.3135L419.521 -50.2951C419.446 -53.3442 419.491 -56.5753 419.485 -59.6383C416.338 -59.8157 413.585 -59.4677 410.133 -59.7765C409.92 -50.9035 410.079 -41.3506 410.085 -32.4153C407.603 -32.4199 406.902 -32.4568 404.599 -31.5764C401.599 -32.625 396.294 -32.4222 393.227 -32.0396C392.723 -31.9774 391.985 -32.1917 391.703 -32.6043C390.595 -34.2222 390.927 -39.5229 390.93 -41.5764C388.412 -41.7377 383.937 -41.7769 381.447 -41.5787C381.502 -44.8422 381.513 -48.1056 381.481 -51.3667C378.564 -51.346 374.355 -51.1916 371.539 -51.3667L371.555 -59.9217L381.261 -60.0024C381.257 -57.2345 381.197 -54.2822 381.25 -51.5304C387.456 -51.6664 394.365 -51.4221 400.368 -51.671C400.401 -54.432 400.449 -57.1538 400.368 -59.9171C394.025 -59.9702 387.756 -60.3136 381.437 -60.2052C381.462 -63.1898 381.56 -66.6192 381.43 -69.5623L362.12 -69.6199L362.301 -78.3754C366.86 -78.3615 370.88 -78.3615 375.444 -78.7994C377.183 -78.9654 379.572 -78.7603 381.401 -78.9262C381.737 -88.5114 381.464 -99.3065 381.511 -109.014C378.639 -108.802 374.283 -108.756 371.42 -108.977L371.551 -117.145C374.381 -117.428 378.056 -117.338 380.962 -117.297C381.098 -120.261 381.124 -123.225 381.04 -126.188C377.863 -126.112 374.685 -126.094 371.508 -126.128C371.537 -132.6 371.305 -140.012 371.567 -146.352C374.427 -146.421 378.575 -146.592 381.295 -146.066L381.208 -126.37C383.21 -126.354 389.229 -126.11 390.664 -126.758C391.616 -128.551 390.001 -136.048 391.604 -136.198C397.284 -136.73 403.648 -136.518 409.365 -136.334C410.543 -136.294 409.899 -127.527 409.922 -126.368C408.507 -126.477 406.928 -126.463 405.508 -126.407C400.684 -126.223 395.745 -126.583 390.938 -126.465C390.851 -119.302 390.847 -112.137 390.928 -104.971C390.959 -103.052 390.871 -99.7974 391.016 -98.0067L408.912 -97.9491C408.913 -100.715 408.782 -104.819 408.947 -107.477C411.76 -107.804 416.44 -107.668 419.397 -107.636C419.403 -104.43 419.365 -101.224 419.283 -98.0182C425.098 -98.009 432.742 -98.2441 438.371 -97.9583C438.438 -94.6879 438.783 -82.1113 437.992 -79.7951C437.211 -79.0599 433.846 -78.917 432.626 -78.6381C431.409 -78.3592 430.165 -77.8776 428.965 -77.7116C428.946 -75.0105 428.995 -72.2956 428.668 -69.6153C425.885 -69.6037 422.137 -69.6959 419.434 -69.5323C419.502 -72.7727 419.523 -76.0154 419.496 -79.2581C429.69 -79.4056 429.407 -77.5641 428.832 -88.622C428.824 -88.7879 428.813 -88.9516 428.798 -89.1175C425.977 -89.0945 422.267 -88.9815 419.498 -89.1313C419.498 -91.6665 419.589 -95.2641 419.366 -97.6817C416.131 -97.6979 412.913 -97.5711 409.68 -97.5434L409.597 -89.1867C403.447 -89.1267 397.079 -89.0276 390.936 -89.1452C390.929 -85.9831 390.823 -82.2104 390.949 -79.0991C395.897 -78.7349 404.537 -79.076 409.87 -79.0668C409.88 -76.5178 409.766 -71.7563 409.986 -69.3341C412.696 -69.2396 416.545 -69.2995 419.311 -69.3894L419.299 -60.0024C426.39 -59.8503 433.506 -60.0324 440.599 -59.9655C442.556 -59.9471 445.841 -60.1476 447.626 -59.5783C448.074 -58.154 447.909 -53.3764 447.756 -51.7862C447.577 -49.9217 440.18 -50.65 438.564 -50.4725C438.216 -45.204 438.448 -37.9972 438.401 -32.5305C441.211 -32.6411 444.023 -32.7103 446.835 -32.7379C447.427 -32.3185 448.176 -31.7492 448.774 -31.3759C450.82 -31.3874 456.913 -30.6937 458.209 -31.1293C461.665 -32.2908 463.903 -31.5395 467.191 -32.0258C467.037 -28.3867 467.096 -25.5658 467.885 -22.005C470.347 -21.9866 474.489 -21.8529 476.829 -22.1064C477.085 -24.4042 476.897 -29.6727 476.854 -32.0558C473.896 -32.1987 470.172 -32.0742 467.191 -32.0258C467.047 -41.3114 467.455 -50.9427 467.195 -60.1684C464.297 -60.3181 460.612 -60.2329 457.656 -60.2467C457.472 -62.8118 457.577 -66.6998 457.573 -69.3686C463.928 -69.4032 470.283 -69.4032 476.637 -69.3709C476.823 -66.8335 476.697 -62.6851 476.731 -59.9655C482.905 -59.9171 489.08 -59.9218 495.254 -59.9748C495.457 -63.365 495.729 -75.937 495.124 -78.9285C492.424 -79.212 489.446 -78.6888 486.7 -78.8801C480.168 -79.3295 473.759 -79.4332 467.226 -79.5761C466.975 -84.976 467.201 -92.5607 467.201 -98.1404C471.906 -97.8615 476.687 -98.281 481.393 -97.873C482.817 -97.7509 484.159 -97.6725 485.59 -97.7186C485.651 -95.6098 485.01 -90.1915 486.227 -88.7695C487.165 -87.6725 493.906 -87.843 494.962 -88.3961C495.618 -88.7395 495.445 -97.0157 495.446 -97.9721C493.394 -98.1196 487.671 -98.2326 485.749 -98.0205C485.801 -101.987 485.761 -105.419 486.356 -109.341C486.604 -110.975 486.673 -115.638 486.196 -117.175C485.09 -117.719 477.983 -117.668 477.149 -117.401C476.5 -116.147 476.671 -109.811 476.631 -107.903C473.663 -107.903 470.114 -107.981 467.204 -107.76C467.144 -105.084 466.937 -100.828 467.118 -98.2833C463.938 -98.4123 460.842 -98.2786 457.581 -98.4469C457.487 -101.487 457.533 -104.806 457.514 -107.871C454.488 -107.97 451.124 -107.924 448.075 -107.947C448.036 -110.987 448.069 -114.093 448.069 -117.14C451.06 -117.214 465.061 -116.838 466.82 -117.546C467.51 -119.148 467.215 -124.672 467.189 -126.677C463.87 -126.728 460.936 -126.606 457.548 -126.781C457.366 -129.498 457.402 -133.656 457.49 -136.38C459.408 -136.546 461.871 -136.375 463.855 -136.483C468.171 -136.719 472.354 -136.765 476.677 -136.725C476.69 -133.547 476.653 -130.182 476.801 -127.025C479.999 -127.055 483.03 -127.226 486.317 -127.226C486.558 -132.96 486.365 -140.24 486.368 -146.069C489.169 -146.207 492.501 -146.156 495.326 -146.172C494.842 -149.164 495.096 -160.701 495.119 -164.359C490.82 -164.407 486.526 -164.213 482.223 -164.29C478.253 -164.359 471.227 -165.363 467.472 -164.527C466.74 -163.089 467.006 -157.484 467.018 -155.596C463.898 -155.603 460.743 -155.647 457.628 -155.527C457.421 -152.99 457.517 -148.758 457.498 -146.092C454.188 -146.025 451.391 -146.013 448.088 -146.156L448.05 -155.571C441.825 -155.817 435.274 -155.414 428.951 -155.617C428.864 -158.528 428.894 -161.632 428.873 -164.559C430.669 -164.552 437.388 -164.239 438.34 -164.962C438.841 -167.154 438.612 -180.929 438.562 -183.925ZM486.644 -22.6457C491.954 -22.6342 497.421 -22.5443 502.691 -23.1689C506.204 -23.5837 509.366 -23.5515 512.89 -23.5238L513.745 -23.6275C514.819 -25.0495 513.878 -39.7258 514.235 -42.5582C514.36 -43.5654 514.229 -49.0713 514.093 -50.083C513.622 -50.5878 512.101 -50.6546 511.375 -50.6569C503.014 -50.6892 494.6 -50.567 486.24 -50.6799C485.635 -49.0482 485.906 -46.8634 485.751 -45.1441C485.208 -39.1219 485.337 -33.3602 486.234 -27.3703C486.464 -25.8377 486.359 -24.2221 486.644 -22.6457ZM523.779 -22.0811C526.851 -22.0742 529.921 -22.088 532.993 -22.1272C533.235 -24.8951 533.072 -29.1196 533.021 -31.9958C530.02 -32.0742 527.02 -32.1042 524.021 -32.088C523.756 -29.7649 523.708 -24.5264 523.779 -22.0811Z" fill="#9E2184"/> -<path d="M713.854 -79.4632C716.606 -79.2535 720.355 -79.4816 723.473 -79.3088C723.582 -76.1859 723.485 -72.5606 723.478 -69.4009L732.397 -69.3894C732.542 -67.0502 732.556 -62.4731 732.217 -60.2052L723.499 -60.1891C723.414 -57.0225 723.469 -53.6599 723.471 -50.4771C725.209 -50.431 730.895 -50.8113 732.012 -50.1891C732.865 -48.1748 732.489 -35.0219 732.169 -32.1134C727.062 -31.8737 718.998 -31.9152 713.865 -32.1065C713.798 -35.3146 713.909 -38.4513 713.789 -41.7032C709.931 -41.9083 698.101 -41.8691 694.469 -41.5926C694.391 -38.4236 694.444 -35.0473 694.441 -31.8645L704.11 -31.8C704.319 -25.5474 704.137 -18.8061 704.176 -12.489C707.389 -12.4521 710.604 -12.4659 713.819 -12.5304L713.826 -22.0903C716.871 -22.2171 720.348 -22.1387 723.427 -22.1295C723.483 -19.0135 723.266 -15.9114 723.381 -12.7402C720.194 -12.6849 717.004 -12.6641 713.817 -12.678C713.685 -9.78788 713.796 -6.19028 713.815 -3.2495C712.068 -3.54681 705.582 -3.71964 704.188 -2.51659C702.966 -1.46336 698.037 -1.9243 696.105 -1.97961C695.866 0.825188 695.85 3.81207 695.868 6.63531C701.911 6.64223 707.788 6.40025 713.803 6.39103C713.621 8.03197 713.52 14.1025 713.815 15.5821C711.657 15.2364 707.97 15.3309 705.762 15.3055C702.358 15.2664 705.372 22.2634 703.605 24.6073C702.093 25.1581 696.762 24.8608 694.9 24.817C694.28 19.2673 695.725 12.1089 695.594 6.43019C692.144 6.37488 688.691 6.37719 685.241 6.43941C685.077 10.415 685.587 21.2263 684.914 24.5266C684.033 25.2618 677.518 24.9046 675.981 24.8769C676.112 16.0384 675.955 6.99023 675.907 -1.86668L672.593 -1.91508C670.304 -3.51683 669.14 -3.24258 666.322 -3.21723C666.345 -6.38157 666.34 -9.54358 666.306 -12.7056C663.713 -12.8301 660.371 -12.754 657.732 -12.7586L656.774 -14.8513C654.817 -14.5102 649.848 -14.4226 647.493 -14.2544C647.237 -19.055 648.419 -38.3038 646.774 -41.3206C644.821 -42.0927 631.468 -41.6525 628.043 -41.7654C628.027 -44.6578 628.057 -47.5479 628.131 -50.438C632.807 -50.7076 642.662 -50.0323 646.704 -50.6477C647.518 -51.7862 647.207 -58.1932 647.191 -59.9494H675.301C675.412 -62.0951 675.119 -67.3659 675.79 -68.9884C677.179 -69.5554 692.939 -69.6683 694.172 -68.9653C694.948 -67.3728 694.469 -53.4525 694.501 -50.5025C696.767 -50.3481 699.936 -50.4518 702.296 -50.4449C706.041 -50.431 710.046 -50.3066 713.768 -50.4357C713.909 -53.4802 713.828 -57.0732 713.828 -60.1614C710.791 -60.2721 707.408 -60.226 704.352 -60.2444C704.31 -63.2474 704.299 -66.2504 704.322 -69.2534C706.737 -69.4862 711.148 -69.3802 713.75 -69.4194C713.911 -72.4777 713.831 -76.3426 713.854 -79.4632ZM685.269 -50.544C679.698 -50.6869 674.128 -50.7145 668.557 -50.6293C666.398 -50.6062 657.984 -50.862 656.681 -50.1729C655.34 -47.4557 657.069 -27.0431 657.126 -22.1871L673.137 -22.1433L685.225 -22.1087C685.384 -30.3549 685.672 -42.3831 685.269 -50.544ZM675.794 -2.3299C678.836 -2.38752 681.878 -2.40598 684.921 -2.38293C685.467 -3.26102 685.257 -11.014 685.248 -12.7033C682.478 -12.7102 678.979 -12.6296 676.299 -12.8808C675.142 -11.5026 675.663 -4.46404 675.794 -2.3299ZM656.866 -14.9458C656.87 -15.8216 656.983 -17.6307 656.679 -18.3521L656.299 -18.6333C656.287 -17.5063 656.186 -16.3447 656.497 -15.28L656.866 -14.9458Z" fill="#9E2184"/> -<path d="M581.016 -50.3112L589.848 -50.3089C589.822 -44.0194 590.249 -38.0872 590.175 -31.8553C586.172 -31.9198 574.535 -32.4891 571.293 -32.1365C571 -26.4139 571.182 -18.8315 571.154 -12.9891C573.786 -12.9868 577.024 -13.0698 579.613 -12.9614C579.742 -9.73718 579.935 -6.1972 579.905 -2.99138C586.464 -3.03056 593.024 -3.02363 599.583 -2.97062C599.546 -6.11191 599.576 -9.2532 599.675 -12.3922C602.71 -12.4752 605.745 -12.5051 608.781 -12.4821C609.085 -10.4171 608.949 -4.91809 608.677 -2.88996C605.619 -2.83696 602.558 -2.83927 599.5 -2.89688L599.52 6.87961C597.036 6.26656 584.102 6.39794 580.843 6.39794C580.615 9.54153 580.624 12.5007 580.61 15.6512C577.824 15.695 575.038 15.6881 572.251 15.6328C572.323 12.3025 572.346 9.88723 572.069 6.53622C571.8 3.30274 571.323 0.062336 571.336 -3.15501C567.937 -2.98907 564.74 -3.17806 561.346 -3.27255C558.32 -3.35552 555.347 -3.22185 552.327 -3.50533C552.21 -9.67728 552.355 -16.029 552.429 -22.2148C554.367 -22.2217 560.154 -21.9382 561.419 -22.6066C562 -23.8511 562.438 -32.2217 560.647 -32.6274C558.661 -33.0791 554.657 -32.7034 552.353 -32.7564C552.302 -35.7456 552.267 -38.7348 552.249 -41.7239C556.16 -41.7539 560.288 -41.7746 564.16 -41.7124C567.764 -41.6548 577.769 -40.4817 580.659 -41.4405C581.272 -42.9362 580.97 -48.3177 581.016 -50.3112Z" fill="#9E2184"/> -<path d="M334.156 -12.3945C335.514 -12.5512 341.769 -12.5973 342.865 -12.3807C343.776 -10.9426 342.965 3.84664 342.426 6.04762C341.666 6.67449 335.241 6.42096 333.582 6.43709C333.379 12.2772 333.85 19.0576 333.411 24.7547C331.704 25.0083 326.867 24.8746 324.987 24.8585C325.039 18.7764 322.947 -8.78074 324.611 -11.4334C326.258 -12.3991 331.258 -11.9405 333.826 -12.3415L334.156 -12.3945Z" fill="#9E2184"/> -<path d="M295.8 -12.4798C298.874 -12.3853 302.101 -12.4521 305.189 -12.4728C305.16 -9.33156 305.167 -6.19027 305.208 -3.05128L314.588 -2.97754C314.528 2.19187 314.507 7.35899 314.524 12.5284C314.56 15.3286 314.883 22.2565 314.431 24.7432C312.614 25.029 307.764 25.1212 306.065 24.4459C305.342 23.2521 305.794 17.6955 305.618 15.9924C305.29 12.8349 304.869 9.63831 304.931 6.46245C302.85 6.32186 297.581 6.81509 296.212 6.05223C295.389 4.05177 295.754 -9.55742 295.8 -12.4798Z" fill="#9E2184"/> -<path d="M637.626 6.50395C643.04 6.22278 651.507 6.94644 656.462 6.4325C656.504 9.44011 656.451 12.5468 656.437 15.5637C654.298 15.5222 648.608 14.946 647.368 15.8656C646.451 17.2622 646.789 21.9915 646.794 23.9873L646.642 24.5197C645.526 25.1328 630.633 24.8446 628.108 24.8124C628.091 18.97 627.978 12.6874 628.163 6.88193C631.366 6.63763 634.337 7.08934 637.626 6.50395Z" fill="#9E2184"/> -<path d="M610.104 6.97179C611.643 6.83351 617.101 6.74362 618.447 7.22761C619.083 8.76022 618.643 22.2588 618.615 24.8262C612.515 24.9414 606.112 24.8423 599.989 24.84C590.537 22.9617 591.129 26.1099 591.588 15.1857C593.353 15.1696 597.88 15.566 599.087 14.9829C600.138 13.872 599.733 9.08518 599.721 7.19764C602.784 7.16999 607.168 7.28753 610.104 6.97179Z" fill="#9E2184"/> -<path d="M486.087 15.6328C492.257 15.6812 498.428 15.6858 504.598 15.6512C507.124 15.6489 511.878 15.5268 514.213 15.8195C514.261 17.6102 514.531 23.3881 514.038 24.8377C513.621 24.9852 513.798 24.9921 513.512 24.9391C508.44 25.1489 502.664 24.8953 497.502 24.9691C494.852 25.006 488.574 25.1466 486.151 24.9207C486.221 21.9131 486.126 18.6612 486.087 15.6328Z" fill="#9E2184"/> -<path d="M428.942 -2.98908C431.901 -3.11584 435.411 -3.03286 438.412 -3.03517C438.435 0.424171 438.701 12.8995 438.261 15.642L428.953 15.6812C428.9 12.6252 428.275 -0.629083 428.942 -2.98908Z" fill="#9E2184"/> -<path d="M552.383 6.65836C555.278 6.47629 558.585 6.57539 561.482 6.65144C561.586 8.99531 561.448 23.07 560.959 24.8354C560.696 24.87 560.431 24.8999 560.166 24.9253C558.733 25.0613 553.333 25.4692 552.927 24.6072C551.743 22.0905 552.19 9.10363 552.383 6.65836Z" fill="#9E2184"/> -<path d="M495.396 -3.05129C498.596 -3.12734 501.797 -3.12506 504.996 -3.04439C505.04 -0.389393 505.148 3.53318 504.888 6.11213C502.108 6.22967 498.313 6.18358 495.542 6.06604C495.291 3.70143 495.39 -0.536871 495.396 -3.05129Z" fill="#9E2184"/> -<path d="M656.878 -2.98907C659.95 -3.07435 663.024 -3.05129 666.096 -2.91761C666.096 -0.311012 666.212 3.91808 665.806 6.32187C663.098 6.4855 659.413 6.39331 656.629 6.40022C656.608 4.4251 656.438 -1.33661 656.878 -2.98907Z" fill="#9E2184"/> -<path d="M713.814 15.5821C716.829 15.619 720.415 15.5729 723.386 15.7204C723.351 18.7234 723.271 21.8394 723.287 24.8354C720.254 24.8516 716.829 24.9391 713.831 24.8124C713.773 21.7356 713.766 18.6589 713.814 15.5821Z" fill="#9E2184"/> -<path d="M656.601 15.6167C659.639 15.6813 662.861 15.6282 665.915 15.6305C666.083 18.675 666.004 21.7172 665.894 24.7617C664.055 24.9968 658.659 24.8562 656.668 24.8424C656.528 21.95 656.601 18.5506 656.601 15.6167Z" fill="#9E2184"/> -<path d="M713.814 -3.24954C716.873 -3.19423 720.323 -3.2311 723.34 -3.04211C723.31 -1.18684 723.388 4.46655 723.04 5.93925C720.351 5.96229 716.481 5.88393 713.872 6.05448C713.886 2.95237 713.865 -0.147433 713.814 -3.24954Z" fill="#9E2184"/> -<path d="M277.088 6.91189C280.213 6.87502 283.339 6.87731 286.464 6.92571C286.646 8.76715 286.432 14.2223 285.911 16.0016C283.373 15.9947 280.613 16.1283 278.133 15.672C277.364 15.5061 277.496 13.6324 277.413 13.0101C277.08 10.5072 276.08 9.47701 277.088 6.91189Z" fill="#9E2184"/> -<path d="M353.108 6.67684C356.037 6.59157 358.969 6.58694 361.899 6.663C361.957 8.94925 362.227 14.1832 361.437 16.0892C359.562 16.0984 357.458 15.9025 355.598 15.7965C352.553 15.6259 352.582 13.2867 352.783 10.9405C352.911 9.45629 352.824 8.19563 353.108 6.67684Z" fill="#9E2184"/> -<path d="M73.4393 693.175V662.558H80.652L89.7572 680.243C89.9675 680.691 90.1568 681.147 90.325 681.609C90.5073 682.058 90.6685 682.507 90.8087 682.955H90.9348C90.9208 682.479 90.9068 682.002 90.8928 681.525C90.8928 681.049 90.8928 680.572 90.8928 680.095V662.558H96.9069V693.175H89.7572L80.5258 675.448C80.3155 675.028 80.1263 674.593 79.9581 674.144C79.7898 673.696 79.6426 673.247 79.5165 672.799H79.3693C79.3973 673.275 79.4113 673.745 79.4113 674.208C79.4253 674.656 79.4323 675.126 79.4323 675.616V693.175H73.4393ZM101.617 681.988V662.558H108.62V682.724C108.62 684.897 109.026 686.432 109.839 687.329C110.652 688.212 111.781 688.654 113.225 688.654C114.627 688.654 115.734 688.212 116.547 687.329C117.374 686.432 117.788 684.897 117.788 682.724V662.558H124.727V681.988C124.727 685.997 123.676 688.948 121.573 690.841C119.484 692.733 116.709 693.68 113.246 693.68C109.727 693.68 106.909 692.733 104.792 690.841C102.676 688.948 101.617 685.997 101.617 681.988ZM127.335 668.046V662.558H151.37V668.046H142.896V693.175H135.83V668.046H127.335ZM152.274 668.046V662.558H176.31V668.046H167.835V693.175H160.77V668.046H152.274ZM186.487 693.175V681.736L176.499 662.558H184.174L189.494 673.072C189.663 673.422 189.817 673.759 189.957 674.081C190.097 674.39 190.23 674.712 190.357 675.049H190.462C190.588 674.712 190.714 674.39 190.84 674.081C190.98 673.773 191.142 673.436 191.324 673.072L196.644 662.558H203.436L193.574 681.567V693.175H186.487ZM222.95 693.175V681.736L212.962 662.558H220.637L225.958 673.072C226.126 673.422 226.28 673.759 226.42 674.081C226.56 674.39 226.694 674.712 226.82 675.049H226.925C227.051 674.712 227.177 674.39 227.303 674.081C227.444 673.773 227.605 673.436 227.787 673.072L233.107 662.558H239.899L230.037 681.567V693.175H222.95ZM239.92 678.75V676.983C239.92 671.908 241.133 668.151 243.558 665.712C245.998 663.273 249.138 662.053 252.979 662.053C256.806 662.053 259.939 663.273 262.379 665.712C264.832 668.151 266.058 671.908 266.058 676.983V678.75C266.058 683.824 264.832 687.582 262.379 690.021C259.939 692.46 256.806 693.68 252.979 693.68C249.138 693.68 245.998 692.46 243.558 690.021C241.133 687.582 239.92 683.824 239.92 678.75ZM247.175 680.243C247.175 683.187 247.694 685.331 248.731 686.677C249.769 688.009 251.184 688.675 252.979 688.675C254.773 688.675 256.189 688.009 257.227 686.677C258.278 685.331 258.804 683.187 258.804 680.243V675.511C258.804 672.567 258.278 670.436 257.227 669.119C256.189 667.787 254.773 667.121 252.979 667.121C251.184 667.121 249.769 667.787 248.731 669.119C247.694 670.436 247.175 672.567 247.175 675.511V680.243ZM269.928 681.988V662.558H276.93V682.724C276.93 684.897 277.337 686.432 278.15 687.329C278.963 688.212 280.091 688.654 281.535 688.654C282.937 688.654 284.045 688.212 284.858 687.329C285.685 686.432 286.098 684.897 286.098 682.724V662.558H293.038V681.988C293.038 685.997 291.986 688.948 289.884 690.841C287.795 692.733 285.019 693.68 281.556 693.68C278.038 693.68 275.22 692.733 273.103 690.841C270.986 688.948 269.928 685.997 269.928 681.988Z" fill="white"/> -<path d="M73.208 634.343V607.327H84.0811C87.0127 607.327 89.2578 608.137 90.8164 609.758C92.375 611.366 93.1543 613.562 93.1543 616.345C93.1543 619.116 92.3812 621.317 90.835 622.95C89.3011 624.571 87.0251 625.381 84.0068 625.381H79.3682V634.343H73.208ZM79.3682 621.039H82.9492C84.4707 621.039 85.5283 620.612 86.1221 619.759C86.7158 618.893 87.0127 617.78 87.0127 616.419C87.0127 615.071 86.7158 613.976 86.1221 613.135C85.5283 612.281 84.4707 611.854 82.9492 611.854H79.3682V621.039ZM94.6201 625.474V624.88C94.6201 622.06 95.5046 619.802 97.2734 618.107C99.0423 616.413 101.362 615.565 104.231 615.565C107.076 615.565 109.291 616.369 110.874 617.978C112.457 619.586 113.249 621.806 113.249 624.639V626.457H98.1641V623.191H107.441V622.932C107.441 622.016 107.169 621.256 106.625 620.649C106.081 620.043 105.271 619.74 104.194 619.74C103.007 619.74 102.098 620.173 101.467 621.039C100.848 621.905 100.539 623.024 100.539 624.397V625.641C100.539 627.199 100.873 628.418 101.541 629.296C102.221 630.174 103.205 630.613 104.491 630.613C105.407 630.613 106.186 630.403 106.829 629.982C107.472 629.562 107.986 629.049 108.369 628.442L113.008 630.354C112.426 631.714 111.424 632.803 110.002 633.619C108.592 634.436 106.78 634.844 104.565 634.844C101.436 634.844 98.9928 634.003 97.2363 632.32C95.4922 630.626 94.6201 628.343 94.6201 625.474ZM115.197 629.036C115.197 627.106 115.952 625.616 117.461 624.564C118.982 623.513 120.949 622.981 123.361 622.969H127.443V621.874C127.443 621.058 127.239 620.414 126.831 619.944C126.423 619.474 125.73 619.239 124.753 619.239C123.776 619.239 123.058 619.437 122.601 619.833C122.143 620.229 121.914 620.755 121.914 621.41V621.744L116.292 621.726V621.354C116.292 619.66 117.09 618.281 118.686 617.217C120.294 616.141 122.434 615.603 125.105 615.603C127.802 615.603 129.855 616.116 131.266 617.143C132.688 618.169 133.399 619.802 133.399 622.041V630.205C133.399 630.947 133.461 631.659 133.585 632.339C133.721 633.007 133.913 633.582 134.16 634.064V634.343H128.297C128.136 634.046 127.994 633.681 127.87 633.248C127.759 632.815 127.685 632.376 127.647 631.931C127.239 632.623 126.509 633.248 125.458 633.805C124.419 634.361 123.108 634.64 121.524 634.64C119.644 634.64 118.117 634.17 116.941 633.229C115.779 632.289 115.197 630.892 115.197 629.036ZM121.116 628.572C121.116 629.352 121.339 629.964 121.784 630.409C122.229 630.842 122.91 631.059 123.825 631.059C124.815 631.059 125.662 630.731 126.367 630.075C127.085 629.407 127.443 628.634 127.443 627.756V626.197H124.809C123.547 626.197 122.613 626.389 122.007 626.772C121.413 627.156 121.116 627.756 121.116 628.572ZM137.37 634.343V616.104H143.159L143.215 618.386H143.289C143.759 617.582 144.477 616.932 145.441 616.438C146.419 615.93 147.563 615.677 148.874 615.677C150.754 615.677 152.282 616.202 153.457 617.254C154.632 618.305 155.22 620.093 155.22 622.616V634.343H149.264V623.136C149.264 622.047 149.029 621.28 148.559 620.835C148.101 620.377 147.451 620.148 146.61 620.148C145.893 620.148 145.243 620.359 144.662 620.779C144.081 621.2 143.635 621.763 143.326 622.468V634.343H137.37ZM158.801 627.7V616.104H164.775V627.273C164.775 628.424 165.01 629.228 165.48 629.686C165.951 630.131 166.6 630.354 167.429 630.354C168.159 630.354 168.808 630.131 169.377 629.686C169.946 629.24 170.385 628.684 170.694 628.016V616.104H176.65V634.343H170.88L170.806 632.042H170.75C170.23 632.871 169.482 633.533 168.505 634.027C167.54 634.522 166.396 634.77 165.072 634.77C163.217 634.77 161.708 634.225 160.545 633.137C159.382 632.036 158.801 630.224 158.801 627.7ZM178.691 620.408V616.104H191.03V620.408H178.691ZM181.475 628.758V617.532L181.586 617.161V610.927H187.356V627.867C187.356 628.931 187.517 629.636 187.839 629.982C188.16 630.329 188.643 630.502 189.286 630.502C189.595 630.502 189.892 630.477 190.177 630.428C190.461 630.366 190.74 630.279 191.012 630.168V634.287C190.69 634.411 190.214 634.528 189.583 634.64C188.952 634.751 188.204 634.807 187.338 634.807C185.495 634.807 184.054 634.33 183.015 633.378C181.988 632.413 181.475 630.873 181.475 628.758ZM202.979 634.343V607.327H213.853C216.784 607.327 219.029 608.137 220.588 609.758C222.146 611.366 222.926 613.562 222.926 616.345C222.926 619.116 222.153 621.317 220.606 622.95C219.073 624.571 216.797 625.381 213.778 625.381H209.14V634.343H202.979ZM209.14 621.039H212.721C214.242 621.039 215.3 620.612 215.894 619.759C216.487 618.893 216.784 617.78 216.784 616.419C216.784 615.071 216.487 613.976 215.894 613.135C215.3 612.281 214.242 611.854 212.721 611.854H209.14V621.039ZM225.635 634.343V616.104H231.665V634.343H225.635ZM225.245 610.37C225.245 609.504 225.542 608.774 226.136 608.181C226.729 607.575 227.577 607.271 228.678 607.271C229.766 607.271 230.601 607.568 231.183 608.162C231.764 608.756 232.055 609.492 232.055 610.37C232.055 611.236 231.758 611.972 231.164 612.578C230.57 613.184 229.729 613.487 228.641 613.487C227.54 613.487 226.699 613.184 226.117 612.578C225.536 611.972 225.245 611.236 225.245 610.37ZM234.708 625.492V624.898C234.708 622.066 235.617 619.802 237.436 618.107C239.254 616.4 241.647 615.547 244.616 615.547C247.585 615.547 249.972 616.4 251.778 618.107C253.597 619.802 254.506 622.066 254.506 624.898V625.492C254.506 628.325 253.597 630.595 251.778 632.302C249.972 633.996 247.585 634.844 244.616 634.844C241.635 634.844 239.235 633.996 237.417 632.302C235.611 630.595 234.708 628.325 234.708 625.492ZM240.757 624.639V625.733C240.757 627.243 241.085 628.424 241.74 629.277C242.408 630.118 243.361 630.539 244.598 630.539C245.847 630.539 246.799 630.118 247.455 629.277C248.123 628.424 248.457 627.243 248.457 625.733V624.639C248.457 623.142 248.123 621.979 247.455 621.15C246.787 620.309 245.835 619.889 244.598 619.889C243.373 619.889 242.427 620.309 241.759 621.15C241.091 621.979 240.757 623.142 240.757 624.639ZM257.493 634.343V616.104H263.282L263.338 618.386H263.412C263.882 617.582 264.6 616.932 265.564 616.438C266.542 615.93 267.686 615.677 268.997 615.677C270.877 615.677 272.405 616.202 273.58 617.254C274.755 618.305 275.343 620.093 275.343 622.616V634.343H269.387V623.136C269.387 622.047 269.152 621.28 268.682 620.835C268.224 620.377 267.575 620.148 266.733 620.148C266.016 620.148 265.367 620.359 264.785 620.779C264.204 621.2 263.758 621.763 263.449 622.468V634.343H257.493ZM278.163 625.474V624.88C278.163 622.06 279.048 619.802 280.816 618.107C282.585 616.413 284.905 615.565 287.774 615.565C290.619 615.565 292.834 616.369 294.417 617.978C296 619.586 296.792 621.806 296.792 624.639V626.457H281.707V623.191H290.984V622.932C290.984 622.016 290.712 621.256 290.168 620.649C289.624 620.043 288.813 619.74 287.737 619.74C286.55 619.74 285.641 620.173 285.01 621.039C284.391 621.905 284.082 623.024 284.082 624.397V625.641C284.082 627.199 284.416 628.418 285.084 629.296C285.764 630.174 286.748 630.613 288.034 630.613C288.95 630.613 289.729 630.403 290.372 629.982C291.015 629.562 291.529 629.049 291.912 628.442L296.551 630.354C295.969 631.714 294.967 632.803 293.545 633.619C292.135 634.436 290.323 634.844 288.108 634.844C284.979 634.844 282.536 634.003 280.779 632.32C279.035 630.626 278.163 628.343 278.163 625.474ZM298.685 625.474V624.88C298.685 622.06 299.569 619.802 301.338 618.107C303.107 616.413 305.426 615.565 308.296 615.565C311.141 615.565 313.355 616.369 314.938 617.978C316.522 619.586 317.313 621.806 317.313 624.639V626.457H302.229V623.191H311.506V622.932C311.506 622.016 311.234 621.256 310.689 620.649C310.145 620.043 309.335 619.74 308.259 619.74C307.071 619.74 306.162 620.173 305.531 621.039C304.913 621.905 304.604 623.024 304.604 624.397V625.641C304.604 627.199 304.938 628.418 305.605 629.296C306.286 630.174 307.269 630.613 308.556 630.613C309.471 630.613 310.25 630.403 310.894 629.982C311.537 629.562 312.05 629.049 312.434 628.442L317.072 630.354C316.491 631.714 315.489 632.803 314.066 633.619C312.656 634.436 310.844 634.844 308.63 634.844C305.5 634.844 303.057 634.003 301.301 632.32C299.557 630.626 298.685 628.343 298.685 625.474ZM320.134 634.343V616.104H325.997L326.071 618.367H326.127C326.56 617.6 327.147 616.963 327.89 616.456C328.632 615.949 329.467 615.695 330.395 615.695C330.716 615.695 331.025 615.72 331.322 615.77C331.619 615.819 331.829 615.868 331.953 615.918V620.612C331.73 620.538 331.471 620.482 331.174 620.445C330.889 620.408 330.568 620.39 330.209 620.39C329.38 620.39 328.601 620.643 327.871 621.15C327.141 621.658 326.578 622.319 326.183 623.136V634.343H320.134Z" fill="white"/> -<path d="M553.094 600.867H559.532L565.247 618.624C565.358 618.909 565.445 619.193 565.507 619.478C565.581 619.762 565.655 620.059 565.729 620.368H565.841C565.915 620.059 565.989 619.756 566.063 619.459C566.15 619.162 566.237 618.884 566.323 618.624L572.094 600.867H578.031L568.939 627.994H562.186L553.094 600.867ZM577.753 622.576C577.753 620.647 578.507 619.156 580.017 618.105C581.538 617.053 583.505 616.521 585.917 616.509H589.999V615.414C589.999 614.598 589.795 613.955 589.387 613.484C588.979 613.014 588.286 612.779 587.309 612.779C586.331 612.779 585.614 612.977 585.156 613.373C584.699 613.769 584.47 614.295 584.47 614.95V615.284L578.848 615.266V614.895C578.848 613.2 579.646 611.821 581.241 610.757C582.849 609.681 584.989 609.143 587.661 609.143C590.358 609.143 592.411 609.656 593.821 610.683C595.244 611.709 595.955 613.342 595.955 615.581V623.745C595.955 624.487 596.017 625.199 596.141 625.879C596.277 626.547 596.468 627.122 596.716 627.605V627.883H590.853C590.692 627.586 590.549 627.221 590.426 626.788C590.314 626.355 590.24 625.916 590.203 625.471C589.795 626.164 589.065 626.788 588.014 627.345C586.975 627.901 585.663 628.18 584.08 628.18C582.2 628.18 580.672 627.71 579.497 626.77C578.334 625.83 577.753 624.432 577.753 622.576ZM583.672 622.112C583.672 622.892 583.895 623.504 584.34 623.949C584.785 624.382 585.465 624.599 586.381 624.599C587.37 624.599 588.218 624.271 588.923 623.615C589.64 622.947 589.999 622.174 589.999 621.296V619.737H587.364C586.103 619.737 585.169 619.929 584.562 620.313C583.969 620.696 583.672 621.296 583.672 622.112ZM599.944 627.883V600.181H605.938V627.883H599.944ZM609.927 627.883V609.644H615.957V627.883H609.927ZM609.537 603.91C609.537 603.044 609.834 602.315 610.428 601.721C611.021 601.115 611.869 600.812 612.97 600.812C614.058 600.812 614.893 601.109 615.475 601.702C616.056 602.296 616.347 603.032 616.347 603.91C616.347 604.776 616.05 605.512 615.456 606.118C614.862 606.724 614.021 607.027 612.933 607.027C611.832 607.027 610.991 606.724 610.409 606.118C609.828 605.512 609.537 604.776 609.537 603.91ZM619 619.051V618.457C619 615.761 619.724 613.559 621.171 611.852C622.618 610.132 624.511 609.273 626.849 609.273C628.123 609.273 629.211 609.489 630.114 609.922C631.017 610.343 631.722 610.905 632.229 611.61V600.181H638.074V627.883H632.396L632.322 625.526H632.285C631.815 626.293 631.11 626.943 630.17 627.475C629.23 627.994 628.123 628.254 626.849 628.254C624.424 628.254 622.507 627.394 621.097 625.675C619.699 623.943 619 621.735 619 619.051ZM625.049 619.144C625.049 620.591 625.352 621.766 625.958 622.669C626.564 623.572 627.479 624.024 628.704 624.024C629.545 624.024 630.263 623.789 630.856 623.318C631.45 622.848 631.877 622.292 632.137 621.649V615.804C631.877 615.161 631.456 614.616 630.875 614.171C630.306 613.726 629.589 613.503 628.723 613.503C627.486 613.503 626.564 613.961 625.958 614.876C625.352 615.779 625.049 616.948 625.049 618.383V619.144Z" fill="white"/> -<path d="M554.601 681.651V672.231C554.601 668.782 555.533 666.07 557.397 664.093C559.262 662.116 561.876 661.128 565.241 661.128C568.605 661.128 571.227 662.109 573.105 664.072C574.984 666.02 575.923 668.74 575.923 672.231V681.651C575.923 685.184 574.956 687.925 573.021 689.874C571.087 691.808 568.493 692.768 565.241 692.754C561.862 692.754 559.241 691.787 557.376 689.853C555.526 687.904 554.601 685.17 554.601 681.651ZM561.666 682.787C561.666 684.343 561.953 685.57 562.528 686.467C563.117 687.35 564.028 687.792 565.262 687.792C566.496 687.792 567.4 687.35 567.975 686.467C568.563 685.57 568.858 684.343 568.858 682.787V671.2C568.858 669.616 568.563 668.383 567.975 667.499C567.4 666.602 566.496 666.154 565.262 666.154C564.028 666.154 563.117 666.602 562.528 667.499C561.953 668.383 561.666 669.616 561.666 671.2V682.787ZM578.194 679.591V678.35C578.194 673.079 579.694 668.915 582.694 665.859C585.694 662.789 589.998 661.254 595.606 661.254H596.888V666.784H595.774C592.325 666.784 589.655 667.717 587.762 669.581C585.884 671.432 584.944 674.67 584.944 679.296L585.134 679.969C585.134 683.081 585.519 685.177 586.29 686.257C587.075 687.322 588.106 687.855 589.381 687.855C590.629 687.855 591.582 687.427 592.241 686.572C592.914 685.703 593.251 684.189 593.251 682.03C593.251 680.306 592.928 678.988 592.283 678.077C591.638 677.151 590.664 676.689 589.36 676.689C588.169 676.689 587.159 677.144 586.332 678.056C585.519 678.953 585.113 680.144 585.113 681.63H583.536C583.536 678.827 584.3 676.577 585.828 674.88C587.356 673.17 589.304 672.315 591.673 672.315C594.323 672.315 596.419 673.184 597.961 674.922C599.503 676.647 600.274 679.044 600.274 682.114C600.274 685.366 599.272 687.953 597.267 689.874C595.262 691.794 592.627 692.754 589.36 692.754C586.01 692.754 583.311 691.71 581.264 689.621C579.218 687.532 578.194 684.189 578.194 679.591ZM598.907 694.878L610.767 661.633H616.634L604.753 694.878H598.907ZM615.877 679.591V678.35C615.877 673.079 617.377 668.915 620.377 665.859C623.377 662.789 627.681 661.254 633.288 661.254H634.571V666.784H633.457C630.008 666.784 627.337 667.717 625.445 669.581C623.566 671.432 622.627 674.67 622.627 679.296L622.816 679.969C622.816 683.081 623.202 685.177 623.973 686.257C624.758 687.322 625.788 687.855 627.064 687.855C628.312 687.855 629.265 687.427 629.924 686.572C630.597 685.703 630.933 684.189 630.933 682.03C630.933 680.306 630.611 678.988 629.966 678.077C629.321 677.151 628.347 676.689 627.043 676.689C625.851 676.689 624.842 677.144 624.015 678.056C623.202 678.953 622.795 680.144 622.795 681.63H621.218C621.218 678.827 621.982 676.577 623.51 674.88C625.038 673.17 626.987 672.315 629.356 672.315C632.006 672.315 634.102 673.184 635.644 674.922C637.186 676.647 637.957 679.044 637.957 682.114C637.957 685.366 636.954 687.953 634.95 689.874C632.945 691.794 630.309 692.754 627.043 692.754C623.693 692.754 620.994 691.71 618.947 689.621C616.9 687.532 615.877 684.189 615.877 679.591ZM639.513 671.726C639.513 668.488 640.515 665.915 642.52 664.009C644.539 662.088 647.181 661.128 650.448 661.128C653.784 661.128 656.476 662.172 658.522 664.261C660.583 666.35 661.614 669.693 661.614 674.292V675.532C661.614 680.719 660.114 684.834 657.114 687.876C654.113 690.904 649.81 692.439 644.202 692.481H642.898V687.035H644.034C647.469 687.035 650.118 686.109 651.983 684.259C653.861 682.409 654.8 679.212 654.8 674.67L654.674 673.913C654.674 670.927 654.296 668.88 653.539 667.773C652.782 666.665 651.73 666.112 650.384 666.112C649.151 666.112 648.198 666.539 647.525 667.394C646.866 668.235 646.536 669.707 646.536 671.81C646.536 673.605 646.859 674.943 647.504 675.827C648.148 676.71 649.116 677.151 650.405 677.151C651.625 677.151 652.642 676.717 653.455 675.848C654.282 674.964 654.695 673.78 654.695 672.294H656.167C656.167 675 655.431 677.215 653.959 678.939C652.501 680.663 650.56 681.525 648.134 681.525C645.485 681.525 643.382 680.656 641.826 678.918C640.284 677.179 639.513 674.782 639.513 671.726Z" fill="white"/> -<path d="M72.6781 526.108V523.111C72.6781 513.149 75.4881 505.318 81.1083 499.618C86.7285 493.892 94.5994 491.028 104.721 491.028H108.077V502.175H105.2C99.1541 502.175 94.5195 503.933 91.2965 507.449C88.0736 510.939 86.4621 517.198 86.4621 526.228L86.5021 527.106C86.5021 532.807 87.168 536.602 88.4998 538.493C89.8582 540.384 91.6161 541.33 93.7737 541.33C95.798 541.33 97.4228 540.598 98.648 539.133C99.8733 537.641 100.486 534.671 100.486 530.223C100.486 527 99.9132 524.603 98.7679 523.031C97.6492 521.433 95.9977 520.634 93.8136 520.634C91.7893 520.634 90.0713 521.406 88.6596 522.951C87.2479 524.47 86.542 526.547 86.542 529.184H84.1448C84.1448 523.99 85.6231 519.955 88.5797 517.078C91.5362 514.175 95.0522 512.723 99.1275 512.723C103.789 512.723 107.504 514.268 110.275 517.358C113.045 520.421 114.43 524.842 114.43 530.622C114.43 536.935 112.459 541.889 108.517 545.485C104.574 549.054 99.6202 550.839 93.6538 550.839C87.1546 550.839 82.0272 548.855 78.2716 544.886C74.5426 540.891 72.6781 534.631 72.6781 526.108ZM120.5 511.205C120.5 504.919 122.471 499.991 126.413 496.422C130.355 492.826 135.322 491.028 141.315 491.028C147.788 491.028 152.889 493.013 156.618 496.981C160.373 500.95 162.251 507.21 162.251 515.76V518.716C162.251 528.651 159.441 536.469 153.821 542.169C148.227 547.869 140.357 550.732 130.208 550.759H126.852V539.812H129.729C135.775 539.838 140.41 538.107 143.633 534.618C146.856 531.129 148.467 524.882 148.467 515.879L148.427 514.761C148.427 509.194 147.761 505.465 146.43 503.574C145.098 501.656 143.34 500.697 141.156 500.697C139.131 500.697 137.507 501.443 136.281 502.934C135.056 504.399 134.443 507.289 134.443 511.604C134.443 514.987 135.003 517.464 136.121 519.036C137.267 520.581 138.932 521.353 141.116 521.353C143.14 521.353 144.858 520.607 146.27 519.116C147.708 517.597 148.427 515.52 148.427 512.883H150.745C150.745 518.05 149.28 522.072 146.35 524.949C143.42 527.799 139.904 529.224 135.802 529.224C131.141 529.224 127.425 527.666 124.655 524.549C121.885 521.433 120.5 516.985 120.5 511.205ZM168.721 526.108V523.111C168.721 513.149 171.531 505.318 177.151 499.618C182.771 493.892 190.642 491.028 200.763 491.028H204.12V502.175H201.243C195.197 502.175 190.562 503.933 187.339 507.449C184.116 510.939 182.505 517.198 182.505 526.228L182.545 527.106C182.545 532.807 183.21 536.602 184.542 538.493C185.901 540.384 187.659 541.33 189.816 541.33C191.84 541.33 193.465 540.598 194.69 539.133C195.916 537.641 196.528 534.671 196.528 530.223C196.528 527 195.956 524.603 194.81 523.031C193.692 521.433 192.04 520.634 189.856 520.634C187.832 520.634 186.114 521.406 184.702 522.951C183.29 524.47 182.584 526.547 182.584 529.184H180.187C180.187 523.99 181.666 519.955 184.622 517.078C187.579 514.175 191.095 512.723 195.17 512.723C199.831 512.723 203.547 514.268 206.317 517.358C209.087 520.421 210.472 524.842 210.472 530.622C210.472 536.935 208.501 541.889 204.559 545.485C200.617 549.054 195.663 550.839 189.696 550.839C183.197 550.839 178.07 548.855 174.314 544.886C170.585 540.891 168.721 534.631 168.721 526.108ZM216.542 511.205C216.542 504.919 218.513 499.991 222.455 496.422C226.397 492.826 231.365 491.028 237.358 491.028C243.83 491.028 248.931 493.013 252.66 496.981C256.416 500.95 258.294 507.21 258.294 515.76V518.716C258.294 528.651 255.484 536.469 249.863 542.169C244.27 547.869 236.399 550.732 226.251 550.759H222.895V539.812H225.771C231.818 539.838 236.452 538.107 239.675 534.618C242.898 531.129 244.51 524.882 244.51 515.879L244.47 514.761C244.47 509.194 243.804 505.465 242.472 503.574C241.14 501.656 239.382 500.697 237.198 500.697C235.174 500.697 233.549 501.443 232.324 502.934C231.099 504.399 230.486 507.289 230.486 511.604C230.486 514.987 231.045 517.464 232.164 519.036C233.309 520.581 234.974 521.353 237.158 521.353C239.182 521.353 240.9 520.607 242.312 519.116C243.751 517.597 244.47 515.52 244.47 512.883H246.787C246.787 518.05 245.322 522.072 242.392 524.949C239.462 527.799 235.946 529.224 231.844 529.224C227.183 529.224 223.467 527.666 220.697 524.549C217.927 521.433 216.542 516.985 216.542 511.205ZM287.733 529.863V511.964C287.733 505.278 289.531 500.111 293.127 496.462C296.723 492.813 301.664 490.988 307.95 490.988C314.236 490.988 319.177 492.786 322.773 496.382C326.395 499.951 328.206 505.145 328.206 511.964V529.863C328.206 536.789 326.315 542.023 322.533 545.565C318.777 549.108 313.916 550.866 307.95 550.839C301.611 550.812 296.656 549.041 293.087 545.525C289.518 541.983 287.733 536.762 287.733 529.863ZM301.637 532.7C301.637 535.47 302.157 537.601 303.195 539.093C304.261 540.584 305.846 541.33 307.95 541.33C310.054 541.33 311.639 540.584 312.704 539.093C313.77 537.601 314.303 535.47 314.303 532.7V509.407C314.303 506.584 313.77 504.426 312.704 502.934C311.639 501.443 310.054 500.697 307.95 500.697C305.846 500.697 304.261 501.443 303.195 502.934C302.157 504.426 301.637 506.584 301.637 509.407V532.7ZM357.969 550V535.297L358.408 534.618V509.487H358.089L347.021 528.105H363.402L364.601 527.746H377.426V538.533H334.156V528.625L359.487 491.827H370.754V550H357.969ZM383.136 550V541.33L404.152 519.515C405.75 517.651 407.122 515.746 408.267 513.802C409.413 511.857 409.985 509.846 409.985 507.769C409.985 505.238 409.413 503.427 408.267 502.335C407.122 501.243 405.617 500.697 403.753 500.697C401.808 500.697 400.237 501.336 399.038 502.615C397.839 503.867 397.24 506.331 397.24 510.006V511.644H383.136V508.208C383.136 503.227 385.054 499.112 388.89 495.863C392.725 492.613 397.76 490.988 403.992 490.988C410.518 490.988 415.472 492.44 418.855 495.343C422.238 498.22 423.943 502.135 423.969 507.09C423.969 510.765 423.183 514.055 421.612 516.958C420.067 519.862 417.856 522.818 414.98 525.828L403.952 538.853H425.328V550H383.136ZM431.797 529.863V511.964C431.797 505.278 433.595 500.111 437.191 496.462C440.787 492.813 445.728 490.988 452.014 490.988C458.3 490.988 463.241 492.786 466.836 496.382C470.459 499.951 472.27 505.145 472.27 511.964V529.863C472.27 536.789 470.379 542.023 466.597 545.565C462.841 549.108 457.98 550.866 452.014 550.839C445.674 550.812 440.72 549.041 437.151 545.525C433.582 541.983 431.797 536.762 431.797 529.863ZM445.701 532.7C445.701 535.47 446.22 537.601 447.259 539.093C448.325 540.584 449.909 541.33 452.014 541.33C454.118 541.33 455.703 540.584 456.768 539.093C457.834 537.601 458.366 535.47 458.366 532.7V509.407C458.366 506.584 457.834 504.426 456.768 502.934C455.703 501.443 454.118 500.697 452.014 500.697C449.909 500.697 448.325 501.443 447.259 502.934C446.22 504.426 445.701 506.584 445.701 509.407V532.7ZM501.39 534.178C501.39 530.369 502.402 527.2 504.427 524.669C506.477 522.139 508.675 520.527 511.019 519.835V519.675C508.648 518.61 506.717 516.998 505.226 514.841C503.761 512.657 503.028 509.913 503.028 506.61C503.028 501.842 504.733 498.047 508.142 495.223C511.578 492.4 516.359 490.988 522.486 490.988C528.612 490.988 533.366 492.44 536.749 495.343C540.159 498.22 541.863 501.976 541.863 506.61C541.863 510.02 541.091 512.83 539.546 515.04C538.028 517.225 536.097 518.756 533.753 519.635V519.795C536.176 520.461 538.401 522.072 540.425 524.629C542.476 527.16 543.501 530.343 543.501 534.178C543.501 539.319 541.557 543.381 537.668 546.364C533.806 549.347 528.745 550.839 522.486 550.839C516.2 550.839 511.112 549.347 507.223 546.364C503.334 543.381 501.39 539.319 501.39 534.178ZM515.414 532.66C515.414 535.776 516.026 538.041 517.252 539.452C518.504 540.837 520.235 541.53 522.446 541.53C524.63 541.53 526.335 540.824 527.56 539.412C528.785 538.001 529.398 535.75 529.398 532.66C529.398 529.437 528.745 527.173 527.44 525.868C526.161 524.536 524.497 523.87 522.446 523.87C520.395 523.87 518.703 524.536 517.372 525.868C516.066 527.173 515.414 529.437 515.414 532.66ZM516.333 508.448C516.333 511.138 516.905 513.189 518.051 514.601C519.196 515.986 520.661 516.679 522.446 516.679C524.204 516.679 525.655 515.986 526.801 514.601C527.973 513.189 528.559 511.138 528.559 508.448C528.559 505.731 528.039 503.734 527 502.455C525.988 501.15 524.47 500.497 522.446 500.497C520.421 500.497 518.89 501.123 517.851 502.375C516.839 503.627 516.333 505.651 516.333 508.448ZM549.411 534.178C549.411 530.369 550.423 527.2 552.448 524.669C554.499 522.139 556.696 520.527 559.04 519.835V519.675C556.67 518.61 554.738 516.998 553.247 514.841C551.782 512.657 551.049 509.913 551.049 506.61C551.049 501.842 552.754 498.047 556.163 495.223C559.599 492.4 564.381 490.988 570.507 490.988C576.633 490.988 581.388 492.44 584.77 495.343C588.18 498.22 589.884 501.976 589.884 506.61C589.884 510.02 589.112 512.83 587.567 515.04C586.049 517.225 584.118 518.756 581.774 519.635V519.795C584.198 520.461 586.422 522.072 588.446 524.629C590.497 527.16 591.523 530.343 591.523 534.178C591.523 539.319 589.578 543.381 585.689 546.364C581.827 549.347 576.766 550.839 570.507 550.839C564.221 550.839 559.133 549.347 555.245 546.364C551.356 543.381 549.411 539.319 549.411 534.178ZM563.435 532.66C563.435 535.776 564.048 538.041 565.273 539.452C566.525 540.837 568.256 541.53 570.467 541.53C572.651 541.53 574.356 540.824 575.581 539.412C576.806 538.001 577.419 535.75 577.419 532.66C577.419 529.437 576.766 527.173 575.461 525.868C574.183 524.536 572.518 523.87 570.467 523.87C568.416 523.87 566.725 524.536 565.393 525.868C564.088 527.173 563.435 529.437 563.435 532.66ZM564.354 508.448C564.354 511.138 564.927 513.189 566.072 514.601C567.217 515.986 568.682 516.679 570.467 516.679C572.225 516.679 573.677 515.986 574.822 514.601C575.994 513.189 576.58 511.138 576.58 508.448C576.58 505.731 576.06 503.734 575.022 502.455C574.009 501.15 572.491 500.497 570.467 500.497C568.443 500.497 566.911 501.123 565.872 502.375C564.86 503.627 564.354 505.651 564.354 508.448ZM597.433 534.178C597.433 530.369 598.445 527.2 600.469 524.669C602.52 522.139 604.717 520.527 607.061 519.835V519.675C604.691 518.61 602.76 516.998 601.268 514.841C599.803 512.657 599.071 509.913 599.071 506.61C599.071 501.842 600.775 498.047 604.185 495.223C607.621 492.4 612.402 490.988 618.528 490.988C624.654 490.988 629.409 492.44 632.792 495.343C636.201 498.22 637.906 501.976 637.906 506.61C637.906 510.02 637.133 512.83 635.588 515.04C634.07 517.225 632.139 518.756 629.795 519.635V519.795C632.219 520.461 634.443 522.072 636.467 524.629C638.518 527.16 639.544 530.343 639.544 534.178C639.544 539.319 637.599 543.381 633.711 546.364C629.848 549.347 624.788 550.839 618.528 550.839C612.242 550.839 607.155 549.347 603.266 546.364C599.377 543.381 597.433 539.319 597.433 534.178ZM611.456 532.66C611.456 535.776 612.069 538.041 613.294 539.452C614.546 540.837 616.277 541.53 618.488 541.53C620.672 541.53 622.377 540.824 623.602 539.412C624.827 538.001 625.44 535.75 625.44 532.66C625.44 529.437 624.788 527.173 623.482 525.868C622.204 524.536 620.539 523.87 618.488 523.87C616.437 523.87 614.746 524.536 613.414 525.868C612.109 527.173 611.456 529.437 611.456 532.66ZM612.375 508.448C612.375 511.138 612.948 513.189 614.093 514.601C615.239 515.986 616.704 516.679 618.488 516.679C620.246 516.679 621.698 515.986 622.843 514.601C624.015 513.189 624.601 511.138 624.601 508.448C624.601 505.731 624.082 503.734 623.043 502.455C622.031 501.15 620.512 500.497 618.488 500.497C616.464 500.497 614.932 501.123 613.893 502.375C612.881 503.627 612.375 505.651 612.375 508.448ZM646.413 529.863V511.964C646.413 505.278 648.211 500.111 651.806 496.462C655.402 492.813 660.343 490.988 666.629 490.988C672.915 490.988 677.856 492.786 681.452 496.382C685.075 499.951 686.886 505.145 686.886 511.964V529.863C686.886 536.789 684.995 542.023 681.212 545.565C677.457 549.108 672.596 550.866 666.629 550.839C660.29 550.812 655.336 549.041 651.766 545.525C648.197 541.983 646.413 536.762 646.413 529.863ZM660.317 532.7C660.317 535.47 660.836 537.601 661.875 539.093C662.94 540.584 664.525 541.33 666.629 541.33C668.733 541.33 670.318 540.584 671.384 539.093C672.449 537.601 672.982 535.47 672.982 532.7V509.407C672.982 506.584 672.449 504.426 671.384 502.934C670.318 501.443 668.733 500.697 666.629 500.697C664.525 500.697 662.94 501.443 661.875 502.934C660.836 504.426 660.317 506.584 660.317 509.407V532.7ZM716.965 529.863V511.964C716.965 505.278 718.763 500.111 722.358 496.462C725.954 492.813 730.895 490.988 737.181 490.988C743.467 490.988 748.408 492.786 752.004 496.382C755.627 499.951 757.438 505.145 757.438 511.964V529.863C757.438 536.789 755.547 542.023 751.764 545.565C748.009 549.108 743.148 550.866 737.181 550.839C730.842 550.812 725.888 549.041 722.318 545.525C718.749 541.983 716.965 536.762 716.965 529.863ZM730.869 532.7C730.869 535.47 731.388 537.601 732.427 539.093C733.492 540.584 735.077 541.33 737.181 541.33C739.285 541.33 740.87 540.584 741.936 539.093C743.001 537.601 743.534 535.47 743.534 532.7V509.407C743.534 506.584 743.001 504.426 741.936 502.934C740.87 501.443 739.285 500.697 737.181 500.697C735.077 500.697 733.492 501.443 732.427 502.934C731.388 504.426 730.869 506.584 730.869 509.407V532.7ZM787.2 550V535.297L787.64 534.618V509.487H787.32L776.253 528.105H792.634L793.832 527.746H806.658V538.533H763.388V528.625L788.718 491.827H799.985V550H787.2ZM812.368 550V541.33L833.383 519.515C834.982 517.651 836.353 515.746 837.499 513.802C838.644 511.857 839.217 509.846 839.217 507.769C839.217 505.238 838.644 503.427 837.499 502.335C836.353 501.243 834.848 500.697 832.984 500.697C831.04 500.697 829.468 501.336 828.269 502.615C827.071 503.867 826.471 506.331 826.471 510.006V511.644H812.368V508.208C812.368 503.227 814.286 499.112 818.121 495.863C821.957 492.613 826.991 490.988 833.224 490.988C839.749 490.988 844.704 492.44 848.086 495.343C851.469 498.22 853.174 502.135 853.201 507.09C853.201 510.765 852.415 514.055 850.843 516.958C849.298 519.862 847.088 522.818 844.211 525.828L833.184 538.853H854.559V550H812.368ZM861.028 529.863V511.964C861.028 505.278 862.826 500.111 866.422 496.462C870.018 492.813 874.959 490.988 881.245 490.988C887.531 490.988 892.472 492.786 896.068 496.382C899.69 499.951 901.501 505.145 901.501 511.964V529.863C901.501 536.789 899.61 542.023 895.828 545.565C892.072 549.108 887.211 550.866 881.245 550.839C874.906 550.812 869.951 549.041 866.382 545.525C862.813 541.983 861.028 536.762 861.028 529.863ZM874.932 532.7C874.932 535.47 875.452 537.601 876.49 539.093C877.556 540.584 879.141 541.33 881.245 541.33C883.349 541.33 884.934 540.584 885.999 539.093C887.065 537.601 887.598 535.47 887.598 532.7V509.407C887.598 506.584 887.065 504.426 885.999 502.934C884.934 501.443 883.349 500.697 881.245 500.697C879.141 500.697 877.556 501.443 876.49 502.934C875.452 504.426 874.932 506.584 874.932 509.407V532.7Z" fill="white"/> -<path d="M958.701 286.92C958.83 286.847 958.963 286.763 959.096 286.67C959.188 286.605 959.28 286.532 959.375 286.458C959.409 286.432 959.441 286.406 959.476 286.38C961.15 284.993 963.031 282.098 964.37 278.587C964.376 278.57 964.383 278.553 964.389 278.535C964.485 278.284 964.577 278.03 964.668 277.771C966.65 272.051 967.265 264.751 963.927 258.782C961.828 255.027 958.834 251.88 955.36 249.677C952.38 247.756 950.566 244.511 950.491 240.968C950.435 236.85 949.321 232.652 947.222 228.897C943.914 222.987 937.306 219.688 931.355 218.374C929.273 217.914 927.107 217.631 924.973 217.702C923.494 217.752 921.828 217.873 920.508 218.612C915.98 221.144 909.315 236.078 915.282 246.75C917.382 250.506 920.375 253.652 923.85 255.856C926.829 257.777 928.643 261.022 928.719 264.564C928.775 268.683 929.889 272.88 931.988 276.636C937.955 287.308 954.171 289.45 958.699 286.918L958.701 286.92Z" fill="#FFC900"/> -<path d="M958.701 286.92C958.83 286.847 958.963 286.763 959.096 286.67C959.188 286.605 959.28 286.532 959.375 286.458C959.409 286.432 959.441 286.406 959.476 286.38C961.15 284.993 963.031 282.098 964.37 278.587C964.376 278.57 964.383 278.553 964.389 278.535C964.485 278.284 964.577 278.03 964.668 277.771C966.65 272.051 967.265 264.751 963.927 258.782C961.828 255.027 958.834 251.88 955.36 249.677C952.38 247.756 950.566 244.511 950.491 240.968C950.435 236.85 949.321 232.652 947.222 228.897C943.914 222.987 937.306 219.688 931.355 218.374C929.273 217.914 927.107 217.631 924.973 217.702C923.494 217.752 921.828 217.873 920.508 218.612C915.98 221.144 909.315 236.078 915.282 246.75C917.382 250.506 920.375 253.652 923.85 255.856C926.829 257.777 928.643 261.022 928.719 264.564C928.775 268.683 929.889 272.88 931.988 276.636C937.955 287.308 954.171 289.45 958.699 286.918L958.701 286.92ZM934.211 275.395C932.302 271.978 931.34 268.256 931.303 264.578C931.184 260.16 928.894 256.066 925.153 253.783C922.04 251.824 919.325 248.973 917.461 245.641C912.21 236.247 918.295 222.872 921.711 220.963C925.323 218.943 939.814 220.927 945.016 230.235C946.925 233.651 947.887 237.374 947.924 241.052C947.955 245.517 950.2 249.53 953.986 251.896C957.099 253.855 959.769 256.622 961.678 260.039C966.929 269.432 960.862 282.797 957.372 284.749C953.956 286.658 939.413 284.702 934.211 275.397L934.211 275.395Z" fill="black" stroke="black" stroke-width="0.187907"/> -<path d="M931.222 245.877L932.537 243.695" stroke="black" stroke-width="2.36476" stroke-miterlimit="10" stroke-linecap="round"/> -<path d="M926.489 241.979C929.444 241.969 931.832 239.566 931.823 236.611C931.813 233.656 929.41 231.268 926.455 231.277C923.5 231.287 921.112 233.69 921.121 236.645C921.131 239.6 923.534 241.988 926.489 241.979Z" fill="white" stroke="black" stroke-width="2.06698" stroke-miterlimit="10"/> -<path d="M935.866 236.899C938.821 236.89 941.209 234.487 941.2 231.532C941.191 228.577 938.788 226.189 935.833 226.198C932.878 226.207 930.489 228.61 930.499 231.566C930.508 234.521 932.911 236.909 935.866 236.899Z" fill="white" stroke="black" stroke-width="2.06698" stroke-miterlimit="10"/> -<path d="M935.356 226.423C934.065 228.139 933.993 230.564 935.336 232.378C936.482 233.927 938.357 234.62 940.138 234.33C941.429 232.615 941.501 230.19 940.158 228.375C939.012 226.827 937.137 226.134 935.356 226.423Z" fill="black"/> -<path d="M926.263 231.489C925.022 233.187 924.967 235.56 926.284 237.34C927.37 238.808 929.113 239.499 930.805 239.311C932.046 237.613 932.101 235.239 930.784 233.459C929.698 231.992 927.955 231.301 926.263 231.489Z" fill="black"/> -<path d="M932.85 245.048C934.07 245.376 935.486 245.307 936.663 244.886C937.849 244.461 939.317 243.276 939.963 242.177" stroke="black" stroke-width="2.36476" stroke-miterlimit="10" stroke-linecap="round"/> -<path d="M944.374 276.36C943.969 276.805 943.963 277.568 944.405 277.973C946.18 279.588 948.153 280.984 950.029 282.003C950.378 282.241 950.758 282.139 951.089 281.955C951.254 281.862 951.372 281.685 951.494 281.511C951.808 280.901 951.563 280.274 951.083 280.001C949.336 279.019 947.537 277.746 945.939 276.246C945.495 275.845 944.775 275.921 944.374 276.36Z" fill="black" stroke="black" stroke-width="0.375815" stroke-miterlimit="10"/> -<path d="M941.228 274.083L941.311 274.036C941.843 273.628 941.945 273.028 941.62 272.448C941.165 271.833 940.795 271.169 940.425 270.508C939.731 269.266 939.121 267.978 938.554 266.773C938.313 266.146 937.668 265.966 937.039 266.206C936.412 266.447 936.231 267.093 936.472 267.722C937 269.055 937.742 270.381 938.481 271.706C938.896 272.45 939.268 273.113 939.769 273.813C940.125 274.259 940.726 274.36 941.223 274.083L941.228 274.083Z" fill="black" stroke="black" stroke-width="0.375815" stroke-miterlimit="10"/> -<path d="M935.58 262.258L935.829 262.119C936.243 261.888 936.472 261.326 936.406 260.821C935.994 259.311 935.375 257.81 934.588 256.402C934.218 255.739 933.846 255.076 933.393 254.463C932.985 253.931 932.303 253.875 931.853 254.238C931.321 254.646 931.265 255.327 931.628 255.778C932.036 256.309 932.36 256.889 932.684 257.47C933.378 258.713 933.909 260.046 934.307 261.344C934.382 262.062 935.039 262.455 935.578 262.258L935.58 262.258Z" fill="black" stroke="black" stroke-width="0.375815" stroke-miterlimit="10"/> -<path d="M957.686 278.488C957.944 278.56 958.107 278.469 958.272 278.376C958.603 278.192 958.843 277.841 958.869 277.499C958.983 275.373 958.829 272.957 958.381 270.598C958.268 270.007 957.694 269.568 957.024 269.727C956.433 269.841 955.995 270.414 956.154 271.084C956.592 273.228 956.737 275.431 956.659 277.433C956.642 277.986 957.05 278.518 957.686 278.49L957.686 278.488Z" fill="black" stroke="black" stroke-width="0.375815" stroke-miterlimit="10"/> -<path d="M944.835 247.031C944.208 247.272 944.027 247.918 944.22 248.461C944.506 249.172 944.878 249.835 945.245 250.494C946.032 251.901 946.985 253.214 948.059 254.355C948.374 254.721 948.972 254.82 949.468 254.544L949.717 254.405C950.122 253.961 950.173 253.279 949.813 252.831C948.836 251.858 948.056 250.663 947.362 249.421C947.038 248.841 946.715 248.262 946.473 247.633C946.065 247.101 945.457 246.787 944.833 247.029L944.835 247.031Z" fill="black" stroke="black" stroke-width="0.375815" stroke-miterlimit="10"/> -<path d="M952.762 257.799C952.23 258.207 952.174 258.888 952.453 259.386C953.265 260.452 953.959 261.695 954.655 262.935C955.025 263.598 955.396 264.261 955.68 264.968C955.921 265.595 956.566 265.775 957.196 265.535L957.279 265.487C957.777 265.208 957.96 264.563 957.763 264.02C957.477 263.309 957.059 262.566 956.642 261.819C955.901 260.493 955.077 259.217 954.302 258.022C953.944 257.571 953.214 257.436 952.764 257.799L952.762 257.799Z" fill="black" stroke="black" stroke-width="0.375815" stroke-miterlimit="10"/> -<path d="M945.343 263.216C945.922 262.891 946.105 262.246 945.781 261.668L942.261 255.374C941.937 254.795 941.291 254.612 940.714 254.936C940.137 255.261 939.952 255.906 940.276 256.483L943.796 262.778C944.116 263.359 944.761 263.54 945.343 263.216Z" fill="black" stroke="black" stroke-width="0.375815" stroke-miterlimit="10"/> -<path d="M952.383 275.802C952.962 275.478 953.145 274.832 952.821 274.255L949.301 267.961C948.977 267.381 948.331 267.198 947.754 267.523C947.177 267.847 946.992 268.493 947.316 269.07L950.836 275.364C951.156 275.946 951.801 276.126 952.383 275.802Z" fill="black" stroke="black" stroke-width="0.375815" stroke-miterlimit="10"/> -<path d="M135.11 143.72L143.378 94.9783H156.599L148.328 143.72H135.11ZM196.034 96.0475C192.24 94.6665 188.232 93.9736 184.196 94.0009C171.149 94.0009 161.957 100.603 161.878 110.068C161.806 117.064 168.441 120.966 173.45 123.293C178.591 125.681 180.318 127.202 180.293 129.334C180.261 132.596 176.188 134.086 172.394 134.086C167.107 134.086 164.301 133.34 159.962 131.532L158.262 130.759L156.408 141.656C159.492 143.014 165.197 144.192 171.117 144.252C184.998 144.252 194.009 137.727 194.113 127.62C194.163 122.082 190.648 117.867 183.026 114.393C178.41 112.155 175.584 110.638 175.613 108.357C175.613 106.336 178.007 104.172 183.177 104.172C186.564 104.096 189.93 104.731 193.059 106.037L194.242 106.599L196.034 96.0475ZM229.999 94.9783H219.827C216.677 94.9783 214.318 95.8437 212.935 99.002L193.383 143.471H207.299C207.299 143.471 209.527 137.558 210.039 136.259L226.712 136.279C227.101 137.961 228.296 143.471 228.296 143.471H240.651L229.999 94.9783ZM213.826 126.312C214.917 123.507 219.087 112.704 219.087 112.704C219.008 112.834 220.171 109.884 220.837 108.056L221.73 112.254C221.73 112.254 224.26 123.875 224.787 126.312H213.826ZM123.891 94.9783L110.992 128.1L109.618 121.368C107.218 113.61 99.7362 105.204 91.3711 100.996L103.166 143.471L117.105 143.456L137.847 94.9783H123.827" fill="white"/> -<path d="M98.373 94.9777H77.1708L77 95.9898C93.5668 100.021 104.528 109.759 109.079 121.457L104.449 99.0759C103.649 95.9948 101.333 95.0746 98.4646 94.9677" fill="white"/> -</g> -<defs> -<linearGradient id="paint0_linear_17007_2405" x1="3.00001" y1="333.901" x2="1211" y2="385.21" gradientUnits="userSpaceOnUse"> -<stop stop-color="white" stop-opacity="0.29"/> -<stop offset="1" stop-color="white" stop-opacity="0.12"/> -</linearGradient> -</defs> -</svg> diff --git a/src/assets/chains/arbitrum.svg b/src/assets/chains/arbitrum.svg index fd76971ed..30a5e059e 100644 --- a/src/assets/chains/arbitrum.svg +++ b/src/assets/chains/arbitrum.svg @@ -1,6 +1,6 @@ <svg width="73" height="80" viewBox="0 0 73 80" fill="none" xmlns="http://www.w3.org/2000/svg"> <metadata> - <![CDATA[if you have found this link, congratz! please let us know in our discord! https://peanut.to/claim#?c=42161&v=v4&i=384&p=bDx82DdZrctC2pj8&t=ui]]> + <![CDATA[if you have found this link, congratz! please let us know in our discord! https://peanut.me/claim#?c=42161&v=v4&i=384&p=bDx82DdZrctC2pj8&t=ui]]> </metadata> <path d="M45.7349 36.4348L51.7537 26.5257L67.9772 51.0417L67.9848 55.7467L67.9318 23.3707C67.8935 22.579 67.4603 21.8549 66.7694 21.4277L37.5611 5.12742C36.8783 4.80155 36.0114 4.80547 35.3296 5.1377C35.2373 5.18271 35.151 5.23115 35.0683 5.28448L34.9665 5.34662L6.61498 21.2868L6.50504 21.3357C6.36333 21.3984 6.22061 21.4791 6.08596 21.5721C5.54838 21.9459 5.19133 22.4993 5.07584 23.1192C5.0587 23.2131 5.04559 23.3091 5.04004 23.4059L5.08442 49.7891L20.1959 27.0649C22.0981 24.0518 26.2435 23.0806 30.0919 23.1339L34.6079 23.2494L7.99728 64.6548L11.134 66.4069L38.0634 23.2914L49.9665 23.2494L23.1067 67.4531L34.2998 73.6998L35.6372 74.4455C36.203 74.6686 36.8697 74.6799 37.4401 74.4798L67.0589 57.8262L61.396 61.01L45.7349 36.4348ZM48.031 68.5251L36.726 51.3093L43.6274 39.947L58.4746 62.6526L48.031 68.5251Z" diff --git a/src/components/0_Bruddle/BaseInput.tsx b/src/components/0_Bruddle/BaseInput.tsx index 26ef2f515..d3e271766 100644 --- a/src/components/0_Bruddle/BaseInput.tsx +++ b/src/components/0_Bruddle/BaseInput.tsx @@ -29,4 +29,7 @@ const BaseInput = forwardRef<HTMLInputElement, BaseInputProps>( } ) +BaseInput.displayName = 'BaseInput' + +export { BaseInput } export default BaseInput diff --git a/src/components/0_Bruddle/BaseSelect.tsx b/src/components/0_Bruddle/BaseSelect.tsx index acd8f2f84..13aa05fe7 100644 --- a/src/components/0_Bruddle/BaseSelect.tsx +++ b/src/components/0_Bruddle/BaseSelect.tsx @@ -100,4 +100,5 @@ const BaseSelect = forwardRef<HTMLButtonElement, BaseSelectProps>( BaseSelect.displayName = 'BaseSelect' +export { BaseSelect } export default BaseSelect diff --git a/src/components/0_Bruddle/Button.tsx b/src/components/0_Bruddle/Button.tsx index a6604a5a5..a003522d5 100644 --- a/src/components/0_Bruddle/Button.tsx +++ b/src/components/0_Bruddle/Button.tsx @@ -1,9 +1,10 @@ 'use client' -import React, { forwardRef, useEffect, useRef, useState, useCallback } from 'react' +import React, { forwardRef, useCallback, useEffect, useRef } from 'react' import { twMerge } from 'tailwind-merge' import { Icon, type IconName } from '../Global/Icons/Icon' import Loading from '../Global/Loading' import { useHaptic } from 'use-haptic' +import { useLongPress } from '@/hooks/useLongPress' export type ButtonVariant = | 'purple' @@ -11,15 +12,21 @@ export type ButtonVariant = | 'stroke' | 'transparent-light' | 'transparent-dark' - | 'green' - | 'yellow' | 'transparent' | 'primary-soft' -export type ButtonSize = 'small' | 'medium' | 'large' | 'xl' | 'xl-fixed' +export type ButtonSize = 'small' | 'medium' | 'large' type ButtonShape = 'default' | 'square' type ShadowSize = '3' | '4' | '6' | '8' type ShadowType = 'primary' | 'secondary' +/** + * Primary button component. + * + * @prop variant - Visual style. 'purple' for primary CTAs, 'stroke' for secondary. + * @prop size - Height override. Omit for default h-13 (tallest). 'large' is h-10 (shorter!). + * @prop shadowSize - Drop shadow depth. '4' is standard (160+ usages). + * @prop longPress - Hold-to-confirm behavior with progress bar animation. + */ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { variant?: ButtonVariant size?: ButtonSize @@ -47,8 +54,6 @@ const buttonVariants: Record<ButtonVariant, string> = { stroke: 'btn-stroke', 'transparent-light': 'btn-transparent-light', 'transparent-dark': 'btn-transparent-dark', - green: 'bg-green-1', - yellow: 'bg-secondary-1', 'primary-soft': 'bg-white', transparent: 'bg-transparent border-none hover:bg-transparent !active:bg-transparent focus:bg-transparent disabled:bg-transparent disabled:hover:bg-transparent', @@ -57,9 +62,8 @@ const buttonVariants: Record<ButtonVariant, string> = { const buttonSizes: Record<ButtonSize, string> = { small: 'btn-small', medium: 'btn-medium', + /** @deprecated large (h-10) is shorter than default (h-13). Avoid for primary CTAs. */ large: 'btn-large', - xl: 'btn-xl', - 'xl-fixed': 'btn-xl-fixed', } const buttonShadows: Record<ShadowType, Record<ShadowSize, string>> = { @@ -104,12 +108,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>( const buttonRef = (ref as React.RefObject<HTMLButtonElement>) || localRef const { triggerHaptic } = useHaptic() - - // Long press state - const [isLongPressed, setIsLongPressed] = useState(false) - const [pressTimer, setPressTimer] = useState<NodeJS.Timeout | null>(null) - const [pressProgress, setPressProgress] = useState(0) - const [progressInterval, setProgressInterval] = useState<NodeJS.Timeout | null>(null) + const { isLongPressed, pressProgress, handlers: longPressHandlers } = useLongPress(longPress) useEffect(() => { if (!buttonRef.current) return @@ -117,83 +116,9 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>( buttonRef.current.classList.add('notranslate') }, []) - // Long press handlers - const handlePressStart = useCallback(() => { - if (!longPress) return - - longPress.onLongPressStart?.() - setPressProgress(0) - - const duration = longPress.duration || 2000 - const updateInterval = 16 // ~60fps - const increment = (100 / duration) * updateInterval - - // Progress animation - const progressTimer = setInterval(() => { - setPressProgress((prev) => { - const newProgress = prev + increment - if (newProgress >= 100) { - clearInterval(progressTimer) - return 100 - } - return newProgress - }) - }, updateInterval) - - setProgressInterval(progressTimer) - - // Long press completion timer - const timer = setTimeout(() => { - setIsLongPressed(true) - longPress.onLongPress?.() - clearInterval(progressTimer) - }, duration) - - setPressTimer(timer) - }, [longPress]) - - const handlePressEnd = useCallback(() => { - if (!longPress) return - - if (pressTimer) { - clearTimeout(pressTimer) - setPressTimer(null) - } - - if (progressInterval) { - clearInterval(progressInterval) - setProgressInterval(null) - } - - if (isLongPressed) { - longPress.onLongPressEnd?.() - setIsLongPressed(false) - } - - setPressProgress(0) - }, [longPress, pressTimer, progressInterval, isLongPressed]) - - const handlePressCancel = useCallback(() => { - if (!longPress) return - - if (pressTimer) { - clearTimeout(pressTimer) - setPressTimer(null) - } - - if (progressInterval) { - clearInterval(progressInterval) - setProgressInterval(null) - } - - setIsLongPressed(false) - setPressProgress(0) - }, [longPress, pressTimer, progressInterval]) - const handleClick = useCallback( (e: React.MouseEvent<HTMLButtonElement>) => { if (longPress && !isLongPressed) { - // If long press is enabled but not completed, don't trigger onClick return } @@ -203,21 +128,9 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>( onClick?.(e) }, - [longPress, isLongPressed, onClick] + [longPress, isLongPressed, onClick, disableHaptics, triggerHaptic] ) - // Cleanup timers on unmount - useEffect(() => { - return () => { - if (pressTimer) { - clearTimeout(pressTimer) - } - if (progressInterval) { - clearInterval(progressInterval) - } - } - }, [pressTimer, progressInterval]) - const buttonClasses = twMerge( `btn w-full flex items-center gap-2 transition-all duration-100 active:translate-x-[3px] active:translate-y-[${shadowSize}px] active:shadow-none notranslate`, buttonVariants[variant], @@ -255,12 +168,12 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>( ref={buttonRef} translate="no" onClick={handleClick} - onMouseDown={longPress ? handlePressStart : undefined} - onMouseUp={longPress ? handlePressEnd : undefined} - onMouseLeave={longPress ? handlePressCancel : undefined} - onTouchStart={longPress ? handlePressStart : undefined} - onTouchEnd={longPress ? handlePressEnd : undefined} - onTouchCancel={longPress ? handlePressCancel : undefined} + onMouseDown={longPress ? longPressHandlers.onMouseDown : undefined} + onMouseUp={longPress ? longPressHandlers.onMouseUp : undefined} + onMouseLeave={longPress ? longPressHandlers.onMouseLeave : undefined} + onTouchStart={longPress ? longPressHandlers.onTouchStart : undefined} + onTouchEnd={longPress ? longPressHandlers.onTouchEnd : undefined} + onTouchCancel={longPress ? longPressHandlers.onTouchCancel : undefined} {...props} > {/* Progress bar for long press */} diff --git a/src/components/0_Bruddle/Card.tsx b/src/components/0_Bruddle/Card.tsx index d42052e6b..c36bbe7bb 100644 --- a/src/components/0_Bruddle/Card.tsx +++ b/src/components/0_Bruddle/Card.tsx @@ -1,4 +1,3 @@ -import classNames from 'classnames' import { twMerge } from 'tailwind-merge' type ShadowSize = '4' | '6' | '8' @@ -59,7 +58,7 @@ const Description = ({ children, className, ...props }: React.HTMLAttributes<HTM ) const Content = ({ children, className, ...props }: React.HTMLAttributes<HTMLDivElement>) => ( - <div className={classNames('card-content', className)} {...props}> + <div className={twMerge('card-content', className)} {...props}> {children} </div> ) diff --git a/src/components/0_Bruddle/Checkbox.tsx b/src/components/0_Bruddle/Checkbox.tsx index 0f991cf3a..f38dda4f0 100644 --- a/src/components/0_Bruddle/Checkbox.tsx +++ b/src/components/0_Bruddle/Checkbox.tsx @@ -26,4 +26,7 @@ const Checkbox = ({ className, label, value, onChange }: CheckboxProps) => ( </label> ) +Checkbox.displayName = 'Checkbox' + +export { Checkbox } export default Checkbox diff --git a/src/components/0_Bruddle/CloudsBackground.tsx b/src/components/0_Bruddle/CloudsBackground.tsx index 1128351a9..58357a927 100644 --- a/src/components/0_Bruddle/CloudsBackground.tsx +++ b/src/components/0_Bruddle/CloudsBackground.tsx @@ -227,4 +227,7 @@ const CloudsBackground: React.FC<CloudsBackgroundProps> = ({ minimal = false }) ) } +CloudsBackground.displayName = 'CloudsBackground' + +export { CloudsBackground } export default CloudsBackground diff --git a/src/components/0_Bruddle/Divider.tsx b/src/components/0_Bruddle/Divider.tsx index dacc77f8b..508e8f108 100644 --- a/src/components/0_Bruddle/Divider.tsx +++ b/src/components/0_Bruddle/Divider.tsx @@ -16,4 +16,7 @@ const Divider = ({ text, className, dividerClassname, textClassname, ...props }: ) } +Divider.displayName = 'Divider' + +export { Divider } export default Divider diff --git a/src/components/0_Bruddle/PageContainer.tsx b/src/components/0_Bruddle/PageContainer.tsx index d35383e6a..60657d5b5 100644 --- a/src/components/0_Bruddle/PageContainer.tsx +++ b/src/components/0_Bruddle/PageContainer.tsx @@ -19,4 +19,7 @@ const PageContainer = (props: PageContainerProps) => { ) } +PageContainer.displayName = 'PageContainer' + +export { PageContainer } export default PageContainer diff --git a/src/components/0_Bruddle/Title.tsx b/src/components/0_Bruddle/Title.tsx index fd6a45067..9f5df1c13 100644 --- a/src/components/0_Bruddle/Title.tsx +++ b/src/components/0_Bruddle/Title.tsx @@ -18,4 +18,7 @@ const Title = ({ ) } +Title.displayName = 'Title' + +export { Title } export default Title diff --git a/src/components/Card/CardGeoScreen.tsx b/src/components/Card/CardGeoScreen.tsx index 2f1b9de66..5f177be90 100644 --- a/src/components/Card/CardGeoScreen.tsx +++ b/src/components/Card/CardGeoScreen.tsx @@ -96,7 +96,7 @@ const CardGeoScreen = ({ </div> <div className="text-center"> <h1 className="font-bold">Verification Required</h1> - <p className="mt-2 text-sm text-black">Card Purchare requires identity verification.</p> + <p className="mt-2 text-sm text-black">Card Purchase requires identity verification.</p> </div> </Card> diff --git a/src/components/Card/CardInfoScreen.tsx b/src/components/Card/CardInfoScreen.tsx index 07bfe5e93..612b13a42 100644 --- a/src/components/Card/CardInfoScreen.tsx +++ b/src/components/Card/CardInfoScreen.tsx @@ -142,7 +142,7 @@ const CardInfoScreen = ({ onContinue, hasPurchased, slotsRemaining, recentPurcha every spend of you and your friends. </p> <a - href="https://peanut.to/card/faq" + href="https://peanut.me/card/faq" target="_blank" rel="noopener noreferrer" className="mt-2 inline-block text-sm text-black underline" diff --git a/src/components/Common/PointsCard.tsx b/src/components/Common/PointsCard.tsx index 5a39115cd..36b395260 100644 --- a/src/components/Common/PointsCard.tsx +++ b/src/components/Common/PointsCard.tsx @@ -1,12 +1,13 @@ import Card from '../Global/Card' import InvitesIcon from '../Home/InvitesIcon' +import { formatPoints } from '@/utils/format.utils' const PointsCard = ({ points, pointsDivRef }: { points: number; pointsDivRef: React.RefObject<HTMLDivElement> }) => { return ( <Card ref={pointsDivRef} className="flex flex-row items-center justify-center gap-3 p-3"> <InvitesIcon /> <p className="text-sm font-medium text-black"> - You've earned {points} {points === 1 ? 'point' : 'points'}! + You've earned {formatPoints(points)} {points === 1 ? 'point' : 'points'}! </p> </Card> ) diff --git a/src/components/Global/AnimateOnView.tsx b/src/components/Global/AnimateOnView.tsx new file mode 100644 index 000000000..64f07753b --- /dev/null +++ b/src/components/Global/AnimateOnView.tsx @@ -0,0 +1,52 @@ +'use client' + +import { useRef, useEffect, type CSSProperties } from 'react' + +type AnimateOnViewProps = { + children: React.ReactNode + className?: string + delay?: string + y?: string + x?: string + rotate?: string + style?: CSSProperties +} & React.HTMLAttributes<HTMLElement> + +export function AnimateOnView({ children, className, delay, y, x, rotate, style, ...rest }: AnimateOnViewProps) { + const ref = useRef<HTMLDivElement>(null) + + useEffect(() => { + const el = ref.current + if (!el) return + const observer = new IntersectionObserver( + ([entry]) => { + if (entry.isIntersecting) { + el.classList.add('in-view') + observer.disconnect() + } + }, + { threshold: 0.1 } + ) + observer.observe(el) + return () => observer.disconnect() + }, []) + + return ( + <div + ref={ref} + className={`animate-on-view ${className || ''}`} + style={ + { + '--aov-delay': delay || '0s', + '--aov-y': y || '20px', + '--aov-x': x || '0px', + '--aov-rotate': rotate || '0deg', + ...style, + } as CSSProperties + } + {...rest} + > + {children} + </div> + ) +} diff --git a/src/components/Global/FooterVisibilityObserver.tsx b/src/components/Global/FooterVisibilityObserver.tsx new file mode 100644 index 000000000..bda7d96ad --- /dev/null +++ b/src/components/Global/FooterVisibilityObserver.tsx @@ -0,0 +1,31 @@ +'use client' + +import { useFooterVisibility } from '@/context/footerVisibility' +import { useEffect, useRef } from 'react' + +export function FooterVisibilityObserver() { + const footerRef = useRef<HTMLDivElement>(null) + const { setIsFooterVisible } = useFooterVisibility() + + useEffect(() => { + const el = footerRef.current + if (!el) return + + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + setIsFooterVisible(entry.isIntersecting) + }) + }, + { root: null, rootMargin: '0px', threshold: 0.1 } + ) + + observer.observe(el) + + return () => { + observer.unobserve(el) + } + }, [setIsFooterVisible]) + + return <div ref={footerRef} /> +} diff --git a/src/components/Global/InvitesGraph/index.tsx b/src/components/Global/InvitesGraph/index.tsx index 60dfddc9c..d07a20400 100644 --- a/src/components/Global/InvitesGraph/index.tsx +++ b/src/components/Global/InvitesGraph/index.tsx @@ -266,6 +266,27 @@ export default function InvitesGraph(props: InvitesGraphProps) { const data = isMinimal ? props.data : fetchedGraphData if (!data) return null + // Minimal mode (points page): cap at 200 nodes for performance + if (isMinimal && data.nodes.length > 200) { + const sortedNodes = [...data.nodes].sort((a, b) => (b.totalPoints ?? 0) - (a.totalPoints ?? 0)) + const limitedNodes = sortedNodes.slice(0, 200) + const limitedNodeIds = new Set(limitedNodes.map((n) => n.id)) + const filteredEdges = data.edges.filter( + (edge) => limitedNodeIds.has(edge.source) && limitedNodeIds.has(edge.target) + ) + return { + nodes: limitedNodes, + edges: filteredEdges, + p2pEdges: [], + stats: { + ...data.stats, + totalNodes: limitedNodes.length, + totalEdges: filteredEdges.length, + totalP2PEdges: 0, + }, + } + } + // Performance mode: limit to top 1000 nodes on frontend (payment graph only) const performanceMode = !isMinimal && (props as FullModeProps).performanceMode if (performanceMode && data.nodes.length > 1000) { diff --git a/src/components/Global/QRScanner/useQRScanner.ts b/src/components/Global/QRScanner/useQRScanner.ts index b8e6c2c0b..0f1f01535 100644 --- a/src/components/Global/QRScanner/useQRScanner.ts +++ b/src/components/Global/QRScanner/useQRScanner.ts @@ -11,7 +11,7 @@ const CONFIG = { CAMERA_RETRY_DELAY_MS: 1000, MAX_CAMERA_RETRIES: 3, IOS_CAMERA_DELAY_MS: 200, - SCANNER_MAX_SCANS_PER_SECOND: 25, + SCANNER_MAX_SCANS_PER_SECOND: 8, SCANNER_CLOSE_DELAY_MS: 1500, VIDEO_ELEMENT_RETRY_DELAY_MS: 100, MAX_VIDEO_ELEMENT_RETRIES: 2, @@ -24,23 +24,20 @@ const CAMERA_ERRORS = { } as const /** - * Custom scan region: top 2/3 of video, horizontally centered. - * Matches the visual overlay position better. + * Scan region: half the video area, centered slightly above middle. * Uses 800x800 downscale for dense QR codes (Mercado Pago, PIX). */ const calculateScanRegion = (video: HTMLVideoElement) => { - // Use 2/3 of the smaller dimension for a square scan region - const smallerDimension = Math.min(video.videoWidth, video.videoHeight) - const scanRegionSize = Math.round((2 / 3) * smallerDimension) + const regionW = Math.round(video.videoWidth * 0.7) + const regionH = Math.round(video.videoHeight * 0.7) return { - x: Math.round((video.videoWidth - scanRegionSize) / 2), // Centered horizontally - y: 0, // Top aligned - width: scanRegionSize, - height: scanRegionSize, - // Larger downscale for dense QR codes (default is 400x400) - downScaledWidth: Math.min(scanRegionSize, 800), - downScaledHeight: Math.min(scanRegionSize, 800), + x: Math.round((video.videoWidth - regionW) / 2), + y: Math.round(((video.videoHeight - regionH) / 2) * 0.7), + width: regionW, + height: regionH, + downScaledWidth: Math.min(regionW, 800), + downScaledHeight: Math.min(regionH, 800), } } @@ -219,11 +216,25 @@ export function useQRScanner(onScan: QRScanHandler, onClose: (() => void) | unde preferredCamera, }) - // Enable scanning both normal and inverted QR codes (dark on light AND light on dark) - scanner.setInversionMode('both') + scanner.setInversionMode('original') scannerRef.current = scanner await scanner.start() + + // Request continuous autofocus — some devices default to single-shot + // focus on start, leaving the image blurry when the user moves the phone. + try { + const stream = videoRef.current?.srcObject as MediaStream | null + const track = stream?.getVideoTracks()[0] + if (track && 'applyConstraints' in track) { + await track.applyConstraints({ + advanced: [{ focusMode: 'continuous' } as MediaTrackConstraintSet], + }) + } + } catch { + // Not all devices support focusMode — safe to ignore + } + console.log('[QR Scanner] Camera started, ready to scan') retryCountRef.current = 0 } catch (err: any) { diff --git a/src/components/LandingPage/CloudsCss.tsx b/src/components/LandingPage/CloudsCss.tsx new file mode 100644 index 000000000..ab099317f --- /dev/null +++ b/src/components/LandingPage/CloudsCss.tsx @@ -0,0 +1,41 @@ +import borderCloud from '@/assets/illustrations/border-cloud.svg' +import { type CSSProperties } from 'react' + +type CloudConfig = { + top: string + width: number + speed: string + direction: 'ltr' | 'rtl' + delay?: string +} + +const defaultClouds: CloudConfig[] = [ + { top: '10%', width: 180, speed: '38s', direction: 'ltr' }, + { top: '45%', width: 220, speed: '44s', direction: 'ltr' }, + { top: '80%', width: 210, speed: '42s', direction: 'ltr' }, + { top: '25%', width: 200, speed: '40s', direction: 'rtl' }, + { top: '65%', width: 190, speed: '36s', direction: 'rtl' }, +] + +export function CloudsCss({ clouds = defaultClouds }: { clouds?: CloudConfig[] }) { + return ( + <div className="absolute left-0 top-0 h-full w-full overflow-hidden"> + {clouds.map((cloud, i) => ( + <img + key={i} + src={borderCloud.src} + alt="" + className={`absolute left-0 cloud-${cloud.direction}`} + style={ + { + top: cloud.top, + width: cloud.width, + '--cloud-speed': cloud.speed, + '--cloud-delay': cloud.delay || '0s', + } as CSSProperties + } + /> + ))} + </div> + ) +} diff --git a/src/components/LandingPage/CurrencySelect.tsx b/src/components/LandingPage/CurrencySelect.tsx index cdc13e8bd..e6276d955 100644 --- a/src/components/LandingPage/CurrencySelect.tsx +++ b/src/components/LandingPage/CurrencySelect.tsx @@ -58,7 +58,7 @@ const CurrencySelect = ({ <PopoverButton as={React.Fragment}>{trigger}</PopoverButton> <PopoverPanel anchor="bottom end" - className="mt-4 h-72 w-72 overflow-scroll rounded-sm border border-black bg-white shadow-lg sm:w-80 md:w-96" + className="z-50 mt-4 h-72 w-72 overflow-scroll rounded-sm border border-black bg-white shadow-lg sm:w-80 md:w-96" > <div className="flex max-h-full w-full flex-col gap-4 overflow-hidden p-4"> <div className="relative w-full"> diff --git a/src/components/LandingPage/LandingPageClient.tsx b/src/components/LandingPage/LandingPageClient.tsx new file mode 100644 index 000000000..ef9566466 --- /dev/null +++ b/src/components/LandingPage/LandingPageClient.tsx @@ -0,0 +1,217 @@ +'use client' + +import { useFooterVisibility } from '@/context/footerVisibility' +import { useEffect, useState, useRef, useCallback, type ReactNode } from 'react' +import { DropLink, FAQs, Hero, Marquee, NoFees, CardPioneers } from '@/components/LandingPage' +import TweetCarousel from '@/components/LandingPage/TweetCarousel' +import underMaintenanceConfig from '@/config/underMaintenance.config' + +type CTAButton = { + label: string + href: string + isExternal?: boolean + subtext?: string +} + +type FAQQuestion = { + id: string + question: string + answer: string +} + +type LandingPageClientProps = { + heroConfig: { + primaryCta: CTAButton + } + faqData: { + heading: string + questions: FAQQuestion[] + marquee: { visible: boolean; message: string } + } + marqueeMessages: string[] + // Server-rendered slots + mantecaSlot: ReactNode + regulatedRailsSlot: ReactNode + yourMoneySlot: ReactNode + securitySlot: ReactNode + sendInSecondsSlot: ReactNode + footerSlot: ReactNode +} + +export function LandingPageClient({ + heroConfig, + faqData, + marqueeMessages, + mantecaSlot, + regulatedRailsSlot, + yourMoneySlot, + securitySlot, + sendInSecondsSlot, + footerSlot, +}: LandingPageClientProps) { + const { isFooterVisible } = useFooterVisibility() + const [buttonVisible, setButtonVisible] = useState(true) + const [isScrollFrozen, setIsScrollFrozen] = useState(false) + const [buttonScale, setButtonScale] = useState(1) + const [animationComplete, setAnimationComplete] = useState(false) + const [shrinkingPhase, setShrinkingPhase] = useState(false) + const [hasGrown, setHasGrown] = useState(false) + const sendInSecondsRef = useRef<HTMLDivElement>(null) + const frozenScrollY = useRef(0) + const virtualScrollY = useRef(0) + const touchStartY = useRef(0) + + // Use refs to avoid re-attaching listeners on every state change + const isScrollFrozenRef = useRef(isScrollFrozen) + const animationCompleteRef = useRef(animationComplete) + const shrinkingPhaseRef = useRef(shrinkingPhase) + const hasGrownRef = useRef(hasGrown) + isScrollFrozenRef.current = isScrollFrozen + animationCompleteRef.current = animationComplete + shrinkingPhaseRef.current = shrinkingPhase + hasGrownRef.current = hasGrown + + useEffect(() => { + if (isFooterVisible) { + setButtonVisible(false) + } else { + setButtonVisible(true) + } + }, [isFooterVisible]) + + // Shared logic: accumulate virtual scroll delta and animate the button scale + const handleScrollDelta = useCallback((deltaY: number) => { + if (!isScrollFrozenRef.current || animationCompleteRef.current) return + if (deltaY <= 0) return + + virtualScrollY.current += deltaY + + const maxVirtualScroll = 500 + const newScale = Math.min(1.5, 1 + (virtualScrollY.current / maxVirtualScroll) * 0.5) + setButtonScale(newScale) + + if (newScale >= 1.5) { + setAnimationComplete(true) + setHasGrown(true) + document.body.style.overflow = '' + setIsScrollFrozen(false) + } + }, []) + + useEffect(() => { + const handleScroll = () => { + if (sendInSecondsRef.current) { + const targetElement = document.getElementById('sticky-button-target') + if (!targetElement) return + + const targetRect = targetElement.getBoundingClientRect() + const currentScrollY = window.scrollY + + const stickyButtonTop = window.innerHeight - 16 - 52 + const stickyButtonBottom = window.innerHeight - 16 + + const shouldFreeze = + targetRect.top <= stickyButtonBottom - 60 && + targetRect.bottom >= stickyButtonTop - 60 && + !animationCompleteRef.current && + !shrinkingPhaseRef.current && + !hasGrownRef.current + + if (shouldFreeze && !isScrollFrozenRef.current) { + setIsScrollFrozen(true) + frozenScrollY.current = currentScrollY + virtualScrollY.current = 0 + document.body.style.overflow = 'hidden' + window.scrollTo(0, frozenScrollY.current) + } else if (isScrollFrozenRef.current && !animationCompleteRef.current) { + window.scrollTo(0, frozenScrollY.current) + } else if ( + animationCompleteRef.current && + !shrinkingPhaseRef.current && + currentScrollY > frozenScrollY.current + 50 + ) { + setShrinkingPhase(true) + } else if (shrinkingPhaseRef.current) { + const shrinkDistance = Math.max(0, currentScrollY - (frozenScrollY.current + 50)) + const maxShrinkDistance = 200 + const shrinkProgress = Math.min(1, shrinkDistance / maxShrinkDistance) + const newScale = 1.5 - shrinkProgress * 0.5 + setButtonScale(Math.max(1, newScale)) + } else if (animationCompleteRef.current && currentScrollY < frozenScrollY.current - 100) { + setAnimationComplete(false) + setShrinkingPhase(false) + setButtonScale(1) + setHasGrown(false) + } + } + } + + const handleWheel = (event: WheelEvent) => { + if (isScrollFrozenRef.current && !animationCompleteRef.current) { + event.preventDefault() + handleScrollDelta(event.deltaY) + } + } + + const handleTouchStart = (event: TouchEvent) => { + touchStartY.current = event.touches[0].clientY + } + + const handleTouchMove = (event: TouchEvent) => { + if (isScrollFrozenRef.current && !animationCompleteRef.current) { + event.preventDefault() + const deltaY = touchStartY.current - event.touches[0].clientY + touchStartY.current = event.touches[0].clientY + handleScrollDelta(deltaY) + } + } + + window.addEventListener('scroll', handleScroll) + window.addEventListener('wheel', handleWheel, { passive: false }) + window.addEventListener('touchstart', handleTouchStart, { passive: true }) + window.addEventListener('touchmove', handleTouchMove, { passive: false }) + handleScroll() + + return () => { + window.removeEventListener('scroll', handleScroll) + window.removeEventListener('wheel', handleWheel) + window.removeEventListener('touchstart', handleTouchStart) + window.removeEventListener('touchmove', handleTouchMove) + document.body.style.overflow = '' + } + }, [handleScrollDelta]) + + const marqueeProps = { visible: true, message: marqueeMessages } + + return ( + <> + <Hero primaryCta={heroConfig.primaryCta} buttonVisible={buttonVisible} buttonScale={buttonScale} /> + <Marquee {...marqueeProps} /> + {mantecaSlot} + <Marquee {...marqueeProps} /> + {!underMaintenanceConfig.disableCardPioneers && ( + <> + <CardPioneers /> + <Marquee {...marqueeProps} /> + </> + )} + <TweetCarousel /> + <Marquee {...marqueeProps} /> + {regulatedRailsSlot} + <Marquee {...marqueeProps} /> + {yourMoneySlot} + <Marquee {...marqueeProps} /> + <DropLink /> + <Marquee {...marqueeProps} /> + {securitySlot} + <Marquee {...marqueeProps} /> + <div ref={sendInSecondsRef}>{sendInSecondsSlot}</div> + <Marquee {...marqueeProps} /> + <NoFees /> + <Marquee {...marqueeProps} /> + <FAQs heading={faqData.heading} questions={faqData.questions} marquee={faqData.marquee} /> + <Marquee {...marqueeProps} /> + {footerSlot} + </> + ) +} diff --git a/src/components/LandingPage/LandingPageShell.tsx b/src/components/LandingPage/LandingPageShell.tsx new file mode 100644 index 000000000..94a848860 --- /dev/null +++ b/src/components/LandingPage/LandingPageShell.tsx @@ -0,0 +1,11 @@ +import type { ReactNode } from 'react' +import { FooterVisibilityObserver } from '@/components/Global/FooterVisibilityObserver' + +export function LandingPageShell({ children }: { children: ReactNode }) { + return ( + <div className="enable-select !m-0 w-full !p-0"> + {children} + <FooterVisibilityObserver /> + </div> + ) +} diff --git a/src/components/LandingPage/Manteca.tsx b/src/components/LandingPage/Manteca.tsx index 22ad4d9ee..8b600b256 100644 --- a/src/components/LandingPage/Manteca.tsx +++ b/src/components/LandingPage/Manteca.tsx @@ -1,58 +1,41 @@ -import { motion } from 'framer-motion' -import { useEffect, useState } from 'react' import mantecaIphone from '@/assets/iphone-ss/manteca_ss.png' import Image from 'next/image' import { MEPA_ARGENTINA_LOGO, PIX_BRZ_LOGO, Star } from '@/assets' -import { CloudImages } from './imageAssets' +import { CloudsCss } from './CloudsCss' +import { AnimateOnView } from '@/components/Global/AnimateOnView' -const Manteca = () => { - const [screenWidth, setScreenWidth] = useState(typeof window !== 'undefined' ? window.innerWidth : 1200) - - const starConfigs = [ - { className: 'absolute left-12 top-10', delay: 0.2 }, - { className: 'absolute left-56 top-1/2', delay: 0.2 }, - { className: 'absolute bottom-20 left-20', delay: 0.2 }, - { className: 'absolute -top-16 right-20 md:top-58', delay: 0.6 }, - { className: 'absolute bottom-20 right-44', delay: 0.6 }, - ] - - const isMobile = screenWidth < 768 - - useEffect(() => { - const handleResize = () => { - setScreenWidth(window.innerWidth) - } - - handleResize() - window.addEventListener('resize', handleResize) - return () => window.removeEventListener('resize', handleResize) - }, []) +const starConfigs = [ + { className: 'absolute left-12 top-10', delay: '0.2s', rotate: '22deg' }, + { className: 'absolute left-56 top-1/2', delay: '0.2s', rotate: '22deg' }, + { className: 'absolute bottom-20 left-20', delay: '0.2s', rotate: '22deg' }, + { className: 'absolute -top-16 right-20 md:top-58', delay: '0.6s', rotate: '22deg' }, + { className: 'absolute bottom-20 right-44', delay: '0.6s', rotate: '22deg' }, +] +const Manteca = () => { return ( <section id="qr-pay" className="relative overflow-hidden py-20 text-n-1 md:h-[850px] lg:h-[750px]" style={{ backgroundColor: '#F9F4F0' }} > - {!isMobile && <CloudImages screenWidth={screenWidth} />} + <div className="hidden md:block"> + <CloudsCss /> + </div> - {!isMobile && ( - <> - {starConfigs.map((config, index) => ( - <motion.img - key={index} - src={Star.src} - alt="Floating Star" - width={50} - height={50} - className={config.className} - initial={{ opacity: 0, translateY: 20, translateX: 5, rotate: 22 }} - whileInView={{ opacity: 1, translateY: 0, translateX: 0, rotate: 22 }} - transition={{ type: 'spring', damping: 5, delay: config.delay }} - /> - ))} - </> - )} + <div className="hidden md:block"> + {starConfigs.map((config, index) => ( + <AnimateOnView + key={index} + className={config.className} + delay={config.delay} + x="5px" + rotate={config.rotate} + > + <img src={Star.src} alt="" width={50} height={50} /> + </AnimateOnView> + ))} + </div> <div className="relative flex flex-col items-center justify-center px-4"> <h1 className="font-roboto-flex-extrabold text-center text-[4rem] font-extraBlack md:text-left lg:text-headingMedium"> @@ -72,24 +55,22 @@ const Manteca = () => { </h3> </div> - {isMobile && ( - <div className="mt-4 flex flex-col items-center justify-center gap-4"> - <Image src={mantecaIphone} alt="Mercado pago payment" width={250} height={250} /> + {/* Mobile layout */} + <div className="mt-4 flex flex-col items-center justify-center gap-4 md:hidden"> + <Image src={mantecaIphone} alt="Mercado pago payment" width={250} height={250} /> - <div className="flex gap-8"> - <Image src={MEPA_ARGENTINA_LOGO} alt="Mepa Argentina" width={100} height={100} /> - <Image src={PIX_BRZ_LOGO} alt="Pix Brz" width={100} height={100} /> - </div> + <div className="flex gap-8"> + <Image src={MEPA_ARGENTINA_LOGO} alt="Mepa Argentina" width={100} height={100} /> + <Image src={PIX_BRZ_LOGO} alt="Pix Brz" width={100} height={100} /> </div> - )} + </div> - {!isMobile && ( - <div className="absolute -bottom-24 left-1/2 mx-auto flex -translate-x-1/2 items-center justify-center gap-20 lg:gap-36"> - <Image src={MEPA_ARGENTINA_LOGO} alt="Mepa Argentina" width={170} height={170} /> - <Image src={mantecaIphone} alt="Mercado pago payment" width={250} height={250} /> - <Image src={PIX_BRZ_LOGO} alt="Pix Brazil" width={170} height={170} /> - </div> - )} + {/* Desktop layout */} + <div className="absolute -bottom-24 left-1/2 mx-auto hidden -translate-x-1/2 items-center justify-center gap-20 md:flex lg:gap-36"> + <Image src={MEPA_ARGENTINA_LOGO} alt="Mepa Argentina" width={170} height={170} /> + <Image src={mantecaIphone} alt="Mercado pago payment" width={250} height={250} /> + <Image src={PIX_BRZ_LOGO} alt="Pix Brazil" width={170} height={170} /> + </div> </section> ) } diff --git a/src/components/LandingPage/RegulatedRails.tsx b/src/components/LandingPage/RegulatedRails.tsx index 8ccea37f5..e1e391d68 100644 --- a/src/components/LandingPage/RegulatedRails.tsx +++ b/src/components/LandingPage/RegulatedRails.tsx @@ -1,4 +1,3 @@ -'use client' import Image from 'next/image' import { MarqueeWrapper } from '../Global/MarqueeWrapper' import { @@ -11,11 +10,10 @@ import { MERCADO_PAGO_ICON, PIX_ICON, WISE_ICON, + Star, } from '@/assets' -import { useEffect, useState } from 'react' -import { motion } from 'framer-motion' -import borderCloud from '@/assets/illustrations/border-cloud.svg' -import { Star } from '@/assets' +import { CloudsCss } from './CloudsCss' +import { AnimateOnView } from '@/components/Global/AnimateOnView' const bgColor = '#F9F4F0' @@ -31,78 +29,28 @@ const logos = [ { logo: WISE_ICON, alt: 'Wise' }, ] -export function RegulatedRails() { - const [screenWidth, setScreenWidth] = useState(typeof window !== 'undefined' ? window.innerWidth : 1200) - - useEffect(() => { - const handleResize = () => { - setScreenWidth(window.innerWidth) - } - - handleResize() - window.addEventListener('resize', handleResize) - return () => window.removeEventListener('resize', handleResize) - }, []) - - const createCloudAnimation = (side: 'left' | 'right', top: string, width: number, speed: number) => { - const vpWidth = screenWidth || 1080 - const totalDistance = vpWidth + width +const regulatedRailsClouds = [ + { top: '20%', width: 200, speed: '38s', direction: 'ltr' as const }, + { top: '60%', width: 220, speed: '34s', direction: 'rtl' as const }, +] - return { - initial: { x: side === 'left' ? -width : vpWidth }, - animate: { x: side === 'left' ? vpWidth : -width }, - transition: { - ease: 'linear', - duration: totalDistance / speed, - repeat: Infinity, - }, - } - } +export function RegulatedRails() { return ( <section id="regulated-rails" className="relative overflow-hidden py-20 text-n-1" style={{ backgroundColor: bgColor }} > - <div className="absolute left-0 top-0 h-full w-full overflow-hidden"> - {/* Animated clouds */} - <motion.img - src={borderCloud.src} - alt="Floating Border Cloud" - className="absolute left-0" - style={{ top: '20%', width: 200 }} - {...createCloudAnimation('left', '20%', 200, 35)} - /> - <motion.img - src={borderCloud.src} - alt="Floating Border Cloud" - className="absolute right-0" - style={{ top: '60%', width: 220 }} - {...createCloudAnimation('right', '60%', 220, 40)} - /> - </div> + <CloudsCss clouds={regulatedRailsClouds} /> + <div className="relative max-w-5xl px-10 py-8 md:px-24 md:py-16"> - {/* Animated stars */} - <motion.img - src={Star.src} - alt="Floating Star" - width={50} - height={50} - className="absolute -right-72 -top-12" - initial={{ opacity: 0, translateY: 20, translateX: 5, rotate: 22 }} - whileInView={{ opacity: 1, translateY: 0, translateX: 0, rotate: 22 }} - transition={{ type: 'spring', damping: 5, delay: 0.2 }} - /> - <motion.img - src={Star.src} - alt="Floating Star" - width={50} - height={50} - className="absolute -right-0 -top-16 md:top-58" - initial={{ opacity: 0, translateY: 20, translateX: 5, rotate: 22 }} - whileInView={{ opacity: 1, translateY: 0, translateX: 0, rotate: 22 }} - transition={{ type: 'spring', damping: 5, delay: 0.6 }} - /> + <AnimateOnView className="absolute -right-72 -top-12" delay="0.2s" x="5px" rotate="22deg"> + <img src={Star.src} alt="" width={50} height={50} /> + </AnimateOnView> + <AnimateOnView className="absolute -right-0 -top-16 md:top-58" delay="0.6s" x="5px" rotate="22deg"> + <img src={Star.src} alt="" width={50} height={50} /> + </AnimateOnView> + <h1 className="font-roboto-flex-extrabold text-left text-[3.25rem] font-extraBlack !leading-[5rem] md:text-6xl lg:text-headingMedium"> REGULATED RAILS, SELF-CUSTODY CONTROL </h1> diff --git a/src/components/LandingPage/SendInSecondsCTA.tsx b/src/components/LandingPage/SendInSecondsCTA.tsx new file mode 100644 index 000000000..65be1b83d --- /dev/null +++ b/src/components/LandingPage/SendInSecondsCTA.tsx @@ -0,0 +1,34 @@ +'use client' + +import { motion } from 'framer-motion' +import { Button } from '@/components/0_Bruddle/Button' + +export function SendInSecondsCTA() { + return ( + <div className="relative mt-12 inline-block md:mt-24"> + <motion.div + className="relative" + initial={{ opacity: 0, translateY: 4, translateX: 0, rotate: 0.75 }} + animate={{ + opacity: 1, + translateY: 0, + translateX: 0, + rotate: 0, + scale: 1, + pointerEvents: 'auto' as const, + }} + whileHover={{ translateY: 6, translateX: 0, rotate: 0.75 }} + transition={{ type: 'spring', damping: 15 }} + > + <a href="/send"> + <Button + shadowSize="4" + className="bg-white px-7 py-3 text-base font-extrabold hover:bg-white/90 md:px-9 md:py-8 md:text-xl" + > + SEND NOW + </Button> + </a> + </motion.div> + </div> + ) +} diff --git a/src/components/LandingPage/hero.tsx b/src/components/LandingPage/hero.tsx index 0085fb2cb..c54f977d0 100644 --- a/src/components/LandingPage/hero.tsx +++ b/src/components/LandingPage/hero.tsx @@ -1,10 +1,9 @@ -import { ButterySmoothGlobalMoney, PeanutGuyGIF, Sparkle } from '@/assets' +'use client' + +import { ButterySmoothGlobalMoney, PeanutGuyGIF, Star } from '@/assets' import { motion } from 'framer-motion' -import { useEffect, useState } from 'react' -import { twMerge } from 'tailwind-merge' -import { CloudImages, HeroImages } from './imageAssets' -import Image from 'next/image' import { Button } from '@/components/0_Bruddle/Button' +import { CloudsCss } from './CloudsCss' type CTAButton = { label: string @@ -20,7 +19,6 @@ type HeroProps = { buttonScale?: number } -// Helper functions moved outside component for better performance const getInitialAnimation = (variant: 'primary' | 'secondary') => ({ opacity: 0, translateY: 4, @@ -31,7 +29,7 @@ const getInitialAnimation = (variant: 'primary' | 'secondary') => ({ const getAnimateAnimation = (variant: 'primary' | 'secondary', buttonVisible?: boolean, buttonScale?: number) => ({ opacity: buttonVisible ? 1 : 0, translateY: buttonVisible ? 0 : 20, - translateX: buttonVisible ? (variant === 'primary' ? 0 : 0) : 20, + translateX: buttonVisible ? 0 : 20, rotate: buttonVisible ? 0 : 1, scale: buttonScale || 1, pointerEvents: buttonVisible ? ('auto' as const) : ('none' as const), @@ -48,34 +46,7 @@ const transitionConfig = { type: 'spring', damping: 15 } as const const getButtonContainerClasses = (variant: 'primary' | 'secondary') => `relative z-20 mt-8 md:mt-12 flex flex-col items-center justify-center ${variant === 'primary' ? 'mx-auto w-fit' : 'right-[calc(50%-120px)]'}` -const getButtonClasses = (variant: 'primary' | 'secondary') => - `${variant === 'primary' ? 'btn bg-white fill-n-1 text-n-1 hover:bg-white/90' : 'btn-yellow'} px-7 md:px-9 py-3 md:py-8 text-base md:text-xl btn-shadow-primary-4` - -const renderSparkle = (variant: 'primary' | 'secondary') => - variant === 'primary' && ( - <img - src={Sparkle.src} - className={twMerge('absolute -right-4 -top-4 h-auto w-5 sm:-right-5 sm:-top-5 sm:w-6')} - alt="Sparkle" - /> - ) - export function Hero({ primaryCta, secondaryCta, buttonVisible, buttonScale = 1 }: HeroProps) { - const [screenWidth, setScreenWidth] = useState(typeof window !== 'undefined' ? window.innerWidth : 1200) - - useEffect(() => { - const handleResize = () => { - setScreenWidth(window.innerWidth) - } - - handleResize() - window.addEventListener('resize', handleResize) - - return () => { - window.removeEventListener('resize', handleResize) - } - }, []) - const renderCTAButton = (cta: CTAButton, variant: 'primary' | 'secondary') => { return ( <motion.div @@ -85,8 +56,6 @@ export function Hero({ primaryCta, secondaryCta, buttonVisible, buttonScale = 1 whileHover={getHoverAnimation(variant)} transition={transitionConfig} > - {/* {renderSparkle(variant)} */} - <a href={cta.href} target={cta.isExternal ? '_blank' : undefined} @@ -111,7 +80,7 @@ export function Hero({ primaryCta, secondaryCta, buttonVisible, buttonScale = 1 id="hero" className="relative flex min-h-[85vh] w-full flex-col items-center justify-between bg-primary-1 px-4 py-4 xl:h-fit xl:justify-center" > - <CloudImages screenWidth={screenWidth} /> + <CloudsCss /> <div className="relative mt-10 w-full md:mt-0"> <img src={ButterySmoothGlobalMoney.src} @@ -119,7 +88,22 @@ export function Hero({ primaryCta, secondaryCta, buttonVisible, buttonScale = 1 alt="Buttery Smooth Global Money" /> - <HeroImages /> + <motion.img + initial={{ opacity: 0, translateY: 20, translateX: 5 }} + whileInView={{ opacity: 1, translateY: 0, translateX: 0 }} + transition={{ type: 'spring', damping: 5 }} + src={Star.src} + alt="" + className="absolute bottom-[-4%] left-[1%] w-8 sm:bottom-[11%] sm:left-[12%] md:bottom-[18%] md:left-[5%] md:w-12" + /> + <motion.img + initial={{ opacity: 0, translateY: 28, translateX: -5 }} + whileInView={{ opacity: 1, translateY: 0, translateX: 0 }} + transition={{ type: 'spring', damping: 5 }} + src={Star.src} + alt="" + className="absolute right-[1.5%] top-[-12%] w-8 sm:right-[6%] sm:top-[8%] md:right-[5%] md:top-[8%] md:w-12 lg:right-[10%]" + /> </div> <img src={PeanutGuyGIF.src} @@ -127,7 +111,7 @@ export function Hero({ primaryCta, secondaryCta, buttonVisible, buttonScale = 1 alt="Peanut Guy" /> - <div className="relative mb-4 flex w-full flex-col items-center justify-center md:mb-0"> + <div className="relative z-20 mb-4 flex w-full flex-col items-center justify-center md:mb-0"> <h2 className="font-roboto-flex-extrabold mt-18 text-center text-[2.375rem] font-extraBlack text-black md:text-heading"> TAP. SEND. ANYWHERE </h2> @@ -141,7 +125,22 @@ export function Hero({ primaryCta, secondaryCta, buttonVisible, buttonScale = 1 </span> {primaryCta && renderCTAButton(primaryCta, 'primary')} {secondaryCta && renderCTAButton(secondaryCta, 'secondary')} - <HeroImages /> + <motion.img + initial={{ opacity: 0, translateY: 20, translateX: 5 }} + whileInView={{ opacity: 1, translateY: 0, translateX: 0 }} + transition={{ type: 'spring', damping: 5 }} + src={Star.src} + alt="" + className="absolute bottom-[-4%] left-[1%] w-8 sm:bottom-[11%] sm:left-[12%] md:bottom-[18%] md:left-[5%] md:w-12" + /> + <motion.img + initial={{ opacity: 0, translateY: 28, translateX: -5 }} + whileInView={{ opacity: 1, translateY: 0, translateX: 0 }} + transition={{ type: 'spring', damping: 5 }} + src={Star.src} + alt="" + className="absolute right-[1.5%] top-[-12%] w-8 sm:right-[6%] sm:top-[8%] md:right-[5%] md:top-[8%] md:w-12 lg:right-[10%]" + /> </div> </section> ) diff --git a/src/components/LandingPage/imageAssets.tsx b/src/components/LandingPage/imageAssets.tsx deleted file mode 100644 index 36f244ba8..000000000 --- a/src/components/LandingPage/imageAssets.tsx +++ /dev/null @@ -1,124 +0,0 @@ -'use client' -import { Star } from '@/assets' -import { motion } from 'framer-motion' -import borderCloud from '@/assets/illustrations/border-cloud.svg' - -const CloudAnimation = ({ - top, - imageSrc, - styleMod, - screenWidth, - width = 200, - speed = 45, - delay = 0, - direction = 'left-to-right', -}: { - top: string - imageSrc: string - styleMod?: string - screenWidth?: number - width?: number - speed?: number - delay?: number - direction?: 'left-to-right' | 'right-to-left' -}) => { - const vpWidth = screenWidth || 1080 - const totalDistance = vpWidth + width - - return ( - <motion.img - src={imageSrc} - alt="Floating Cloud" - className={`absolute left-0 ${styleMod || ''}`} - style={{ top, width }} - initial={{ - x: direction === 'left-to-right' ? -width : vpWidth, - }} - animate={{ - x: direction === 'left-to-right' ? vpWidth : -width, - }} - transition={{ - ease: 'linear', - duration: totalDistance / speed, - repeat: Infinity, - delay: delay, - }} - /> - ) -} - -export const CloudImages = ({ screenWidth }: { screenWidth: number }) => { - return ( - <div className="absolute left-0 top-0 h-full w-full overflow-hidden"> - {/* 3 clouds moving left-to-right */} - <CloudAnimation - top="10%" - imageSrc={borderCloud.src} - screenWidth={screenWidth} - width={180} - speed={30} - delay={0} - direction="left-to-right" - /> - <CloudAnimation - top="45%" - imageSrc={borderCloud.src} - screenWidth={screenWidth} - width={220} - speed={40} - delay={0} - direction="left-to-right" - /> - <CloudAnimation - top="80%" - imageSrc={borderCloud.src} - screenWidth={screenWidth} - width={210} - speed={38} - delay={0} - direction="left-to-right" - /> - - {/* 2 clouds moving right-to-left */} - <CloudAnimation - top="25%" - imageSrc={borderCloud.src} - screenWidth={screenWidth} - width={200} - speed={35} - delay={0} - direction="right-to-left" - /> - <CloudAnimation - top="65%" - imageSrc={borderCloud.src} - screenWidth={screenWidth} - width={190} - speed={32} - delay={0} - direction="right-to-left" - /> - </div> - ) -} - -export const HeroImages = () => { - return ( - <> - <motion.img - initial={{ opacity: 0, translateY: 20, translateX: 5 }} - whileInView={{ opacity: 1, translateY: 0, translateX: 0 }} - transition={{ type: 'spring', damping: 5 }} - src={Star.src} - className="absolute bottom-[-4%] left-[1%] w-8 sm:bottom-[11%] sm:left-[12%] md:bottom-[18%] md:left-[5%] md:w-12" - /> - <motion.img - initial={{ opacity: 0, translateY: 28, translateX: -5 }} - whileInView={{ opacity: 1, translateY: 0, translateX: 0 }} - transition={{ type: 'spring', damping: 5 }} - src={Star.src} - className="absolute right-[1.5%] top-[-12%] w-8 sm:right-[6%] sm:top-[8%] md:right-[5%] md:top-[8%] md:w-12 lg:right-[10%]" - /> - </> - ) -} diff --git a/src/components/LandingPage/landingPageData.ts b/src/components/LandingPage/landingPageData.ts new file mode 100644 index 000000000..e3750c386 --- /dev/null +++ b/src/components/LandingPage/landingPageData.ts @@ -0,0 +1,54 @@ +export const heroConfig = { + primaryCta: { + label: 'SIGN UP', + href: '/setup', + subtext: 'currently in waitlist', + }, +} + +export const marqueeMessages = ['No fees', 'Instant', '24/7', 'USD', 'EUR', 'USDT/USDC', 'GLOBAL', 'SELF-CUSTODIAL'] + +export const faqData = { + heading: 'Faqs', + questions: [ + { + id: '0', + question: 'Why Peanut?', + answer: `It's time to take control of your money. No banks, no borders. Just buttery smooth global money.`, + }, + { + id: '1', + question: 'What is Peanut?', + answer: `Peanut is the easiest way to send digital dollars to anyone anywhere. Peanut's tech is powered by cutting-edge cryptography and the security of biometric user authentication as well as a network of modern and fully licensed banking providers.`, + }, + { + id: '2', + question: 'Do I have to KYC?', + answer: `No! You can use core functionalities (like sending and receiving money) without KYC. Bank connections, however, trigger a one\u2011time check handled by Persona, a SOC2 Type 2 certified and GDPR compliant ISO 27001\u2013certified provider used by brands like Square and Robinhood. Your documents remain locked away with Persona, not Peanut, and Peanut only gets a yes/no response, keeping your privacy intact.`, + }, + { + id: '3', + question: 'Could a thief drain my wallet if they stole my phone?', + answer: `Not without your face or fingerprint. The passkey is sealed in the Secure Enclave of your phone and never exported. It\u2019s secured by NIST\u2011recommended P\u2011256 Elliptic Curve cryptography. Defeating that would be tougher than guessing all 10\u00B9\u2070\u00B9\u2070 combinations of a 30\u2011character password made of emoji.\nThis means that neither Peanut or even regulators could freeze, us or you to hand over your account, because we can\u2019t hand over what we don\u2019t have. Your key never touches our servers; compliance requests only see cryptographic and encrypted signatures. Cracking those signatures would demand more energy than the Sun outputs in a full century.`, + }, + { + id: '4', + question: `What happens to my funds if Peanut\u2019s servers were breached?`, + answer: "Nothing. Your funds sit in your self\u2011custodied smart account (not on Peanut servers). Every transfer still needs a signature from your biometric passkey, so a server\u2011side attacker has no way to move a cent without the private key sealed in your device's Secure Enclave. Even if Peanut were offline, you could point any ERC\u20114337\u2011compatible wallet at your smart account and recover access independently.", + }, + { + id: '5', + question: 'How does Peanut make money?', + answer: 'We plan to charge merchants for accepting Peanut as a payment method, whilst still being much cheaper than VISA and Mastercard. For users, we only charge minimal amounts!', + }, + { + id: '6', + question: 'My question is not here', + answer: 'Check out our full FAQ page at https://peanutprotocol.notion.site/FAQ-2a4838117579805dad62ff47c9d2eb7a or visit our support page at https://peanut.me/support for more help.', + }, + ], + marquee: { + visible: false, + message: 'Peanut', + }, +} diff --git a/src/components/LandingPage/marquee.tsx b/src/components/LandingPage/marquee.tsx index e8922fad9..764c591c1 100644 --- a/src/components/LandingPage/marquee.tsx +++ b/src/components/LandingPage/marquee.tsx @@ -10,7 +10,7 @@ type MarqueeProps = { export function Marquee({ visible = true, - message = ['No fees', 'Instant', '24/7', 'Dollars', 'Fiat / Crypto'], + message = ['No fees', 'Instant', '24/7', 'Dollars', 'USDT/USDC'], imageSrc = HandThumbsUp.src, backgroundColor = 'bg-secondary-1', }: MarqueeProps) { diff --git a/src/components/LandingPage/sendInSeconds.tsx b/src/components/LandingPage/sendInSeconds.tsx index 84707ff6b..15d58efab 100644 --- a/src/components/LandingPage/sendInSeconds.tsx +++ b/src/components/LandingPage/sendInSeconds.tsx @@ -1,153 +1,56 @@ -import { useEffect, useState } from 'react' -import { motion } from 'framer-motion' import Image from 'next/image' -import borderCloud from '@/assets/illustrations/border-cloud.svg' import exclamations from '@/assets/illustrations/exclamations.svg' import payZeroFees from '@/assets/illustrations/pay-zero-fees.svg' import mobileSendInSeconds from '@/assets/illustrations/mobile-send-in-seconds.svg' -import { Star, Sparkle } from '@/assets' -import { Button } from '@/components/0_Bruddle/Button' +import { Star } from '@/assets' +import { CloudsCss } from './CloudsCss' +import { AnimateOnView } from '@/components/Global/AnimateOnView' +import { SendInSecondsCTA } from './SendInSecondsCTA' + +const sendInSecondsClouds = [ + { top: '15%', width: 320, speed: '40s', direction: 'ltr' as const }, + { top: '40%', width: 200, speed: '34s', direction: 'rtl' as const }, + { top: '70%', width: 180, speed: '30s', direction: 'ltr' as const }, + { top: '80%', width: 320, speed: '46s', direction: 'rtl' as const }, +] + +const starConfigs = [ + { + className: 'absolute right-10 top-10 md:right-1/4 md:top-20', + width: 50, + height: 50, + delay: '0.2s', + x: '5px', + rotate: '45deg', + }, + { className: 'absolute bottom-16 left-1/3', width: 40, height: 40, delay: '0.4s', x: '-5px', rotate: '-10deg' }, + { + className: 'absolute bottom-20 left-[2rem] md:bottom-72 md:right-[14rem]', + width: 50, + height: 50, + delay: '0.6s', + x: '5px', + rotate: '-22deg', + }, + { className: 'absolute left-[20rem] top-72', width: 60, height: 60, delay: '0.8s', x: '-5px', rotate: '12deg' }, +] export function SendInSeconds() { - const [screenWidth, setScreenWidth] = useState(typeof window !== 'undefined' ? window.innerWidth : 1200) - - useEffect(() => { - const handleResize = () => { - setScreenWidth(window.innerWidth) - } - - handleResize() - window.addEventListener('resize', handleResize) - return () => window.removeEventListener('resize', handleResize) - }, []) - - const createCloudAnimation = (side: 'left' | 'right', width: number, speed: number) => { - const vpWidth = screenWidth || 1080 - const totalDistance = vpWidth + width - - return { - initial: { x: side === 'left' ? -width : vpWidth }, - animate: { x: side === 'left' ? vpWidth : -width }, - transition: { - ease: 'linear', - duration: totalDistance / speed, - repeat: Infinity, - }, - } - } - - // Button helper functions adapted from hero.tsx - const getInitialAnimation = () => ({ - opacity: 0, - translateY: 4, - translateX: 0, - rotate: 0.75, - }) - - const getAnimateAnimation = (buttonVisible: boolean, buttonScale: number = 1) => ({ - opacity: buttonVisible ? 1 : 0, - translateY: buttonVisible ? 0 : 20, - translateX: buttonVisible ? 0 : 20, - rotate: buttonVisible ? 0 : 1, - scale: buttonScale, - pointerEvents: buttonVisible ? ('auto' as const) : ('none' as const), - }) - - const getHoverAnimation = () => ({ - translateY: 6, - translateX: 0, - rotate: 0.75, - }) - - const transitionConfig = { type: 'spring', damping: 15 } as const - - const getButtonClasses = () => - `btn bg-white fill-n-1 text-n-1 hover:bg-white/90 px-9 md:px-11 py-4 md:py-10 text-lg md:text-2xl btn-shadow-primary-4` - - const renderSparkle = () => ( - <img - src={Sparkle.src} - className="absolute -right-4 -top-4 h-auto w-5 sm:-right-5 sm:-top-5 sm:w-6" - alt="Sparkle" - /> - ) - return ( <section id="send-in-seconds" className="relative overflow-hidden bg-secondary-1 px-4 py-16 text-n-1 md:py-32"> - {/* Decorative clouds, stars, and exclamations */} - <div className="absolute left-0 top-0 h-full w-full overflow-hidden"> - {/* Animated clouds */} - <motion.img - src={borderCloud.src} - alt="Floating Border Cloud" - className="absolute left-0" - style={{ top: '15%', width: 320 }} - {...createCloudAnimation('left', 320, 35)} - /> - <motion.img - src={borderCloud.src} - alt="Floating Border Cloud" - className="absolute right-0" - style={{ top: '40%', width: 200 }} - {...createCloudAnimation('right', 200, 40)} - /> - <motion.img - src={borderCloud.src} - alt="Floating Border Cloud" - className="absolute left-0" - style={{ top: '70%', width: 180 }} - {...createCloudAnimation('left', 180, 45)} - /> - <motion.img - src={borderCloud.src} - alt="Floating Border Cloud" - className="absolute right-0" - style={{ top: '80%', width: 320 }} - {...createCloudAnimation('right', 320, 30)} - /> - </div> - - {/* Animated stars and exclamations */} - <motion.img - src={Star.src} - alt="Floating Star" - width={50} - height={50} - className="absolute right-10 top-10 md:right-1/4 md:top-20" - initial={{ opacity: 0, translateY: 20, translateX: 5, rotate: 45 }} - whileInView={{ opacity: 1, translateY: 0, translateX: 0, rotate: 45 }} - transition={{ type: 'spring', damping: 5, delay: 0.2 }} - /> - <motion.img - src={Star.src} - alt="Floating Star" - width={40} - height={40} - className="absolute bottom-16 left-1/3" - initial={{ opacity: 0, translateY: 25, translateX: -5, rotate: -10 }} - whileInView={{ opacity: 1, translateY: 0, translateX: 0, rotate: -10 }} - transition={{ type: 'spring', damping: 5, delay: 0.4 }} - /> - <motion.img - src={Star.src} - alt="Floating Star" - width={50} - height={50} - className="absolute bottom-20 left-[2rem] md:bottom-72 md:right-[14rem]" - initial={{ opacity: 0, translateY: 18, translateX: 5, rotate: -22 }} - whileInView={{ opacity: 1, translateY: 0, translateX: 0, rotate: -22 }} - transition={{ type: 'spring', damping: 5, delay: 0.6 }} - /> - <motion.img - src={Star.src} - alt="Floating Star" - width={60} - height={60} - className="absolute left-[20rem] top-72" - initial={{ opacity: 0, translateY: 22, translateX: -5, rotate: 12 }} - whileInView={{ opacity: 1, translateY: 0, translateX: 0, rotate: 12 }} - transition={{ type: 'spring', damping: 5, delay: 0.8 }} - /> + <CloudsCss clouds={sendInSecondsClouds} /> + + {starConfigs.map((config, i) => ( + <AnimateOnView + key={i} + className={config.className} + delay={config.delay} + x={config.x} + rotate={config.rotate} + > + <img src={Star.src} alt="" width={config.width} height={config.height} /> + </AnimateOnView> + ))} {/* Exclamations */} <Image @@ -188,24 +91,8 @@ export function SendInSeconds() { ALWAYS UNDER YOUR CONTROL. </p> - {/* Fixed CTA Button */} - <div className="relative mt-12 inline-block md:mt-24"> - <motion.div - className="relative" - initial={getInitialAnimation()} - animate={getAnimateAnimation(true, 1)} - whileHover={getHoverAnimation()} - transition={transitionConfig} - > - <a href="/send"> - <Button - shadowSize="4" - className="bg-white px-7 py-3 text-base font-extrabold hover:bg-white/90 md:px-9 md:py-8 md:text-xl" - > - SEND NOW - </Button> - </a> - </motion.div> + <div id="sticky-button-target"> + <SendInSecondsCTA /> </div> </div> </section> diff --git a/src/components/Marketing/BlogCard.tsx b/src/components/Marketing/BlogCard.tsx new file mode 100644 index 000000000..87e3573c2 --- /dev/null +++ b/src/components/Marketing/BlogCard.tsx @@ -0,0 +1,32 @@ +import Link from 'next/link' +import { Card } from '@/components/0_Bruddle/Card' + +interface BlogCardProps { + slug: string + title: string + excerpt: string + date: string + category?: string + hrefPrefix?: string +} + +export function BlogCard({ slug, title, excerpt, date, category, hrefPrefix = '/blog' }: BlogCardProps) { + const safeSlug = encodeURIComponent(slug) + return ( + <Link href={`${hrefPrefix}/${safeSlug}`}> + <Card + shadowSize="4" + className="h-full p-5 transition-all hover:shadow-primary-6 hover:-translate-x-1 hover:-translate-y-1" + > + {category && ( + <span className="mb-2 inline-block rounded-sm bg-primary-1/20 px-2 py-0.5 text-xs font-semibold"> + {category} + </span> + )} + <h3 className="text-lg font-bold leading-snug">{title}</h3> + <p className="mt-2 line-clamp-3 text-sm text-black/70">{excerpt}</p> + <time className="mt-3 block text-xs text-black/50">{date}</time> + </Card> + </Link> + ) +} diff --git a/src/components/Marketing/ComparisonTable.tsx b/src/components/Marketing/ComparisonTable.tsx new file mode 100644 index 000000000..abe0bca8f --- /dev/null +++ b/src/components/Marketing/ComparisonTable.tsx @@ -0,0 +1,32 @@ +import { Card } from '@/components/0_Bruddle/Card' + +interface ComparisonTableProps { + peanutName?: string + competitorName: string + rows: Array<{ feature: string; peanut: string; competitor: string }> +} + +export function ComparisonTable({ peanutName = 'Peanut', competitorName, rows }: ComparisonTableProps) { + return ( + <Card shadowSize="4" className="overflow-hidden"> + <table className="w-full text-left text-sm"> + <thead> + <tr className="border-b border-n-1 bg-primary-1/20"> + <th className="px-4 py-3 font-semibold">Feature</th> + <th className="px-4 py-3 font-bold">{peanutName}</th> + <th className="px-4 py-3 font-semibold">{competitorName}</th> + </tr> + </thead> + <tbody> + {rows.map((row, i) => ( + <tr key={i} className={i % 2 === 1 ? 'bg-primary-3/30' : ''}> + <td className="border-b border-n-1/20 px-4 py-3 font-medium">{row.feature}</td> + <td className="border-b border-n-1/20 bg-primary-1/10 px-4 py-3">{row.peanut}</td> + <td className="border-b border-n-1/20 px-4 py-3">{row.competitor}</td> + </tr> + ))} + </tbody> + </table> + </Card> + ) +} diff --git a/src/components/Marketing/ContentPage.tsx b/src/components/Marketing/ContentPage.tsx new file mode 100644 index 000000000..61981a1e8 --- /dev/null +++ b/src/components/Marketing/ContentPage.tsx @@ -0,0 +1,60 @@ +import type { ReactNode } from 'react' +import Link from 'next/link' +import { JsonLd } from './JsonLd' +import { BASE_URL } from '@/constants/general.consts' +import { MarketingErrorBoundary } from './MarketingErrorBoundary' + +interface ContentPageProps { + /** Compiled MDX content element */ + children: ReactNode + /** Breadcrumb items: [{name, href}] */ + breadcrumbs: Array<{ name: string; href: string }> +} + +/** + * Universal wrapper for MDX-rendered marketing pages. + * Handles BreadcrumbList JSON-LD + visible breadcrumb nav. + * The MDX body owns all layout (Hero is full-bleed, prose sections are contained). + */ +export function ContentPage({ children, breadcrumbs }: ContentPageProps) { + const breadcrumbSchema = { + '@context': 'https://schema.org', + '@type': 'BreadcrumbList', + itemListElement: breadcrumbs.map((crumb, i) => ({ + '@type': 'ListItem', + position: i + 1, + name: crumb.name, + item: crumb.href.startsWith('http') ? crumb.href : `${BASE_URL}${crumb.href}`, + })), + } + + return ( + <> + <JsonLd data={breadcrumbSchema} /> + <MarketingErrorBoundary> + <article className="content-page select-text bg-background"> + {children} + <nav aria-label="Breadcrumb" className="mx-auto max-w-[640px] px-6 pb-8 pt-4 md:px-4"> + <ol className="flex flex-wrap items-center gap-1 text-xs text-grey-1"> + {breadcrumbs.map((crumb, i) => ( + <li key={crumb.href} className="flex items-center gap-1"> + {i > 0 && <span aria-hidden>/</span>} + {i < breadcrumbs.length - 1 ? ( + <Link + href={crumb.href} + className="underline decoration-n-1/30 underline-offset-2 hover:text-n-1" + > + {crumb.name} + </Link> + ) : ( + <span className="font-medium text-n-1">{crumb.name}</span> + )} + </li> + ))} + </ol> + </nav> + </article> + </MarketingErrorBoundary> + </> + ) +} diff --git a/src/components/Marketing/DestinationGrid.tsx b/src/components/Marketing/DestinationGrid.tsx new file mode 100644 index 000000000..3f84b6e16 --- /dev/null +++ b/src/components/Marketing/DestinationGrid.tsx @@ -0,0 +1,86 @@ +import Link from 'next/link' +import { Card } from '@/components/0_Bruddle/Card' +import { COUNTRIES_SEO, getCountryName } from '@/data/seo' +import { getFlagUrl } from '@/constants/countryCurrencyMapping' +import { localizedPath } from '@/i18n/config' +import { CARD_HOVER } from '@/components/Marketing/mdx/constants' +import type { Locale } from '@/i18n/types' + +const SLUG_TO_ISO2: Record<string, string> = { + argentina: 'ar', + australia: 'au', + brazil: 'br', + canada: 'ca', + colombia: 'co', + 'costa-rica': 'cr', + indonesia: 'id', + japan: 'jp', + kenya: 'ke', + malaysia: 'my', + mexico: 'mx', + pakistan: 'pk', + peru: 'pe', + philippines: 'ph', + poland: 'pl', + portugal: 'pt', + singapore: 'sg', + 'south-africa': 'za', + spain: 'es', + sweden: 'se', + tanzania: 'tz', + thailand: 'th', + turkey: 'tr', + 'united-arab-emirates': 'ae', + 'united-kingdom': 'gb', + 'united-states': 'us', + vietnam: 'vn', +} + +interface DestinationGridProps { + /** If provided, only show these country slugs */ + countries?: string[] + /** Country slug to exclude from the grid */ + exclude?: string + title?: string + locale?: Locale +} + +export function DestinationGrid({ countries, exclude, title = 'Send money to', locale = 'en' }: DestinationGridProps) { + let slugs = countries ?? Object.keys(COUNTRIES_SEO) + if (exclude) slugs = slugs.filter((s) => s !== exclude) + + return ( + <section className="py-10 md:py-14"> + {title && <h2 className="mb-6 text-h2 font-bold md:text-h1">{title}</h2>} + <div className="grid grid-cols-2 gap-4 md:grid-cols-3"> + {slugs.map((slug) => { + const seo = COUNTRIES_SEO[slug] + if (!seo) return null + + const countryName = getCountryName(slug, locale) + const flagCode = SLUG_TO_ISO2[slug] + + return ( + <Link key={slug} href={localizedPath('send-money-to', locale, slug)}> + <Card shadowSize="4" className={`flex-row items-center gap-3 p-4 ${CARD_HOVER}`}> + {flagCode && ( + <img + src={getFlagUrl(flagCode)} + alt={`${countryName} flag`} + width={32} + height={24} + className="rounded-sm" + /> + )} + <div> + <span className="font-semibold">{countryName}</span> + <span className="ml-1 text-sm text-black/50">→</span> + </div> + </Card> + </Link> + ) + })} + </div> + </section> + ) +} diff --git a/src/components/Marketing/FAQSection.tsx b/src/components/Marketing/FAQSection.tsx new file mode 100644 index 000000000..a9a0cb15c --- /dev/null +++ b/src/components/Marketing/FAQSection.tsx @@ -0,0 +1,40 @@ +import { JsonLd } from './JsonLd' +import { Card } from '@/components/0_Bruddle/Card' + +interface FAQSectionProps { + faqs: Array<{ q: string; a: string }> + title?: string +} + +export function FAQSection({ faqs, title = 'Frequently Asked Questions' }: FAQSectionProps) { + const faqSchema = { + '@context': 'https://schema.org', + '@type': 'FAQPage', + mainEntity: faqs.map((faq) => ({ + '@type': 'Question', + name: faq.q, + acceptedAnswer: { + '@type': 'Answer', + text: faq.a, + }, + })), + } + + return ( + <section className="py-10 md:py-14"> + <h2 className="mb-6 text-h2 font-bold md:text-h1">{title}</h2> + <Card shadowSize="4" className="overflow-hidden"> + {faqs.map((faq, i) => ( + <details key={i} className="group border-b border-n-1 last:border-b-0"> + <summary className="flex cursor-pointer list-none items-center justify-between px-5 py-4 font-bold transition-colors hover:bg-primary-3/20 [&::-webkit-details-marker]:hidden"> + {faq.q} + <span className="ml-4 shrink-0 text-lg transition-transform group-open:rotate-45">+</span> + </summary> + <div className="border-t border-n-1/20 px-5 py-4 text-sm text-black/70">{faq.a}</div> + </details> + ))} + </Card> + <JsonLd data={faqSchema} /> + </section> + ) +} diff --git a/src/components/Marketing/HelpLanding.tsx b/src/components/Marketing/HelpLanding.tsx new file mode 100644 index 000000000..4c1d2d6a4 --- /dev/null +++ b/src/components/Marketing/HelpLanding.tsx @@ -0,0 +1,136 @@ +'use client' + +import { useState, useMemo, useEffect } from 'react' +import Link from 'next/link' +import { useSearchParams } from 'next/navigation' +import { Icon } from '@/components/Global/Icons/Icon' + +interface HelpArticle { + slug: string + title: string + description: string + category: string +} + +interface HelpLandingStrings { + searchPlaceholder: string + cantFind: string + cantFindDesc: string +} + +interface HelpLandingProps { + articles: HelpArticle[] + categories: string[] + locale: string + strings?: HelpLandingStrings +} + +const PROSE_WIDTH = 'max-w-[640px]' + +export default function HelpLanding({ articles, categories, locale, strings }: HelpLandingProps) { + const [searchTerm, setSearchTerm] = useState('') + const searchParams = useSearchParams() + + // Auto-open Crisp chat when ?chat=open (e.g. redirected from /support) + useEffect(() => { + if (searchParams.get('chat') !== 'open') return + const interval = setInterval(() => { + if (window.$crisp) { + window.$crisp.push(['do', 'chat:open']) + clearInterval(interval) + } + }, 200) + return () => clearInterval(interval) + }, [searchParams]) + + const filteredArticles = useMemo(() => { + if (!searchTerm.trim()) return articles + + const lower = searchTerm.toLowerCase().trim() + return articles.filter( + (a) => + a.title.toLowerCase().includes(lower) || + a.description.toLowerCase().includes(lower) || + a.category.toLowerCase().includes(lower) + ) + }, [articles, searchTerm]) + + const filteredCategories = useMemo(() => { + const activeCats = new Set(filteredArticles.map((a) => a.category)) + return categories.filter((c) => activeCats.has(c)) + }, [categories, filteredArticles]) + + return ( + <> + {/* Search */} + <div className={`mx-auto mb-8 mt-10 ${PROSE_WIDTH} px-6 md:mt-12 md:px-4`}> + <div className="relative"> + <div className="absolute left-3 top-1/2 -translate-y-1/2 text-grey-1"> + <Icon name="search" size={18} /> + </div> + <input + type="text" + aria-label={strings?.searchPlaceholder ?? 'Search help articles'} + placeholder={strings?.searchPlaceholder ?? 'Search help articles...'} + value={searchTerm} + onChange={(e) => setSearchTerm(e.target.value)} + className="h-12 w-full rounded-sm border border-n-1 bg-white pl-10 pr-4 text-base caret-primary-1 focus:outline-none focus:ring-1 focus:ring-n-1" + /> + </div> + </div> + + {/* Articles by category */} + <div className={`mx-auto ${PROSE_WIDTH} px-6 md:px-4`}> + {filteredCategories.length > 0 ? ( + <div className="flex flex-col gap-10"> + {filteredCategories.map((category) => ( + <section key={category}> + <h2 className="mb-4 text-xs font-bold uppercase tracking-widest text-grey-1"> + {category} + </h2> + <div className="flex flex-col gap-px overflow-hidden rounded-sm border border-n-1"> + {filteredArticles + .filter((a) => a.category === category) + .map((article) => ( + <Link + key={article.slug} + href={`/${locale}/help/${article.slug}`} + className="group flex items-center justify-between border-b border-n-1/10 bg-white px-5 py-4 transition-colors last:border-b-0 hover:bg-primary-3/20" + > + <div className="flex flex-col gap-0.5"> + <h3 className="text-base font-semibold text-n-1 group-hover:underline"> + {article.title} + </h3> + <p className="line-clamp-1 text-sm leading-[1.75] text-grey-1"> + {article.description} + </p> + </div> + <Icon + name="arrow-up-right" + size={16} + className="shrink-0 text-grey-1" + /> + </Link> + ))} + </div> + </section> + ))} + </div> + ) : ( + <div className="py-12 text-center text-grey-1"> + <p className="text-base">No articles match your search.</p> + </div> + )} + + {/* Contact CTA */} + <div className="my-8 border-l-4 border-primary-1 py-1 pl-6"> + <p className="font-semibold text-n-1">{strings?.cantFind ?? "Can't find what you need?"}</p> + <p className="mt-1 text-base leading-[1.75] text-grey-1"> + {strings?.cantFindDesc ?? + 'Click the chat bubble in the bottom-right corner to talk to our support team. We typically reply within minutes.'} + </p> + </div> + </div> + </> + ) +} diff --git a/src/components/Marketing/JsonLd.tsx b/src/components/Marketing/JsonLd.tsx new file mode 100644 index 000000000..40e4f2ba0 --- /dev/null +++ b/src/components/Marketing/JsonLd.tsx @@ -0,0 +1,12 @@ +/** + * Server component that renders JSON-LD structured data. + * Accepts any schema.org-compatible object. + */ +export function JsonLd({ data }: { data: Record<string, unknown> }) { + return ( + <script + type="application/ld+json" + dangerouslySetInnerHTML={{ __html: JSON.stringify(data).replace(/</g, '\\u003c') }} + /> + ) +} diff --git a/src/components/Marketing/MarketingErrorBoundary.tsx b/src/components/Marketing/MarketingErrorBoundary.tsx new file mode 100644 index 000000000..d698a5dea --- /dev/null +++ b/src/components/Marketing/MarketingErrorBoundary.tsx @@ -0,0 +1,41 @@ +'use client' + +import { Component, type ReactNode } from 'react' + +interface Props { + children: ReactNode + fallback?: ReactNode +} + +interface State { + hasError: boolean +} + +export class MarketingErrorBoundary extends Component<Props, State> { + constructor(props: Props) { + super(props) + this.state = { hasError: false } + } + + static getDerivedStateFromError() { + return { hasError: true } + } + + componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { + console.error('MDX rendering error:', error, errorInfo) + } + + render() { + if (this.state.hasError) { + return ( + this.props.fallback || ( + <div className="mx-auto max-w-2xl px-6 py-16 text-center"> + <h2 className="text-2xl font-bold text-n-1">Content unavailable</h2> + <p className="mt-4 text-grey-1">Please try refreshing the page.</p> + </div> + ) + ) + } + return this.props.children + } +} diff --git a/src/components/Marketing/MarketingHero.tsx b/src/components/Marketing/MarketingHero.tsx new file mode 100644 index 000000000..9c8d5d480 --- /dev/null +++ b/src/components/Marketing/MarketingHero.tsx @@ -0,0 +1,66 @@ +import Title from '@/components/0_Bruddle/Title' +import Link from 'next/link' +import { CloudsCss } from '@/components/LandingPage/CloudsCss' +import { MarqueeComp } from '@/components/Global/MarqueeWrapper' +import { HandThumbsUp } from '@/assets' + +const marketingClouds = [ + { top: '15%', width: 160, speed: '45s', direction: 'ltr' as const }, + { top: '55%', width: 180, speed: '50s', direction: 'rtl' as const }, + { top: '85%', width: 150, speed: '48s', direction: 'ltr' as const, delay: '8s' }, +] + +interface MarketingHeroProps { + title: string + subtitle: string + ctaText?: string + ctaHref?: string + image?: string +} + +export function MarketingHero({ + title, + subtitle, + ctaText = 'Get Started', + ctaHref = '/home', + image, +}: MarketingHeroProps) { + return ( + <> + <section className="relative overflow-hidden bg-primary-1 px-4 py-16 text-center md:px-8 md:py-20"> + <CloudsCss clouds={marketingClouds} /> + <div className="relative z-10 mx-auto max-w-3xl"> + {image && ( + <img + src={image} + alt="" + className="mx-auto mb-4 h-16 w-16 rounded-xl object-contain" + onError={(e) => { + e.currentTarget.style.display = 'none' + }} + /> + )} + <h1> + <Title text={title} className="text-4xl md:text-6xl" /> + </h1> + <p className="mt-4 text-lg font-bold text-black md:text-2xl">{subtitle}</p> + {ctaText && ( + <div className="mt-8"> + <Link + href={ctaHref} + className="btn btn-purple btn-shadow-primary-4 inline-flex w-auto px-8 active:translate-x-[3px] active:translate-y-[4px] active:shadow-none" + > + {ctaText} + </Link> + </div> + )} + </div> + </section> + <MarqueeComp + message={['No fees', 'Instant', '24/7', 'Dollars', 'USDT/USDC']} + imageSrc={HandThumbsUp.src} + backgroundColor="bg-secondary-1" + /> + </> + ) +} diff --git a/src/components/Marketing/MarketingNav.tsx b/src/components/Marketing/MarketingNav.tsx new file mode 100644 index 000000000..1291604b3 --- /dev/null +++ b/src/components/Marketing/MarketingNav.tsx @@ -0,0 +1,19 @@ +import Image from 'next/image' +import Link from 'next/link' +import { PEANUT_LOGO_BLACK } from '@/assets' + +export function MarketingNav() { + return ( + <nav className="flex items-center justify-between border-b border-n-1 bg-white px-4 py-3 md:px-8"> + <Link href="/"> + <Image src={PEANUT_LOGO_BLACK} alt="Peanut" width={110} height={40} /> + </Link> + <Link + href="/home" + className="btn btn-purple btn-shadow-primary-4 active:translate-x-[3px] active:translate-y-[4px] active:shadow-none" + > + Get Started + </Link> + </nav> + ) +} diff --git a/src/components/Marketing/MarketingShell.tsx b/src/components/Marketing/MarketingShell.tsx new file mode 100644 index 000000000..7ee14a00b --- /dev/null +++ b/src/components/Marketing/MarketingShell.tsx @@ -0,0 +1,8 @@ +interface MarketingShellProps { + children: React.ReactNode + className?: string +} + +export function MarketingShell({ children, className }: MarketingShellProps) { + return <div className={`mx-auto max-w-3xl px-4 py-8 md:py-12 ${className ?? ''}`}>{children}</div> +} diff --git a/src/components/Marketing/RelatedPages.tsx b/src/components/Marketing/RelatedPages.tsx new file mode 100644 index 000000000..aaf9fdd55 --- /dev/null +++ b/src/components/Marketing/RelatedPages.tsx @@ -0,0 +1,25 @@ +import Link from 'next/link' + +interface RelatedPagesProps { + pages: Array<{ title: string; href: string }> + title?: string +} + +export function RelatedPages({ pages, title = 'Related Pages' }: RelatedPagesProps) { + if (pages.length === 0) return null + + return ( + <section className="py-10 md:py-14"> + <h2 className="mb-6 text-h2 font-bold md:text-h1">{title}</h2> + <ul className="flex flex-col gap-2"> + {pages.map((page) => ( + <li key={page.href}> + <Link href={page.href} className="text-black underline"> + {page.title} + </Link> + </li> + ))} + </ul> + </section> + ) +} diff --git a/src/components/Marketing/Section.tsx b/src/components/Marketing/Section.tsx new file mode 100644 index 000000000..94bbda722 --- /dev/null +++ b/src/components/Marketing/Section.tsx @@ -0,0 +1,14 @@ +interface SectionProps { + title: string + children: React.ReactNode + id?: string +} + +export function Section({ title, children, id }: SectionProps) { + return ( + <section id={id} className="py-10 md:py-14"> + <h2 className="mb-6 text-h2 font-bold md:text-h1">{title}</h2> + {children} + </section> + ) +} diff --git a/src/components/Marketing/Steps.tsx b/src/components/Marketing/Steps.tsx new file mode 100644 index 000000000..badcb6cf9 --- /dev/null +++ b/src/components/Marketing/Steps.tsx @@ -0,0 +1,25 @@ +import { Card } from '@/components/0_Bruddle/Card' + +interface StepsProps { + steps: Array<{ title: string; description: string }> +} + +export function Steps({ steps }: StepsProps) { + return ( + <ol className="flex flex-col gap-4"> + {steps.map((step, i) => ( + <li key={i}> + <Card shadowSize="4" className="flex-row items-start gap-4 p-4"> + <span className="flex size-10 shrink-0 items-center justify-center rounded-full bg-primary-1 text-base font-bold"> + {i + 1} + </span> + <div> + <h3 className="font-bold">{step.title}</h3> + <p className="mt-1 text-sm text-black/70">{step.description}</p> + </div> + </Card> + </li> + ))} + </ol> + ) +} diff --git a/src/components/Marketing/index.ts b/src/components/Marketing/index.ts new file mode 100644 index 000000000..7d10cac3a --- /dev/null +++ b/src/components/Marketing/index.ts @@ -0,0 +1,10 @@ +export { JsonLd } from './JsonLd' +export { MarketingNav } from './MarketingNav' +export { MarketingHero } from './MarketingHero' +export { MarketingShell } from './MarketingShell' +export { Section } from './Section' +export { Steps } from './Steps' +export { ComparisonTable } from './ComparisonTable' +export { FAQSection } from './FAQSection' +export { DestinationGrid } from './DestinationGrid' +export { BlogCard } from './BlogCard' diff --git a/src/components/Marketing/mdx/CTA.tsx b/src/components/Marketing/mdx/CTA.tsx new file mode 100644 index 000000000..2e212c918 --- /dev/null +++ b/src/components/Marketing/mdx/CTA.tsx @@ -0,0 +1,86 @@ +import Link from 'next/link' +import Image from 'next/image' +import { Button } from '@/components/0_Bruddle/Button' +import { Card } from '@/components/0_Bruddle/Card' +import { PeanutGuyGIF } from '@/assets' +import { PROSE_WIDTH } from './constants' + +interface CTAProps { + text: string + href: string + /** subtitle shown below the button in 'card' variant */ + subtitle?: string + variant?: 'primary' | 'secondary' | 'card' +} + +/** + * MDX call-to-action. + * + * - primary: standalone purple button within prose column (default) + * - secondary: subtle inline text link with arrow — for mid-content CTAs + * - card: bordered card with button + subtitle — for final/end-of-page CTAs + * + * Special: href="#chat" opens Crisp chat via click interceptor (no navigation). + */ +export function CTA({ text, href, subtitle, variant = 'primary' }: CTAProps) { + if (variant === 'secondary') { + const linkClass = + 'inline-flex items-center gap-1 font-semibold text-n-1 underline decoration-n-1/30 underline-offset-2 hover:decoration-n-1' + return ( + <div className={`mx-auto ${PROSE_WIDTH} px-6 py-4 md:px-4`}> + {href.startsWith('#') ? ( + <a href={href} className={linkClass}> + {text} <span aria-hidden="true">→</span> + </a> + ) : ( + <Link href={href} className={linkClass}> + {text} <span aria-hidden="true">→</span> + </Link> + )} + </div> + ) + } + + if (variant === 'card') { + return ( + <div className={`mx-auto ${PROSE_WIDTH} px-6 py-10 md:px-4 md:py-14`}> + <div className="relative"> + <Image + src={PeanutGuyGIF} + alt="Peanut mascot" + width={200} + height={200} + className="absolute -top-24 left-1/2 -z-0 h-40 w-40 -translate-x-1/2 md:-top-28 md:h-48 md:w-48" + unoptimized + /> + <Card shadowSize="4" className="relative z-10 items-center gap-4 p-6 text-center md:p-10"> + <a href={href}> + <Button + shadowSize="4" + variant="purple" + className="w-full px-8 text-base font-bold sm:w-auto md:px-12 md:text-lg" + > + {text} + </Button> + </a> + {subtitle && <p className="mt-3 text-sm text-grey-1">{subtitle}</p>} + </Card> + </div> + </div> + ) + } + + return ( + <div className={`mx-auto ${PROSE_WIDTH} px-6 py-8 text-center md:px-4 md:py-12`}> + <a href={href}> + <Button + shadowSize="4" + variant="purple" + className="w-full px-8 text-base font-bold sm:w-auto md:px-12 md:text-lg" + > + {text} + </Button> + </a> + </div> + ) +} diff --git a/src/components/Marketing/mdx/Callout.tsx b/src/components/Marketing/mdx/Callout.tsx new file mode 100644 index 000000000..79b9c80db --- /dev/null +++ b/src/components/Marketing/mdx/Callout.tsx @@ -0,0 +1,28 @@ +import type { ReactNode } from 'react' +import { Card } from '@/components/0_Bruddle/Card' +import { PROSE_WIDTH } from './constants' + +interface CalloutProps { + type?: 'info' | 'tip' | 'warning' + children: ReactNode +} + +const STYLES: Record<string, { bg: string; border: string; label: string }> = { + info: { bg: 'bg-primary-3/20', border: 'border-primary-3', label: 'Info' }, + tip: { bg: 'bg-green-50', border: 'border-green-300', label: 'Tip' }, + warning: { bg: 'bg-yellow-50', border: 'border-yellow-300', label: 'Important' }, +} + +/** Highlighted callout box for tips, warnings, or important info. */ +export function Callout({ type = 'info', children }: CalloutProps) { + const style = STYLES[type] ?? STYLES.info + + return ( + <div className={`mx-auto ${PROSE_WIDTH} px-6 md:px-4`}> + <Card className={`${style.bg} border-l-4 ${style.border} my-8 p-5`}> + <p className="mb-1 text-xs font-bold uppercase tracking-wide text-n-1/40">{style.label}</p> + <div className="text-sm leading-relaxed text-grey-1">{children}</div> + </Card> + </div> + ) +} diff --git a/src/components/Marketing/mdx/CountryGrid.tsx b/src/components/Marketing/mdx/CountryGrid.tsx new file mode 100644 index 000000000..f25de0836 --- /dev/null +++ b/src/components/Marketing/mdx/CountryGrid.tsx @@ -0,0 +1,37 @@ +import { DestinationGrid } from '@/components/Marketing/DestinationGrid' + +interface CountryGridProps { + /** Comma-separated country slugs to show. If omitted, shows all countries. */ + countries?: string + /** Country slug to exclude (typically the current page's country). */ + exclude?: string + title?: string +} + +/** + * MDX wrapper for DestinationGrid. Renders a flag+name grid of country links. + * Like Wise's "Send money to other countries" section. + * + * Usage in MDX: + * <CountryGrid exclude="argentina" title="Send money to other countries" /> + * <CountryGrid countries="brazil,colombia,mexico" /> + */ +export function CountryGrid({ countries, exclude, title = 'Send money to other countries' }: CountryGridProps) { + let slugs: string[] | undefined + + if (countries) { + slugs = countries.split(',').map((s) => s.trim()) + } + + if (exclude && slugs) { + slugs = slugs.filter((s) => s !== exclude) + } + + return ( + <section className="px-4 py-10 md:px-8 md:py-14"> + <div className="mx-auto max-w-5xl"> + <DestinationGrid countries={slugs} title={title} exclude={exclude} /> + </div> + </section> + ) +} diff --git a/src/components/Marketing/mdx/ExchangeWidget.tsx b/src/components/Marketing/mdx/ExchangeWidget.tsx new file mode 100644 index 000000000..5f71dd49a --- /dev/null +++ b/src/components/Marketing/mdx/ExchangeWidget.tsx @@ -0,0 +1,91 @@ +'use client' + +import { Suspense, useEffect } from 'react' +import { useRouter, useSearchParams } from 'next/navigation' +import ExchangeRateWidget from '@/components/Global/ExchangeRateWidget' +import { Star } from '@/assets' +import { CloudsCss } from '@/components/LandingPage/CloudsCss' + +const widgetClouds = [ + { top: '10%', width: 140, speed: '38s', direction: 'ltr' as const }, + { top: '75%', width: 120, speed: '44s', direction: 'rtl' as const, delay: '5s' }, +] + +interface ExchangeWidgetProps { + /** ISO 4217 destination currency code, e.g. "ARS", "BRL" */ + destinationCurrency?: string + /** ISO 4217 source currency code. Defaults to "USD". */ + sourceCurrency?: string +} + +function ExchangeWidgetInner({ destinationCurrency, sourceCurrency = 'USD' }: ExchangeWidgetProps) { + const router = useRouter() + const searchParams = useSearchParams() + + // Set initial currencies in URL if not already set + useEffect(() => { + if (destinationCurrency && !searchParams.get('to')) { + const params = new URLSearchParams(searchParams.toString()) + params.set('to', destinationCurrency) + if (!params.get('from')) params.set('from', sourceCurrency) + router.replace(`?${params.toString()}`, { scroll: false }) + } + }, [destinationCurrency, sourceCurrency, searchParams, router]) + + return ( + <section className="relative my-8 w-full pb-14 pt-10 md:pb-18 md:pt-14" style={{ backgroundColor: '#90A8ED' }}> + <div className="pointer-events-none absolute inset-0 overflow-hidden"> + <CloudsCss clouds={widgetClouds} /> + <img + src={Star.src} + alt="" + width={36} + height={36} + className="absolute left-[8%] top-6 md:left-[12%] md:top-8" + /> + <img + src={Star.src} + alt="" + width={28} + height={28} + className="absolute bottom-8 right-[10%] md:bottom-10 md:right-[14%]" + /> + </div> + <div className="relative z-10 mx-auto max-w-[640px] px-6 md:px-4"> + <ExchangeRateWidget + ctaLabel="Send Money" + ctaIcon="arrow-up-right" + ctaAction={(from, to) => { + router.push(`/send?from=${from}&to=${to}`) + }} + /> + </div> + </section> + ) +} + +/** + * Embeddable exchange rate calculator for MDX content pages. + * + * Usage in MDX: + * <ExchangeWidget destinationCurrency="ARS" /> + * <ExchangeWidget destinationCurrency="BRL" sourceCurrency="EUR" /> + */ +export function ExchangeWidget({ destinationCurrency, sourceCurrency }: ExchangeWidgetProps) { + return ( + <Suspense + fallback={ + <section + className="relative my-8 w-full overflow-hidden pb-14 pt-10 md:pb-18 md:pt-14" + style={{ backgroundColor: '#90A8ED' }} + > + <div className="mx-auto flex max-w-[640px] justify-center px-6 md:px-4"> + <div className="btn btn-shadow-primary-4 h-[300px] w-full animate-pulse bg-white md:w-[420px]" /> + </div> + </section> + } + > + <ExchangeWidgetInner destinationCurrency={destinationCurrency} sourceCurrency={sourceCurrency} /> + </Suspense> + ) +} diff --git a/src/components/Marketing/mdx/FAQ.tsx b/src/components/Marketing/mdx/FAQ.tsx new file mode 100644 index 000000000..24cf62454 --- /dev/null +++ b/src/components/Marketing/mdx/FAQ.tsx @@ -0,0 +1,79 @@ +import { Children, isValidElement, type ReactNode } from 'react' +import { FAQsPanel } from '@/components/Global/FAQs' +import { PeanutsBG } from '@/assets' +import { JsonLd } from '@/components/Marketing/JsonLd' + +interface FAQItemProps { + question: string + children: ReactNode +} + +/** Individual FAQ item. Used as a child of <FAQ>. */ +export function FAQItem({ question, children }: FAQItemProps) { + // FAQItem doesn't render on its own — FAQ collects these via children. + // This exists for type safety and readability in MDX content. + return <div data-question={question}>{children}</div> +} + +interface FAQProps { + title?: string + children: ReactNode +} + +/** Extract text content from React nodes for JSON-LD plain text */ +function extractText(node: ReactNode): string { + if (typeof node === 'string') return node + if (typeof node === 'number') return String(node) + if (!node) return '' + if (Array.isArray(node)) return node.map(extractText).join('') + if (isValidElement(node)) return extractText(node.props.children) + return '' +} + +/** + * MDX FAQ component. Purple section with peanut pattern overlay, + * animated accordion, and FAQPage JSON-LD. Matches LP styling exactly. + */ +export function FAQ({ title = 'FAQ', children }: FAQProps) { + // Collect FAQItem children into question/answer pairs + const questions: Array<{ id: string; question: string; answer: string }> = [] + + Children.forEach(children, (child) => { + if (!isValidElement(child)) return + if (child.type === FAQItem || child.props?.question) { + const id = `faq-${questions.length}` + questions.push({ + id, + question: child.props.question, + answer: extractText(child.props.children), + }) + } + }) + + if (questions.length === 0) return null + + const faqSchema = { + '@context': 'https://schema.org', + '@type': 'FAQPage', + mainEntity: questions.map((q) => ({ + '@type': 'Question', + name: q.question, + acceptedAnswer: { '@type': 'Answer', text: q.answer }, + })), + } + + return ( + <section + className="overflow-x-hidden" + style={{ + backgroundColor: '#6340df', + backgroundImage: `url(${PeanutsBG.src})`, + backgroundSize: '10rem auto', + backgroundRepeat: 'repeat', + }} + > + <FAQsPanel heading={title} questions={questions} /> + <JsonLd data={faqSchema} /> + </section> + ) +} diff --git a/src/components/Marketing/mdx/Hero.tsx b/src/components/Marketing/mdx/Hero.tsx new file mode 100644 index 000000000..5e68c1ddb --- /dev/null +++ b/src/components/Marketing/mdx/Hero.tsx @@ -0,0 +1,60 @@ +import Link from 'next/link' +import { CloudsCss } from '@/components/LandingPage/CloudsCss' +import { MarqueeComp } from '@/components/Global/MarqueeWrapper' +import { HandThumbsUp } from '@/assets' + +const marketingClouds = [ + { top: '15%', width: 160, speed: '45s', direction: 'ltr' as const }, + { top: '55%', width: 180, speed: '50s', direction: 'rtl' as const }, + { top: '85%', width: 150, speed: '48s', direction: 'ltr' as const, delay: '8s' }, +] + +interface HeroProps { + title: string + subtitle?: string + cta?: string + ctaHref?: string + /** @deprecated — ignored. Use standalone <ExchangeWidget> in MDX body instead. */ + currency?: string +} + +/** + * MDX Hero — large bold title (Roboto Flex), subtitle, white CTA button + * on pink background. + */ +export function Hero({ title, subtitle, cta, ctaHref }: HeroProps) { + return ( + <> + <section className="relative overflow-hidden bg-primary-1 px-4 py-16 text-center md:px-8 md:py-24"> + <CloudsCss clouds={marketingClouds} /> + <div className="relative z-10 mx-auto max-w-4xl"> + <h1 className="font-roboto-flex-extrabold text-[2.5rem] font-extraBlack uppercase leading-[0.95] text-black md:text-[4.5rem]"> + {title} + </h1> + {subtitle && ( + <p className="font-roboto-flex-extrabold mt-6 text-[1.25rem] uppercase text-black md:mt-8 md:text-[2rem]"> + {subtitle} + </p> + )} + {cta && ctaHref && ( + <div className="mt-8"> + <Link + href={ctaHref} + className="btn btn-shadow-primary-4 inline-flex w-auto bg-white px-8 font-extrabold hover:bg-white/90 active:translate-x-[3px] active:translate-y-[4px] active:shadow-none" + > + {cta} + </Link> + </div> + )} + </div> + </section> + <MarqueeComp + message={['No fees', 'Instant', '24/7', 'Dollars', 'USDT/USDC']} + imageSrc={HandThumbsUp.src} + backgroundColor="bg-secondary-1" + /> + {/* Spacer ensures consistent gap between Hero block and prose content */} + <div className="h-10 md:h-14" /> + </> + ) +} diff --git a/src/components/Marketing/mdx/ProseStars.tsx b/src/components/Marketing/mdx/ProseStars.tsx new file mode 100644 index 000000000..4c50edf43 --- /dev/null +++ b/src/components/Marketing/mdx/ProseStars.tsx @@ -0,0 +1,84 @@ +import { Star } from '@/assets' +import { AnimateOnView } from '@/components/Global/AnimateOnView' + +interface StarPlacement { + className: string + width: number + height: number + delay: string + x: string + rotate: string +} + +/** + * Pre-defined star placement sets. Each h2 cycles through these + * via a module-level counter so stars appear in varied positions. + */ +const placements: StarPlacement[][] = [ + [ + { + className: 'absolute -right-4 -top-2 md:right-8', + width: 40, + height: 40, + delay: '0.15s', + x: '5px', + rotate: '22deg', + }, + ], + [ + { + className: 'absolute -left-4 top-0 md:left-8', + width: 35, + height: 35, + delay: '0.25s', + x: '-5px', + rotate: '-15deg', + }, + ], + [ + { + className: 'absolute -right-2 -top-4 md:right-16', + width: 32, + height: 32, + delay: '0.1s', + x: '3px', + rotate: '45deg', + }, + { + className: 'absolute -left-6 top-4 md:left-4 hidden md:block', + width: 28, + height: 28, + delay: '0.5s', + x: '-4px', + rotate: '-10deg', + }, + ], + [ + { + className: 'absolute -left-2 -top-2 md:left-12', + width: 38, + height: 38, + delay: '0.2s', + x: '-3px', + rotate: '12deg', + }, + ], +] + +let counter = 0 + +/** Decorative stars placed in the margins around prose h2 headings. */ +export function ProseStars() { + const set = placements[counter % placements.length] + counter++ + + return ( + <> + {set.map((star, i) => ( + <AnimateOnView key={i} className={star.className} delay={star.delay} x={star.x} rotate={star.rotate}> + <img src={Star.src} alt="" width={star.width} height={star.height} /> + </AnimateOnView> + ))} + </> + ) +} diff --git a/src/components/Marketing/mdx/RelatedPages.tsx b/src/components/Marketing/mdx/RelatedPages.tsx new file mode 100644 index 000000000..5619b5078 --- /dev/null +++ b/src/components/Marketing/mdx/RelatedPages.tsx @@ -0,0 +1,64 @@ +import { Children, isValidElement, type ReactNode } from 'react' +import Link from 'next/link' +import { Card } from '@/components/0_Bruddle/Card' +import { PROSE_WIDTH, CARD_HOVER } from './constants' + +interface RelatedLinkProps { + href: string + children: ReactNode +} + +/** Individual related page link. Used as a child of <RelatedPages>. */ +export function RelatedLink({ href, children }: RelatedLinkProps) { + return <div data-href={href}>{children}</div> +} + +interface RelatedPagesProps { + title?: string + children: ReactNode +} + +/** + * MDX Related Pages component. Renders a grid of internal link cards + * at the bottom of content pages for SEO internal linking. + * + * Usage in MDX: + * <RelatedPages title="Related Guides"> + * <RelatedLink href="/pay-with/mercadopago">Pay with Mercado Pago</RelatedLink> + * <RelatedLink href="/compare/wise">Peanut vs Wise</RelatedLink> + * </RelatedPages> + */ +export function RelatedPages({ title = 'Related Pages', children }: RelatedPagesProps) { + const links: Array<{ href: string; text: string }> = [] + + Children.forEach(children, (child) => { + if (!isValidElement(child)) return + if (child.type === RelatedLink || child.props?.href) { + links.push({ + href: child.props.href, + text: + typeof child.props.children === 'string' + ? child.props.children + : String(child.props.children ?? ''), + }) + } + }) + + if (links.length === 0) return null + + return ( + <nav className={`mx-auto ${PROSE_WIDTH} px-6 py-10 md:px-4 md:py-14`}> + <h2 className="mb-5 text-xl font-bold text-n-1 md:text-2xl">{title}</h2> + <div className="grid grid-cols-1 gap-3 sm:grid-cols-2"> + {links.map((link) => ( + <Link key={link.href} href={link.href} className="flex"> + <Card shadowSize="4" className={`flex-1 flex-row items-center gap-3 p-4 ${CARD_HOVER}`}> + <span className="font-semibold">{link.text}</span> + <span className="ml-auto text-sm text-black/50">→</span> + </Card> + </Link> + ))} + </div> + </nav> + ) +} diff --git a/src/components/Marketing/mdx/Stars.tsx b/src/components/Marketing/mdx/Stars.tsx new file mode 100644 index 000000000..e031486a6 --- /dev/null +++ b/src/components/Marketing/mdx/Stars.tsx @@ -0,0 +1,57 @@ +import { Star } from '@/assets' +import { AnimateOnView } from '@/components/Global/AnimateOnView' + +interface StarConfig { + className: string + width: number + height: number + delay: string + x: string + rotate: string +} + +const defaultStars: StarConfig[] = [ + { + className: 'absolute right-6 top-6 md:right-12 md:top-10', + width: 40, + height: 40, + delay: '0.2s', + x: '5px', + rotate: '22deg', + }, + { + className: 'absolute left-8 bottom-8 md:left-16', + width: 35, + height: 35, + delay: '0.5s', + x: '-5px', + rotate: '-15deg', + }, + { + className: 'absolute right-1/4 bottom-12 hidden md:block', + width: 30, + height: 30, + delay: '0.8s', + x: '3px', + rotate: '45deg', + }, +] + +/** Decorative animated stars. Sprinkle on sections for visual interest. */ +export function Stars({ configs = defaultStars }: { configs?: StarConfig[] }) { + return ( + <> + {configs.map((config, i) => ( + <AnimateOnView + key={i} + className={config.className} + delay={config.delay} + x={config.x} + rotate={config.rotate} + > + <img src={Star.src} alt="" width={config.width} height={config.height} /> + </AnimateOnView> + ))} + </> + ) +} diff --git a/src/components/Marketing/mdx/Steps.tsx b/src/components/Marketing/mdx/Steps.tsx new file mode 100644 index 000000000..ec2797897 --- /dev/null +++ b/src/components/Marketing/mdx/Steps.tsx @@ -0,0 +1,86 @@ +import { Children, isValidElement, type ReactNode } from 'react' +import { Steps as StepsCards } from '@/components/Marketing/Steps' +import { JsonLd } from '@/components/Marketing/JsonLd' +import { CloudsCss } from '@/components/LandingPage/CloudsCss' +import { Stars } from './Stars' + +interface StepProps { + title: string + children: ReactNode +} + +/** Individual step. Used as a child of <Steps>. */ +export function Step({ title, children }: StepProps) { + return <div data-title={title}>{children}</div> +} + +interface StepsProps { + title?: string + children: ReactNode +} + +/** Extract text content from React nodes for descriptions and JSON-LD */ +function extractText(node: ReactNode): string { + if (typeof node === 'string') return node + if (typeof node === 'number') return String(node) + if (!node) return '' + if (Array.isArray(node)) return node.map(extractText).join('') + if (isValidElement(node)) return extractText(node.props.children) + return '' +} + +const stepsClouds = [ + { top: '15%', width: 160, speed: '40s', direction: 'ltr' as const }, + { top: '60%', width: 140, speed: '34s', direction: 'rtl' as const }, + { top: '85%', width: 120, speed: '46s', direction: 'ltr' as const, delay: '6s' }, +] + +/** + * MDX Steps component. Full-bleed yellow section with numbered step cards, + * clouds, and HowTo JSON-LD. Matches LP styling. + * + * Usage in MDX: + * <Steps title="How It Works"> + * <Step title="Sign up">Create a Peanut account...</Step> + * <Step title="Deposit">Send stablecoins or bank transfer.</Step> + * </Steps> + */ +export function Steps({ title = 'How It Works', children }: StepsProps) { + const steps: Array<{ title: string; description: string }> = [] + + Children.forEach(children, (child) => { + if (!isValidElement(child)) return + if (child.type === Step || child.props?.title) { + steps.push({ + title: child.props.title, + description: extractText(child.props.children), + }) + } + }) + + if (steps.length === 0) return null + + const howToSchema = { + '@context': 'https://schema.org', + '@type': 'HowTo', + name: title, + step: steps.map((step, i) => ({ + '@type': 'HowToStep', + position: i + 1, + name: step.title, + text: step.description || step.title, + })), + } + + return ( + <section className="relative overflow-hidden bg-secondary-1 px-4 py-16 md:py-24"> + <CloudsCss clouds={stepsClouds} /> + <Stars /> + <div className="relative z-10 mx-auto max-w-3xl"> + <h2 className="mb-8 text-h2 font-bold md:text-h1">{title}</h2> + <StepsCards steps={steps} /> + </div> + <JsonLd data={howToSchema} /> + </section> + ) +} diff --git a/src/components/Marketing/mdx/Tabs.tsx b/src/components/Marketing/mdx/Tabs.tsx new file mode 100644 index 000000000..1ee8403af --- /dev/null +++ b/src/components/Marketing/mdx/Tabs.tsx @@ -0,0 +1,71 @@ +'use client' + +import * as RadixTabs from '@radix-ui/react-tabs' +import { type ReactNode } from 'react' +import { PROSE_WIDTH } from './constants' + +interface TabsProps { + /** Comma-separated tab labels, e.g. "Peanut,Wise,Western Union" */ + labels: string + children: ReactNode +} + +interface TabPanelProps { + /** Must match one of the labels exactly */ + label: string + children: ReactNode +} + +const triggerClasses = + 'flex-1 rounded-xl border border-transparent px-3 py-2 text-sm font-medium text-grey-1 transition-all data-[state=active]:border-primary-1 data-[state=active]:bg-primary-1/10 data-[state=active]:text-primary-1' + +/** + * Tabbed content for MDX pages. + * + * Usage: + * ```mdx + * <Tabs labels="Peanut,Wise,Western Union"> + * <TabPanel label="Peanut"> + * Content about Peanut... + * </TabPanel> + * <TabPanel label="Wise"> + * Content about Wise... + * </TabPanel> + * <TabPanel label="Western Union"> + * Content about Western Union... + * </TabPanel> + * </Tabs> + * ``` + */ +export function Tabs({ labels, children }: TabsProps) { + const tabs = labels.split(',').map((l) => l.trim()) + return ( + <div className={`mx-auto my-8 ${PROSE_WIDTH} px-6 md:px-4`}> + <RadixTabs.Root defaultValue={tabs[0]} className="w-full"> + <RadixTabs.List + className="flex w-full items-center rounded-xl bg-white p-1 shadow-sm ring-1 ring-n-1/10" + aria-label="Content tabs" + > + {tabs.map((tab) => ( + <RadixTabs.Trigger key={tab} value={tab} className={triggerClasses}> + {tab} + </RadixTabs.Trigger> + ))} + </RadixTabs.List> + {children} + </RadixTabs.Root> + </div> + ) +} + +export function TabPanel({ label, children }: TabPanelProps) { + return ( + <RadixTabs.Content + value={label} + forceMount + className="mt-4 text-base leading-[1.75] text-grey-1 data-[state=inactive]:hidden" + > + {children} + </RadixTabs.Content> + ) +} diff --git a/src/components/Marketing/mdx/components.tsx b/src/components/Marketing/mdx/components.tsx new file mode 100644 index 000000000..6c39904dd --- /dev/null +++ b/src/components/Marketing/mdx/components.tsx @@ -0,0 +1,107 @@ +import Link from 'next/link' +import { Hero } from './Hero' +import { Steps, Step } from './Steps' +import { FAQ, FAQItem } from './FAQ' +import { CTA } from './CTA' +import { Callout } from './Callout' +import { ExchangeWidget } from './ExchangeWidget' +import { RelatedPages, RelatedLink } from './RelatedPages' +import { CountryGrid } from './CountryGrid' +import { ProseStars } from './ProseStars' +import { Tabs, TabPanel } from './Tabs' +import { PROSE_WIDTH } from './constants' + +/** + * Component map for MDX content rendering. + * These components are available in .md/.mdx files without imports. + * + * Prose column: PROSE_WIDTH (~Wise's 600px content width) + * Text color: text-grey-1 (#5F646D) for body, text-n-1 for headings + * Line-height: leading-[1.75] for generous readability + * Paragraph spacing: mb-6 (24px) matching Wise + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const mdxComponents: Record<string, React.ComponentType<any>> = { + // Custom components + Hero, + Steps, + Step, + FAQ, + FAQItem, + CTA, + Callout, + ExchangeWidget, + RelatedPages, + RelatedLink, + CountryGrid, + Tabs, + TabPanel, + + // Element overrides — prose styling + h1: (props: React.HTMLAttributes<HTMLHeadingElement>) => ( + <h1 + className={`mx-auto mb-5 mt-10 ${PROSE_WIDTH} px-6 text-2xl font-extrabold text-n-1 md:mt-12 md:px-4 md:text-3xl`} + {...props} + /> + ), + h2: (props: React.HTMLAttributes<HTMLHeadingElement>) => ( + <div className="relative"> + <ProseStars /> + <h2 + className={`mx-auto mb-5 mt-14 ${PROSE_WIDTH} px-6 text-2xl font-extrabold text-n-1 md:mt-16 md:px-4 md:text-3xl`} + {...props} + /> + </div> + ), + h3: (props: React.HTMLAttributes<HTMLHeadingElement>) => ( + <h3 + className={`mx-auto mb-3 mt-10 ${PROSE_WIDTH} px-6 text-xl font-bold text-n-1 md:px-4 md:text-2xl`} + {...props} + /> + ), + p: (props: React.HTMLAttributes<HTMLParagraphElement>) => ( + <p className={`mx-auto mb-6 ${PROSE_WIDTH} px-6 text-base leading-[1.75] text-grey-1 md:px-4`} {...props} /> + ), + a: ({ href = '', ...props }: React.AnchorHTMLAttributes<HTMLAnchorElement>) => ( + <Link + href={href} + className="text-n-1 underline decoration-n-1/30 underline-offset-2 hover:decoration-n-1" + {...props} + /> + ), + ul: (props: React.HTMLAttributes<HTMLUListElement>) => ( + <ul className={`mx-auto my-5 ${PROSE_WIDTH} list-disc space-y-3 pl-12 pr-6 md:pl-10 md:pr-4`} {...props} /> + ), + ol: (props: React.HTMLAttributes<HTMLOListElement>) => ( + <ol className={`mx-auto my-5 ${PROSE_WIDTH} list-decimal space-y-3 pl-12 pr-6 md:pl-10 md:pr-4`} {...props} /> + ), + li: (props: React.HTMLAttributes<HTMLLIElement>) => ( + <li className="text-base leading-[1.75] text-grey-1" {...props} /> + ), + strong: (props: React.HTMLAttributes<HTMLElement>) => <strong className="font-semibold text-n-1" {...props} />, + table: (props: React.HTMLAttributes<HTMLTableElement>) => ( + <div className={`mx-auto my-8 ${PROSE_WIDTH} overflow-x-auto px-6 md:px-4`}> + <div className="overflow-hidden rounded-sm border border-n-1"> + <table className="w-full border-collapse text-left text-sm" {...props} /> + </div> + </div> + ), + th: (props: React.HTMLAttributes<HTMLTableCellElement>) => ( + <th + className="border-b border-n-1 bg-primary-1/15 px-4 py-3 text-xs font-bold uppercase tracking-wide text-n-1" + {...props} + /> + ), + td: (props: React.HTMLAttributes<HTMLTableCellElement>) => ( + <td className="border-b border-n-1/10 px-4 py-3 text-grey-1" {...props} /> + ), + blockquote: (props: React.HTMLAttributes<HTMLQuoteElement>) => ( + <blockquote + className={`mx-auto my-8 ${PROSE_WIDTH} border-l-4 border-primary-1 py-1 pl-6 pr-6 md:pr-4`} + {...props} + /> + ), + hr: (props: React.HTMLAttributes<HTMLHRElement>) => ( + <hr className={`mx-auto my-12 ${PROSE_WIDTH} border-n-1/10`} {...props} /> + ), +} diff --git a/src/components/Marketing/mdx/constants.ts b/src/components/Marketing/mdx/constants.ts new file mode 100644 index 000000000..da9a9173b --- /dev/null +++ b/src/components/Marketing/mdx/constants.ts @@ -0,0 +1,8 @@ +/** Prose content column width class. Matches Wise's ~600px content width for readability. */ +export const PROSE_WIDTH = 'max-w-[640px]' + +/** Standard hover/active classes for interactive cards with Bruddle shadow. + * Hover: card lifts up-left, shadow grows to compensate (appears stationary). + * Active: card presses into shadow. */ +export const CARD_HOVER = + 'transition-all duration-150 hover:-translate-x-0.5 hover:-translate-y-0.5 hover:shadow-[6px_6px_0_#000] active:translate-x-[3px] active:translate-y-[4px] active:shadow-none' diff --git a/src/components/Marketing/pages/ReceiveMoneyContent.tsx b/src/components/Marketing/pages/ReceiveMoneyContent.tsx new file mode 100644 index 000000000..ee37237f0 --- /dev/null +++ b/src/components/Marketing/pages/ReceiveMoneyContent.tsx @@ -0,0 +1,143 @@ +import Link from 'next/link' +import { getFlagUrl, findMappingBySlug } from '@/constants/countryCurrencyMapping' +import { CORRIDORS, getCountryName, getLocalizedSEO } from '@/data/seo' +import { getTranslations, t, localizedPath, localizedBarePath } from '@/i18n' +import type { Locale } from '@/i18n/types' +import { MarketingHero } from '@/components/Marketing/MarketingHero' +import { MarketingShell } from '@/components/Marketing/MarketingShell' +import { Section } from '@/components/Marketing/Section' +import { Steps } from '@/components/Marketing/Steps' +import { FAQSection } from '@/components/Marketing/FAQSection' +import { JsonLd } from '@/components/Marketing/JsonLd' +import { RelatedPages } from '@/components/Marketing/RelatedPages' +import { Card } from '@/components/0_Bruddle/Card' + +interface ReceiveMoneyContentProps { + sourceCountry: string + locale: Locale +} + +export function ReceiveMoneyContent({ sourceCountry, locale }: ReceiveMoneyContentProps) { + const i18n = getTranslations(locale) + const sourceName = getCountryName(sourceCountry, locale) + const sourceSeo = getLocalizedSEO(sourceCountry, locale) + + // Destinations that receive money from this source + const destinations = CORRIDORS.filter((c) => c.from === sourceCountry).map((c) => c.to) + + const sourceMapping = findMappingBySlug(sourceCountry) + + const howToSteps = [ + { + title: t(i18n.stepCreateAccount), + description: t(i18n.stepCreateAccountDesc), + }, + { + title: t(i18n.stepDepositFunds), + description: t(i18n.stepDepositFundsDesc, { method: sourceSeo?.instantPayment ?? '' }), + }, + { + title: i18n.sendMoney, + description: t(i18n.receiveMoneyFromDesc, { country: sourceName }), + }, + ] + + const baseUrl = 'https://peanut.me' + + const breadcrumbSchema = { + '@context': 'https://schema.org', + '@type': 'BreadcrumbList', + itemListElement: [ + { '@type': 'ListItem', position: 1, name: i18n.home, item: baseUrl }, + { + '@type': 'ListItem', + position: 2, + name: t(i18n.receiveMoneyFrom, { country: sourceName }), + item: `${baseUrl}/${locale}/receive-money-from/${sourceCountry}`, + }, + ], + } + + const faqs = sourceSeo?.faqs ?? [] + + // Related pages for internal linking + const relatedPages = [ + { + title: t(i18n.hubTitle, { country: sourceName }), + href: localizedBarePath(locale, sourceCountry), + }, + { + title: t(i18n.sendMoneyTo, { country: sourceName }), + href: localizedPath('send-money-to', locale, sourceCountry), + }, + ] + + // Add from-to corridor links for each destination + for (const dest of destinations.slice(0, 3)) { + const destName = getCountryName(dest, locale) + relatedPages.push({ + title: t(i18n.sendMoneyFromTo, { from: sourceName, to: destName }), + href: localizedPath('send-money-from', locale, `${sourceCountry}/to/${dest}`), + }) + } + + const today = new Date().toISOString().split('T')[0] + + return ( + <> + <JsonLd data={breadcrumbSchema} /> + + <MarketingHero + title={t(i18n.receiveMoneyFrom, { country: sourceName })} + subtitle={t(i18n.receiveMoneyFromDesc, { country: sourceName })} + /> + + <MarketingShell> + {/* Destination countries grid */} + <Section title={t(i18n.receiveMoneyFrom, { country: sourceName })}> + <div className="grid grid-cols-2 gap-3 md:grid-cols-3"> + {destinations.map((destSlug) => { + const destName = getCountryName(destSlug, locale) + const destMapping = findMappingBySlug(destSlug) + return ( + <Link + key={destSlug} + href={localizedPath('send-money-from', locale, `${sourceCountry}/to/${destSlug}`)} + > + <Card className="flex-row items-center gap-2 p-3 transition-all hover:shadow-4 hover:-translate-x-1 hover:-translate-y-1"> + {destMapping?.flagCode && ( + <img + src={getFlagUrl(destMapping.flagCode)} + alt={`${destName} flag`} + width={24} + height={18} + className="rounded-sm" + /> + )} + <span className="text-sm font-medium"> + {sourceName} → {destName} + </span> + </Card> + </Link> + ) + })} + </div> + </Section> + + {/* How it works */} + <Section title={i18n.howItWorks}> + <Steps steps={howToSteps} /> + </Section> + + {/* FAQs */} + {faqs.length > 0 && <FAQSection faqs={faqs} title={i18n.frequentlyAskedQuestions} />} + + {/* Related pages */} + <RelatedPages pages={relatedPages} title={i18n.relatedPages} /> + + {/* Last updated */} + <p className="py-4 text-xs text-gray-400">{t(i18n.lastUpdated, { date: today })}</p> + </MarketingShell> + </> + ) +} diff --git a/src/components/Points/CashCard.tsx b/src/components/Points/CashCard.tsx index 0f19fd97f..c5d825611 100644 --- a/src/components/Points/CashCard.tsx +++ b/src/components/Points/CashCard.tsx @@ -4,28 +4,30 @@ import { Icon } from '@/components/Global/Icons/Icon' import { Tooltip } from '@/components/Tooltip' interface CashCardProps { - cashbackAllowance: number | null + hasCashbackLeft: boolean lifetimeEarned: number } -export const CashCard = ({ cashbackAllowance, lifetimeEarned }: CashCardProps) => { +export const CashCard = ({ hasCashbackLeft, lifetimeEarned }: CashCardProps) => { return ( <div className="flex flex-col gap-1.5"> - {/* cashback allowance display with tooltip */} - {cashbackAllowance !== null && ( - <div className="flex items-center gap-1.5"> - <h2 className="text-xl font-bold text-black">Cashback left: ${cashbackAllowance.toFixed(2)}</h2> - <Tooltip - content="You earn cashback on payments and withdrawals. Use Peanut more and invite friends to unlock a higher cashback allowance." - position="bottom" - > - <Icon name="info" className="size-4 flex-shrink-0 text-grey-1" /> - </Tooltip> - </div> - )} + <div className="flex items-center gap-1.5"> + <h2 className="text-xl font-bold text-black"> + Lifetime cashback claimed: ${lifetimeEarned.toFixed(2)} + </h2> + <Tooltip + content="The more points you have and higher Tier you are, the more cashback you get. The best way to get more cashback is to invite friends!" + position="bottom" + > + <Icon name="info" className="size-4 flex-shrink-0 text-grey-1" /> + </Tooltip> + </div> - {/* lifetime earned - subtle */} - <p className="text-sm text-grey-1">Lifetime earned: ${lifetimeEarned.toFixed(2)}</p> + {hasCashbackLeft ? ( + <p className="text-sm text-grey-1">You have unclaimed cashback left! Make a payment to claim it.</p> + ) : ( + <p className="text-sm text-grey-1">Invite friends to unlock more cashback.</p> + )} </div> ) } diff --git a/src/components/Points/InviteePointsBadge.tsx b/src/components/Points/InviteePointsBadge.tsx new file mode 100644 index 000000000..bd0313651 --- /dev/null +++ b/src/components/Points/InviteePointsBadge.tsx @@ -0,0 +1,21 @@ +'use client' + +import { useCountUp } from '@/hooks/useCountUp' +import { formatPoints } from '@/utils/format.utils' + +interface InviteePointsBadgeProps { + points: number + inView: boolean +} + +/** animated points badge for invitee rows — triggers when scrolled into view */ +const InviteePointsBadge = ({ points, inView }: InviteePointsBadgeProps) => { + const animated = useCountUp(points, { duration: 1.2, enabled: inView }) + return ( + <p className="text-grey-1"> + +{formatPoints(animated)} {points === 1 ? 'pt' : 'pts'} + </p> + ) +} + +export default InviteePointsBadge diff --git a/src/components/Setup/Views/SignTestTransaction.tsx b/src/components/Setup/Views/SignTestTransaction.tsx index 2b98eab6c..ad39241b1 100644 --- a/src/components/Setup/Views/SignTestTransaction.tsx +++ b/src/components/Setup/Views/SignTestTransaction.tsx @@ -160,13 +160,13 @@ const SignTestTransaction = () => { } } - const isLoading = isSigning || isProcessing || isFetchingUser - const isDisabled = isLoading || !user + const isLoading = isSigning || isProcessing || isFetchingUser || !user + const isDisabled = isLoading const displayError = error || setupError // determine button text based on state const getButtonText = () => { - if (isFetchingUser) return 'Loading...' + if (isFetchingUser || !user) return 'Loading...' if (testTransactionCompleted && displayError) return 'Retry account setup' return 'Sign test transaction' } diff --git a/src/components/TransactionDetails/TransactionDetailsReceipt.tsx b/src/components/TransactionDetails/TransactionDetailsReceipt.tsx index a266ae8f9..03544ebc3 100644 --- a/src/components/TransactionDetails/TransactionDetailsReceipt.tsx +++ b/src/components/TransactionDetails/TransactionDetailsReceipt.tsx @@ -18,6 +18,7 @@ import { useUserStore } from '@/redux/hooks' import { chargesApi } from '@/services/charges' import useClaimLink from '@/components/Claim/useClaimLink' import { formatAmount, formatDate, isStableCoin, formatCurrency } from '@/utils/general.utils' +import { formatPoints } from '@/utils/format.utils' import { getAvatarUrl } from '@/utils/history.utils' import { formatIban, @@ -1131,7 +1132,7 @@ export const TransactionDetailsReceipt = ({ value={ <div className="flex items-center gap-2"> <Image src={STAR_STRAIGHT_ICON} alt="star" width={16} height={16} /> - <span>{transaction.points}</span> + <span>{formatPoints(transaction.points)}</span> </div> } hideBottomBorder={shouldHideBorder('points')} diff --git a/src/constants/countryCurrencyMapping.ts b/src/constants/countryCurrencyMapping.ts index 0d07002d4..b82de71d9 100644 --- a/src/constants/countryCurrencyMapping.ts +++ b/src/constants/countryCurrencyMapping.ts @@ -109,3 +109,8 @@ export function isUKCountry(countryIdentifier: string | undefined): boolean { const lower = countryIdentifier.toLowerCase() return lower === 'united-kingdom' || lower === 'gb' || lower === 'gbr' } + +/** Find a currency mapping by country slug (e.g. 'argentina', 'united-kingdom'). */ +export function findMappingBySlug(slug: string): CountryCurrencyMapping | undefined { + return countryCurrencyMappings.find((m) => m.path === slug || m.country.toLowerCase().replace(/ /g, '-') === slug) +} diff --git a/src/constants/points.consts.ts b/src/constants/points.consts.ts index 431ba3b41..6a787ea54 100644 --- a/src/constants/points.consts.ts +++ b/src/constants/points.consts.ts @@ -1,16 +1,10 @@ /** * Points System Constants * - * Shared constants for points display and calculations. - * Should match backend values in peanut-api-ts/src/points/constants.ts + * Shared constants for points display. + * Transitivity multiplier is no longer hardcoded — use `contributedPoints` from API. */ -/** - * Transitivity multiplier for referral points - * Users earn this percentage of their invitees' points - */ -export const TRANSITIVITY_MULTIPLIER = 0.5 // 50% of invitees' points - /** * Tier thresholds for display purposes * Note: Actual tier calculation happens on backend diff --git a/src/constants/routes.ts b/src/constants/routes.ts index 0a7b4f639..64bff38aa 100644 --- a/src/constants/routes.ts +++ b/src/constants/routes.ts @@ -10,6 +10,7 @@ * These should not be handled by catch-all routes */ export const DEDICATED_ROUTES = [ + // App routes (auth-gated) 'qr', 'api', 'setup', @@ -23,6 +24,42 @@ export const DEDICATED_ROUTES = [ 'invite', 'support', 'dev', + 'send', + 'profile', + 'kyc', + 'maintenance', + 'quests', + 'receipt', + 'crisp-proxy', + 'card-payment', + 'add-money', + 'withdraw', + 'sdk', + 'qr-pay', + + // Public pages (existing) + 'careers', + 'privacy', + 'terms', + 'lp', + 'exchange', + + // Future SEO routes (pre-register so catch-all doesn't intercept) + 'send-money-to', + 'receive-money-from', + 'deposit', + 'pay-with', + 'convert', + 'compare', + 'blog', + 'help', + 'faq', + 'how-it-works', + + // Locale prefixes + 'en', + 'es', + 'pt', ] as const /** diff --git a/src/content b/src/content new file mode 160000 index 000000000..065575532 --- /dev/null +++ b/src/content @@ -0,0 +1 @@ +Subproject commit 065575532e31ed9cb4c83357009fec78f0ed415c diff --git a/src/data/seo/comparisons.ts b/src/data/seo/comparisons.ts new file mode 100644 index 000000000..ee17d2a46 --- /dev/null +++ b/src/data/seo/comparisons.ts @@ -0,0 +1,142 @@ +// Typed wrappers for competitor comparison data. +// Reads from peanut-content: input/data/competitors/ + content/compare/ +// Public API unchanged from previous version. + +import { readEntityData, readPageContent, listEntitySlugs, listContentSlugs, isPublished } from '@/lib/content' +import { extractFaqs } from './utils' + +// --- Entity frontmatter (input/data/competitors/{slug}.md) --- + +interface CompetitorEntityFrontmatter { + slug: string + name: string + type: string + fee_model: string + speed: string + rate_type: string + supports_mercadopago: boolean + supports_pix: boolean + local_spending_argentina: boolean + local_spending_brazil: boolean + global_availability: boolean +} + +// --- Content frontmatter (content/compare/{slug}/{lang}.md) --- + +interface CompareContentFrontmatter { + title: string + description: string + slug: string + lang: string + published: boolean + competitor: string + schema_types: string[] + alternates?: Record<string, string> +} + +// --- Public types (unchanged) --- + +export interface Competitor { + name: string + tagline: string + rows: Array<{ feature: string; peanut: string; competitor: string }> + prosCompetitor: string[] + consCompetitor: string[] + verdict: string + faqs: Array<{ q: string; a: string }> + image?: string +} + +// --- Loader --- + +function loadCompetitors(): Record<string, Competitor> { + const result: Record<string, Competitor> = {} + + // Get competitor slugs from content directory (content/compare/) + const contentSlugs = listContentSlugs('compare') + // Also check entity data for completeness + const entitySlugs = listEntitySlugs('competitors') + const allSlugs = [...new Set([...contentSlugs, ...entitySlugs])] + + for (const slug of allSlugs) { + const entity = readEntityData<CompetitorEntityFrontmatter>('competitors', slug) + if (!entity) continue + + const content = readPageContent<CompareContentFrontmatter>('compare', slug, 'en') + + if (!content || !isPublished(content)) continue + + const fm = entity.frontmatter + const body = content.body + + // Extract structured data from entity + generated content + result[slug] = { + name: fm.name, + tagline: buildTagline(fm), + rows: buildComparisonRows(fm), + prosCompetitor: buildPros(fm), + consCompetitor: buildCons(fm), + verdict: buildVerdict(fm), + faqs: extractFaqs(body), + } + } + + return result +} + +function buildTagline(fm: CompetitorEntityFrontmatter): string { + return `Compare Peanut with ${fm.name} for sending money to Latin America.` +} + +function buildComparisonRows( + fm: CompetitorEntityFrontmatter +): Array<{ feature: string; peanut: string; competitor: string }> { + return [ + { feature: 'Fee Model', peanut: 'Free deposits & payments', competitor: fm.fee_model }, + { feature: 'Speed', peanut: 'Instant local payments', competitor: fm.speed }, + { feature: 'Rate Type', peanut: 'Cripto dólar / market rate', competitor: fm.rate_type }, + { + feature: 'Mercado Pago', + peanut: 'Yes', + competitor: fm.supports_mercadopago ? 'Yes' : 'No', + }, + { feature: 'Pix', peanut: 'Yes', competitor: fm.supports_pix ? 'Yes' : 'No' }, + { + feature: 'Local Spending (Argentina)', + peanut: 'Yes — QR + ATM', + competitor: fm.local_spending_argentina ? 'Yes' : 'No', + }, + { + feature: 'Local Spending (Brazil)', + peanut: 'Yes — Pix QR', + competitor: fm.local_spending_brazil ? 'Yes' : 'No', + }, + ] +} + +function buildPros(fm: CompetitorEntityFrontmatter): string[] { + const pros: string[] = [] + if (fm.global_availability) pros.push('Available globally') + if (fm.speed.includes('instant') || fm.speed.includes('Instant')) pros.push('Fast transfers') + pros.push('Well-known brand') + return pros +} + +function buildCons(fm: CompetitorEntityFrontmatter): string[] { + const cons: string[] = [] + if (!fm.supports_mercadopago) cons.push('No Mercado Pago support') + if (!fm.supports_pix) cons.push('No Pix support') + if (!fm.local_spending_argentina) cons.push('No local spending in Argentina') + if (!fm.local_spending_brazil) cons.push('No local spending in Brazil') + if (fm.rate_type !== 'cripto-dolar') cons.push('Uses less favorable exchange rate') + return cons +} + +function buildVerdict(fm: CompetitorEntityFrontmatter): string { + if (!fm.supports_mercadopago && !fm.supports_pix) { + return `${fm.name} is a solid choice for international transfers, but if you need to pay locally in Argentina or Brazil, Peanut offers better rates and direct local payment access.` + } + return `Both services have their strengths. Peanut excels for local payments in Latin America with better exchange rates.` +} + +export const COMPETITORS: Record<string, Competitor> = loadCompetitors() diff --git a/src/data/seo/corridors.ts b/src/data/seo/corridors.ts new file mode 100644 index 000000000..d3403fdf8 --- /dev/null +++ b/src/data/seo/corridors.ts @@ -0,0 +1,236 @@ +// Typed wrappers for corridor/country SEO data. +// Reads from peanut-content: input/data/countries/ + content/countries/ + content/send-to/ +// Public API unchanged from previous version. + +import { + readEntityData, + readPageContent, + readPageContentLocalized, + listEntitySlugs, + listContentSlugs, + listCorridorOrigins, + isPublished, +} from '@/lib/content' +import type { Locale } from '@/i18n/types' +import { extractFaqs } from './utils' + +// --- Entity frontmatter schema (input/data/countries/{slug}.md) --- + +interface CountryEntityFrontmatter { + slug: string + name: string + currency: string + local_id: string + local_payment_methods: string[] + corridors: Array<{ + origin: string + priority: 'high' | 'medium' | 'low' + common_use_cases: string[] + }> +} + +// --- Content frontmatter schema (content/countries/{slug}/{lang}.md) --- + +interface CountryContentFrontmatter { + title: string + description: string + slug: string + lang: string + published: boolean + schema_types: string[] + alternates?: Record<string, string> +} + +// --- Spending method entity frontmatter --- + +interface SpendingMethodFrontmatter { + slug: string + name: string + type: string +} + +// --- Public types (matches fields consumed by page components) --- + +export interface CountrySEO { + name: string + region: string + currency: string + localPaymentMethods: string[] + context: string + instantPayment?: string + payMerchants: boolean + faqs: Array<{ q: string; a: string }> + corridors: Array<{ + origin: string + priority: 'high' | 'medium' | 'low' + }> +} + +export interface Corridor { + from: string + to: string +} + +// --- Loader --- + +function loadAll() { + const countrySlugs = listEntitySlugs('countries') + const countries: Record<string, CountrySEO> = {} + const corridors: Corridor[] = [] + const publishedCountries = new Set<string>() + + // First pass: determine which countries have published content pages + const contentSlugs = listContentSlugs('countries') + for (const slug of contentSlugs) { + const content = readPageContent<CountryContentFrontmatter>('countries', slug, 'en') + if (content && isPublished(content)) { + publishedCountries.add(slug) + } + } + + // If no published content yet, treat all countries with entity data + content as available + // This allows the site to work during the transition period when published: false + if (publishedCountries.size === 0) { + for (const slug of contentSlugs) { + const content = readPageContent<CountryContentFrontmatter>('countries', slug, 'en') + if (content) publishedCountries.add(slug) + } + } + + for (const slug of countrySlugs) { + if (!publishedCountries.has(slug)) continue + + const entity = readEntityData<CountryEntityFrontmatter>('countries', slug) + if (!entity) continue + + const content = readPageContent<CountryContentFrontmatter>('countries', slug, 'en') + const fm = entity.frontmatter + + // Resolve the first local payment method name for instantPayment display + const paymentMethods = fm.local_payment_methods ?? [] + let instantPayment: string | undefined + let payMerchants = false + + if (paymentMethods.length > 0) { + const methodEntity = readEntityData<SpendingMethodFrontmatter>('spending-methods', paymentMethods[0]) + instantPayment = methodEntity?.frontmatter.name ?? paymentMethods[0] + // QR-type methods support merchant payments + payMerchants = methodEntity?.frontmatter.type === 'qr' + } + + // Extract FAQs from the content body + const faqs = content ? extractFaqs(content.body) : [] + + countries[slug] = { + name: fm.name, + region: inferRegion(slug), + currency: fm.currency, + localPaymentMethods: paymentMethods, + context: content?.body ?? '', + instantPayment, + payMerchants, + faqs, + corridors: fm.corridors?.map((c) => ({ origin: c.origin, priority: c.priority })) ?? [], + } + + // Build corridors from entity data (some entities use destination: instead of origin:, skip those) + if (fm.corridors) { + for (const corridor of fm.corridors) { + if (corridor.origin) { + corridors.push({ from: corridor.origin, to: slug }) + } + } + } + } + + // Also add corridors discovered from content/send-to/{dest}/from/{origin}/ + for (const dest of listContentSlugs('send-to')) { + for (const origin of listCorridorOrigins(dest)) { + if (!corridors.some((c) => c.from === origin && c.to === dest)) { + corridors.push({ from: origin, to: dest }) + } + } + } + + // Deduplicate corridors + const seen = new Set<string>() + const uniqueCorridors = corridors.filter((c) => { + const key = `${c.from}→${c.to}` + if (seen.has(key)) return false + seen.add(key) + return true + }) + + return { countries, corridors: uniqueCorridors } +} + +/** Infer region from slug — simple heuristic based on known country lists */ +function inferRegion(slug: string): string { + const latam = [ + 'argentina', + 'brazil', + 'mexico', + 'colombia', + 'chile', + 'peru', + 'costa-rica', + 'panama', + 'bolivia', + 'guatemala', + ] + const northAmerica = ['united-states', 'canada'] + const asiaOceania = [ + 'australia', + 'philippines', + 'japan', + 'india', + 'indonesia', + 'malaysia', + 'singapore', + 'thailand', + 'vietnam', + 'pakistan', + 'saudi-arabia', + 'united-arab-emirates', + ] + const africa = ['kenya', 'nigeria', 'south-africa', 'tanzania'] + + if (latam.includes(slug)) return 'latam' + if (northAmerica.includes(slug)) return 'north-america' + if (asiaOceania.includes(slug)) return 'asia-oceania' + if (africa.includes(slug)) return 'africa' + return 'europe' +} + +const _loaded = loadAll() + +export const COUNTRIES_SEO: Record<string, CountrySEO> = _loaded.countries +export const CORRIDORS: Corridor[] = _loaded.corridors + +/** Get country SEO data with locale-specific content (falls back via chain) */ +export function getLocalizedSEO(country: string, locale: Locale): CountrySEO | null { + const base = COUNTRIES_SEO[country] + if (!base) return null + if (locale === 'en') return base + + const localized = readPageContentLocalized<CountryContentFrontmatter>('countries', country, locale) + if (!localized) return base + + const localizedFaqs = extractFaqs(localized.body) + + return { + ...base, + context: localized.body, + faqs: localizedFaqs.length > 0 ? localizedFaqs : base.faqs, + } +} + +/** Get localized country display name */ +export function getCountryName(slug: string, _locale: Locale): string { + // Read name from entity data + const entity = readEntityData<CountryEntityFrontmatter>('countries', slug) + if (entity) return entity.frontmatter.name + + // Fallback: title-case the slug + return slug.replace(/-/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase()) +} diff --git a/src/data/seo/exchanges.ts b/src/data/seo/exchanges.ts new file mode 100644 index 000000000..9486629d6 --- /dev/null +++ b/src/data/seo/exchanges.ts @@ -0,0 +1,108 @@ +// Typed wrappers for exchange deposit data. +// Reads from peanut-content: input/data/exchanges/ + content/deposit/ +// Public API unchanged from previous version. + +import { readEntityData, readPageContent, listEntitySlugs, listContentSlugs } from '@/lib/content' +import { extractFaqs, extractSteps, extractTroubleshooting } from './utils' + +// --- Entity frontmatter (input/data/exchanges/{slug}.md) --- + +interface ExchangeEntityFrontmatter { + slug: string + name: string + type: string + supported_networks: string[] + supported_stablecoins: string[] + withdrawal_fee_usdc: string + min_withdrawal: string + kyc_required: boolean + geo_restrictions: string +} + +// --- Content frontmatter (content/deposit/{slug}/{lang}.md) --- + +interface DepositContentFrontmatter { + title: string + description: string + slug: string + deposit_source?: string + lang: string + published: boolean + schema_types: string[] +} + +// --- Public types (unchanged) --- + +export interface Exchange { + name: string + recommendedNetwork: string + alternativeNetworks: string[] + withdrawalFee: string + processingTime: string + networkFee: string + steps: string[] + troubleshooting: Array<{ issue: string; fix: string }> + faqs: Array<{ q: string; a: string }> + image?: string +} + +// --- Loader --- + +function loadExchanges(): Record<string, Exchange> { + const result: Record<string, Exchange> = {} + const entitySlugs = listEntitySlugs('exchanges') + + for (const slug of entitySlugs) { + const entity = readEntityData<ExchangeEntityFrontmatter>('exchanges', slug) + if (!entity) continue + + const fm = entity.frontmatter + + // Extract steps from entity body (numbered list under ## Deposit to Peanut Flow) + const steps = extractSteps(entity.body, /Deposit to Peanut Flow|Step-by-Step|How to Deposit/) + const troubleshooting = extractTroubleshooting(entity.body) + const faqs = extractFaqs(entity.body) + + // Determine recommended network (first in list, or common fast ones) + const networks = fm.supported_networks ?? [] + const recommended = pickRecommendedNetwork(networks) + + result[slug] = { + name: fm.name, + recommendedNetwork: recommended, + alternativeNetworks: networks.filter((n) => n !== recommended), + withdrawalFee: fm.withdrawal_fee_usdc ?? 'Varies', + processingTime: estimateProcessingTime(recommended), + networkFee: 'Covered by Peanut', + steps, + troubleshooting, + faqs, + } + } + + return result +} + +function pickRecommendedNetwork(networks: string[]): string { + // Prefer fast/cheap networks + const preference = ['polygon', 'arbitrum', 'base', 'solana', 'tron', 'avalanche', 'ethereum'] + for (const pref of preference) { + if (networks.includes(pref)) return pref + } + return networks[0] ?? 'polygon' +} + +function estimateProcessingTime(network: string): string { + const times: Record<string, string> = { + polygon: '~2 minutes', + arbitrum: '~2 minutes', + base: '~2 minutes', + solana: '~1 minute', + tron: '~3 minutes', + avalanche: '~2 minutes', + ethereum: '~5 minutes', + } + return times[network] ?? '1-10 minutes' +} + +export const EXCHANGES: Record<string, Exchange> = loadExchanges() diff --git a/src/data/seo/index.ts b/src/data/seo/index.ts new file mode 100644 index 000000000..e25b4fbe9 --- /dev/null +++ b/src/data/seo/index.ts @@ -0,0 +1,11 @@ +export { COUNTRIES_SEO, CORRIDORS, getLocalizedSEO, getCountryName } from './corridors' +export type { CountrySEO, Corridor } from './corridors' + +export { COMPETITORS } from './comparisons' +export type { Competitor } from './comparisons' + +export { EXCHANGES } from './exchanges' +export type { Exchange } from './exchanges' + +export { PAYMENT_METHODS, PAYMENT_METHOD_SLUGS } from './payment-methods' +export type { PaymentMethod } from './payment-methods' diff --git a/src/data/seo/payment-methods.ts b/src/data/seo/payment-methods.ts new file mode 100644 index 000000000..13c2dad2c --- /dev/null +++ b/src/data/seo/payment-methods.ts @@ -0,0 +1,83 @@ +// Typed wrapper for payment method data. +// Reads from peanut-content: input/data/spending-methods/ + content/pay-with/ +// Note: "payment-methods" → "spending-methods" in new repo. +// Public API unchanged from previous version. + +import { readEntityData, readPageContent, listEntitySlugs, listContentSlugs } from '@/lib/content' +import { extractFaqs, extractSteps } from './utils' + +// --- Entity frontmatter (input/data/spending-methods/{slug}.md) --- + +interface SpendingMethodEntityFrontmatter { + slug: string + name: string + type: string + countries: string[] + user_base?: string + transaction_types?: string[] + availability?: string + speed?: string +} + +// --- Content frontmatter (content/pay-with/{slug}/{lang}.md) --- + +interface PayWithContentFrontmatter { + title: string + description: string + slug: string + lang: string + published: boolean + schema_types: string[] + alternates?: Record<string, string> +} + +// --- Public types (unchanged) --- + +export interface PaymentMethod { + slug: string + name: string + countries: string[] + description: string + steps: string[] + faqs: Array<{ q: string; a: string }> +} + +// --- Loader --- + +function loadPaymentMethods(): Record<string, PaymentMethod> { + const result: Record<string, PaymentMethod> = {} + + // Get methods that have both entity data and content pages + const contentSlugs = new Set(listContentSlugs('pay-with')) + const entitySlugs = listEntitySlugs('spending-methods') + + for (const slug of entitySlugs) { + // Only include methods that have a pay-with content page + if (!contentSlugs.has(slug)) continue + + const entity = readEntityData<SpendingMethodEntityFrontmatter>('spending-methods', slug) + if (!entity) continue + + const content = readPageContent<PayWithContentFrontmatter>('pay-with', slug, 'en') + if (!content) continue + + const fm = entity.frontmatter + + result[slug] = { + slug, + name: fm.name, + countries: fm.countries ?? [], + description: content.body, + steps: extractSteps(content.body, /Merchant QR Payments|How to Pay|Steps|How It Works/, (line) => { + const match = line.match(/^\d+\.\s+\*\*(.+?)\*\*/) + return match ? match[1].trim() : null + }), + faqs: extractFaqs(content.body), + } + } + + return result +} + +export const PAYMENT_METHODS = loadPaymentMethods() +export const PAYMENT_METHOD_SLUGS = Object.keys(PAYMENT_METHODS) diff --git a/src/data/seo/utils.ts b/src/data/seo/utils.ts new file mode 100644 index 000000000..1a8989464 --- /dev/null +++ b/src/data/seo/utils.ts @@ -0,0 +1,97 @@ +// Shared extraction utilities for SEO content loaders. +// Parses structured data (FAQs, steps, troubleshooting) from markdown/MDX body text. + +export interface FAQ { + q: string + a: string +} + +/** + * Extract FAQ items from markdown/MDX body. + * Supports two formats: + * 1. Markdown: ## FAQ section with ### question headings + * 2. MDX: <FAQItem question="...">answer</FAQItem> components + */ +export function extractFaqs(body: string): FAQ[] { + const faqs: FAQ[] = [] + + // Format 1: Markdown ## FAQ section with ### headings + const faqSection = body.match(/## (?:FAQ|Frequently Asked Questions)\s*\n([\s\S]*?)(?=\n## [^#]|$)/i) + if (faqSection) { + const lines = faqSection[1].split('\n') + let currentQ = '' + let currentA = '' + + for (const line of lines) { + if (line.startsWith('### ')) { + if (currentQ && currentA.trim()) faqs.push({ q: currentQ, a: currentA.trim() }) + currentQ = line.replace(/^### /, '').replace(/\*\*/g, '').trim() + currentA = '' + } else if (currentQ) { + currentA += line + '\n' + } + } + if (currentQ && currentA.trim()) faqs.push({ q: currentQ, a: currentA.trim() }) + } + + // Format 2: MDX <FAQItem question="...">answer</FAQItem> + if (faqs.length === 0) { + const faqItems = body.matchAll(/<FAQItem\s+question="([^"]+)"[^>]*>([\s\S]*?)<\/FAQItem>/g) + for (const match of faqItems) { + faqs.push({ q: match[1], a: match[2].trim() }) + } + } + + return faqs +} + +/** + * Extract numbered steps from a markdown section. + * @param body - markdown body text + * @param headingPattern - regex pattern to match the section heading (without ## prefix) + * @param lineParser - optional custom line parser; defaults to extracting `1. step text` + */ +export function extractSteps( + body: string, + headingPattern: RegExp, + lineParser?: (line: string) => string | null +): string[] { + const steps: string[] = [] + const section = body.match( + new RegExp(`##?#?\\s+(?:${headingPattern.source})\\s*\\n([\\s\\S]*?)(?=\\n##?#?\\s|$)`, 'i') + ) + if (!section) return steps + + const defaultParser = (line: string): string | null => { + const match = line.match(/^\d+\.\s+(.+)/) + return match ? match[1].replace(/\*\*/g, '').trim() : null + } + + const parse = lineParser ?? defaultParser + + const lines = section[1].split('\n') + for (const line of lines) { + const result = parse(line) + if (result) steps.push(result) + } + return steps +} + +/** + * Extract troubleshooting items from markdown body. + * Looks for `- **issue**: fix` patterns under a ## Troubleshooting heading. + */ +export function extractTroubleshooting(body: string): Array<{ issue: string; fix: string }> { + const items: Array<{ issue: string; fix: string }> = [] + const section = body.match(/## (?:Troubleshooting|Common Issues)\s*\n([\s\S]*?)(?=\n## [^#]|$)/i) + if (!section) return items + + const lines = section[1].split('\n') + for (const line of lines) { + const match = line.match(/^[-*]\s+\*\*(.+?)\*\*[:\s]+(.+)/) + if (match) { + items.push({ issue: match[1], fix: match[2].trim() }) + } + } + return items +} diff --git a/src/data/team.ts b/src/data/team.ts new file mode 100644 index 000000000..480139e6d --- /dev/null +++ b/src/data/team.ts @@ -0,0 +1,50 @@ +/** + * Team member data for the /team page and blog author attribution. + * + * TODO (team): Fill in real team member data: + * - name: Full name + * - role: Job title + * - bio: 1-2 sentence bio focusing on expertise (builds E-E-A-T for Google) + * - slug: URL-safe identifier (used for /team/{slug} if individual pages are added later) + * - image: Path to headshot in /public/team/ (recommended: 400x400px, WebP format) + * - social: Optional links to LinkedIn, Twitter/X, GitHub + * + * Why this matters for SEO: + * - Google's E-E-A-T (Experience, Expertise, Authoritativeness, Trust) signals + * - Blog posts linked to real author profiles rank better + * - Author structured data (schema.org/Person) builds entity recognition + */ + +export interface TeamMember { + slug: string + name: string + role: string + bio: string + image?: string + social?: { + linkedin?: string + twitter?: string + github?: string + } +} + +export const TEAM_MEMBERS: TeamMember[] = [ + // TODO (team): Replace with real team data + { + slug: 'hugo', + name: 'Hugo Montenegro', + role: 'Co-Founder', + bio: 'Building Peanut to make cross-border payments accessible to everyone.', + }, + { + slug: 'konrad', + name: 'Konrad', + role: 'Co-Founder', + bio: 'Focused on growth and making Peanut the easiest way to send money internationally.', + }, +] + +/** Find a team member by slug */ +export function getTeamMember(slug: string): TeamMember | undefined { + return TEAM_MEMBERS.find((m) => m.slug === slug) +} diff --git a/src/hooks/useCountUp.ts b/src/hooks/useCountUp.ts new file mode 100644 index 000000000..3498be3c9 --- /dev/null +++ b/src/hooks/useCountUp.ts @@ -0,0 +1,92 @@ +'use client' + +import { useEffect, useRef, useState } from 'react' +import { animate } from 'framer-motion' + +const STORAGE_PREFIX = 'peanut_points_' + +interface UseCountUpOptions { + /** localStorage key suffix for remembering last-seen value across visits */ + storageKey?: string + /** Animation duration in seconds (default: 1.5) */ + duration?: number + /** Only start when true — use with intersection observer for scroll-triggered animations */ + enabled?: boolean +} + +/** + * Animates a number from a previous value to the current value. + * + * - If `storageKey` is provided, remembers the last-seen value in localStorage + * so returning to the page animates from the old value to the new one. + * - If `enabled` is false, waits to start (useful for scroll-into-view triggers). + * - Returns the current animated integer value. + */ +export function useCountUp(target: number, options: UseCountUpOptions = {}): number { + const { storageKey, duration = 1.5, enabled = true } = options + + const [display, setDisplay] = useState(() => { + if (!storageKey) return target + if (typeof window === 'undefined') return target + const stored = localStorage.getItem(STORAGE_PREFIX + storageKey) + return stored ? parseInt(stored, 10) : target + }) + + const hasAnimated = useRef(false) + const isAnimating = useRef(false) + const controlsRef = useRef<ReturnType<typeof animate> | null>(null) + const prevTargetRef = useRef(target) + + useEffect(() => { + if (!enabled || hasAnimated.current) return + + const from = display + const to = target + + // nothing to animate + if (from === to) { + hasAnimated.current = true + if (storageKey) { + localStorage.setItem(STORAGE_PREFIX + storageKey, String(to)) + } + return + } + + hasAnimated.current = true + isAnimating.current = true + + controlsRef.current = animate(from, to, { + duration, + ease: [0.25, 0.1, 0.25, 1], + onUpdate(value) { + setDisplay(Math.round(value)) + }, + onComplete() { + isAnimating.current = false + setDisplay(to) + if (storageKey) { + localStorage.setItem(STORAGE_PREFIX + storageKey, String(to)) + } + }, + }) + + return () => { + controlsRef.current?.stop() + isAnimating.current = false + } + // eslint-disable-next-line react-hooks/exhaustive-deps -- display intentionally excluded to avoid re-triggering + }, [enabled, target, duration, storageKey]) + + // if target changes after animation completed (e.g. refetch), snap to new value + useEffect(() => { + if (prevTargetRef.current !== target && hasAnimated.current && !isAnimating.current) { + setDisplay(target) + if (storageKey) { + localStorage.setItem(STORAGE_PREFIX + storageKey, String(target)) + } + } + prevTargetRef.current = target + }, [target, storageKey]) + + return display +} diff --git a/src/hooks/useHomeCarouselCTAs.tsx b/src/hooks/useHomeCarouselCTAs.tsx index 8613eccf9..dc408c42c 100644 --- a/src/hooks/useHomeCarouselCTAs.tsx +++ b/src/hooks/useHomeCarouselCTAs.tsx @@ -159,7 +159,7 @@ export const useHomeCarouselCTAs = () => { id: 'latam-cashback-invite', title: ( <span> - Earn <b>20% cashback</b> on QR payments + Earn <b>cashback</b> on QR payments </span> ), description: ( diff --git a/src/hooks/useLongPress.ts b/src/hooks/useLongPress.ts new file mode 100644 index 000000000..e438cde8f --- /dev/null +++ b/src/hooks/useLongPress.ts @@ -0,0 +1,117 @@ +import { useCallback, useEffect, useRef, useState } from 'react' + +export interface LongPressOptions { + duration?: number // Duration in milliseconds (default: 2000) + onLongPress?: () => void + onLongPressStart?: () => void + onLongPressEnd?: () => void +} + +export interface LongPressReturn { + isLongPressed: boolean + pressProgress: number + handlers: { + onMouseDown: () => void + onMouseUp: () => void + onMouseLeave: () => void + onTouchStart: () => void + onTouchEnd: () => void + onTouchCancel: () => void + } +} + +export function useLongPress(options: LongPressOptions | undefined): LongPressReturn { + const [isLongPressed, setIsLongPressed] = useState(false) + const [pressProgress, setPressProgress] = useState(0) + + const pressTimerRef = useRef<NodeJS.Timeout | null>(null) + const progressIntervalRef = useRef<NodeJS.Timeout | null>(null) + const isLongPressedRef = useRef(false) + + // Keep ref in sync for use in callbacks without stale closures + isLongPressedRef.current = isLongPressed + + const clearTimers = useCallback(() => { + if (pressTimerRef.current) { + clearTimeout(pressTimerRef.current) + pressTimerRef.current = null + } + if (progressIntervalRef.current) { + clearInterval(progressIntervalRef.current) + progressIntervalRef.current = null + } + }, []) + + const handlePressStart = useCallback(() => { + if (!options) return + + options.onLongPressStart?.() + setPressProgress(0) + + const duration = options.duration || 2000 + const updateInterval = 16 // ~60fps + const increment = (100 / duration) * updateInterval + + const progressTimer = setInterval(() => { + setPressProgress((prev) => { + const newProgress = prev + increment + if (newProgress >= 100) { + clearInterval(progressTimer) + return 100 + } + return newProgress + }) + }, updateInterval) + + progressIntervalRef.current = progressTimer + + const timer = setTimeout(() => { + setIsLongPressed(true) + options.onLongPress?.() + clearInterval(progressTimer) + }, duration) + + pressTimerRef.current = timer + }, [options]) + + const handlePressEnd = useCallback(() => { + if (!options) return + + clearTimers() + + if (isLongPressedRef.current) { + options.onLongPressEnd?.() + setIsLongPressed(false) + } + + setPressProgress(0) + }, [options, clearTimers]) + + const handlePressCancel = useCallback(() => { + if (!options) return + + clearTimers() + setIsLongPressed(false) + setPressProgress(0) + }, [options, clearTimers]) + + // Cleanup on unmount + useEffect(() => { + return () => { + clearTimers() + } + }, [clearTimers]) + + return { + isLongPressed, + pressProgress, + handlers: { + onMouseDown: handlePressStart, + onMouseUp: handlePressEnd, + onMouseLeave: handlePressCancel, + onTouchStart: handlePressStart, + onTouchEnd: handlePressEnd, + onTouchCancel: handlePressCancel, + }, + } +} diff --git a/src/i18n/config.ts b/src/i18n/config.ts new file mode 100644 index 000000000..f27fdbca7 --- /dev/null +++ b/src/i18n/config.ts @@ -0,0 +1,70 @@ +import { type Locale, SUPPORTED_LOCALES, DEFAULT_LOCALE } from './types' + +/** All marketing route slugs — same across all locales (Wise pattern) */ +export const ROUTE_SLUGS = [ + 'send-money-to', + 'send-money-from', + 'convert', + 'compare', + 'deposit', + 'blog', + 'receive-money-from', + 'pay-with', + 'team', + 'help', +] as const + +export type RouteSlug = (typeof ROUTE_SLUGS)[number] + +/** Map locale codes to hreflang values */ +const HREFLANG_MAP: Record<Locale, string> = { + en: 'en', + 'es-419': 'es-419', + 'es-ar': 'es-AR', + 'es-es': 'es-ES', + 'pt-br': 'pt-BR', +} + +/** Build a localized path: all locales get /{locale}/ prefix */ +export function localizedPath(route: RouteSlug, locale: Locale, ...segments: string[]): string { + const suffix = segments.length > 0 ? `/${segments.join('/')}` : '' + return `/${locale}/${route}${suffix}` +} + +/** Build a bare localized path (no route prefix): /{locale}/{segment} */ +export function localizedBarePath(locale: Locale, ...segments: string[]): string { + const suffix = segments.length > 0 ? `/${segments.join('/')}` : '' + return `/${locale}${suffix}` +} + +/** Get all alternate URLs for hreflang tags */ +export function getAlternates(route: RouteSlug, ...segments: string[]): Record<string, string> { + const alternates: Record<string, string> = {} + for (const locale of SUPPORTED_LOCALES) { + const langCode = locale === 'en' ? 'x-default' : HREFLANG_MAP[locale] + alternates[langCode] = `https://peanut.me${localizedPath(route, locale, ...segments)}` + } + // Also add 'en' explicitly alongside x-default + alternates['en'] = `https://peanut.me${localizedPath(route, 'en', ...segments)}` + return alternates +} + +/** Get alternate URLs for bare paths (hub pages at /{locale}/{country}) */ +export function getBareAlternates(...segments: string[]): Record<string, string> { + const alternates: Record<string, string> = {} + for (const locale of SUPPORTED_LOCALES) { + const langCode = locale === 'en' ? 'x-default' : HREFLANG_MAP[locale] + alternates[langCode] = `https://peanut.me${localizedBarePath(locale, ...segments)}` + } + alternates['en'] = `https://peanut.me${localizedBarePath('en', ...segments)}` + return alternates +} + +export function isValidLocale(locale: string): locale is Locale { + return SUPPORTED_LOCALES.includes(locale as Locale) +} + +/** Non-default locales (used in generateStaticParams for [locale] segment) */ +export const NON_DEFAULT_LOCALES = SUPPORTED_LOCALES.filter((l) => l !== DEFAULT_LOCALE) + +export { SUPPORTED_LOCALES, DEFAULT_LOCALE, type Locale } diff --git a/src/i18n/en.json b/src/i18n/en.json new file mode 100644 index 000000000..29eaba388 --- /dev/null +++ b/src/i18n/en.json @@ -0,0 +1,49 @@ +{ + "sendMoneyTo": "Send Money to {country}", + "sendMoneyToSubtitle": "Fast, affordable transfers to {country} in {currency}. Better rates than banks.", + "getStarted": "Get Started", + "howItWorks": "How It Works", + "frequentlyAskedQuestions": "Frequently Asked Questions", + "sendMoneyToOtherCountries": "Send money to other countries", + "stepCreateAccount": "Create your Peanut account", + "stepCreateAccountDesc": "Sign up in under 2 minutes with your email or wallet.", + "stepDepositFunds": "Deposit funds", + "stepDepositFundsDesc": "Add money via bank transfer, {method}, or stablecoins (USDC/USDT).", + "stepSendToDesc": "Enter the recipient's details and confirm. They receive {currency} in minutes via {method}.", + "readMore": "Read more", + "allArticles": "All articles", + "blog": "Blog", + "postedOn": "Posted on {date}", + "feature": "Feature", + "verdict": "Verdict", + "home": "Home", + "sendMoney": "Send Money", + "convertTitle": "Convert {from} to {to}", + "amount": "Amount", + "liveRate": "Live Rate", + "depositFrom": "Deposit from {exchange}", + "recommendedNetwork": "Recommended Network", + "withdrawalFee": "Withdrawal Fee", + "processingTime": "Processing Time", + "troubleshooting": "Troubleshooting", + "hubTitle": "Peanut in {country}", + "sendMoneyFromTo": "Send Money from {from} to {to}", + "receiveMoneyFrom": "Receive Money from {country}", + "receiveMoneyFromDesc": "Get money sent to you from {country}. Fast and secure.", + "teamTitle": "Our Team", + "teamSubtitle": "The people behind Peanut.", + "help": "Help", + "helpCenter": "Help Center", + "helpCenterDescription": "Get help with Peanut — verification, passkeys, payments, deposits, and account recovery. Step-by-step guides and answers to common questions.", + "searchHelpArticles": "Search help articles...", + "cantFindAnswer": "Can't find what you need?", + "cantFindAnswerDesc": "Click the chat bubble in the bottom-right corner to talk to our support team. We typically reply within minutes.", + "categoryGettingStarted": "Getting Started", + "categoryAccountSecurity": "Account & Security", + "categoryPayments": "Payments", + "categoryDepositsWithdrawals": "Deposits & Withdrawals", + "categorySendingReceiving": "Sending & Receiving", + "categoryTroubleshooting": "Troubleshooting", + "lastUpdated": "Last updated: {date}", + "relatedPages": "Related Pages" +} diff --git a/src/i18n/es-419.json b/src/i18n/es-419.json new file mode 100644 index 000000000..57a077700 --- /dev/null +++ b/src/i18n/es-419.json @@ -0,0 +1,49 @@ +{ + "sendMoneyTo": "Enviar Dinero a {country}", + "sendMoneyToSubtitle": "Transferencias rápidas y económicas a {country} en {currency}. Mejores tasas que los bancos.", + "getStarted": "Comenzar", + "howItWorks": "Cómo Funciona", + "frequentlyAskedQuestions": "Preguntas Frecuentes", + "sendMoneyToOtherCountries": "Enviar dinero a otros países", + "stepCreateAccount": "Crea tu cuenta Peanut", + "stepCreateAccountDesc": "Regístrate en menos de 2 minutos con tu email o wallet.", + "stepDepositFunds": "Deposita fondos", + "stepDepositFundsDesc": "Agrega dinero por transferencia bancaria, {method}, o stablecoins (USDC/USDT).", + "stepSendToDesc": "Ingresa los datos del destinatario y confirma. Reciben {currency} en minutos vía {method}.", + "readMore": "Leer más", + "allArticles": "Todos los artículos", + "blog": "Blog", + "postedOn": "Publicado el {date}", + "feature": "Característica", + "verdict": "Veredicto", + "home": "Inicio", + "sendMoney": "Enviar Dinero", + "convertTitle": "Convertir {from} a {to}", + "amount": "Monto", + "liveRate": "Tasa en Vivo", + "depositFrom": "Depositar desde {exchange}", + "recommendedNetwork": "Red Recomendada", + "withdrawalFee": "Comisión de Retiro", + "processingTime": "Tiempo de Procesamiento", + "troubleshooting": "Solución de Problemas", + "hubTitle": "Peanut en {country}", + "sendMoneyFromTo": "Enviar Dinero de {from} a {to}", + "receiveMoneyFrom": "Recibir Dinero de {country}", + "receiveMoneyFromDesc": "Recibe dinero enviado desde {country}. Rápido y seguro.", + "teamTitle": "Nuestro Equipo", + "teamSubtitle": "Las personas detrás de Peanut.", + "help": "Ayuda", + "helpCenter": "Centro de Ayuda", + "helpCenterDescription": "Obtén ayuda con Peanut — verificación, passkeys, pagos, depósitos y recuperación de cuenta. Guías paso a paso y respuestas a preguntas frecuentes.", + "searchHelpArticles": "Buscar artículos de ayuda...", + "cantFindAnswer": "¿No encontrás lo que buscás?", + "cantFindAnswerDesc": "Hacé clic en el ícono de chat en la esquina inferior derecha para hablar con nuestro equipo de soporte. Generalmente respondemos en minutos.", + "categoryGettingStarted": "Primeros Pasos", + "categoryAccountSecurity": "Cuenta y Seguridad", + "categoryPayments": "Pagos", + "categoryDepositsWithdrawals": "Depósitos y Retiros", + "categorySendingReceiving": "Envíos y Recepciones", + "categoryTroubleshooting": "Solución de Problemas", + "lastUpdated": "Última actualización: {date}", + "relatedPages": "Páginas Relacionadas" +} diff --git a/src/i18n/es-ar.json b/src/i18n/es-ar.json new file mode 100644 index 000000000..f20aae389 --- /dev/null +++ b/src/i18n/es-ar.json @@ -0,0 +1,49 @@ +{ + "sendMoneyTo": "Enviar Dinero a {country}", + "sendMoneyToSubtitle": "Transferencias rápidas y económicas a {country} en {currency}. Mejores tasas que los bancos.", + "getStarted": "Empezar", + "howItWorks": "Cómo Funciona", + "frequentlyAskedQuestions": "Preguntas Frecuentes", + "sendMoneyToOtherCountries": "Enviar plata a otros países", + "stepCreateAccount": "Creá tu cuenta Peanut", + "stepCreateAccountDesc": "Registrate en menos de 2 minutos con tu email o wallet.", + "stepDepositFunds": "Depositá fondos", + "stepDepositFundsDesc": "Agregá plata por transferencia bancaria, {method}, o stablecoins (USDC/USDT).", + "stepSendToDesc": "Ingresá los datos del destinatario y confirmá. Reciben {currency} en minutos vía {method}.", + "readMore": "Leer más", + "allArticles": "Todos los artículos", + "blog": "Blog", + "postedOn": "Publicado el {date}", + "feature": "Característica", + "verdict": "Veredicto", + "home": "Inicio", + "sendMoney": "Enviar Plata", + "convertTitle": "Convertir {from} a {to}", + "amount": "Monto", + "liveRate": "Cotización en Vivo", + "depositFrom": "Depositar desde {exchange}", + "recommendedNetwork": "Red Recomendada", + "withdrawalFee": "Comisión de Retiro", + "processingTime": "Tiempo de Procesamiento", + "troubleshooting": "Solución de Problemas", + "hubTitle": "Peanut en {country}", + "sendMoneyFromTo": "Enviar Plata de {from} a {to}", + "receiveMoneyFrom": "Recibir Plata de {country}", + "receiveMoneyFromDesc": "Recibí plata enviada desde {country}. Rápido y seguro.", + "teamTitle": "Nuestro Equipo", + "teamSubtitle": "Las personas detrás de Peanut.", + "help": "Ayuda", + "helpCenter": "Centro de Ayuda", + "helpCenterDescription": "Obtené ayuda con Peanut — verificación, passkeys, pagos, depósitos y recuperación de cuenta. Guías paso a paso y respuestas a preguntas frecuentes.", + "searchHelpArticles": "Buscar artículos de ayuda...", + "cantFindAnswer": "¿No encontrás lo que buscás?", + "cantFindAnswerDesc": "Hacé clic en el ícono de chat en la esquina inferior derecha para hablar con nuestro equipo de soporte. Generalmente respondemos en minutos.", + "categoryGettingStarted": "Primeros Pasos", + "categoryAccountSecurity": "Cuenta y Seguridad", + "categoryPayments": "Pagos", + "categoryDepositsWithdrawals": "Depósitos y Retiros", + "categorySendingReceiving": "Envíos y Recepciones", + "categoryTroubleshooting": "Solución de Problemas", + "lastUpdated": "Última actualización: {date}", + "relatedPages": "Páginas Relacionadas" +} diff --git a/src/i18n/es-es.json b/src/i18n/es-es.json new file mode 100644 index 000000000..84055c7bb --- /dev/null +++ b/src/i18n/es-es.json @@ -0,0 +1,49 @@ +{ + "sendMoneyTo": "Enviar Dinero a {country}", + "sendMoneyToSubtitle": "Transferencias rápidas y económicas a {country} en {currency}. Mejores tasas que los bancos.", + "getStarted": "Comenzar", + "howItWorks": "Cómo Funciona", + "frequentlyAskedQuestions": "Preguntas Frecuentes", + "sendMoneyToOtherCountries": "Enviar dinero a otros países", + "stepCreateAccount": "Crea tu cuenta Peanut", + "stepCreateAccountDesc": "Regístrate en menos de 2 minutos con tu email o wallet.", + "stepDepositFunds": "Deposita fondos", + "stepDepositFundsDesc": "Agrega dinero por transferencia bancaria, {method}, o stablecoins (USDC/USDT).", + "stepSendToDesc": "Ingresa los datos del destinatario y confirma. Reciben {currency} en minutos vía {method}.", + "readMore": "Leer más", + "allArticles": "Todos los artículos", + "blog": "Blog", + "postedOn": "Publicado el {date}", + "feature": "Característica", + "verdict": "Veredicto", + "home": "Inicio", + "sendMoney": "Enviar Dinero", + "convertTitle": "Convertir {from} a {to}", + "amount": "Monto", + "liveRate": "Tasa en Vivo", + "depositFrom": "Depositar desde {exchange}", + "recommendedNetwork": "Red Recomendada", + "withdrawalFee": "Comisión de Retiro", + "processingTime": "Tiempo de Procesamiento", + "troubleshooting": "Solución de Problemas", + "hubTitle": "Peanut en {country}", + "sendMoneyFromTo": "Enviar Dinero de {from} a {to}", + "receiveMoneyFrom": "Recibir Dinero de {country}", + "receiveMoneyFromDesc": "Recibe dinero enviado desde {country}. Rápido y seguro.", + "teamTitle": "Nuestro Equipo", + "teamSubtitle": "Las personas detrás de Peanut.", + "help": "Ayuda", + "helpCenter": "Centro de Ayuda", + "helpCenterDescription": "Obtén ayuda con Peanut — verificación, passkeys, pagos, depósitos y recuperación de cuenta. Guías paso a paso y respuestas a preguntas frecuentes.", + "searchHelpArticles": "Buscar artículos de ayuda...", + "cantFindAnswer": "¿No encuentras lo que buscas?", + "cantFindAnswerDesc": "Haz clic en el icono de chat en la esquina inferior derecha para hablar con nuestro equipo de soporte. Normalmente respondemos en minutos.", + "categoryGettingStarted": "Primeros Pasos", + "categoryAccountSecurity": "Cuenta y Seguridad", + "categoryPayments": "Pagos", + "categoryDepositsWithdrawals": "Depósitos y Retiradas", + "categorySendingReceiving": "Envíos y Recepciones", + "categoryTroubleshooting": "Solución de Problemas", + "lastUpdated": "Última actualización: {date}", + "relatedPages": "Páginas Relacionadas" +} diff --git a/src/i18n/index.ts b/src/i18n/index.ts new file mode 100644 index 000000000..86f9005a3 --- /dev/null +++ b/src/i18n/index.ts @@ -0,0 +1,38 @@ +import type { Locale, Translations } from './types' +import en from './en.json' +import es419 from './es-419.json' +import esAr from './es-ar.json' +import esEs from './es-es.json' +import ptBr from './pt-br.json' + +const messages: Record<Locale, Translations> = { + en: en as Translations, + 'es-419': es419 as Translations, + 'es-ar': esAr as Translations, + 'es-es': esEs as Translations, + 'pt-br': ptBr as Translations, +} + +/** Get translations for a locale (falls back to English) */ +export function getTranslations(locale: Locale): Translations { + return messages[locale] ?? messages.en +} + +/** Simple template interpolation: replaces {key} with values */ +export function t(template: string, vars?: Record<string, string>): string { + if (!vars) return template + return template.replace(/\{(\w+)\}/g, (_, key) => vars[key] ?? `{${key}}`) +} + +export { type Locale, type Translations } from './types' +export { SUPPORTED_LOCALES, DEFAULT_LOCALE } from './types' +export { + ROUTE_SLUGS, + localizedPath, + localizedBarePath, + getAlternates, + getBareAlternates, + isValidLocale, + NON_DEFAULT_LOCALES, + type RouteSlug, +} from './config' diff --git a/src/i18n/pt-br.json b/src/i18n/pt-br.json new file mode 100644 index 000000000..1f22b6368 --- /dev/null +++ b/src/i18n/pt-br.json @@ -0,0 +1,49 @@ +{ + "sendMoneyTo": "Enviar Dinheiro para {country}", + "sendMoneyToSubtitle": "Transferências rápidas e acessíveis para {country} em {currency}. Melhores taxas que os bancos.", + "getStarted": "Começar", + "howItWorks": "Como Funciona", + "frequentlyAskedQuestions": "Perguntas Frequentes", + "sendMoneyToOtherCountries": "Enviar dinheiro para outros países", + "stepCreateAccount": "Crie sua conta Peanut", + "stepCreateAccountDesc": "Cadastre-se em menos de 2 minutos com seu email ou carteira.", + "stepDepositFunds": "Deposite fundos", + "stepDepositFundsDesc": "Adicione dinheiro por transferência bancária, {method}, ou stablecoins (USDC/USDT).", + "stepSendToDesc": "Insira os dados do destinatário e confirme. Eles recebem {currency} em minutos via {method}.", + "readMore": "Leia mais", + "allArticles": "Todos os artigos", + "blog": "Blog", + "postedOn": "Publicado em {date}", + "feature": "Recurso", + "verdict": "Veredito", + "home": "Início", + "sendMoney": "Enviar Dinheiro", + "convertTitle": "Converter {from} para {to}", + "amount": "Valor", + "liveRate": "Taxa ao Vivo", + "depositFrom": "Depositar de {exchange}", + "recommendedNetwork": "Rede Recomendada", + "withdrawalFee": "Taxa de Saque", + "processingTime": "Tempo de Processamento", + "troubleshooting": "Solução de Problemas", + "hubTitle": "Peanut em {country}", + "sendMoneyFromTo": "Enviar Dinheiro de {from} para {to}", + "receiveMoneyFrom": "Receber Dinheiro de {country}", + "receiveMoneyFromDesc": "Receba dinheiro enviado de {country}. Rápido e seguro.", + "teamTitle": "Nossa Equipe", + "teamSubtitle": "As pessoas por trás do Peanut.", + "help": "Ajuda", + "helpCenter": "Central de Ajuda", + "helpCenterDescription": "Obtenha ajuda com o Peanut — verificação, passkeys, pagamentos, depósitos e recuperação de conta. Guias passo a passo e respostas para perguntas frequentes.", + "searchHelpArticles": "Buscar artigos de ajuda...", + "cantFindAnswer": "Não encontrou o que precisa?", + "cantFindAnswerDesc": "Clique no ícone de chat no canto inferior direito para falar com nossa equipe de suporte. Geralmente respondemos em minutos.", + "categoryGettingStarted": "Primeiros Passos", + "categoryAccountSecurity": "Conta e Segurança", + "categoryPayments": "Pagamentos", + "categoryDepositsWithdrawals": "Depósitos e Saques", + "categorySendingReceiving": "Envios e Recebimentos", + "categoryTroubleshooting": "Solução de Problemas", + "lastUpdated": "Última atualização: {date}", + "relatedPages": "Páginas Relacionadas" +} diff --git a/src/i18n/types.ts b/src/i18n/types.ts new file mode 100644 index 000000000..ab2fc4000 --- /dev/null +++ b/src/i18n/types.ts @@ -0,0 +1,81 @@ +export type Locale = 'en' | 'es-419' | 'es-ar' | 'es-es' | 'pt-br' + +export const SUPPORTED_LOCALES: Locale[] = ['en', 'es-419', 'es-ar', 'es-es', 'pt-br'] +export const DEFAULT_LOCALE: Locale = 'en' + +export interface Translations { + // Hero / CTA + sendMoneyTo: string // "Send Money to {country}" + sendMoneyToSubtitle: string // "Fast, affordable transfers to {country} in {currency}. Better rates than banks." + getStarted: string + + // Section titles + howItWorks: string + frequentlyAskedQuestions: string + sendMoneyToOtherCountries: string + + // Steps + stepCreateAccount: string + stepCreateAccountDesc: string + stepDepositFunds: string + stepDepositFundsDesc: string // "Add money via bank transfer, {method}, or stablecoins (USDC/USDT)." + stepSendToDesc: string // "Enter the recipient's details and confirm. They receive {currency} in minutes via {method}." + + // Blog + readMore: string + allArticles: string + blog: string + postedOn: string + + // Comparison + feature: string + verdict: string + + // Navigation + home: string + sendMoney: string + + // Converter + convertTitle: string // "Convert {from} to {to}" + amount: string + liveRate: string + + // Deposit + depositFrom: string // "Deposit from {exchange}" + recommendedNetwork: string + withdrawalFee: string + processingTime: string + troubleshooting: string + + // Hub + hubTitle: string // "Peanut in {country}" + + // From-to corridors + sendMoneyFromTo: string // "Send Money from {from} to {to}" + + // Receive money + receiveMoneyFrom: string // "Receive Money from {country}" + receiveMoneyFromDesc: string // "Get money sent to you from {country}. Fast and secure." + + // Team + teamTitle: string // "Our Team" + teamSubtitle: string // "The people behind Peanut." + + // Help center + help: string // "Help" + helpCenter: string // "Help Center" + helpCenterDescription: string // "Get help with Peanut — ..." + searchHelpArticles: string // "Search help articles..." + cantFindAnswer: string // "Can't find what you need?" + cantFindAnswerDesc: string // "Click the chat bubble..." + categoryGettingStarted: string + categoryAccountSecurity: string + categoryPayments: string + categoryDepositsWithdrawals: string + categorySendingReceiving: string + categoryTroubleshooting: string + + // Misc + lastUpdated: string // "Last updated: {date}" + relatedPages: string // "Related Pages" +} diff --git a/src/lib/blog.ts b/src/lib/blog.ts new file mode 100644 index 000000000..df189b600 --- /dev/null +++ b/src/lib/blog.ts @@ -0,0 +1,96 @@ +import matter from 'gray-matter' +import { marked } from 'marked' +import { createHighlighter, type Highlighter } from 'shiki' +import fs from 'fs' +import path from 'path' + +import type { Locale } from '@/i18n/types' + +function getBlogDir(locale: Locale = 'en') { + return path.join(process.cwd(), `src/content/blog/${locale}`) +} + +export interface BlogPost { + slug: string + frontmatter: { + title: string + description: string + date: string + category?: string + author?: string + faqs?: Array<{ question: string; answer: string }> + } + content: string +} + +// Singleton highlighter — created once, reused across all posts +let _highlighter: Highlighter | null = null + +async function getHighlighter(): Promise<Highlighter> { + if (_highlighter) return _highlighter + _highlighter = await createHighlighter({ + themes: ['github-light'], + langs: ['javascript', 'typescript', 'bash', 'json', 'yaml', 'html', 'css', 'python', 'solidity'], + }) + return _highlighter +} + +export function getAllPosts(locale: Locale = 'en'): BlogPost[] { + const dir = getBlogDir(locale) + if (!fs.existsSync(dir)) return [] + + const files = fs.readdirSync(dir).filter((f) => f.endsWith('.md')) + return files + .map((file) => { + const raw = fs.readFileSync(path.join(dir, file), 'utf8') + const { data, content } = matter(raw) + return { + slug: file.replace('.md', ''), + frontmatter: data as BlogPost['frontmatter'], + content, + } + }) + .sort((a, b) => new Date(b.frontmatter.date).getTime() - new Date(a.frontmatter.date).getTime()) +} + +export async function getPostBySlug( + slug: string, + locale: Locale = 'en' +): Promise<{ frontmatter: BlogPost['frontmatter']; html: string } | null> { + const filePath = path.join(getBlogDir(locale), `${slug}.md`) + if (!fs.existsSync(filePath)) return null + + const raw = fs.readFileSync(filePath, 'utf8') + const { data, content } = matter(raw) + + const highlighter = await getHighlighter() + + // Custom renderer for code blocks with shiki syntax highlighting + const renderer = new marked.Renderer() + renderer.code = ({ text, lang }: { text: string; lang?: string }) => { + const language = lang || 'text' + try { + return highlighter.codeToHtml(text, { + lang: language, + theme: 'github-light', + }) + } catch { + // Fallback for unsupported languages + return `<pre><code class="language-${language}">${text}</code></pre>` + } + } + + const html = (await marked(content, { renderer })) as string + + return { frontmatter: data as BlogPost['frontmatter'], html } +} + +export function getPostsByCategory(category: string, locale: Locale = 'en'): BlogPost[] { + return getAllPosts(locale).filter((p) => p.frontmatter.category === category) +} + +export function getAllCategories(locale: Locale = 'en'): string[] { + const posts = getAllPosts(locale) + const cats = new Set(posts.map((p) => p.frontmatter.category).filter(Boolean) as string[]) + return Array.from(cats).sort() +} diff --git a/src/lib/content.ts b/src/lib/content.ts new file mode 100644 index 000000000..764657dea --- /dev/null +++ b/src/lib/content.ts @@ -0,0 +1,210 @@ +// Unified content loader for peanutprotocol/peanut-content. +// +// Two read paths: +// readEntityData(category, slug) → input/data/{category}/{slug}.md (frontmatter only) +// readPageContent(intent, slug, lang) → content/{intent}/{slug}/{lang}.md (frontmatter + body) +// +// Discovers entities by scanning directories. No _index.yaml dependency. +// Implements locale fallback chains per BCP 47 codes. + +import fs from 'fs' +import path from 'path' +import matter from 'gray-matter' + +const CONTENT_ROOT = path.join(process.cwd(), 'src/content') + +// --- Locale fallback chains --- +// es-ar → es-419 → en +// es-es → en +// pt-br → en +// es-419 → en + +const FALLBACK_CHAINS: Record<string, string[]> = { + en: [], + 'es-419': ['en'], + 'es-ar': ['es-419', 'en'], + 'es-es': ['es-419', 'en'], + 'pt-br': ['en'], +} + +/** Get ordered list of locales to try (requested locale first, then fallbacks) */ +export function getLocaleFallbacks(locale: string): string[] { + return [locale, ...(FALLBACK_CHAINS[locale] ?? ['en'])] +} + +// --- Caches --- +// In development, skip caching so content changes are picked up without restart. + +const isDev = process.env.NODE_ENV === 'development' + +const entityCache = new Map<string, unknown>() +const pageCache = new Map<string, unknown>() + +// --- Core types --- + +export interface MarkdownContent<T = Record<string, unknown>> { + frontmatter: T + body: string +} + +// --- Low-level readers --- + +function parseMarkdownFile<T = Record<string, unknown>>(filePath: string): MarkdownContent<T> | null { + try { + const raw = fs.readFileSync(filePath, 'utf8') + const { data, content } = matter(raw) + return { frontmatter: data as T, body: content.trim() } + } catch { + return null + } +} + +// --- Entity data readers (input/data/{category}/{slug}.md) --- + +/** Read structured entity data from input/data/{category}/{slug}.md */ +export function readEntityData<T = Record<string, unknown>>(category: string, slug: string): MarkdownContent<T> | null { + const key = `entity:${category}/${slug}` + if (!isDev && entityCache.has(key)) return entityCache.get(key) as MarkdownContent<T> | null + + const filePath = path.join(CONTENT_ROOT, 'input/data', category, `${slug}.md`) + const result = parseMarkdownFile<T>(filePath) + entityCache.set(key, result) + return result +} + +// --- Page content readers (content/{intent}/{slug}/{lang}.md) --- + +/** Read generated page content from content/{intent}/{slug}/{lang}.md */ +export function readPageContent<T = Record<string, unknown>>( + intent: string, + slug: string, + lang: string +): MarkdownContent<T> | null { + const key = `page:${intent}/${slug}/${lang}` + if (!isDev && pageCache.has(key)) return pageCache.get(key) as MarkdownContent<T> | null + + const filePath = path.join(CONTENT_ROOT, 'content', intent, slug, `${lang}.md`) + const result = parseMarkdownFile<T>(filePath) + pageCache.set(key, result) + return result +} + +/** Read page content with locale fallback */ +export function readPageContentLocalized<T = Record<string, unknown>>( + intent: string, + slug: string, + lang: string +): MarkdownContent<T> | null { + for (const locale of getLocaleFallbacks(lang)) { + const content = readPageContent<T>(intent, slug, locale) + if (content) return content + } + return null +} + +/** Read corridor content: content/send-to/{destination}/from/{origin}/{lang}.md */ +export function readCorridorContent<T = Record<string, unknown>>( + destination: string, + origin: string, + lang: string +): MarkdownContent<T> | null { + const key = `corridor:${destination}/from/${origin}/${lang}` + if (!isDev && pageCache.has(key)) return pageCache.get(key) as MarkdownContent<T> | null + + const filePath = path.join(CONTENT_ROOT, 'content/send-to', destination, 'from', origin, `${lang}.md`) + const result = parseMarkdownFile<T>(filePath) + pageCache.set(key, result) + return result +} + +/** Read corridor content with locale fallback */ +export function readCorridorContentLocalized<T = Record<string, unknown>>( + destination: string, + origin: string, + lang: string +): MarkdownContent<T> | null { + for (const locale of getLocaleFallbacks(lang)) { + const content = readCorridorContent<T>(destination, origin, locale) + if (content) return content + } + return null +} + +// --- Directory scanners (replaces _index.yaml) --- + +/** List all entity slugs in a category by scanning input/data/{category}/ */ +export function listEntitySlugs(category: string): string[] { + const dir = path.join(CONTENT_ROOT, 'input/data', category) + try { + return fs + .readdirSync(dir) + .filter((f) => f.endsWith('.md') && f !== 'README.md') + .map((f) => f.replace('.md', '')) + } catch { + return [] + } +} + +/** List all content slugs for an intent by scanning content/{intent}/ */ +export function listContentSlugs(intent: string): string[] { + const dir = path.join(CONTENT_ROOT, 'content', intent) + try { + return fs.readdirSync(dir).filter((f) => { + const stat = fs.statSync(path.join(dir, f)) + return stat.isDirectory() + }) + } catch { + return [] + } +} + +/** List corridor origins for a destination: content/send-to/{destination}/from/ */ +export function listCorridorOrigins(destination: string): string[] { + const dir = path.join(CONTENT_ROOT, 'content/send-to', destination, 'from') + try { + return fs.readdirSync(dir).filter((f) => { + const stat = fs.statSync(path.join(dir, f)) + return stat.isDirectory() + }) + } catch { + return [] + } +} + +/** List available locales for a content page */ +export function listPageLocales(intent: string, slug: string): string[] { + const dir = path.join(CONTENT_ROOT, 'content', intent, slug) + try { + return fs + .readdirSync(dir) + .filter((f) => f.endsWith('.md')) + .map((f) => f.replace('.md', '')) + } catch { + return [] + } +} + +/** Check if a page content file exists for the given locale (no fallback) */ +export function pageLocaleExists(intent: string, slug: string, locale: string): boolean { + return fs.existsSync(path.join(CONTENT_ROOT, 'content', intent, slug, `${locale}.md`)) +} + +// --- Publication status --- + +interface PublishableContent { + published?: boolean +} + +/** Check if content is published (defaults to false if field missing) */ +export function isPublished(content: MarkdownContent<PublishableContent> | null): boolean { + if (!content) return false + return content.frontmatter.published === true +} + +/** List published content slugs for an intent */ +export function listPublishedSlugs(intent: string): string[] { + return listContentSlugs(intent).filter((slug) => { + const content = readPageContent<PublishableContent>(intent, slug, 'en') + return isPublished(content) + }) +} diff --git a/src/lib/mdx.ts b/src/lib/mdx.ts new file mode 100644 index 000000000..2686462ea --- /dev/null +++ b/src/lib/mdx.ts @@ -0,0 +1,29 @@ +import { compileMDX } from 'next-mdx-remote/rsc' +import remarkGfm from 'remark-gfm' +import { mdxComponents } from '@/components/Marketing/mdx/components' + +/** + * Compile markdown/MDX content into a React element with registered components. + * Uses next-mdx-remote/rsc for server-side rendering (zero client JS). + * + * Note: frontmatter is already stripped by content.ts (gray-matter). + * The source passed here is body-only — no parseFrontmatter needed. + * + * format: 'mdx' — enables JSX component tags in content. + * remarkGfm — enables GFM tables, strikethrough, autolinks, etc. + * + * Limitation: next-mdx-remote/rsc strips JSX expression props ({...}). + * Components that need structured data accept JSON strings instead. + */ +export async function renderContent(source: string) { + return compileMDX<Record<string, unknown>>({ + source, + components: mdxComponents, + options: { + mdxOptions: { + format: 'mdx', + remarkPlugins: [remarkGfm], + }, + }, + }) +} diff --git a/src/lib/seo/schemas.tsx b/src/lib/seo/schemas.tsx new file mode 100644 index 000000000..dcecfa0ed --- /dev/null +++ b/src/lib/seo/schemas.tsx @@ -0,0 +1,55 @@ +import { BASE_URL } from '@/constants/general.consts' + +const baseUrl = BASE_URL || 'https://peanut.me' + +export function faqSchema(faqs: { question: string; answer: string }[]) { + return { + '@context': 'https://schema.org', + '@type': 'FAQPage', + mainEntity: faqs.map((faq) => ({ + '@type': 'Question', + name: faq.question, + acceptedAnswer: { + '@type': 'Answer', + text: faq.answer, + }, + })), + } +} + +export function howToSchema(name: string, description: string, steps: { name: string; text: string }[]) { + return { + '@context': 'https://schema.org', + '@type': 'HowTo', + name, + description, + step: steps.map((step, i) => ({ + '@type': 'HowToStep', + position: i + 1, + name: step.name, + text: step.text, + })), + } +} + +export function breadcrumbSchema(items: { name: string; url: string }[]) { + return { + '@context': 'https://schema.org', + '@type': 'BreadcrumbList', + itemListElement: items.map((item, i) => ({ + '@type': 'ListItem', + position: i + 1, + name: item.name, + item: `${baseUrl}${item.url}`, + })), + } +} + +export function JsonLd({ data }: { data: object }) { + return ( + <script + type="application/ld+json" + dangerouslySetInnerHTML={{ __html: JSON.stringify(data).replace(/</g, '\\u003c') }} + /> + ) +} diff --git a/src/proxy.ts b/src/proxy.ts index 7ab6fc401..34b2cf5be 100644 --- a/src/proxy.ts +++ b/src/proxy.ts @@ -48,7 +48,7 @@ export function proxy(request: NextRequest) { // Handle promo link redirection if (isPromoLink(url)) { const fragment = url.searchParams.toString() - const redirectUrl = `https://peanut.to/claim?&${promoList[fragment]}` + const redirectUrl = `https://peanut.me/claim?&${promoList[fragment]}` return NextResponse.redirect(redirectUrl) } diff --git a/src/services/points.ts b/src/services/points.ts index 3e72d6b58..c0f1a99eb 100644 --- a/src/services/points.ts +++ b/src/services/points.ts @@ -341,7 +341,7 @@ export const pointsApi = { getCashStatus: async (): Promise<{ success: boolean data: { - cashbackAllowance: number | null + hasCashbackLeft: boolean lifetimeEarned: number lifetimeBreakdown: { cashback: number diff --git a/src/styles/globals.css b/src/styles/globals.css index ce97f85fa..c851dcfb7 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -685,3 +685,92 @@ input::placeholder { z-index: 5; border-radius: inherit; } + +/* ── Landing page: CSS cloud drift animations ── */ +@keyframes cloud-drift-ltr { + from { + transform: translateX(-300px); + } + to { + transform: translateX(100vw); + } +} + +@keyframes cloud-drift-rtl { + from { + transform: translateX(100vw); + } + to { + transform: translateX(-300px); + } +} + +.cloud-ltr { + animation: cloud-drift-ltr var(--cloud-speed, 35s) linear infinite; + animation-delay: var(--cloud-delay, 0s); +} + +.cloud-rtl { + animation: cloud-drift-rtl var(--cloud-speed, 35s) linear infinite; + animation-delay: var(--cloud-delay, 0s); +} + +/* ── Landing page: entrance animations (replaces framer-motion whileInView) ── */ +/* Spring animation approximating framer-motion { type: 'spring', damping: 5, stiffness: 100 } + damping:5 is heavily underdamped — large overshoot with visible bounces. + Sampled from spring physics: e^(-ζωt) * cos(ωd*t) with ζ=0.25, ω=10 */ +@keyframes fade-in-up-spring { + 0% { + opacity: 0; + transform: translateY(var(--aov-y, 20px)) translateX(var(--aov-x, 0px)) rotate(var(--aov-rotate, 0deg)); + } + 12% { + opacity: 1; + transform: translateY(calc(var(--aov-y, 20px) * -1.2)) translateX(calc(var(--aov-x, 0px) * -1.2)) + rotate(var(--aov-rotate, 0deg)); + } + 24% { + transform: translateY(calc(var(--aov-y, 20px) * 0.6)) translateX(calc(var(--aov-x, 0px) * 0.6)) + rotate(var(--aov-rotate, 0deg)); + } + 38% { + transform: translateY(calc(var(--aov-y, 20px) * -0.35)) translateX(calc(var(--aov-x, 0px) * -0.35)) + rotate(var(--aov-rotate, 0deg)); + } + 52% { + transform: translateY(calc(var(--aov-y, 20px) * 0.18)) translateX(calc(var(--aov-x, 0px) * 0.18)) + rotate(var(--aov-rotate, 0deg)); + } + 68% { + transform: translateY(calc(var(--aov-y, 20px) * -0.08)) translateX(calc(var(--aov-x, 0px) * -0.08)) + rotate(var(--aov-rotate, 0deg)); + } + 82% { + transform: translateY(calc(var(--aov-y, 20px) * 0.03)) translateX(calc(var(--aov-x, 0px) * 0.03)) + rotate(var(--aov-rotate, 0deg)); + } + 100% { + opacity: 1; + transform: translateY(0) translateX(0) rotate(var(--aov-rotate, 0deg)); + } +} + +.animate-on-view { + opacity: 0; +} + +.animate-on-view.in-view { + animation: fade-in-up-spring 1.8s linear forwards; + animation-delay: var(--aov-delay, 0s); +} + +/* ── Marketing content pages ── */ + +/* + * Prose styling is handled via MDX element mappings in components.tsx. + * Only structural and zebra-stripe styles remain here (can't be done via components). + */ + +.content-page tbody tr:nth-child(even) { + @apply bg-primary-3/30; +} diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 45d2e615c..790eb5e5b 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -1,3 +1,4 @@ interface Window { gtag?: (command: string, ...args: unknown[]) => void + $crisp?: Array<unknown[]> } diff --git a/src/utils/__mocks__/wagmi-config.ts b/src/utils/__mocks__/wagmi-config.ts index 8354efe1d..1a1690de8 100644 --- a/src/utils/__mocks__/wagmi-config.ts +++ b/src/utils/__mocks__/wagmi-config.ts @@ -8,7 +8,7 @@ export const projectId = 'test-project-id' export const metadata = { name: 'Peanut Protocol', description: 'Test', - url: 'https://peanut.to', + url: 'https://peanut.me', icons: [], } diff --git a/src/utils/cookie-migration.utils.ts b/src/utils/cookie-migration.utils.ts index 46a810139..dec62cf6b 100644 --- a/src/utils/cookie-migration.utils.ts +++ b/src/utils/cookie-migration.utils.ts @@ -9,21 +9,5 @@ import { cookies } from 'next/headers' export async function getJWTCookie() { const cookieStore = await cookies() - const cookie = cookieStore.get('jwt-token') - - if (cookie?.value) { - try { - cookieStore.set('jwt-token', cookie.value, { - httpOnly: false, // Required for client-side services to read token (see TODO above) - secure: process.env.NODE_ENV === 'production', - path: '/', - sameSite: 'lax', - maxAge: 30 * 24 * 60 * 60, - }) - } catch (error) { - console.warn('Failed to refresh JWT cookie:', error) - } - } - - return cookie + return cookieStore.get('jwt-token') } diff --git a/src/utils/format.utils.ts b/src/utils/format.utils.ts index 7059a2143..c0f0b2742 100644 --- a/src/utils/format.utils.ts +++ b/src/utils/format.utils.ts @@ -1,3 +1,26 @@ +/** + * Format points for display with thousands separators (e.g. 564,554). + */ +export function formatPoints(points: number): string { + return points.toLocaleString('en-US') +} + +/** + * Shorten large point values to compact form. + * Returns { number, suffix } so the suffix (K/M) can be styled separately. + */ +export function shortenPoints(points: number): { number: string; suffix: string } { + if (points >= 1_000_000) { + const m = points / 1_000_000 + return { number: m >= 10 ? Math.round(m).toString() : m.toFixed(1).replace(/\.0$/, ''), suffix: 'M' } + } + if (points >= 1_000) { + const k = points / 1_000 + return { number: k >= 10 ? Math.round(k).toString() : k.toFixed(1).replace(/\.0$/, ''), suffix: 'K' } + } + return { number: points.toString(), suffix: '' } +} + export const sanitizeBankAccount = (value: string | undefined): string => { if (!value) return '' return value.replace(/[\s\-\._]/g, '').toLowerCase()