feat: redesign archgw -> plano + website in Next.js (#613)

* feat: redesign archgw -> plano + website

* feat(www): refactor landing page sections, add new diagrams and UI improvements

* feat(www): sections enhanced for clarify & diagrams added

* feat(www): improvements to mobile design, layout of diagrams

* feat(www): clean + typecheck

* feat(www): feedback loop changes

* feat(www): fix type error

* fix lib/utils error

* feat(www): ran biome formatting

* feat(www): graphic changes

* feat(www): web analytics

* fea(www): changes

* feat(www): introduce monorepo

This change brings Turborepo monorepo to independently handle the marketing website, the docs website and any other future use cases for mutli-platform support. They are using internal @katanemo package handlers for the design system and logic.

* fix(www): transpiler failure

* fix(www): tsconfig issue

* fix(www): next.config issue

* feat(docs): hold off on docs

* Delete next.config.ts

* feat(www): content fix

* feat(www): introduce blog

* feat(www): content changes

* Update package-lock.json

* feat: update text

* Update IntroSection.tsx

* feat: Turbopack issue

* fix

* Update IntroSection.tsx

* feat: updated Research page

* refactor(www): text clarity, padding adj.

* format(www)

* fix: add missing lib/ files to git - fixes Vercel GitHub deployment

- Updated .gitignore to properly exclude Python lib/ but include Next.js lib/ directories
- Added packages/ui/src/lib/utils.ts (cn utility function)
- Added apps/www/src/lib/sanity.ts (Sanity client configuration)
- Fixes module resolution errors in Vercel GitHub deployments (case-sensitive filesystem)

* Update .gitignore

* style(www): favicon + metadata

* fix(www): links

* fix(www): add analytics

* fix(www): add

* fix(www): fix links + image

* fix(www): fix links + image

* fix(www): fix links

* fix(www): remove from tools testing.md
This commit is contained in:
Musa 2025-12-18 15:55:15 -08:00 committed by GitHub
parent 48bbc7cce7
commit 0c3efdbef2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
119 changed files with 27142 additions and 266 deletions

16
.gitignore vendored
View file

@ -14,8 +14,6 @@ dist/
downloads/ downloads/
eggs/ eggs/
.eggs/ .eggs/
lib/
lib64/
parts/ parts/
sdist/ sdist/
var/ var/
@ -133,3 +131,17 @@ crates/target/
build.log build.log
archgw.log archgw.log
# Next.js / Turborepo
.next/
out/
.turbo
*.tsbuildinfo
next-env.d.ts
apps/*/node_modules/
packages/*/node_modules/
apps/*/.next/
apps/*/out/
apps/*/dist/
./node_modules
.vercel

1
apps/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.vercel

44
apps/www/.gitignore vendored Normal file
View file

@ -0,0 +1,44 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
# sanity
.sanity/

36
apps/www/README.md Normal file
View file

@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.

37
apps/www/biome.json Normal file
View file

@ -0,0 +1,37 @@
{
"$schema": "https://biomejs.dev/schemas/2.2.0/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"files": {
"ignoreUnknown": true,
"includes": ["**", "!node_modules", "!.next", "!dist", "!build"]
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": {
"noUnknownAtRules": "off"
}
},
"domains": {
"next": "recommended",
"react": "recommended"
}
},
"assist": {
"actions": {
"source": {
"organizeImports": "on"
}
}
}
}

22
apps/www/components.json Normal file
View file

@ -0,0 +1,22 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/app/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": {}
}

50
apps/www/next.config.ts Normal file
View file

@ -0,0 +1,50 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
transpilePackages: [
"@katanemo/ui",
"@katanemo/shared-styles",
"@katanemo/tailwind-config",
"@katanemo/tsconfig",
],
experimental: {
// Ensure workspace packages are handled correctly
externalDir: true,
},
// Webpack config for production builds
webpack: (config, { isServer }) => {
// Ensure proper resolution of dependencies in monorepo
config.resolve.modules = [
...(config.resolve.modules || []),
"node_modules",
"../../node_modules",
];
if (!isServer) {
config.resolve.fallback = {
...config.resolve.fallback,
fs: false,
};
}
return config;
},
// Turbopack config for dev mode (Next.js 16 default)
turbopack: {
resolveAlias: {
// Turbopack should handle monorepo resolution automatically
// but we can add specific aliases if needed
},
},
images: {
remotePatterns: [
{
protocol: "https",
hostname: "cdn.sanity.io",
port: "",
pathname: "/**",
},
],
},
};
export default nextConfig;

2384
apps/www/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

50
apps/www/package.json Normal file
View file

@ -0,0 +1,50 @@
{
"name": "@katanemo/www",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "biome check",
"format": "biome format --write",
"typecheck": "tsc --noEmit",
"clean": "rm -rf .next",
"sanity": "sanity dev",
"sanity:build": "sanity build",
"sanity:deploy": "sanity deploy",
"migrate:blogs": "tsx scripts/migrate-blogs.ts"
},
"dependencies": {
"@katanemo/shared-styles": "*",
"@katanemo/ui": "*",
"@portabletext/react": "^5.0.0",
"@portabletext/types": "^3.0.0",
"@sanity/client": "^7.13.0",
"@sanity/image-url": "^1.2.0",
"@vercel/analytics": "^1.5.0",
"csv-parse": "^6.1.0",
"framer-motion": "^12.23.24",
"jsdom": "^27.2.0",
"next": "^16.0.7",
"next-sanity": "^11.6.9",
"papaparse": "^5.5.3",
"react": "19.2.0",
"react-dom": "19.2.0",
"sanity": "^4.18.0",
"styled-components": "^6.1.19"
},
"devDependencies": {
"@biomejs/biome": "2.2.0",
"@katanemo/tailwind-config": "*",
"@katanemo/tsconfig": "*",
"@tailwindcss/postcss": "^4",
"@types/jsdom": "^27.0.0",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"tailwindcss": "^4",
"tw-animate-css": "^1.4.0",
"typescript": "^5"
}
}

View file

@ -0,0 +1,7 @@
const config = {
plugins: {
"@tailwindcss/postcss": {},
},
};
export default config;

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 329 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 317 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 24 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 39 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 186 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 141 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 50 KiB

View file

@ -0,0 +1,76 @@
<svg width="313" height="246" viewBox="0 0 313 246" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="86" y="67" width="48" height="48" fill="#7780D9" style="fill:#7780D9;fill:color(display-p3 0.4667 0.5020 0.8510);fill-opacity:1;"/>
<rect x="89.6923" y="70.6923" width="40.6154" height="40.6154" fill="#B9BFFF" style="fill:#B9BFFF;fill:color(display-p3 0.7246 0.7499 1.0000);fill-opacity:1;"/>
<path d="M91.5385 72.5385H95.2308V76.2308H91.5385V72.5385Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M91.5385 78.0769H95.2308V81.7692H91.5385V78.0769Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M91.5385 83.6154H95.2308V87.3077H91.5385V83.6154Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M91.5385 89.1538H95.2308V92.8461H91.5385V89.1538Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M91.5385 94.6923H95.2308V98.3846H91.5385V94.6923Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M91.5385 100.231H95.2308V103.923H91.5385V100.231Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M91.5385 105.769H95.2308V109.462H91.5385V105.769Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M108.154 72.5385H111.846V76.2308H108.154V72.5385Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M108.154 78.0769H111.846V81.7692H108.154V78.0769Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M108.154 83.6154H111.846V87.3077H108.154V83.6154Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M108.154 89.1538H111.846V92.8461H108.154V89.1538Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M108.154 94.6923H111.846V98.3846H108.154V94.6923Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M108.154 100.231H111.846V103.923H108.154V100.231Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M108.154 105.769H111.846V109.462H108.154V105.769Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M97.0768 72.5385H100.769V76.2308H97.0768V72.5385Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M97.0768 78.0769H100.769V81.7692H97.0768V78.0769Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M97.0768 83.6154H100.769V87.3077H97.0768V83.6154Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M97.0768 89.1538H100.769V92.8461H97.0768V89.1538Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M97.0768 94.6923H100.769V98.3846H97.0768V94.6923Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M97.0768 100.231H100.769V103.923H97.0768V100.231Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M97.0768 105.769H100.769V109.462H97.0768V105.769Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M113.692 72.5385H117.385V76.2308H113.692V72.5385Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M113.692 78.0769H117.385V81.7692H113.692V78.0769Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M113.692 83.6154H117.385V87.3077H113.692V83.6154Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M113.692 89.1538H117.385V92.8461H113.692V89.1538Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M113.692 94.6923H117.385V98.3846H113.692V94.6923Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M113.692 100.231H117.385V103.923H113.692V100.231Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M113.692 105.769H117.385V109.462H113.692V105.769Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M102.615 72.5385H106.308V76.2308H102.615V72.5385Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M102.615 78.0769H106.308V81.7692H102.615V78.0769Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M102.615 83.6154H106.308V87.3077H102.615V83.6154Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M102.615 89.1538H106.308V92.8461H102.615V89.1538Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M102.615 94.6923H106.308V98.3846H102.615V94.6923Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M102.615 100.231H106.308V103.923H102.615V100.231Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M102.615 105.769H106.308V109.462H102.615V105.769Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M119.231 72.5385H122.923V76.2308H119.231V72.5385Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M119.231 78.0769H122.923V81.7692H119.231V78.0769Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M119.231 83.6154H122.923V87.3077H119.231V83.6154Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M119.231 89.1538H122.923V92.8461H119.231V89.1538Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M119.231 94.6923H122.923V98.3846H119.231V94.6923Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M119.231 100.231H122.923V103.923H119.231V100.231Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M119.231 105.769H122.923V109.462H119.231V105.769Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M124.769 72.5385H128.462V76.2308H124.769V72.5385Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M124.769 78.0769H128.462V81.7692H124.769V78.0769Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M124.769 83.6154H128.462V87.3077H124.769V83.6154Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M124.769 89.1538H128.462V92.8461H124.769V89.1538Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M124.769 94.6923H128.462V98.3846H124.769V94.6923Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M124.769 100.231H128.462V103.923H124.769V100.231Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M124.769 105.769H128.462V109.462H124.769V105.769Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<circle cx="24" cy="24" r="23.5" fill="url(#paint0_linear_271_1624)" stroke="#B0B7FF" style="stroke:#B0B7FF;stroke:color(display-p3 0.6897 0.7182 1.0000);stroke-opacity:1;"/>
<line x1="23" y1="91" x2="47" y2="91" stroke="black" stroke-opacity="0.2" style="stroke:black;stroke-opacity:0.2;" stroke-width="2"/>
<line x1="67" y1="91" x2="82" y2="91" stroke="black" stroke-opacity="0.2" style="stroke:black;stroke-opacity:0.2;" stroke-width="2"/>
<line x1="24" y1="55" x2="24" y2="90" stroke="black" stroke-opacity="0.2" style="stroke:black;stroke-opacity:0.2;" stroke-width="2"/>
<line x1="110" y1="119" x2="110" y2="144" stroke="black" stroke-opacity="0.2" style="stroke:black;stroke-opacity:0.2;" stroke-width="2"/>
<line x1="82" y1="187" x2="82" y2="206" stroke="black" stroke-opacity="0.1" style="stroke:black;stroke-opacity:0.1;" stroke-width="2" stroke-linecap="square"/>
<line x1="139" y1="186" x2="139" y2="207" stroke="#B0B7FF" style="stroke:#B0B7FF;stroke:color(display-p3 0.6897 0.7182 1.0000);stroke-opacity:1;" stroke-width="2"/>
<rect x="73" y="149" width="75" height="33" stroke="#CCCFEE" style="stroke:#CCCFEE;stroke:color(display-p3 0.7991 0.8104 0.9346);stroke-opacity:1;" stroke-width="2"/>
<rect x="23" y="212" width="75" height="33" stroke="#CCCFEE" style="stroke:#CCCFEE;stroke:color(display-p3 0.7991 0.8104 0.9346);stroke-opacity:1;" stroke-width="2"/>
<rect x="129" y="212" width="75" height="33" stroke="#CCCFEE" style="stroke:#CCCFEE;stroke:color(display-p3 0.7991 0.8104 0.9346);stroke-opacity:1;" stroke-width="2"/>
<rect x="237" y="212" width="75" height="33" stroke="#ABB2FA" style="stroke:#ABB2FA;stroke:color(display-p3 0.6706 0.6980 0.9804);stroke-opacity:1;" stroke-width="2"/>
<path d="M64 90.5L49.75 98.7272L49.75 82.2728L64 90.5Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M229 227.5L214.75 235.727L214.75 219.273L229 227.5Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M82.5305 171V160.05H85.9655C86.6555 160.05 87.2555 160.185 87.7655 160.455C88.2755 160.715 88.6705 161.085 88.9505 161.565C89.2405 162.045 89.3855 162.61 89.3855 163.26C89.3855 163.99 89.1955 164.625 88.8155 165.165C88.4455 165.695 87.9405 166.07 87.3005 166.29L89.5355 171H87.6905L85.6955 166.5H84.1505V171H82.5305ZM84.1505 165.075H85.9655C86.5055 165.075 86.9355 164.915 87.2555 164.595C87.5755 164.265 87.7355 163.83 87.7355 163.29C87.7355 162.73 87.5755 162.29 87.2555 161.97C86.9355 161.65 86.5055 161.49 85.9655 161.49H84.1505V165.075ZM94.0146 171.135C93.3346 171.135 92.7446 171.005 92.2446 170.745C91.7446 170.485 91.3596 170.115 91.0896 169.635C90.8196 169.155 90.6846 168.59 90.6846 167.94V165.81C90.6846 165.15 90.8196 164.585 91.0896 164.115C91.3596 163.635 91.7446 163.265 92.2446 163.005C92.7446 162.745 93.3346 162.615 94.0146 162.615C94.6946 162.615 95.2846 162.745 95.7846 163.005C96.2846 163.265 96.6696 163.635 96.9396 164.115C97.2096 164.585 97.3446 165.15 97.3446 165.81V167.94C97.3446 168.59 97.2096 169.155 96.9396 169.635C96.6696 170.115 96.2846 170.485 95.7846 170.745C95.2846 171.005 94.6946 171.135 94.0146 171.135ZM94.0146 169.71C94.5646 169.71 94.9896 169.56 95.2896 169.26C95.5896 168.95 95.7396 168.51 95.7396 167.94V165.81C95.7396 165.23 95.5896 164.79 95.2896 164.49C94.9896 164.19 94.5646 164.04 94.0146 164.04C93.4746 164.04 93.0496 164.19 92.7396 164.49C92.4396 164.79 92.2896 165.23 92.2896 165.81V167.94C92.2896 168.51 92.4396 168.95 92.7396 169.26C93.0496 169.56 93.4746 169.71 94.0146 169.71ZM102.244 171.15C101.254 171.15 100.464 170.865 99.8738 170.295C99.2838 169.715 98.9888 168.93 98.9888 167.94V162.75H100.609V167.94C100.609 168.51 100.754 168.955 101.044 169.275C101.334 169.585 101.734 169.74 102.244 169.74C102.764 169.74 103.169 169.585 103.459 169.275C103.759 168.955 103.909 168.51 103.909 167.94V162.75H105.529V167.94C105.529 168.93 105.229 169.715 104.629 170.295C104.039 170.865 103.244 171.15 102.244 171.15ZM111.403 171C110.653 171 110.068 170.795 109.648 170.385C109.228 169.975 109.018 169.405 109.018 168.675V164.22H106.738V162.75H109.018V160.425H110.638V162.75H113.863V164.22H110.638V168.675C110.638 169.245 110.913 169.53 111.463 169.53H113.713V171H111.403ZM115.462 171V169.53H118.357V164.22H115.837V162.75H119.932V169.53H122.587V171H115.462ZM118.987 161.325C118.637 161.325 118.357 161.235 118.147 161.055C117.937 160.865 117.832 160.615 117.832 160.305C117.832 159.985 117.937 159.735 118.147 159.555C118.357 159.365 118.637 159.27 118.987 159.27C119.337 159.27 119.617 159.365 119.827 159.555C120.037 159.735 120.142 159.985 120.142 160.305C120.142 160.615 120.037 160.865 119.827 161.055C119.617 161.235 119.337 161.325 118.987 161.325ZM123.751 171V162.75H125.356V164.325H125.746L125.356 164.7C125.356 164.04 125.551 163.525 125.941 163.155C126.331 162.785 126.871 162.6 127.561 162.6C128.381 162.6 129.036 162.865 129.526 163.395C130.016 163.915 130.261 164.62 130.261 165.51V171H128.641V165.69C128.641 165.15 128.496 164.735 128.206 164.445C127.916 164.155 127.521 164.01 127.021 164.01C126.511 164.01 126.106 164.165 125.806 164.475C125.516 164.775 125.371 165.215 125.371 165.795V171H123.751ZM133.075 173.7V172.305H135.61C136.03 172.305 136.34 172.205 136.54 172.005C136.75 171.805 136.855 171.51 136.855 171.12V170.295L136.885 168.765H136.54L136.87 168.465C136.87 169.095 136.67 169.59 136.27 169.95C135.88 170.31 135.35 170.49 134.68 170.49C133.83 170.49 133.16 170.21 132.67 169.65C132.18 169.09 131.935 168.335 131.935 167.385V165.705C131.935 164.755 132.18 164 132.67 163.44C133.16 162.88 133.83 162.6 134.68 162.6C135.35 162.6 135.88 162.785 136.27 163.155C136.67 163.515 136.87 164.01 136.87 164.64L136.54 164.325H136.87L136.855 162.75H138.46V171.15C138.46 171.94 138.21 172.56 137.71 173.01C137.21 173.47 136.515 173.7 135.625 173.7H133.075ZM135.205 169.095C135.715 169.095 136.115 168.94 136.405 168.63C136.705 168.31 136.855 167.87 136.855 167.31V165.795C136.855 165.235 136.705 164.8 136.405 164.49C136.115 164.17 135.715 164.01 135.205 164.01C134.675 164.01 134.265 164.165 133.975 164.475C133.695 164.775 133.555 165.215 133.555 165.795V167.31C133.555 167.88 133.695 168.32 133.975 168.63C134.265 168.94 134.675 169.095 135.205 169.095Z" fill="black" style="fill:black;fill-opacity:1;"/>
<path d="M253.893 234.15C253.213 234.15 252.623 234.025 252.123 233.775C251.633 233.515 251.253 233.145 250.983 232.665C250.723 232.175 250.593 231.605 250.593 230.955V226.095C250.593 225.435 250.723 224.865 250.983 224.385C251.253 223.905 251.633 223.54 252.123 223.29C252.623 223.03 253.213 222.9 253.893 222.9C254.573 222.9 255.158 223.03 255.648 223.29C256.148 223.54 256.528 223.905 256.788 224.385C257.058 224.865 257.193 225.43 257.193 226.08V230.955C257.193 231.605 257.058 232.175 256.788 232.665C256.528 233.145 256.148 233.515 255.648 233.775C255.158 234.025 254.573 234.15 253.893 234.15ZM253.893 232.71C254.443 232.71 254.858 232.56 255.138 232.26C255.428 231.95 255.573 231.515 255.573 230.955V226.095C255.573 225.525 255.428 225.09 255.138 224.79C254.858 224.49 254.443 224.34 253.893 224.34C253.353 224.34 252.938 224.49 252.648 224.79C252.358 225.09 252.213 225.525 252.213 226.095V230.955C252.213 231.515 252.358 231.95 252.648 232.26C252.938 232.56 253.353 232.71 253.893 232.71ZM262.122 234.15C261.132 234.15 260.342 233.865 259.752 233.295C259.162 232.715 258.867 231.93 258.867 230.94V225.75H260.487V230.94C260.487 231.51 260.632 231.955 260.922 232.275C261.212 232.585 261.612 232.74 262.122 232.74C262.642 232.74 263.047 232.585 263.337 232.275C263.637 231.955 263.787 231.51 263.787 230.94V225.75H265.407V230.94C265.407 231.93 265.107 232.715 264.507 233.295C263.917 233.865 263.122 234.15 262.122 234.15ZM271.281 234C270.531 234 269.946 233.795 269.526 233.385C269.106 232.975 268.896 232.405 268.896 231.675V227.22H266.616V225.75H268.896V223.425H270.516V225.75H273.741V227.22H270.516V231.675C270.516 232.245 270.791 232.53 271.341 232.53H273.591V234H271.281ZM275.385 236.7V225.75H276.99V227.325H277.335L276.99 227.7C276.99 227.05 277.19 226.54 277.59 226.17C278 225.79 278.545 225.6 279.225 225.6C280.055 225.6 280.715 225.88 281.205 226.44C281.705 226.99 281.955 227.745 281.955 228.705V231.03C281.955 231.67 281.84 232.225 281.61 232.695C281.39 233.155 281.075 233.515 280.665 233.775C280.265 234.025 279.785 234.15 279.225 234.15C278.555 234.15 278.015 233.965 277.605 233.595C277.195 233.215 276.99 232.7 276.99 232.05L277.335 232.425H276.96L277.005 234.345V236.7H275.385ZM278.67 232.74C279.2 232.74 279.61 232.59 279.9 232.29C280.2 231.98 280.35 231.535 280.35 230.955V228.795C280.35 228.215 280.2 227.775 279.9 227.475C279.61 227.165 279.2 227.01 278.67 227.01C278.16 227.01 277.755 227.17 277.455 227.49C277.155 227.8 277.005 228.235 277.005 228.795V230.955C277.005 231.515 277.155 231.955 277.455 232.275C277.755 232.585 278.16 232.74 278.67 232.74ZM286.854 234.15C285.864 234.15 285.074 233.865 284.484 233.295C283.894 232.715 283.599 231.93 283.599 230.94V225.75H285.219V230.94C285.219 231.51 285.364 231.955 285.654 232.275C285.944 232.585 286.344 232.74 286.854 232.74C287.374 232.74 287.779 232.585 288.069 232.275C288.369 231.955 288.519 231.51 288.519 230.94V225.75H290.139V230.94C290.139 231.93 289.839 232.715 289.239 233.295C288.649 233.865 287.854 234.15 286.854 234.15ZM296.013 234C295.263 234 294.678 233.795 294.258 233.385C293.838 232.975 293.628 232.405 293.628 231.675V227.22H291.348V225.75H293.628V223.425H295.248V225.75H298.473V227.22H295.248V231.675C295.248 232.245 295.523 232.53 296.073 232.53H298.323V234H296.013Z" fill="black" style="fill:black;fill-opacity:1;"/>
<path d="M31.9155 234L34.7055 223.05H36.8355L39.6255 234H37.9905L37.3305 231.225H34.2255L33.5655 234H31.9155ZM34.5255 229.89H37.0155L36.2655 226.725C36.1355 226.165 36.0255 225.68 35.9355 225.27C35.8555 224.85 35.8005 224.565 35.7705 224.415C35.7405 224.565 35.6855 224.85 35.6055 225.27C35.5255 225.68 35.4155 226.16 35.2755 226.71L34.5255 229.89ZM41.8546 236.7V235.305H44.3896C44.8096 235.305 45.1196 235.205 45.3196 235.005C45.5296 234.805 45.6346 234.51 45.6346 234.12V233.295L45.6646 231.765H45.3196L45.6496 231.465C45.6496 232.095 45.4496 232.59 45.0496 232.95C44.6596 233.31 44.1296 233.49 43.4596 233.49C42.6096 233.49 41.9396 233.21 41.4496 232.65C40.9596 232.09 40.7146 231.335 40.7146 230.385V228.705C40.7146 227.755 40.9596 227 41.4496 226.44C41.9396 225.88 42.6096 225.6 43.4596 225.6C44.1296 225.6 44.6596 225.785 45.0496 226.155C45.4496 226.515 45.6496 227.01 45.6496 227.64L45.3196 227.325H45.6496L45.6346 225.75H47.2396V234.15C47.2396 234.94 46.9896 235.56 46.4896 236.01C45.9896 236.47 45.2946 236.7 44.4046 236.7H41.8546ZM43.9846 232.095C44.4946 232.095 44.8946 231.94 45.1846 231.63C45.4846 231.31 45.6346 230.87 45.6346 230.31V228.795C45.6346 228.235 45.4846 227.8 45.1846 227.49C44.8946 227.17 44.4946 227.01 43.9846 227.01C43.4546 227.01 43.0446 227.165 42.7546 227.475C42.4746 227.775 42.3346 228.215 42.3346 228.795V230.31C42.3346 230.88 42.4746 231.32 42.7546 231.63C43.0446 231.94 43.4546 232.095 43.9846 232.095ZM52.2588 234.15C51.5888 234.15 50.9988 234.02 50.4888 233.76C49.9888 233.49 49.6038 233.115 49.3338 232.635C49.0638 232.155 48.9288 231.595 48.9288 230.955V228.795C48.9288 228.145 49.0638 227.585 49.3338 227.115C49.6038 226.635 49.9888 226.265 50.4888 226.005C50.9988 225.735 51.5888 225.6 52.2588 225.6C52.9388 225.6 53.5288 225.735 54.0288 226.005C54.5288 226.265 54.9138 226.635 55.1838 227.115C55.4538 227.585 55.5888 228.145 55.5888 228.795V230.265H50.4888V230.955C50.4888 231.565 50.6388 232.03 50.9388 232.35C51.2488 232.67 51.6938 232.83 52.2738 232.83C52.7438 232.83 53.1238 232.75 53.4138 232.59C53.7038 232.42 53.8838 232.175 53.9538 231.855H55.5588C55.4388 232.555 55.0788 233.115 54.4788 233.535C53.8788 233.945 53.1388 234.15 52.2588 234.15ZM54.0288 229.29V228.78C54.0288 228.18 53.8788 227.715 53.5788 227.385C53.2788 227.055 52.8388 226.89 52.2588 226.89C51.6888 226.89 51.2488 227.055 50.9388 227.385C50.6388 227.715 50.4888 228.185 50.4888 228.795V229.17L54.1488 229.155L54.0288 229.29ZM57.2629 234V225.75H58.8679V227.325H59.2579L58.8679 227.7C58.8679 227.04 59.0629 226.525 59.4529 226.155C59.8429 225.785 60.3829 225.6 61.0729 225.6C61.8929 225.6 62.5479 225.865 63.0379 226.395C63.5279 226.915 63.7729 227.62 63.7729 228.51V234H62.1529V228.69C62.1529 228.15 62.0079 227.735 61.7179 227.445C61.4279 227.155 61.0329 227.01 60.5329 227.01C60.0229 227.01 59.6179 227.165 59.3179 227.475C59.0279 227.775 58.8829 228.215 58.8829 228.795V234H57.2629ZM69.6471 234C68.8971 234 68.3121 233.795 67.8921 233.385C67.4721 232.975 67.2621 232.405 67.2621 231.675V227.22H64.9821V225.75H67.2621V223.425H68.8821V225.75H72.1071V227.22H68.8821V231.675C68.8821 232.245 69.1571 232.53 69.7071 232.53H71.9571V234H69.6471ZM81.3804 234L84.1704 223.05H86.3004L89.0904 234H87.4554L86.7954 231.225H83.6904L83.0304 234H81.3804ZM83.9904 229.89H86.4804L85.7304 226.725C85.6004 226.165 85.4904 225.68 85.4004 225.27C85.3204 224.85 85.2654 224.565 85.2354 224.415C85.2054 224.565 85.1504 224.85 85.0704 225.27C84.9904 225.68 84.8804 226.16 84.7404 226.71L83.9904 229.89Z" fill="black" fill-opacity="0.43" style="fill:black;fill-opacity:0.43;"/>
<path d="M137.916 234L140.706 223.05H142.836L145.626 234H143.991L143.331 231.225H140.226L139.566 234H137.916ZM140.526 229.89H143.016L142.266 226.725C142.136 226.165 142.026 225.68 141.936 225.27C141.856 224.85 141.801 224.565 141.771 224.415C141.741 224.565 141.686 224.85 141.606 225.27C141.526 225.68 141.416 226.16 141.276 226.71L140.526 229.89ZM147.855 236.7V235.305H150.39C150.81 235.305 151.12 235.205 151.32 235.005C151.53 234.805 151.635 234.51 151.635 234.12V233.295L151.665 231.765H151.32L151.65 231.465C151.65 232.095 151.45 232.59 151.05 232.95C150.66 233.31 150.13 233.49 149.46 233.49C148.61 233.49 147.94 233.21 147.45 232.65C146.96 232.09 146.715 231.335 146.715 230.385V228.705C146.715 227.755 146.96 227 147.45 226.44C147.94 225.88 148.61 225.6 149.46 225.6C150.13 225.6 150.66 225.785 151.05 226.155C151.45 226.515 151.65 227.01 151.65 227.64L151.32 227.325H151.65L151.635 225.75H153.24V234.15C153.24 234.94 152.99 235.56 152.49 236.01C151.99 236.47 151.295 236.7 150.405 236.7H147.855ZM149.985 232.095C150.495 232.095 150.895 231.94 151.185 231.63C151.485 231.31 151.635 230.87 151.635 230.31V228.795C151.635 228.235 151.485 227.8 151.185 227.49C150.895 227.17 150.495 227.01 149.985 227.01C149.455 227.01 149.045 227.165 148.755 227.475C148.475 227.775 148.335 228.215 148.335 228.795V230.31C148.335 230.88 148.475 231.32 148.755 231.63C149.045 231.94 149.455 232.095 149.985 232.095ZM158.259 234.15C157.589 234.15 156.999 234.02 156.489 233.76C155.989 233.49 155.604 233.115 155.334 232.635C155.064 232.155 154.929 231.595 154.929 230.955V228.795C154.929 228.145 155.064 227.585 155.334 227.115C155.604 226.635 155.989 226.265 156.489 226.005C156.999 225.735 157.589 225.6 158.259 225.6C158.939 225.6 159.529 225.735 160.029 226.005C160.529 226.265 160.914 226.635 161.184 227.115C161.454 227.585 161.589 228.145 161.589 228.795V230.265H156.489V230.955C156.489 231.565 156.639 232.03 156.939 232.35C157.249 232.67 157.694 232.83 158.274 232.83C158.744 232.83 159.124 232.75 159.414 232.59C159.704 232.42 159.884 232.175 159.954 231.855H161.559C161.439 232.555 161.079 233.115 160.479 233.535C159.879 233.945 159.139 234.15 158.259 234.15ZM160.029 229.29V228.78C160.029 228.18 159.879 227.715 159.579 227.385C159.279 227.055 158.839 226.89 158.259 226.89C157.689 226.89 157.249 227.055 156.939 227.385C156.639 227.715 156.489 228.185 156.489 228.795V229.17L160.149 229.155L160.029 229.29ZM163.263 234V225.75H164.868V227.325H165.258L164.868 227.7C164.868 227.04 165.063 226.525 165.453 226.155C165.843 225.785 166.383 225.6 167.073 225.6C167.893 225.6 168.548 225.865 169.038 226.395C169.528 226.915 169.773 227.62 169.773 228.51V234H168.153V228.69C168.153 228.15 168.008 227.735 167.718 227.445C167.428 227.155 167.033 227.01 166.533 227.01C166.023 227.01 165.618 227.165 165.318 227.475C165.028 227.775 164.883 228.215 164.883 228.795V234H163.263ZM175.647 234C174.897 234 174.312 233.795 173.892 233.385C173.472 232.975 173.262 232.405 173.262 231.675V227.22H170.982V225.75H173.262V223.425H174.882V225.75H178.107V227.22H174.882V231.675C174.882 232.245 175.157 232.53 175.707 232.53H177.957V234H175.647ZM188.01 234V223.05H191.235C192.275 223.05 193.09 223.3 193.68 223.8C194.27 224.3 194.565 224.99 194.565 225.87C194.565 226.37 194.455 226.805 194.235 227.175C194.025 227.535 193.73 227.815 193.35 228.015C192.97 228.215 192.525 228.315 192.015 228.315V228.165C192.565 228.155 193.05 228.26 193.47 228.48C193.89 228.69 194.22 229.005 194.46 229.425C194.7 229.845 194.82 230.345 194.82 230.925C194.82 231.545 194.68 232.09 194.4 232.56C194.13 233.02 193.74 233.375 193.23 233.625C192.73 233.875 192.135 234 191.445 234H188.01ZM189.585 232.605H191.31C191.89 232.605 192.35 232.45 192.69 232.14C193.03 231.83 193.2 231.4 193.2 230.85C193.2 230.29 193.03 229.84 192.69 229.5C192.35 229.16 191.89 228.99 191.31 228.99H189.585V232.605ZM189.585 227.64H191.22C191.76 227.64 192.185 227.495 192.495 227.205C192.805 226.915 192.96 226.525 192.96 226.035C192.96 225.545 192.805 225.16 192.495 224.88C192.185 224.59 191.765 224.445 191.235 224.445H189.585V227.64Z" fill="black" style="fill:black;fill-opacity:1;"/>
<defs>
<linearGradient id="paint0_linear_271_1624" x1="24.6154" y1="-8.61538" x2="24" y2="48" gradientUnits="userSpaceOnUse">
<stop stop-color="#5A57E9" style="stop-color:#5A57E9;stop-color:color(display-p3 0.3512 0.3417 0.9119);stop-opacity:1;"/>
<stop offset="1" stop-color="white" style="stop-color:white;stop-opacity:1;"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 25 KiB

View file

@ -0,0 +1,53 @@
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="26" height="26" fill="#7780D9" style="fill:#7780D9;fill:color(display-p3 0.4667 0.5020 0.8510);fill-opacity:1;"/>
<rect x="2" y="2" width="22" height="22" fill="#B9BFFF" style="fill:#B9BFFF;fill:color(display-p3 0.7246 0.7499 1.0000);fill-opacity:1;"/>
<path d="M3 3H5V5H3V3Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3 6H5V8H3V6Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3 9H5V11H3V9Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3 12H5V14H3V12Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3 15H5V17H3V15Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3 18H5V20H3V18Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3 21H5V23H3V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 3H14V5H12V3Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M12 6H14V8H12V6Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M12 9H14V11H12V9Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M12 12H14V14H12V12Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 15H14V17H12V15Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 18H14V20H12V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 21H14V23H12V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M6 3H8V5H6V3Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M6 6H8V8H6V6Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M6 9H8V11H6V9Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M6 12H8V14H6V12Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M6 15H8V17H6V15Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M6 18H8V20H6V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M6 21H8V23H6V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 3H17V5H15V3Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M15 6H17V8H15V6Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M15 9H17V11H15V9Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 12H17V14H15V12Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 15H17V17H15V15Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 18H17V20H15V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 21H17V23H15V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M9 3H11V5H9V3Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M9 6H11V8H9V6Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M9 9H11V11H9V9Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M9 12H11V14H9V12Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M9 15H11V17H9V15Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M9 18H11V20H9V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M9 21H11V23H9V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 3H20V5H18V3Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M18 6H20V8H18V6Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 9H20V11H18V9Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 12H20V14H18V12Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 15H20V17H18V15Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 18H20V20H18V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 21H20V23H18V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 3H23V5H21V3Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 6H23V8H21V6Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 9H23V11H21V9Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 12H23V14H21V12Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 15H23V17H21V15Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 18H23V20H21V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 21H23V23H21V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
</svg>

After

Width:  |  Height:  |  Size: 6.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -0,0 +1,54 @@
<svg width="126" height="48" viewBox="0 0 126 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M33.723 43.0923V17.2768H38.0374V20.99H39.0276L38.0374 22.0156C38.0374 20.436 38.5089 19.1983 39.4519 18.3024C40.3949 17.3829 41.668 16.9232 43.2712 16.9232C45.228 16.9232 46.7958 17.5951 47.9746 18.9389C49.1534 20.2828 49.7427 22.0863 49.7427 24.3496V29.6188C49.7427 31.1276 49.4716 32.4479 48.9294 33.5795C48.4107 34.6876 47.6681 35.5481 46.7015 36.161C45.7349 36.774 44.5914 37.0805 43.2712 37.0805C41.668 37.0805 40.3949 36.6326 39.4519 35.7367C38.5089 34.8172 38.0374 33.5677 38.0374 31.9881L39.0276 33.0137H38.002L38.1435 37.6463V43.0923H33.723ZM41.7152 33.2612C42.8468 33.2612 43.7309 32.9312 44.3675 32.271C45.004 31.6109 45.3223 30.6679 45.3223 29.442V24.5618C45.3223 23.3358 45.004 22.3928 44.3675 21.7327C43.7309 21.0725 42.8468 20.7425 41.7152 20.7425C40.6071 20.7425 39.7348 21.0843 39.0983 21.768C38.4617 22.4282 38.1435 23.3594 38.1435 24.5618V29.442C38.1435 30.6443 38.4617 31.5873 39.0983 32.271C39.7348 32.9312 40.6071 33.2612 41.7152 33.2612ZM62.9549 36.7269C61.6819 36.7269 60.562 36.4675 59.5954 35.9489C58.6524 35.4302 57.9097 34.6994 57.3675 33.7563C56.8252 32.7897 56.5541 31.6817 56.5541 30.4321V14.9075H50.3301V10.9114H60.9746V30.4321C60.9746 31.1394 61.175 31.7052 61.5758 32.1296C62.0001 32.5304 62.5659 32.7308 63.2732 32.7308H69.1436V36.7269H62.9549ZM76.2025 37.0805C74.1986 37.0805 72.619 36.55 71.4638 35.4891C70.3086 34.4282 69.731 33.0019 69.731 31.2101C69.731 29.3005 70.3675 27.827 71.6406 26.7897C72.9137 25.7523 74.7172 25.2337 77.0512 25.2337H81.8961V23.5716C81.8961 22.6285 81.5896 21.8977 80.9766 21.379C80.3636 20.8368 79.5267 20.5657 78.4658 20.5657C77.4992 20.5657 76.6976 20.7779 76.0611 21.2022C75.4245 21.6266 75.0473 22.2042 74.9294 22.935H70.6151C70.8272 21.0961 71.6524 19.6344 73.0905 18.5499C74.5286 17.4655 76.3675 16.9232 78.6072 16.9232C80.9884 16.9232 82.8627 17.5244 84.2301 18.7268C85.621 19.9055 86.3165 21.5087 86.3165 23.5362V36.7269H82.0375V33.332H81.3302L82.0375 32.3771C82.0375 33.8153 81.5071 34.9587 80.4462 35.8074C79.3852 36.6561 77.9707 37.0805 76.2025 37.0805ZM77.6524 33.7563C78.9019 33.7563 79.9157 33.438 80.6937 32.8015C81.4953 32.165 81.8961 31.3398 81.8961 30.326V27.9567H77.122C76.2261 27.9567 75.507 28.216 74.9648 28.7347C74.4225 29.2533 74.1514 29.937 74.1514 30.7858C74.1514 31.7052 74.4579 32.4361 75.0709 32.9783C75.7074 33.497 76.5679 33.7563 77.6524 33.7563ZM88.8489 36.7269V17.2768H93.1633V20.99H94.3656L93.1633 22.0156C93.1633 20.4124 93.623 19.1629 94.5424 18.267C95.4855 17.3711 96.7704 16.9232 98.3971 16.9232C100.307 16.9232 101.827 17.5598 102.959 18.8328C104.114 20.1059 104.692 21.8152 104.692 23.9606V36.7269H100.271V24.4203C100.271 23.2415 99.9649 22.3339 99.3519 21.6973C98.7389 21.0608 97.8784 20.7425 96.7704 20.7425C95.6859 20.7425 94.8254 21.0725 94.1888 21.7327C93.5758 22.3928 93.2694 23.3358 93.2694 24.5618V36.7269H88.8489ZM115.11 37.0451C113.46 37.0451 112.022 36.7387 110.796 36.1257C109.594 35.4891 108.651 34.605 107.967 33.4734C107.307 32.3182 106.977 30.9626 106.977 29.4066V24.5971C106.977 23.0411 107.307 21.6973 107.967 20.5657C108.651 19.4105 109.594 18.5264 110.796 17.9134C112.022 17.2768 113.46 16.9586 115.11 16.9586C116.784 16.9586 118.222 17.2768 119.425 17.9134C120.627 18.5264 121.558 19.4105 122.218 20.5657C122.902 21.6973 123.244 23.0293 123.244 24.5618V29.4066C123.244 30.9626 122.902 32.3182 122.218 33.4734C121.558 34.605 120.627 35.4891 119.425 36.1257C118.222 36.7387 116.784 37.0451 115.11 37.0451ZM115.11 33.1905C116.289 33.1905 117.197 32.8722 117.833 32.2357C118.493 31.5756 118.823 30.6325 118.823 29.4066V24.5971C118.823 23.3476 118.493 22.4046 117.833 21.768C117.197 21.1315 116.289 20.8132 115.11 20.8132C113.955 20.8132 113.047 21.1315 112.387 21.768C111.727 22.4046 111.397 23.3476 111.397 24.5971V29.4066C111.397 30.6325 111.727 31.5756 112.387 32.2357C113.047 32.8722 113.955 33.1905 115.11 33.1905Z" fill="#7780D9" style="fill:#7780D9;fill:color(display-p3 0.4667 0.5020 0.8510);fill-opacity:1;"/>
<rect y="11" width="26" height="26" fill="#7780D9" style="fill:#7780D9;fill:color(display-p3 0.4667 0.5020 0.8510);fill-opacity:1;"/>
<rect x="2" y="13" width="22" height="22" fill="#B9BFFF" style="fill:#B9BFFF;fill:color(display-p3 0.7246 0.7499 1.0000);fill-opacity:1;"/>
<path d="M3 14H5V16H3V14Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3 17H5V19H3V17Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3 20H5V22H3V20Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3 23H5V25H3V23Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3 26H5V28H3V26Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3 29H5V31H3V29Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3 32H5V34H3V32Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 14H14V16H12V14Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M12 17H14V19H12V17Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M12 20H14V22H12V20Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M12 23H14V25H12V23Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 26H14V28H12V26Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 29H14V31H12V29Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 32H14V34H12V32Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M6 14H8V16H6V14Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M6 17H8V19H6V17Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M6 20H8V22H6V20Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M6 23H8V25H6V23Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M6 26H8V28H6V26Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M6 29H8V31H6V29Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M6 32H8V34H6V32Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 14H17V16H15V14Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M15 17H17V19H15V17Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M15 20H17V22H15V20Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 23H17V25H15V23Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 26H17V28H15V26Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 29H17V31H15V29Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 32H17V34H15V32Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M9 14H11V16H9V14Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M9 17H11V19H9V17Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M9 20H11V22H9V20Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M9 23H11V25H9V23Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M9 26H11V28H9V26Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M9 29H11V31H9V29Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M9 32H11V34H9V32Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 14H20V16H18V14Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M18 17H20V19H18V17Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 20H20V22H18V20Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 23H20V25H18V23Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 26H20V28H18V26Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 29H20V31H18V29Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 32H20V34H18V32Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 14H23V16H21V14Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 17H23V19H21V17Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 20H23V22H21V20Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 23H23V25H21V23Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 26H23V28H21V26Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 29H23V31H21V29Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 32H23V34H21V32Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 70 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 34 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -0,0 +1,54 @@
<svg width="235" height="60" viewBox="0 0 235 60" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M43.5977 54.2294V20.8547H49.1754V25.6551H50.4555L49.1754 26.981C49.1754 24.9389 49.785 23.3387 51.0041 22.1805C52.2233 20.9918 53.8692 20.3975 55.9417 20.3975C58.4715 20.3975 60.4984 21.2661 62.0223 23.0035C63.5463 24.7408 64.3083 27.0724 64.3083 29.9984V36.8105C64.3083 38.7612 63.9578 40.468 63.2568 41.931C62.5862 43.3635 61.6261 44.476 60.3765 45.2685C59.1268 46.061 57.6486 46.4572 55.9417 46.4572C53.8692 46.4572 52.2233 45.8781 51.0041 44.7199C49.785 43.5312 49.1754 41.9158 49.1754 39.8737L50.4555 41.1995H49.1297L49.3125 47.1887V54.2294H43.5977ZM53.9301 41.5196C55.3931 41.5196 56.5361 41.0929 57.359 40.2394C58.182 39.386 58.5934 38.1668 58.5934 36.5819V30.2727C58.5934 28.6878 58.182 27.4687 57.359 26.6152C56.5361 25.7618 55.3931 25.3351 53.9301 25.3351C52.4976 25.3351 51.3699 25.7771 50.5469 26.661C49.724 27.5144 49.3125 28.7183 49.3125 30.2727V36.5819C49.3125 38.1364 49.724 39.3555 50.5469 40.2394C51.3699 41.0929 52.4976 41.5196 53.9301 41.5196ZM81.3893 46C79.7434 46 78.2956 45.6647 77.046 44.9942C75.8268 44.3236 74.8667 43.3788 74.1657 42.1596C73.4647 40.91 73.1142 39.4775 73.1142 37.8621V17.7915H65.0676V12.6253H78.829V37.8621C78.829 38.7764 79.0881 39.5079 79.6062 40.0566C80.1548 40.5747 80.8863 40.8338 81.8007 40.8338H89.39V46H81.3893ZM98.5159 46.4572C95.9252 46.4572 93.8831 45.7714 92.3896 44.3998C90.8961 43.0283 90.1494 41.1843 90.1494 38.8679C90.1494 36.3991 90.9723 34.4941 92.6182 33.153C94.2641 31.8119 96.5958 31.1414 99.6132 31.1414H105.877V28.9926C105.877 27.7734 105.48 26.8286 104.688 26.158C103.896 25.457 102.814 25.1065 101.442 25.1065C100.192 25.1065 99.156 25.3808 98.3331 25.9295C97.5101 26.4781 97.0225 27.2248 96.8701 28.1697H91.2924C91.5667 25.7923 92.6335 23.9026 94.4927 22.5005C96.3519 21.0985 98.7293 20.3975 101.625 20.3975C104.703 20.3975 107.126 21.1747 108.894 22.7291C110.692 24.2531 111.592 26.3257 111.592 28.9469V46H106.06V41.611H105.145L106.06 40.3766C106.06 42.2358 105.374 43.7141 104.002 44.8113C102.631 45.9086 100.802 46.4572 98.5159 46.4572ZM100.39 42.1596C102.006 42.1596 103.316 41.7482 104.322 40.9252C105.359 40.1023 105.877 39.0355 105.877 37.7249V34.6617H99.7046C98.5464 34.6617 97.6168 34.997 96.9158 35.6676C96.2148 36.3381 95.8642 37.222 95.8642 38.3192C95.8642 39.5079 96.2605 40.4528 97.0529 41.1538C97.8759 41.8244 98.9884 42.1596 100.39 42.1596ZM114.865 46V20.8547H120.443V25.6551H121.998L120.443 26.981C120.443 24.9084 121.037 23.293 122.226 22.1348C123.445 20.9766 125.106 20.3975 127.209 20.3975C129.678 20.3975 131.644 21.2204 133.107 22.8663C134.601 24.5122 135.347 26.7219 135.347 29.4955V46H129.633V30.0899C129.633 28.5659 129.236 27.3925 128.444 26.5695C127.651 25.7466 126.539 25.3351 125.106 25.3351C123.704 25.3351 122.592 25.7618 121.769 26.6152C120.976 27.4687 120.58 28.6878 120.58 30.2727V46H114.865ZM148.817 46.4115C146.683 46.4115 144.824 46.0152 143.239 45.2228C141.684 44.3998 140.465 43.2569 139.581 41.7939C138.728 40.3004 138.301 38.5478 138.301 36.5362V30.3185C138.301 28.3068 138.728 26.5695 139.581 25.1065C140.465 23.613 141.684 22.4701 143.239 21.6776C144.824 20.8547 146.683 20.4432 148.817 20.4432C150.981 20.4432 152.84 20.8547 154.394 21.6776C155.949 22.4701 157.153 23.613 158.006 25.1065C158.89 26.5695 159.332 28.2916 159.332 30.2727V36.5362C159.332 38.5478 158.89 40.3004 158.006 41.7939C157.153 43.2569 155.949 44.3998 154.394 45.2228C152.84 46.0152 150.981 46.4115 148.817 46.4115ZM148.817 41.4281C150.341 41.4281 151.514 41.0167 152.337 40.1937C153.19 39.3403 153.617 38.1211 153.617 36.5362V30.3185C153.617 28.7031 153.19 27.4839 152.337 26.661C151.514 25.838 150.341 25.4265 148.817 25.4265C147.323 25.4265 146.15 25.838 145.296 26.661C144.443 27.4839 144.016 28.7031 144.016 30.3185V36.5362C144.016 38.1211 144.443 39.3403 145.296 40.1937C146.15 41.0167 147.323 41.4281 148.817 41.4281ZM165.258 33.5645V28.2611H179.888V33.5645H165.258ZM200.443 46V39.3708H185.585V31.0957L198.431 12.6253H204.832L191.071 32.6044V34.3417H200.443V26.7981H206.158V46H200.443ZM222.233 46.4572C220.161 46.4572 218.515 45.8781 217.295 44.7199C216.076 43.5312 215.467 41.9158 215.467 39.8737L216.747 41.1995H215.467V46H209.889V12.6253H215.604V19.666L215.421 25.6551H216.747L215.467 26.981C215.467 24.9389 216.076 23.3387 217.295 22.1805C218.515 20.9918 220.161 20.3975 222.233 20.3975C224.763 20.3975 226.79 21.2661 228.314 23.0035C229.838 24.7408 230.6 27.0877 230.6 30.0441V36.8562C230.6 39.7822 229.838 42.1139 228.314 43.8512C226.79 45.5885 224.763 46.4572 222.233 46.4572ZM220.221 41.5196C221.684 41.5196 222.827 41.0929 223.65 40.2394C224.473 39.386 224.885 38.1668 224.885 36.5819V30.2727C224.885 28.6878 224.473 27.4687 223.65 26.6152C222.827 25.7618 221.684 25.3351 220.221 25.3351C218.789 25.3351 217.661 25.7771 216.838 26.661C216.015 27.5144 215.604 28.7183 215.604 30.2727V36.5819C215.604 38.1364 216.015 39.3555 216.838 40.2394C217.661 41.0929 218.789 41.5196 220.221 41.5196Z" fill="#7780D9" style="fill:#7780D9;fill:color(display-p3 0.4667 0.5020 0.8510);fill-opacity:1;"/>
<rect y="13.2812" width="33.6133" height="33.6133" fill="#7780D9" style="fill:#7780D9;fill:color(display-p3 0.4667 0.5020 0.8510);fill-opacity:1;"/>
<rect x="2.58563" y="15.8672" width="28.442" height="28.442" fill="#B9BFFF" style="fill:#B9BFFF;fill:color(display-p3 0.7246 0.7499 1.0000);fill-opacity:1;"/>
<path d="M3.87848 17.1602H6.46411V19.7458H3.87848V17.1602Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3.87848 21.0381H6.46411V23.6237H3.87848V21.0381Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3.87848 24.917H6.46411V27.5026H3.87848V24.917Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3.87848 28.7949H6.46411V31.3806H3.87848V28.7949Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3.87848 32.6738H6.46411V35.2595H3.87848V32.6738Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3.87848 36.5518H6.46411V39.1374H3.87848V36.5518Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3.87848 40.4307H6.46411V43.0163H3.87848V40.4307Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15.5138 17.1602H18.0994V19.7458H15.5138V17.1602Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M15.5138 21.0381H18.0994V23.6237H15.5138V21.0381Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M15.5138 24.917H18.0994V27.5026H15.5138V24.917Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M15.5138 28.7949H18.0994V31.3806H15.5138V28.7949Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15.5138 32.6738H18.0994V35.2595H15.5138V32.6738Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15.5138 36.5518H18.0994V39.1374H15.5138V36.5518Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15.5138 40.4307H18.0994V43.0163H15.5138V40.4307Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M7.7569 17.1602H10.3425V19.7458H7.7569V17.1602Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M7.7569 21.0381H10.3425V23.6237H7.7569V21.0381Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M7.7569 24.917H10.3425V27.5026H7.7569V24.917Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M7.7569 28.7949H10.3425V31.3806H7.7569V28.7949Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M7.7569 32.6738H10.3425V35.2595H7.7569V32.6738Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M7.7569 36.5518H10.3425V39.1374H7.7569V36.5518Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M7.7569 40.4307H10.3425V43.0163H7.7569V40.4307Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M19.3923 17.1602H21.9779V19.7458H19.3923V17.1602Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M19.3923 21.0381H21.9779V23.6237H19.3923V21.0381Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M19.3923 24.917H21.9779V27.5026H19.3923V24.917Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M19.3923 28.7949H21.9779V31.3806H19.3923V28.7949Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M19.3923 32.6738H21.9779V35.2595H19.3923V32.6738Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M19.3923 36.5518H21.9779V39.1374H19.3923V36.5518Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M19.3923 40.4307H21.9779V43.0163H19.3923V40.4307Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M11.6354 17.1602H14.221V19.7458H11.6354V17.1602Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M11.6354 21.0381H14.221V23.6237H11.6354V21.0381Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M11.6354 24.917H14.221V27.5026H11.6354V24.917Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M11.6354 28.7949H14.221V31.3806H11.6354V28.7949Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M11.6354 32.6738H14.221V35.2595H11.6354V32.6738Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M11.6354 36.5518H14.221V39.1374H11.6354V36.5518Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M11.6354 40.4307H14.221V43.0163H11.6354V40.4307Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M23.2707 17.1602H25.8563V19.7458H23.2707V17.1602Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M23.2707 21.0381H25.8563V23.6237H23.2707V21.0381Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M23.2707 24.917H25.8563V27.5026H23.2707V24.917Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M23.2707 28.7949H25.8563V31.3806H23.2707V28.7949Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M23.2707 32.6738H25.8563V35.2595H23.2707V32.6738Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M23.2707 36.5518H25.8563V39.1374H23.2707V36.5518Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M23.2707 40.4307H25.8563V43.0163H23.2707V40.4307Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M27.1492 17.1602H29.7348V19.7458H27.1492V17.1602Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M27.1492 21.0381H29.7348V23.6237H27.1492V21.0381Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M27.1492 24.917H29.7348V27.5026H27.1492V24.917Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M27.1492 28.7949H29.7348V31.3806H27.1492V28.7949Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M27.1492 32.6738H29.7348V35.2595H27.1492V32.6738Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M27.1492 36.5518H29.7348V39.1374H27.1492V36.5518Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M27.1492 40.4307H29.7348V43.0163H27.1492V40.4307Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -0,0 +1,53 @@
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="26" height="26" fill="#7780D9" style="fill:#7780D9;fill:color(display-p3 0.4667 0.5020 0.8510);fill-opacity:1;"/>
<rect x="2" y="2" width="22" height="22" fill="#B9BFFF" style="fill:#B9BFFF;fill:color(display-p3 0.7246 0.7499 1.0000);fill-opacity:1;"/>
<path d="M3 3H5V5H3V3Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3 6H5V8H3V6Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3 9H5V11H3V9Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M3 12H5V14H3V12Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3 15H5V17H3V15Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3 18H5V20H3V18Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M3 21H5V23H3V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 3H14V5H12V3Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M12 6H14V8H12V6Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M12 9H14V11H12V9Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M12 12H14V14H12V12Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 15H14V17H12V15Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 18H14V20H12V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M12 21H14V23H12V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M6 3H8V5H6V3Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M6 6H8V8H6V6Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M6 9H8V11H6V9Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M6 12H8V14H6V12Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M6 15H8V17H6V15Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M6 18H8V20H6V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M6 21H8V23H6V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 3H17V5H15V3Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M15 6H17V8H15V6Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M15 9H17V11H15V9Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 12H17V14H15V12Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 15H17V17H15V15Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 18H17V20H15V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M15 21H17V23H15V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M9 3H11V5H9V3Z" fill="#B0B7FF" style="fill:#B0B7FF;fill:color(display-p3 0.6897 0.7182 1.0000);fill-opacity:1;"/>
<path d="M9 6H11V8H9V6Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M9 9H11V11H9V9Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M9 12H11V14H9V12Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M9 15H11V17H9V15Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M9 18H11V20H9V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M9 21H11V23H9V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 3H20V5H18V3Z" fill="#ABB2FA" style="fill:#ABB2FA;fill:color(display-p3 0.6706 0.6990 0.9799);fill-opacity:1;"/>
<path d="M18 6H20V8H18V6Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 9H20V11H18V9Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 12H20V14H18V12Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 15H20V17H18V15Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 18H20V20H18V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M18 21H20V23H18V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 3H23V5H21V3Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 6H23V8H21V6Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 9H23V11H21V9Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 12H23V14H21V12Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 15H23V17H21V15Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 18H23V20H21V18Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
<path d="M21 21H23V23H21V21Z" fill="#969FF4" style="fill:#969FF4;fill:color(display-p3 0.5882 0.6220 0.9566);fill-opacity:1;"/>
</svg>

After

Width:  |  Height:  |  Size: 6.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 24 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 48 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 26 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 134 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 102 KiB

1
apps/www/public/file.svg Normal file
View file

@ -0,0 +1 @@
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 28.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="STANDARD_UPDATE" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 1000 141.83" style="enable-background:new 0 0 1000 141.83;" xml:space="preserve">
<path d="M267.52,104.26c2.51,1.01,6.23,1.66,11.16,1.96v2.11h-55.64v-2.11c4.92-0.3,8.65-0.95,11.16-1.96c2.51-1,4.25-2.61,5.2-4.83
c0.95-2.21,1.43-5.48,1.43-9.8V22.37h-0.45l-38.15,87.92h-0.45l-40.87-87.61h-0.45v66.95c0,4.32,0.5,7.59,1.51,9.8
c1,2.21,2.74,3.82,5.2,4.83c2.46,1.01,6.16,1.66,11.08,1.96v2.11H135.8v-2.11c4.92-0.3,8.62-0.95,11.08-1.96
c2.46-1,4.2-2.61,5.2-4.83c1-2.21,1.51-5.48,1.51-9.8V22.22c0-4.32-0.5-7.59-1.51-9.8c-1.01-2.21-2.74-3.82-5.2-4.83
c-2.47-1-6.16-1.66-11.08-1.96V3.52h38.08l34.78,75.93l33.73-75.93h36.29v2.11c-4.93,0.3-8.65,0.96-11.16,1.96
c-2.51,1.01-4.27,2.64-5.28,4.9c-1.01,2.26-1.51,5.5-1.51,9.73v67.41c0,4.32,0.5,7.59,1.51,9.8
C263.25,101.65,265.01,103.25,267.52,104.26z M343.12,53.44c3.11,5.73,4.67,12.21,4.67,19.45c0,7.24-1.56,13.72-4.67,19.45
c-3.12,5.73-7.46,10.16-13.04,13.27c-5.58,3.12-11.94,4.68-19.08,4.68c-7.14,0-13.47-1.56-19-4.68c-5.53-3.11-9.88-7.54-13.04-13.27
c-3.17-5.73-4.75-12.21-4.75-19.45c0-7.24,1.58-13.72,4.75-19.45s7.51-10.15,13.04-13.27c5.53-3.12,11.86-4.68,19-4.68
c7.14,0,13.5,1.56,19.08,4.68C335.66,43.29,340,47.71,343.12,53.44z M328.04,72.89c0-7.14-0.68-13.27-2.04-18.4
c-1.36-5.13-3.32-9.02-5.88-11.69c-2.56-2.66-5.61-4-9.12-4c-3.52,0-6.56,1.33-9.12,4c-2.56,2.67-4.52,6.56-5.88,11.69
c-1.36,5.13-2.04,11.26-2.04,18.4c0,7.14,0.68,13.27,2.04,18.4c1.36,5.13,3.32,9.02,5.88,11.69c2.56,2.67,5.6,4,9.12,4
c3.52,0,6.56-1.33,9.12-4c2.56-2.66,4.52-6.56,5.88-11.69C327.36,86.16,328.04,80.03,328.04,72.89z M398.92,51.63
c2.61,0,4.98,0.45,7.09,1.36V36.4c-1.31-0.6-2.86-0.9-4.67-0.9c-4.63,0-8.72,2.04-12.29,6.11c-3.57,4.07-6.35,8.75-8.93,18.07h-0.34
V36.1h-0.6l-29.86,8.6v1.96c3.42,0,6.06,0.33,7.92,0.98c1.86,0.65,3.19,1.71,4,3.17c0.8,1.46,1.21,3.44,1.21,5.96v37.4
c0,3.12-0.3,5.43-0.9,6.94c-0.6,1.51-1.71,2.64-3.32,3.39c-1.61,0.75-4.17,1.33-7.69,1.73v2.11h41.92v-2.11
c-3.52-0.3-6.16-0.83-7.92-1.58c-1.76-0.75-2.99-1.91-3.69-3.47c-0.7-1.56-1.06-3.9-1.06-7.01V64.53
C382.95,57.1,389.91,51.63,398.92,51.63z M453.56,46.52 M618.97,101.02c-0.6-1.56-0.9-3.89-0.9-7.01V59.62
c0-16.15-8.94-24.13-20.66-24.13c-11.72,0-19.25,8.3-22.47,12.72h-0.3V36.1h-0.6l-29.86,8.6v1.96c3.32,0,5.93,0.33,7.84,0.98
c1.91,0.65,3.27,1.68,4.07,3.09c0.8,1.41,1.21,3.37,1.21,5.88V94c0,3.12-0.3,5.46-0.9,7.01c-0.6,1.56-1.71,2.71-3.32,3.47
c-1.61,0.75-4.17,1.33-7.69,1.73v2.11h39.21v-2.11c-2.71-0.4-4.8-0.98-6.26-1.73c-1.46-0.75-2.44-1.91-2.94-3.47
c-0.5-1.56-0.75-3.89-0.75-7.01V53.69c3.47-4.21,7.55-8.25,14.18-8.25c9.11,0,11.91,6.87,11.91,14.63V94c0,3.12-0.28,5.46-0.83,7.01
c-0.55,1.56-1.51,2.71-2.87,3.47c-1.36,0.75-3.44,1.33-6.26,1.73v2.11h38.76v-2.11c-3.32-0.4-5.76-0.98-7.31-1.73
C620.65,103.73,619.58,102.58,618.97,101.02z M1000,87.52c-3.33,7.27-12.62,22.77-31.52,22.77c-17.95,0-32.87-14.68-32.87-36.79
c0-6.94,1.51-13.32,4.52-19.15c3.02-5.83,7.11-10.43,12.29-13.8c5.18-3.37,10.88-5.05,17.12-5.05c18.11,0,27.14,12.76,27.14,26.06v3
h-44.93c0,0.27-0.01,0.53-0.01,0.8c0,16,7.12,31.37,25.03,31.37c13.62,0,19.32-7.54,21.56-10.25L1000,87.52z M952.06,59.47h28.18
c-0.19-10.93-3.45-20.47-12.36-20.51C959.52,38.93,953.46,46.73,952.06,59.47z M799.99,101.02c-0.6-1.56-0.9-3.89-0.9-7.01V59.62
c0-5.23-0.88-9.65-2.64-13.27c-1.76-3.62-4.2-6.33-7.31-8.14c-3.12-1.81-6.69-2.71-10.71-2.71c-4.63,0-8.72,1.18-12.29,3.54
c-3.57,2.36-6.96,5.76-10.18,10.18h-0.3V0h-0.6L725.2,8.6v1.96c3.32,0,5.93,0.33,7.84,0.98c1.91,0.65,3.27,1.68,4.07,3.09
c0.8,1.41,1.21,3.37,1.21,5.88V94c0,3.12-0.3,5.46-0.9,7.01c-0.6,1.56-1.71,2.71-3.32,3.47c-1.61,0.75-4.17,1.33-7.69,1.73v2.11
h39.21v-2.11c-2.71-0.4-4.8-0.98-6.26-1.73c-1.46-0.75-2.44-1.91-2.94-3.47c-0.5-1.56-0.75-3.89-0.75-7.01V53.69
c3.47-4.21,7.55-8.25,14.18-8.25c3.72,0,6.63,1.23,8.75,3.69c2.11,2.46,3.17,6.11,3.17,10.93V94c0,3.12-0.28,5.46-0.83,7.01
c-0.55,1.56-1.51,2.71-2.87,3.47c-1.36,0.75-3.44,1.33-6.26,1.73v2.11h38.76v-2.11c-3.32-0.4-5.76-0.98-7.31-1.73
C801.67,103.73,800.6,102.58,799.99,101.02z M690.46,101.82c-22.24,0.15-39.88-17.73-39.88-46.74c0-30.66,16.43-48.54,35.22-48.54
c18.79,0,26.85,16.93,30.96,33.56l3.01-0.05V9.45c-7.06-3.91-18.64-8.32-35.47-8.32c-32.46,0-56.96,23.75-56.96,55.46
c0,30.21,20.44,54.1,55.61,53.95c19.39-0.15,32.91-11.72,39.37-20.59l-2.1-2.25C715.86,92.66,707.14,101.67,690.46,101.82z
M914.35,66.41l-10.4-4.98c-6.91-3.09-10.86-7.18-10.86-12.21c0-5.7,5.22-9.6,12.52-9.6c10.63,0,16.14,5.88,18.42,18.95h3.14v-19
c-3.12-1.21-11.36-4.07-19.75-4.07c-16.59,0-26.69,10.43-26.69,22.47c0,4.63,1.23,8.67,3.69,12.14c2.46,3.47,6.16,6.46,11.08,8.97
l10.86,5.43c7.43,3.39,10.41,6.73,10.41,11.76c0,5.56-4.48,9.91-12.97,9.91c-12.41,0-18.31-11.77-19.93-21.22h-3.14v19.45
c4.73,3.06,13.63,5.88,21.87,5.88c15.9,0,26.99-9.74,26.99-23.52C929.58,76.84,924.28,70.63,914.35,66.41z M90.03,62.64v26.99
c0,4.22,0.6,7.46,1.81,9.73c1.21,2.26,3.22,3.9,6.03,4.9c2.81,1.01,7.09,1.66,12.82,1.96v2.11H52.33v-2.11
c4.92-0.3,8.62-0.95,11.08-1.96c2.46-1,4.2-2.61,5.2-4.83c1-2.21,1.51-5.48,1.51-9.8V22.68c0-13.79-6.23-16.59-15.69-16.59
c-10.38,0-16.73,2.79-16.73,16.14v74.91c0,16.93-11,33.03-32.72,33.03c-1.68,0-3.34-0.1-4.98-0.29v-1.81
c5.16-0.31,9.34-2.06,12.52-5.29c3.52-3.57,5.28-9.42,5.28-17.57V22.22c0-4.22-0.5-7.47-1.51-9.73c-1.01-2.26-2.77-3.89-5.28-4.9
c-2.51-1-6.18-1.66-11.01-1.96V3.52h103.05c23.44,0,37.95,11.72,37.95,29.41c0,20.25-19.89,29.71-37.67,29.71H90.03z M90.03,58.59
h7.19c12.23,0,22.52-7.16,22.52-25.51c0-22.43-14.81-25.51-22.15-25.51h-7.56V58.59z M538.1,102.31c2.49,0,4.68-1.09,6.07-2.03v3.58
c-2.78,2.6-7.94,6.38-15.7,6.38c-6.54,0-12.03-4.15-13.49-10.48h-0.39c-2.55,4.82-10.34,10.91-18.84,10.91
c-10.2,0-17.71-6.8-17.71-17.14c0-8.08,5.53-13.46,14.73-16.72l21.82-7.86V58.82c0-9.21-6.66-13.46-13.88-13.46
c-7.37,0-14.17,3.12-21.25,10.34l-2.12-1.98c6.23-10.06,16.15-18.28,30.46-18.28c13.6,0,24.51,8.93,24.37,23.38l-0.28,36.13
C531.87,100.04,534,102.31,538.1,102.31z M514.59,73.67l-8.78,3.56c-6.8,2.69-11.19,5.81-11.19,13.03c0,6.09,4.25,10.34,10.2,10.34
c3.12,0,7.65-2.41,9.78-5.1V73.67z M871.01,102.31c2.5,0,4.68-1.1,6.08-2.03v3.58c-2.78,2.6-7.94,6.39-15.71,6.39
c-6.54,0-12.03-4.15-13.49-10.48h-0.39c-2.55,4.82-10.34,10.91-18.84,10.91c-10.2,0-17.71-6.8-17.71-17.14
c0-8.08,5.53-13.46,14.73-16.72l21.82-7.86V58.82c0-9.21-6.66-13.46-13.88-13.46c-7.37,0-14.17,3.12-21.25,10.34l-2.13-1.98
c6.23-10.06,16.15-18.28,30.46-18.28c13.6,0,24.51,8.93,24.37,23.38l-0.28,36.13C864.78,100.04,866.9,102.31,871.01,102.31z
M847.49,73.67l-8.78,3.56c-6.8,2.69-11.19,5.81-11.19,13.03c0,6.09,4.25,10.34,10.2,10.34c3.12,0,7.65-2.41,9.78-5.1V73.67z
M460.13,40.45c6.45,5.03,9.3,12.27,9.3,18.45c0,16.23-13.87,24.64-29.66,24.64c-4.16,0-8.18-0.59-11.85-1.75
c-2.04,1.57-3.79,3.62-3.79,6.02c0,5.16,8.41,6.2,13.43,6.49l17.12,1.18c13.72,0.89,22.42,5.75,22.42,18
c0,15.49-18.32,28.33-45,28.33c-15.49,0-26.56-5.31-26.56-14.76c0-8.21,4.52-12.91,16.14-18.49c-7.6-2.21-9.36-6.74-9.36-11.17
c0-6.06,5.41-11.5,12.74-16.66c-8.78-3.7-14.95-11.03-14.95-21.85c0-16.23,13.87-24.64,29.66-24.64c7.26,0,13.04,1.65,17.49,4.24
c3.32-6.67,9.87-14.43,21.61-14.43v13.85C472.6,35.96,464.95,36.97,460.13,40.45z M417.93,120.58c0,8.56,9.74,12.39,22.43,12.39
c12.1,0,28.47-5.46,28.47-14.17c0-5.02-2.8-6.2-10.18-6.79L429,109.81c-1.74-0.13-3.31-0.33-4.72-0.6
C420.01,112.54,417.93,115.96,417.93,120.58z M451.13,58.91c0-13.87-4.57-20.51-11.36-20.51s-11.36,6.64-11.36,20.51
s4.57,20.51,11.36,20.51S451.13,72.78,451.13,58.91z"/>
</svg>

After

Width:  |  Height:  |  Size: 7.5 KiB

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1014" height="1012" version="1.1" viewBox="-10 0 1014 1012" xmlns="http://www.w3.org/2000/svg">
<path d="m498 1012h-15l103-284h143q19 0 37-12.5t24-30.5l111-309q15-39-4.5-65.5t-59.5-26.5h-198l-164 457-94 258q-84-20-156-66-71-46-123.5-111t-81.5-146q-30-80-30-170 0-87 28-166 28-78 78-142t118-110 148-68l-96 266-163 442h107l137-376h81l-137 376h107l128-350q14-38-5-65t-59-27h-90l103-286h23q105 0 197 40t160.5 108.5 108.5 160.5 40 197-40 197-108.5 160.5-160.5 108.5-197 40zm305-662h-81l-113 310h81z" fill="#024ad8"/>
</svg>

After

Width:  |  Height:  |  Size: 571 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 46 KiB

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="108.08" fill="none" viewBox="0 0 1000 108.08">
<path fill="#e10600" d="M255.96 0c-11.96 0-23.37 5.8-30.8 15.26l-74.1 92.82h37.55l61.12-75.26c3.03-3.7 5.24-5.53 10-5.53 6.07 0 10.26 5.26 10.26 11.48v32.68c0 5.27-2.7 9.6-7.7 9.6h-7.56v27H297V40.4c0-5.54.15-40.39-41.05-40.39zM32.69.03C14.72.03 0 14.48 0 32.45c0 11.61 2.57 24.71 20.67 31.74l114.4 43.9V86.47c0-9.26-8.86-11.79-8.86-11.79L37.14 43.25c-3.37-1.21-5.53-3.38-5.53-7.97a8.3 8.3 0 0 1 8.37-8.24h59.66c4.03 0 8.28 3.29 8.28 7.7v7.57h27.02V.03H32.69zm291.6 0v108.06h42.42V81.07h-7.57c-5 0-7.83-4.32-7.83-9.59V38.93c0-7.97 7.83-13.91 15.13-10.8 2.7 1.2 5 3.64 6.08 6.48l19.72 51.32c5.13 13.51 17.96 22.16 32.41 22.16h.81c18.64 0 33.9-14.86 33.9-33.64V.03h-27v73.75a7.4 7.4 0 0 1-6.36 7.29 7.1 7.1 0 0 1-7.42-4.6l-24.72-67.8c-1.9-5.4-6.35-8.64-11.75-8.64H324.3zm162.27 0v27.15h81.04c14.32 0 26.88 12.56 26.88 26.88 0 14.31-12.56 26.88-26.88 26.88h-81.04v27.15h81.04a54.22 54.22 0 0 0 47.41-27.97 54.52 54.52 0 0 0 6.62-26.06c0-9.46-2.43-18.24-6.62-26.07A53.79 53.79 0 0 0 567.61.03h-81.05zm146.28 0v27.01h5.67c.67 0 1.35 0 2.16.14 4.98.67 7.97 4.73 7.97 10.13v70.78h27.01V.03h-42.81zm102.65 0c-17.97 0-32.7 14.45-32.7 32.42 0 11.61 2.58 24.71 20.67 31.74l114.4 43.9V86.47c0-9.26-8.85-11.79-8.85-11.79l-89.07-31.43c-3.37-1.21-5.53-3.38-5.53-7.97a8.3 8.3 0 0 1 8.37-8.24h59.66c4.03 0 8.28 3.29 8.28 7.7v7.57h27.02V.03H735.49zm129.44 0v108.06h26.75V69.32a3.25 3.25 0 0 1 3.24-3.24h29.45a6.3 6.3 0 0 1 4.45 1.75l42.28 38.3a7.56 7.56 0 0 0 5.09 1.96H1000V81.07h-12.97c-4.05 0-7.97-1.48-11.07-4.05l-20.12-17.7a6.96 6.96 0 0 1 0-10.4l20.12-17.69a18.23 18.23 0 0 1 11.07-4.05H1000V.03h-23.81c-1.88 0-3.7.7-5.1 1.96l-42.27 38.29a6.6 6.6 0 0 1-4.45 1.76h-29.45a3.25 3.25 0 0 1-3.24-3.25V.03h-26.75zM0 81.07v27.01h26.74V81.07H0zm702.55 0v27.01h26.74V81.07h-26.74z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -0,0 +1,165 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 12.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 51448) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2008"
sodipodi:version="0.32"
inkscape:version="0.48.5 r10040"
sodipodi:docname="T-Mobile_logo.svg"
width="523"
height="123"
viewBox="44 334 523 123"
overflow="visible"
enable-background="new 44 334 523 123"
xml:space="preserve"><metadata
id="metadata27"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs25">
</defs>
<sodipodi:namedview
units="mm"
inkscape:cy="-177.77119"
borderopacity="1.0"
pagecolor="#ffffff"
inkscape:zoom="0.78723292"
inkscape:cx="503.25509"
id="base"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:current-layer="svg2008"
inkscape:window-width="1920"
inkscape:window-height="1018"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
bordercolor="#666666"
width="186.67mm"
height="27.6mm"
inkscape:document-units="px"
showgrid="false"
inkscape:window-maximized="1"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="true"
inkscape:object-nodes="true"
inkscape:snap-smooth-nodes="true"
inkscape:snap-object-midpoints="true"
inkscape:snap-center="true"
showguides="false"
inkscape:guide-bbox="true">
<sodipodi:guide
orientation="0,1"
position="62.635787,-253.72888"
id="guide3247" /><sodipodi:guide
orientation="0,1"
position="243.25454,-217.78617"
id="guide3265" /><sodipodi:guide
orientation="0,1"
position="342.87554,-242.11217"
id="guide4070" /></sodipodi:namedview>
<path
sodipodi:type="arc"
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path3209"
sodipodi:cx="366.91431"
sodipodi:cy="41.449261"
sodipodi:rx="2.5044003"
sodipodi:ry="2.5044003"
d="m 369.41871,41.449261 a 2.5044003,2.5044003 0 1 1 -5.0088,0 2.5044003,2.5044003 0 1 1 5.0088,0 z"
transform="matrix(2.5267527,0,0,2.592437,-506.01172,255.1969)" /><rect
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3211"
width="16.107"
height="16.437"
x="523.84003"
y="391.16901" /><rect
y="391.16901"
x="204.39101"
height="16.437"
width="16.107"
id="rect3213"
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /><rect
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3215"
width="16.107"
height="16.437"
x="156.07899"
y="391.16901" /><rect
y="391.16901"
x="108.5"
height="16.437"
width="16.107"
id="rect3217"
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /><rect
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3219"
width="16.107"
height="16.437"
x="59.225998"
y="391.16901" /><path
style="fill:#ed008c"
inkscape:connector-curvature="0"
id="path3221"
d="m 97.909,358.36 h 1.911 c 12.343,0 18.096,6.603 20.5,24.212 l 3.822,-0.169 -0.51,-27.938 H 60.824 l -0.619,27.938 3.678,0.169 c 0.637,-6.603 1.401,-10.159 3.059,-13.715 2.931,-6.604 9.048,-10.497 16.566,-10.497 h 2.676 v 60.784 c 0,6.434 -0.382,8.466 -1.91,9.99 -1.275,1.185 -3.824,1.693 -6.756,1.693 h -2.931 v 4.063 h 34.919 v -4.063 h -2.949 c -2.913,0 -5.48,-0.509 -6.736,-1.693 -1.529,-1.524 -1.911,-3.557 -1.911,-9.99 V 358.36" /><path
inkscape:connector-curvature="0"
id="path3223"
d="m 264.053,434.891 20.35,-71.006 v 55.721 c 0,6.081 -0.346,8.218 -1.726,9.697 -1.036,1.15 -3.437,1.644 -6.099,1.644 h -1.035 v 3.944 h 28.765 v -3.944 h -1.497 c -2.646,0 -5.062,-0.493 -6.097,-1.644 -1.382,-1.479 -1.727,-3.616 -1.727,-9.697 v -47.502 c 0,-6.082 0.345,-8.383 1.727,-9.862 1.15,-0.986 3.451,-1.644 6.097,-1.644 h 1.497 v -3.781 h -22.321 l -16.799,57.364 -16.437,-57.364 h -22.206 v 3.781 h 2.07 c 6.099,0 7.249,1.315 7.249,9.205 v 45.2 c 0,7.232 -0.345,10.191 -1.381,12.328 -1.15,2.137 -3.583,3.616 -6.098,3.616 h -1.841 v 3.944 h 23.701 v -3.944 h -1.495 c -2.991,0 -5.408,-1.151 -6.805,-3.452 -1.364,-2.301 -1.709,-4.438 -1.709,-12.492 v -51.117 l 20.233,71.006 h 3.584"
style="fill:#999b9e;fill-opacity:1" /><path
inkscape:connector-curvature="0"
id="path3225"
d="m 329.044,379.335 c -14.267,0 -23.586,11.177 -23.586,28.765 0,16.93 9.319,28.436 23.226,28.436 14.035,0 23.355,-11.506 23.355,-28.6 0,-16.931 -9.32,-28.601 -22.995,-28.601 m -0.46,3.78 c 4.126,0 7.692,2.63 9.648,7.068 1.841,4.109 2.646,9.698 2.646,17.752 0,16.6 -4.027,24.818 -12.195,24.818 -8.153,0 -12.082,-8.219 -12.082,-24.983 0,-7.89 0.821,-13.478 2.662,-17.587 1.826,-4.273 5.524,-7.068 9.321,-7.068"
style="fill:#999b9e;fill-opacity:1" /><path
inkscape:connector-curvature="0"
id="path3227"
d="m 371.155,355.995 -16.339,0.822 v 3.616 h 0.789 c 4.833,0 5.885,1.644 5.885,9.369 v 53.419 c 0,6.903 -0.23,8.712 -1.15,11.67 h 3.797 c 2.859,-4.767 3.566,-5.588 4.717,-5.588 0.559,0 1.117,0.164 1.94,0.986 5.653,4.602 8.069,5.588 13.247,5.588 12.409,0 21.384,-11.999 21.384,-29.093 0,-16.108 -8.301,-26.956 -20.71,-26.956 -6.443,0 -11.144,3.123 -13.56,8.711 v -32.544 m 11.933,27.942 c 7.381,0 11.177,7.89 11.177,23.34 0,16.272 -3.912,24.655 -11.391,24.655 -8.284,0 -12.641,-8.548 -12.641,-24.162 0,-7.89 1.037,-13.313 3.453,-17.423 2.169,-3.944 5.868,-6.41 9.402,-6.41"
style="fill:#999b9e;fill-opacity:1" /><path
inkscape:connector-curvature="0"
style="fill:#999b9e;fill-opacity:1"
d="m 426.711,380.157 -16.782,0.986 v 3.616 h 1.266 c 4.815,0 5.852,1.644 5.852,9.205 v 27.778 c 0,7.562 -1.036,9.37 -5.852,9.37 h -1.825 v 3.779 h 25.051 v -3.779 h -1.809 c -4.849,0 -5.9,-1.645 -5.9,-9.37 v -41.585"
id="path3229" /><path
inkscape:connector-curvature="0"
id="path3231"
d="m 455.819,355.995 -16.782,0.822 v 3.616 h 1.251 c 4.832,0 5.867,1.644 5.867,9.369 v 51.939 c 0,7.726 -1.035,9.37 -5.867,9.37 h -1.825 v 3.779 h 25.065 v -3.779 h -1.841 c -4.849,0 -5.868,-1.645 -5.868,-9.37 v -65.746"
style="fill:#999b9e;fill-opacity:1" /><path
inkscape:connector-curvature="0"
id="path3233"
d="m 509.306,407.606 c -0.56,-17.423 -8.844,-28.271 -21.368,-28.271 -12.098,0 -20.826,11.834 -20.826,28.271 0,17.587 8.613,28.929 21.96,28.929 8.629,0 14.612,-4.603 19.56,-14.794 l -3.451,-1.808 c -4.027,8.547 -8.054,11.999 -14.268,11.999 -9.089,0 -12.984,-7.231 -13.101,-24.326 h 31.494 m -31.378,-4.11 c 0.099,-12.327 4.108,-20.052 10.568,-20.052 6.443,0 10.239,7.561 10.125,20.052 h -20.693"
style="fill:#999b9e;fill-opacity:1" /><g
id="g3235"
style="fill:#999b9e;fill-opacity:1">
<g
id="g3237"
style="fill:#999b9e;fill-opacity:1">
<path
inkscape:connector-curvature="0"
d="m 545.988,377.995 c 0.972,0 1.921,0.249 2.847,0.748 0.926,0.499 1.647,1.213 2.163,2.141 0.518,0.928 0.776,1.896 0.776,2.904 0,0.998 -0.255,1.957 -0.765,2.877 -0.508,0.921 -1.223,1.636 -2.14,2.145 -0.919,0.509 -1.879,0.764 -2.882,0.764 -1.003,0 -1.963,-0.254 -2.882,-0.764 -0.918,-0.509 -1.634,-1.223 -2.144,-2.145 -0.512,-0.92 -0.768,-1.879 -0.768,-2.877 0,-1.008 0.259,-1.976 0.779,-2.904 0.519,-0.928 1.242,-1.643 2.166,-2.141 0.93,-0.499 1.879,-0.748 2.85,-0.748 z m 0,0.964 c -0.812,0 -1.604,0.208 -2.372,0.625 -0.769,0.417 -1.371,1.011 -1.806,1.785 -0.434,0.774 -0.65,1.581 -0.65,2.418 0,0.833 0.213,1.631 0.64,2.395 0.426,0.764 1.023,1.359 1.789,1.786 0.767,0.427 1.567,0.64 2.399,0.64 0.834,0 1.632,-0.213 2.399,-0.64 0.766,-0.426 1.361,-1.021 1.785,-1.786 0.424,-0.764 0.637,-1.562 0.637,-2.395 0,-0.837 -0.216,-1.644 -0.648,-2.418 -0.432,-0.773 -1.033,-1.368 -1.805,-1.785 -0.771,-0.417 -1.56,-0.625 -2.368,-0.625 z m -2.54,8.023 v -6.23 h 2.145 c 0.731,0 1.263,0.058 1.59,0.173 0.329,0.115 0.59,0.316 0.784,0.603 0.195,0.286 0.293,0.591 0.293,0.913 0,0.455 -0.164,0.852 -0.49,1.189 -0.324,0.337 -0.757,0.527 -1.296,0.568 0.221,0.092 0.397,0.202 0.53,0.33 0.252,0.245 0.559,0.657 0.922,1.235 l 0.761,1.22 h -1.233 L 546.899,386 c -0.435,-0.769 -0.784,-1.251 -1.047,-1.447 -0.184,-0.145 -0.453,-0.217 -0.806,-0.217 h -0.592 v 2.647 h -1.006 z m 1.007,-3.502 h 1.226 c 0.584,0 0.983,-0.087 1.197,-0.262 0.214,-0.175 0.319,-0.406 0.319,-0.694 0,-0.185 -0.051,-0.351 -0.154,-0.497 -0.103,-0.146 -0.244,-0.256 -0.428,-0.328 -0.182,-0.072 -0.52,-0.107 -1.013,-0.107 h -1.147 v 1.888 z"
id="path3239"
style="fill:#999b9e;fill-opacity:1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.4 KiB

1
apps/www/public/next.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,3 @@
<svg width="91" height="34" viewBox="0 0 91 34" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.723003 33.0923V7.27685H5.03737V10.99H6.02755L5.03737 12.0156C5.03737 10.436 5.50889 9.19827 6.45192 8.30239C7.39495 7.38294 8.66804 6.92321 10.2712 6.92321C12.228 6.92321 13.7958 7.59512 14.9746 8.93894C16.1534 10.2828 16.7427 12.0863 16.7427 14.3496V19.6188C16.7427 21.1276 16.4716 22.4479 15.9294 23.5795C15.4107 24.6876 14.6681 25.5481 13.7015 26.161C12.7349 26.774 11.5914 27.0805 10.2712 27.0805C8.66804 27.0805 7.39495 26.6326 6.45192 25.7367C5.50889 24.8172 5.03737 23.5677 5.03737 21.9881L6.02755 23.0137H5.00201L5.14346 27.6463V33.0923H0.723003ZM8.71519 23.2612C9.84683 23.2612 10.7309 22.9312 11.3675 22.271C12.004 21.6109 12.3223 20.6679 12.3223 19.442V14.5618C12.3223 13.3358 12.004 12.3928 11.3675 11.7327C10.7309 11.0725 9.84683 10.7425 8.71519 10.7425C7.60713 10.7425 6.73483 11.0843 6.09828 11.768C5.46174 12.4282 5.14346 13.3594 5.14346 14.5618V19.442C5.14346 20.6443 5.46174 21.5873 6.09828 22.271C6.73483 22.9312 7.60713 23.2612 8.71519 23.2612ZM29.9549 26.7269C28.6819 26.7269 27.562 26.4675 26.5954 25.9489C25.6524 25.4302 24.9097 24.6994 24.3675 23.7563C23.8252 22.7897 23.5541 21.6817 23.5541 20.4321V4.90748H17.3301V0.911385H27.9746V20.4321C27.9746 21.1394 28.175 21.7052 28.5758 22.1296C29.0001 22.5304 29.5659 22.7308 30.2732 22.7308H36.1436V26.7269H29.9549ZM43.2025 27.0805C41.1986 27.0805 39.619 26.55 38.4638 25.4891C37.3086 24.4282 36.731 23.0019 36.731 21.2101C36.731 19.3005 37.3675 17.827 38.6406 16.7897C39.9137 15.7523 41.7172 15.2337 44.0512 15.2337H48.8961V13.5716C48.8961 12.6285 48.5896 11.8977 47.9766 11.379C47.3636 10.8368 46.5267 10.5657 45.4658 10.5657C44.4992 10.5657 43.6976 10.7779 43.0611 11.2022C42.4245 11.6266 42.0473 12.2042 41.9294 12.935H37.6151C37.8272 11.0961 38.6524 9.63442 40.0905 8.54994C41.5286 7.46545 43.3675 6.92321 45.6072 6.92321C47.9884 6.92321 49.8627 7.52439 51.2301 8.72676C52.621 9.90555 53.3165 11.5087 53.3165 13.5362V26.7269H49.0375V23.332H48.3302L49.0375 22.3771C49.0375 23.8153 48.5071 24.9587 47.4462 25.8074C46.3852 26.6561 44.9707 27.0805 43.2025 27.0805ZM44.6524 23.7563C45.9019 23.7563 46.9157 23.438 47.6937 22.8015C48.4953 22.165 48.8961 21.3398 48.8961 20.326V17.9567H44.122C43.2261 17.9567 42.507 18.216 41.9648 18.7347C41.4225 19.2533 41.1514 19.937 41.1514 20.7858C41.1514 21.7052 41.4579 22.4361 42.0709 22.9783C42.7074 23.497 43.5679 23.7563 44.6524 23.7563ZM55.8489 26.7269V7.27685H60.1633V10.99H61.3656L60.1633 12.0156C60.1633 10.4124 60.623 9.16291 61.5424 8.26703C62.4855 7.37115 63.7704 6.92321 65.3971 6.92321C67.3067 6.92321 68.8274 7.55976 69.959 8.83285C71.1142 10.1059 71.6918 11.8152 71.6918 13.9606V26.7269H67.2714V14.4203C67.2714 13.2415 66.9649 12.3339 66.3519 11.6973C65.7389 11.0608 64.8784 10.7425 63.7704 10.7425C62.6859 10.7425 61.8254 11.0725 61.1888 11.7327C60.5758 12.3928 60.2694 13.3358 60.2694 14.5618V26.7269H55.8489ZM82.1103 27.0451C80.46 27.0451 79.0219 26.7387 77.7959 26.1257C76.5936 25.4891 75.6505 24.605 74.9668 23.4734C74.3067 22.3182 73.9766 20.9626 73.9766 19.4066V14.5971C73.9766 13.0411 74.3067 11.6973 74.9668 10.5657C75.6505 9.41045 76.5936 8.52636 77.7959 7.91339C79.0219 7.27685 80.46 6.95857 82.1103 6.95857C83.7842 6.95857 85.2223 7.27685 86.4247 7.91339C87.627 8.52636 88.5583 9.41045 89.2184 10.5657C89.9021 11.6973 90.2439 13.0293 90.2439 14.5618V19.4066C90.2439 20.9626 89.9021 22.3182 89.2184 23.4734C88.5583 24.605 87.627 25.4891 86.4247 26.1257C85.2223 26.7387 83.7842 27.0451 82.1103 27.0451ZM82.1103 23.1905C83.2891 23.1905 84.1967 22.8722 84.8333 22.2357C85.4934 21.5756 85.8235 20.6325 85.8235 19.4066V14.5971C85.8235 13.3476 85.4934 12.4046 84.8333 11.768C84.1967 11.1315 83.2891 10.8132 82.1103 10.8132C80.9551 10.8132 80.0474 11.1315 79.3873 11.768C78.7272 12.4046 78.3971 13.3476 78.3971 14.5971V19.4066C78.3971 20.6325 78.7272 21.5756 79.3873 22.2357C80.0474 22.8722 80.9551 23.1905 82.1103 23.1905Z" fill="#7780D9" style="fill:#7780D9;fill:color(display-p3 0.4667 0.5020 0.8510);fill-opacity:1;"/>
</svg>

After

Width:  |  Height:  |  Size: 4 KiB

View file

@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 129 B

View file

@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>

After

Width:  |  Height:  |  Size: 386 B

19
apps/www/sanity.config.ts Normal file
View file

@ -0,0 +1,19 @@
import { defineConfig } from "sanity";
import { structureTool } from "sanity/structure";
import { schemaTypes } from "./schemaTypes";
export default defineConfig({
name: "default",
title: "Plano",
projectId: "71ny25bn",
dataset: "production",
basePath: "/studio",
plugins: [structureTool()],
schema: {
types: schemaTypes,
},
});

View file

@ -0,0 +1,214 @@
import { defineField, defineType } from "sanity";
export const blogType = defineType({
name: "blog",
title: "Blog",
type: "document",
fields: [
defineField({
name: "title",
title: "Title",
type: "string",
validation: (rule) => rule.required(),
}),
defineField({
name: "slug",
title: "Slug",
type: "slug",
options: {
source: "title",
maxLength: 96,
},
validation: (rule) => rule.required(),
}),
defineField({
name: "summary",
title: "Post Summary",
type: "text",
description: "A brief summary of the blog post",
}),
defineField({
name: "body",
title: "Post Body",
type: "array",
of: [
{
type: "block",
},
{
type: "image",
fields: [
{
name: "alt",
type: "string",
title: "Alternative text",
},
],
},
],
}),
defineField({
name: "bodyHtml",
title: "Post Body (HTML)",
type: "text",
description: "Raw HTML content from migration (for reference)",
hidden: true,
}),
defineField({
name: "mainImage",
title: "Main Image",
type: "image",
options: {
hotspot: true,
},
fields: [
{
name: "alt",
type: "string",
title: "Alternative text",
},
],
}),
defineField({
name: "mainImageUrl",
title: "Main Image URL",
type: "url",
description: "Fallback URL if image not uploaded to Sanity",
hidden: true,
}),
defineField({
name: "thumbnailImage",
title: "Thumbnail Image",
type: "image",
options: {
hotspot: true,
},
fields: [
{
name: "alt",
type: "string",
title: "Alternative text",
},
],
}),
defineField({
name: "thumbnailImageUrl",
title: "Thumbnail Image URL",
type: "url",
description: "Fallback URL if image not uploaded to Sanity",
hidden: true,
}),
defineField({
name: "featured",
title: "Featured?",
type: "boolean",
initialValue: false,
}),
defineField({
name: "published",
title: "Published",
type: "boolean",
initialValue: false,
}),
defineField({
name: "draft",
title: "Draft",
type: "boolean",
initialValue: false,
}),
defineField({
name: "archived",
title: "Archived",
type: "boolean",
initialValue: false,
}),
defineField({
name: "publishedAt",
title: "Published On",
type: "datetime",
validation: (rule) => rule.required(),
}),
defineField({
name: "createdAt",
title: "Created On",
type: "datetime",
initialValue: () => new Date().toISOString(),
}),
defineField({
name: "updatedAt",
title: "Updated On",
type: "datetime",
initialValue: () => new Date().toISOString(),
}),
defineField({
name: "author",
title: "Author",
type: "object",
fields: [
{
name: "name",
title: "Author Name",
type: "string",
validation: (rule) => rule.required(),
},
{
name: "title",
title: "Author Title",
type: "string",
},
{
name: "image",
title: "Author Image",
type: "image",
options: {
hotspot: true,
},
},
{
name: "imageUrl",
title: "Author Image URL",
type: "url",
description: "Fallback URL if image not uploaded to Sanity",
hidden: true,
},
],
}),
defineField({
name: "color",
title: "Color",
type: "string",
description: "Optional color theme for the blog post",
}),
// Legacy fields from CSV migration (can be hidden in UI)
defineField({
name: "collectionId",
title: "Collection ID",
type: "string",
hidden: true,
}),
defineField({
name: "localeId",
title: "Locale ID",
type: "string",
hidden: true,
}),
defineField({
name: "itemId",
title: "Item ID",
type: "string",
hidden: true,
}),
],
preview: {
select: {
title: "title",
author: "author.name",
media: "mainImage",
publishedAt: "publishedAt",
},
prepare(selection) {
const { author } = selection;
return { ...selection, subtitle: author && `by ${author}` };
},
},
});

View file

@ -0,0 +1,3 @@
import { blogType } from "./blogType";
export const schemaTypes = [blogType];

View file

@ -0,0 +1,326 @@
import { ImageResponse } from "next/og";
import { NextRequest } from "next/server";
import { client, urlFor } from "@/lib/sanity";
export const runtime = "edge";
// Font loading function that uses the request origin
function loadFont(fileName: string, baseUrl: string) {
return fetch(new URL(`/fonts/${fileName}`, baseUrl)).then((res) => {
if (!res.ok) {
throw new Error(
`Failed to fetch font ${fileName}: ${res.status} ${res.statusText}`,
);
}
return res.arrayBuffer();
});
}
async function getBlogPost(slug: string) {
const query = `*[_type == "blog" && slug.current == $slug && published == true][0] {
_id,
title,
slug,
summary,
publishedAt,
mainImage,
author {
name,
title,
image
}
}`;
const post = await client.fetch(query, { slug });
return post;
}
function formatDate(dateString: string): string {
const date = new Date(dateString);
const day = date.getDate();
const month = date.toLocaleDateString("en-US", { month: "long" });
const year = date.getFullYear();
const getOrdinal = (n: number) => {
const s = ["th", "st", "nd", "rd"];
const v = n % 100;
return n + (s[(v - 20) % 10] || s[v] || s[0]);
};
return `${month} ${getOrdinal(day)}, ${year}`;
}
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ slug: string }> },
) {
try {
// Get base URL for font loading - use request origin in production
const fontBaseUrl =
process.env.NEXT_PUBLIC_APP_URL ||
(process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}`
: request.nextUrl.origin);
// Load fonts with error handling
let fontData;
try {
const [
ibmPlexSans,
jetbrainsMonoRegular,
jetbrainsMonoMedium,
jetbrainsMonoBold,
] = await Promise.all([
loadFont("IBMPlexSans-VariableFont_wdth,wght.otf", fontBaseUrl),
loadFont("JetBrainsMono-Regular.otf", fontBaseUrl),
loadFont("JetBrainsMono-Medium.otf", fontBaseUrl),
loadFont("jetbrains-mono-bold.otf", fontBaseUrl),
]).catch((error: Error) => {
console.error("Error loading fonts:", error);
throw new Error(`Failed to load fonts: ${error.message}`);
});
fontData = {
ibmPlexSans,
jetbrainsMonoRegular,
jetbrainsMonoMedium,
jetbrainsMonoBold,
};
} catch (error: unknown) {
const errorMessage =
error instanceof Error ? error.message : "Unknown error";
console.error("Font loading error:", errorMessage);
return new Response(
JSON.stringify({
error: "Failed to load required fonts",
details: errorMessage,
baseUrl: fontBaseUrl,
}),
{ status: 500 },
);
}
const { slug } = await params;
const post = await getBlogPost(slug);
if (!post) {
return new Response(JSON.stringify({ error: "Post not found" }), {
status: 404,
});
}
// Get author image URL if available
let authorImageUrl: string | null = null;
if (post.author?.image) {
authorImageUrl = urlFor(post.author.image).width(120).url();
}
// Use logo PNG
const baseUrl =
process.env.NEXT_PUBLIC_APP_URL ||
(process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}`
: request.nextUrl.origin);
const logoUrl = `${baseUrl}/Logomark.png`;
return new ImageResponse(
<div
style={{
background: "linear-gradient(to top right, #ffffff, #dcdfff)",
width: "100%",
height: "100%",
display: "flex",
flexDirection: "column",
padding: "60px 80px",
position: "relative",
}}
>
{/* Logo - Top Left - SVG as data URL */}
<div
style={{
position: "absolute",
top: "60px",
left: "80px",
display: "flex",
alignItems: "center",
}}
>
<img
src={logoUrl}
alt="Plano"
width="120"
height="48"
style={{
objectFit: "contain",
}}
/>
</div>
{/* Main Content - Left-Aligned, aligned with logo */}
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
justifyContent: "center",
flex: 1,
width: "85%",
marginTop: "150px",
}}
>
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
width: "100%",
}}
>
{/* Title - Left Aligned */}
<h1
style={{
fontSize: "64px",
lineHeight: "1.1",
color: "#000000",
marginBottom: "24px",
letterSpacing: "-0.08em",
fontFamily: "IBM Plex Sans Bold",
textAlign: "left",
}}
>
{post.title}
</h1>
{/* Date - Below Title, Left Aligned */}
{/* {post.publishedAt && (
<div
style={{
fontSize: "20px",
color: "#000000",
marginBottom: "40px",
letterSpacing: "-1.8px",
fontFamily: "IBM Plex Sans Regular",
textAlign: "left",
}}
>
{formatDate(post.publishedAt)}
</div>
)} */}
{/* Author Section - Below Date, Left Aligned */}
{post.author?.name && (
<div
style={{
display: "flex",
alignItems: "center",
gap: "16px",
marginTop: "20px",
}}
>
{authorImageUrl && (
<img
src={authorImageUrl}
alt={post.author.name}
width="48"
height="48"
style={{
borderRadius: "4px",
objectFit: "cover",
}}
/>
)}
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
}}
>
<div
style={{
fontSize: "20px",
color: "#7780d9",
textTransform: "uppercase",
letterSpacing: "0.09em",
fontFamily: "JetBrains Mono Bold",
textAlign: "left",
}}
>
{post.author.name}
</div>
{post.author.title && (
<div
style={{
fontSize: "14px",
color: "#28327D",
textTransform: "uppercase",
letterSpacing: "0.10em",
fontFamily: "JetBrains Mono Medium",
textAlign: "left",
}}
>
{post.author.title}
</div>
)}
</div>
</div>
)}
</div>
</div>
</div>,
{
width: 1200,
height: 630,
fonts: [
{
name: "IBM Plex Sans Regular",
data: fontData.ibmPlexSans,
style: "normal",
weight: 400,
},
{
name: "IBM Plex Sans Medium",
data: fontData.ibmPlexSans,
style: "normal",
weight: 500,
},
{
name: "IBM Plex Sans Bold",
data: fontData.ibmPlexSans,
style: "normal",
weight: 700,
},
{
name: "JetBrains Mono Regular",
data: fontData.jetbrainsMonoRegular,
style: "normal",
weight: 400,
},
{
name: "JetBrains Mono Medium",
data: fontData.jetbrainsMonoMedium,
style: "normal",
weight: 500,
},
{
name: "JetBrains Mono Bold",
data: fontData.jetbrainsMonoBold,
style: "normal",
weight: 600,
},
],
},
);
} catch (error: unknown) {
const errorMessage =
error instanceof Error ? error.message : "Unknown error";
console.error("Error generating image response:", error);
return new Response(
JSON.stringify({
error: "Failed to generate image",
details: errorMessage,
}),
{ status: 500 },
);
}
}

View file

@ -0,0 +1,120 @@
import { Metadata } from "next";
import { client } from "@/lib/sanity";
type Params = Promise<{ slug: string }>;
interface BlogPost {
_id: string;
title: string;
slug: { current: string };
summary?: string;
publishedAt?: string;
author?: {
name?: string;
title?: string;
image?: any;
};
}
async function getBlogPost(slug: string): Promise<BlogPost | null> {
const query = `*[_type == "blog" && slug.current == $slug && published == true][0] {
_id,
title,
slug,
summary,
publishedAt,
author
}`;
const post = await client.fetch(query, { slug });
return post || null;
}
export async function generateMetadata({
params,
}: {
params: Params;
}): Promise<Metadata> {
try {
const resolvedParams = await params;
const post = await getBlogPost(resolvedParams.slug);
if (!post) {
return {
title: "Post Not Found - Plano",
description: "The requested blog post could not be found.",
};
}
// Get baseUrl - use NEXT_PUBLIC_APP_URL if set, otherwise construct from VERCEL_URL
// Restrict to allowed hosts: localhost:3000, archgw-tau.vercel.app, or plano.katanemo.com
let baseUrl = "http://localhost:3000";
if (process.env.NEXT_PUBLIC_APP_URL) {
const url = process.env.NEXT_PUBLIC_APP_URL;
if (
url.includes("archgw-tau.vercel.app") ||
url.includes("plano.katanemo.com") ||
url.includes("localhost:3000")
) {
baseUrl = url;
}
} else if (process.env.VERCEL_URL) {
const hostname = process.env.VERCEL_URL;
// VERCEL_URL is just the hostname, not the full URL
if (hostname === "archgw-tau.vercel.app") {
baseUrl = `https://${hostname}`;
} else if (hostname === "plano.katanemo.com") {
baseUrl = `https://${hostname}`;
}
}
const ogImageUrl = `${baseUrl}/api/og/${resolvedParams.slug}`;
const metadata: Metadata = {
title: `${post.title} - Plano Blog`,
description: post.summary || "Read more on Plano Blog",
openGraph: {
title: post.title,
description: post.summary || "Read more on Plano Blog",
type: "article",
publishedTime: post.publishedAt,
authors: post.author?.name ? [post.author.name] : undefined,
url: `${baseUrl}/blog/${resolvedParams.slug}`,
siteName: "Plano",
images: [
{
url: ogImageUrl,
width: 1200,
height: 630,
alt: post.title,
},
],
locale: "en_US",
},
twitter: {
card: "summary_large_image",
title: post.title,
description: post.summary || "Read more on Plano Blog",
images: [ogImageUrl],
},
};
return metadata;
} catch (error) {
console.error("Error generating metadata:", error);
return {
title: "Blog Post - Plano",
description: "Read this post on Plano Blog",
};
}
}
interface LayoutProps {
children: React.ReactNode;
params: Params;
}
export default async function Layout({ children, params }: LayoutProps) {
return <>{children}</>;
}

View file

@ -0,0 +1,35 @@
import Link from "next/link";
export default function NotFound() {
return (
<div className="min-h-screen bg-white flex items-center justify-center">
<div className="max-w-md mx-auto px-4 text-center">
<h1 className="text-4xl sm:text-5xl font-normal leading-tight tracking-tighter text-black mb-4">
<span className="font-sans">Post Not Found</span>
</h1>
<p className="text-lg font-sans font-[400] tracking-[-0.5px] text-black/70 mb-8">
The blog post you're looking for doesn't exist or has been removed.
</p>
<Link
href="/blog"
className="inline-flex items-center gap-2 text-base font-medium text-black hover:text-[var(--secondary)] transition-colors"
>
<svg
className="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M15 19l-7-7 7-7"
/>
</svg>
Back to Blog
</Link>
</div>
</div>
);
}

View file

@ -0,0 +1,206 @@
import { client, urlFor } from "@/lib/sanity";
import Image from "next/image";
import Link from "next/link";
import { PortableText } from "@/components/PortableText";
import { notFound } from "next/navigation";
import { UnlockPotentialSection } from "@/components/UnlockPotentialSection";
interface BlogPost {
_id: string;
title: string;
slug: { current: string };
summary?: string;
body?: any[];
bodyHtml?: string;
publishedAt?: string;
mainImage?: any;
mainImageUrl?: string;
author?: {
name?: string;
title?: string;
image?: any;
};
}
async function getBlogPost(slug: string): Promise<BlogPost | null> {
const query = `*[_type == "blog" && slug.current == $slug && published == true][0] {
_id,
title,
slug,
summary,
body[]{
...,
asset->{
_id,
url,
metadata {
dimensions {
width,
height,
aspectRatio
}
}
}
},
bodyHtml,
publishedAt,
mainImage,
mainImageUrl,
author
}`;
const post = await client.fetch(query, { slug });
return post || null;
}
async function getAllBlogSlugs(): Promise<string[]> {
const query = `*[_type == "blog" && published == true] {
"slug": slug.current
}`;
const posts = await client.fetch(query);
return posts.map((post: { slug: string }) => post.slug);
}
export async function generateStaticParams() {
const slugs = await getAllBlogSlugs();
return slugs.map((slug) => ({ slug }));
}
export default async function BlogPostPage({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
const post = await getBlogPost(slug);
if (!post) {
notFound();
}
return (
<article className="min-h-screen">
{/* Featured Image - First */}
{(post.mainImage || post.mainImageUrl) && (
<div className="">
<div className="max-w-[89rem] mx-auto px-4 sm:px-6 lg:px-8 pt-8 sm:pt-12 lg:pt-1 pb-8 sm:pb-12">
<div className="relative aspect-[21/8] w-full overflow-hidden rounded-lg">
{post.mainImage ? (
<Image
src={urlFor(post.mainImage).width(1600).url()}
alt={post.title}
fill
className="object-cover"
priority
/>
) : (
<Image
src={post.mainImageUrl!}
alt={post.title}
fill
className="object-cover"
priority
/>
)}
</div>
</div>
</div>
)}
{/* Content Section */}
<div className="max-w-[58rem] mx-auto px-4 sm:px-6 lg:px-8">
{/* Back to Blog Button */}
<div className="pt-4 sm:pt-6 lg:pt-8 pb-4 sm:pb-6">
<Link
href="/blog"
className="inline-flex items-center gap-2 text-sm font-medium text-black/60 hover:text-black transition-colors"
>
<svg
className="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M15 19l-7-7 7-7"
/>
</svg>
Back to Blog
</Link>
</div>
{/* Author and Date */}
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 sm:gap-6 pb-4">
{post.author?.name && (
<div className="flex items-center gap-3">
{post.author.image ? (
<div className="relative w-12 h-12 rounded overflow-hidden shrink-0">
<Image
src={urlFor(post.author.image).width(80).url()}
alt={post.author.name}
fill
className="object-cover"
/>
</div>
) : (
<div className="w-12 h-12 rounded bg-[var(--secondary)]/20 shrink-0" />
)}
<div>
<div className="text-lg font-mono font-semibold tracking-wider text-primary uppercase">
{post.author.name}
</div>
{post.author.title && (
<div className="text-sm font-mono font-normal tracking-wider text-[#28327D] uppercase">
{post.author.title}
</div>
)}
</div>
</div>
)}
{post.publishedAt && (
<time
dateTime={post.publishedAt}
className="text-base font-medium tracking-[-0.9px] text-black sm:ml-auto"
>
{new Date(post.publishedAt).toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
})}
</time>
)}
</div>
{/* Title */}
<div className="pb-6 sm:pb-8 sm:-ml-1.5">
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-medium leading-tight tracking-tighter text-black">
<span className="font-sans">{post.title}</span>
</h1>
</div>
{/* Content */}
<div className="pb-12 sm:pb-16 lg:pb-20 ">
{post.body && post.body.length > 0 ? (
<div className="prose prose-lg max-w-none">
<PortableText content={post.body} />
</div>
) : post.bodyHtml ? (
<div
className="prose prose-lg max-w-none"
dangerouslySetInnerHTML={{ __html: post.bodyHtml }}
/>
) : (
<p className="text-base sm:text-lg font-sans font-normal tracking-[-0.5px] text-black/80">
Content coming soon...
</p>
)}
</div>
</div>
<UnlockPotentialSection variant="transparent" />
</article>
);
}

View file

@ -0,0 +1,119 @@
import { client } from "@/lib/sanity";
import type { Metadata } from "next";
import { UnlockPotentialSection } from "@/components/UnlockPotentialSection";
import { BlogHeader } from "@/components/BlogHeader";
import { FeaturedBlogCard } from "@/components/FeaturedBlogCard";
import { BlogCard } from "@/components/BlogCard";
import { BlogSectionHeader } from "@/components/BlogSectionHeader";
export const metadata: Metadata = {
title: "Blog - Plano",
description: "Latest insights, updates, and stories from Plano",
};
interface BlogPost {
_id: string;
title: string;
slug: { current: string };
summary?: string;
publishedAt?: string;
mainImage?: any;
mainImageUrl?: string;
thumbnailImage?: any;
thumbnailImageUrl?: string;
author?: {
name?: string;
title?: string;
image?: any;
};
featured?: boolean;
}
function formatDate(dateString: string): string {
const date = new Date(dateString);
const day = date.getDate();
const month = date.toLocaleDateString("en-US", { month: "long" });
const year = date.getFullYear();
// Add ordinal suffix
const getOrdinal = (n: number) => {
const s = ["th", "st", "nd", "rd"];
const v = n % 100;
return n + (s[(v - 20) % 10] || s[v] || s[0]);
};
return `${month} ${getOrdinal(day)}, ${year}`;
}
async function getBlogPosts(): Promise<BlogPost[]> {
const query = `*[_type == "blog" && published == true] | order(publishedAt desc) {
_id,
title,
slug,
summary,
publishedAt,
mainImage,
mainImageUrl,
thumbnailImage,
thumbnailImageUrl,
author,
featured
}`;
return await client.fetch(query);
}
export default async function BlogPage() {
const posts = await getBlogPosts();
const featuredPost = posts.find((post) => post.featured) || posts[0];
const recentPosts = posts
.filter((post) => post._id !== featuredPost?._id)
.slice(0, 3);
// Format dates in server component
const featuredPostWithDate = featuredPost
? {
...featuredPost,
formattedDate: featuredPost.publishedAt
? formatDate(featuredPost.publishedAt)
: undefined,
}
: null;
const recentPostsWithDates = recentPosts.map((post) => ({
...post,
formattedDate: post.publishedAt ? formatDate(post.publishedAt) : undefined,
}));
return (
<div className="min-h-screen">
{/* Header Section */}
<BlogHeader />
{/* Featured Post */}
{featuredPostWithDate && (
<section className="">
<div className="max-w-[85rem] mx-auto px-4 sm:px-6 lg:px-8 pb-8 sm:pb-12 lg:pb-0">
<FeaturedBlogCard post={featuredPostWithDate} />
</div>
</section>
)}
{/* Recent Posts Section */}
{recentPostsWithDates.length > 0 && (
<section className="border-b border-black/10 py-8 sm:py-12 lg:py-24">
<div className="max-w-[85rem] mx-auto px-4 sm:px-6 lg:px-8">
<BlogSectionHeader />
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-6 lg:gap-8">
{recentPostsWithDates.map((post, index) => (
<BlogCard key={post._id} post={post} index={index} />
))}
</div>
</div>
</section>
)}
{/* Call to Action Section */}
<UnlockPotentialSection variant="transparent" />
</div>
);
}

View file

@ -0,0 +1,16 @@
import React from "react";
export default function DocsPage() {
return (
<section className="px-4 sm:px-6 lg:px-8 py-12 sm:py-16 lg:py-24">
<div className="max-w-[81rem] mx-auto">
<h1 className="text-4xl sm:text-5xl lg:text-7xl font-normal leading-tight tracking-tighter text-black mb-6">
<span className="font-sans">Documentation</span>
</h1>
<p className="text-lg sm:text-xl lg:text-2xl font-sans font-[400] tracking-[-1.2px] text-black/70">
Coming soon...
</p>
</div>
</section>
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -0,0 +1,2 @@
/* This file is kept for backwards compatibility but styles are imported from @katanemo/shared-styles */
@import "@katanemo/shared-styles/globals.css";

View file

@ -0,0 +1,39 @@
import type { Metadata } from "next";
import Script from "next/script";
import "@katanemo/shared-styles/globals.css";
import { Analytics } from "@vercel/analytics/next";
import { ConditionalLayout } from "@/components/ConditionalLayout";
export const metadata: Metadata = {
title: "Plano - Delivery Infrastructure for Agentic Apps",
description:
"Build agents faster, and deliver them reliably to production - by offloading the critical plumbing work to Plano!",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className="antialiased">
{/* Google tag (gtag.js) */}
<Script
src="https://www.googletagmanager.com/gtag/js?id=G-6J5LQH3Q9G"
strategy="afterInteractive"
/>
<Script id="google-analytics" strategy="afterInteractive">
{`
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-6J5LQH3Q9G');
`}
</Script>
<ConditionalLayout>{children}</ConditionalLayout>
<Analytics />
</body>
</html>
);
}

28
apps/www/src/app/page.tsx Normal file
View file

@ -0,0 +1,28 @@
"use client";
import React from "react";
import { Hero } from "@/components/Hero";
import { IntroSection } from "@/components/IntroSection";
import { IdeaToAgentSection } from "@/components/IdeaToAgentSection";
import { UseCasesSection } from "@/components/UseCasesSection";
import { VerticalCarouselSection } from "@/components/VerticalCarouselSection";
import { HowItWorksSection } from "@/components/HowItWorksSection";
import { UnlockPotentialSection } from "@/components/UnlockPotentialSection";
import { LogoCloud } from "@/components/LogoCloud";
export default function Home() {
return (
<>
<Hero />
<LogoCloud />
<IntroSection />
<IdeaToAgentSection />
<UseCasesSection />
<VerticalCarouselSection />
<HowItWorksSection />
<UnlockPotentialSection variant="transparent" />
{/* Rest of the sections will be refactored next */}
</>
);
}

View file

@ -0,0 +1,28 @@
"use client";
import React from "react";
import {
ResearchHero,
ResearchGrid,
ResearchTimeline,
ResearchCTA,
ResearchCapabilities,
ResearchBenchmarks,
ResearchFamily,
} from "@/components/research";
import { UnlockPotentialSection } from "@/components/UnlockPotentialSection";
export default function ResearchPage() {
return (
<>
<ResearchHero />
<ResearchGrid />
<ResearchTimeline />
<ResearchCTA />
<ResearchCapabilities />
<ResearchBenchmarks />
{/* <ResearchFamily /> */}
<UnlockPotentialSection variant="transparent" />
</>
);
}

View file

@ -0,0 +1,8 @@
"use client";
import { NextStudio } from "next-sanity/studio";
import config from "../../../../sanity.config";
export default function StudioPage() {
return <NextStudio config={config} />;
}

View file

@ -0,0 +1,11 @@
export default function StudioLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="fixed inset-0 h-screen w-screen overflow-hidden">
{children}
</div>
);
}

View file

@ -0,0 +1,90 @@
import React from "react";
interface AsciiDiagramProps {
title?: string;
content: string;
className?: string;
}
export const AsciiDiagram: React.FC<AsciiDiagramProps> = ({
title,
content,
className = "",
}) => {
return (
<div className={`max-w-4xl mx-auto mb-8 ${className}`}>
{title && (
<h2 className="text-2xl font-bold text-gray-900 dark:text-zinc-50 mb-4">
{title}
</h2>
)}
<div className="bg-gray-900 dark:bg-gray-950 rounded-lg p-6 shadow-xl overflow-x-auto">
<pre
className="relative font-mono text-xs leading-none text-white m-0 whitespace-pre"
style={{ fontFamily: "var(--font-jetbrains-mono), monospace" }}
>
<code>{content}</code>
</pre>
</div>
</div>
);
};
// Programmatic diagram builder for non-coders
interface DiagramStep {
id: string;
label: string;
type?: "input" | "inner" | "regular";
x: number;
y: number;
}
interface FlowConnection {
from: string;
to: string;
label?: string;
}
interface DiagramConfig {
title: string;
steps: DiagramStep[];
connections: FlowConnection[];
}
// Simple ASCII diagram generator
export const createDiagram = (config: DiagramConfig): string => {
// This is a simplified version - you can extend this to automatically generate
// the ASCII art from the config
// For now, return the manually created diagrams
return "";
};
// Helper to create boxes
export const createBox = (
label: string,
type: "input" | "inner" | "regular" = "regular",
width: number = 20,
): string[] => {
const padding = Math.max(0, Math.floor((width - label.length) / 2));
const spaces = " ".repeat(padding);
const remaining = width - label.length - padding;
let chars;
switch (type) {
case "input":
chars = { tl: "╔", tr: "╗", bl: "╚", br: "╝", h: "═", v: "║" };
break;
case "inner":
chars = { tl: "┏", tr: "┓", bl: "┗", br: "┛", h: "━", v: "┃" };
break;
case "regular":
default:
chars = { tl: "┌", tr: "┐", bl: "└", br: "┘", h: "─", v: "│" };
}
return [
`${chars.tl}${chars.h.repeat(width)}${chars.tr}`,
`${chars.v}${spaces}${label}${" ".repeat(remaining)}${chars.v}`,
`${chars.bl}${chars.h.repeat(width)}${chars.br}`,
];
};

View file

@ -0,0 +1,87 @@
"use client";
import { motion } from "framer-motion";
import Image from "next/image";
import Link from "next/link";
import { urlFor } from "@/lib/sanity";
interface BlogCardProps {
post: {
_id: string;
title: string;
slug: { current: string };
formattedDate?: string;
author?: {
name?: string;
title?: string;
image?: any;
};
};
index?: number;
}
export function BlogCard({ post, index = 0 }: BlogCardProps) {
return (
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{
duration: 0.4,
delay: index * 0.05,
ease: "easeOut",
}}
>
<Link href={`/blog/${post.slug.current}`} className="group block h-full">
<motion.article
className="h-full min-h-[320px] bg-linear-to-b from-primary/20 to-primary/1 border border-primary/20 rounded-md p-6 sm:p-8 flex flex-col"
whileHover={{
borderColor: "rgba(119, 128, 217, 0.5)",
}}
transition={{
duration: 0.2,
ease: "easeOut",
}}
>
{post.formattedDate && (
<div className="text-base font-medium tracking-[-0.9px] text-black mb-6">
{post.formattedDate}
</div>
)}
<h3 className="text-xl sm:text-2xl font-normal leading-tight tracking-tighter text-black group-hover:text-[var(--secondary)] transition-colors flex-grow">
<span className="font-sans font-medium tracking-[-1.5px]">
{post.title}
</span>
</h3>
{post.author && (
<div className="flex items-center gap-3 mt-auto pt-6">
{post.author.image ? (
<div className="relative w-10 h-10 rounded overflow-hidden shrink-0">
<Image
src={urlFor(post.author.image).width(80).url()}
alt={post.author.name || "Author"}
fill
className="object-cover"
/>
</div>
) : (
<div className="w-10 h-10 rounded-full bg-[var(--secondary)]/20 shrink-0" />
)}
<div>
{post.author.name && (
<div className="text-base font-mono font-semibold tracking-wider text-primary uppercase">
{post.author.name}
</div>
)}
{post.author.title && (
<div className="text-xs font-mono font-normal tracking-wider text-[#28327D] uppercase">
{post.author.title}
</div>
)}
</div>
</div>
)}
</motion.article>
</Link>
</motion.div>
);
}

View file

@ -0,0 +1,25 @@
"use client";
import { motion } from "framer-motion";
export function BlogHeader() {
return (
<motion.section
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{
duration: 0.5,
ease: "easeOut",
}}
>
<div className="max-w-[85rem] mx-auto px-4 sm:px-6 lg:px-8 pt-8 sm:pt-12 lg:pt-1 pb-8 sm:pb-12 lg:pb-16">
<h1 className="text-4xl sm:text-5xl lg:text-7xl font-normal leading-tight tracking-tighter text-black mb-3 sm:mb-4">
<span className="font-sans">What's new with Plano</span>
</h1>
<p className="text-base sm:text-lg md:text-xl lg:text-2xl font-sans font-normal tracking-[-1.0px] sm:tracking-[-1.2px] text-black max-w-3xl">
Building the future of infrastructure and tools for AI developers.
</p>
</div>
</motion.section>
);
}

View file

@ -0,0 +1,9 @@
"use client";
export function BlogSectionHeader() {
return (
<h2 className="text-2xl sm:text-3xl lg:text-4xl font-normal leading-tight tracking-tighter text-black mb-12">
<span className="font-sans">The latest and greatest from our blog.</span>
</h2>
);
}

View file

@ -0,0 +1,21 @@
"use client";
import { usePathname } from "next/navigation";
import { Navbar, Footer } from "@katanemo/ui";
export function ConditionalLayout({ children }: { children: React.ReactNode }) {
const pathname = usePathname();
const isStudio = pathname?.startsWith("/studio");
if (isStudio) {
return <>{children}</>;
}
return (
<div className="min-h-screen">
<Navbar />
<main className="pt-2 md:pt-10">{children}</main>
<Footer />
</div>
);
}

View file

@ -0,0 +1,34 @@
import React from "react";
import { createFlowDiagram, FlowDiagramConfig } from "@/utils/asciiBuilder";
import { AsciiDiagram } from "./AsciiDiagram";
interface DiagramBuilderProps {
config: FlowDiagramConfig;
title?: string;
}
/**
* Simple Diagram Builder Component
*
* Usage:
*
* <DiagramBuilder
* config={{
* title: "My Process",
* width: 60,
* steps: [
* { label: "Start", type: "regular" },
* { label: "Process", type: "inner" },
* { label: "End", type: "regular" }
* ]
* }}
* />
*/
export const DiagramBuilder: React.FC<DiagramBuilderProps> = ({
config,
title,
}) => {
const asciiDiagram = createFlowDiagram(config);
return <AsciiDiagram content={asciiDiagram} title={title} />;
};

View file

@ -0,0 +1,117 @@
"use client";
import { motion } from "framer-motion";
import Image from "next/image";
import Link from "next/link";
import { urlFor } from "@/lib/sanity";
interface FeaturedBlogCardProps {
post: {
_id: string;
title: string;
slug: { current: string };
summary?: string;
formattedDate?: string;
mainImage?: any;
mainImageUrl?: string;
author?: {
name?: string;
title?: string;
image?: any;
};
};
}
export function FeaturedBlogCard({ post }: FeaturedBlogCardProps) {
return (
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{
duration: 0.4,
ease: "easeOut",
}}
>
<Link href={`/blog/${post.slug.current}`} className="group block">
<motion.div
className="bg-linear-to-b from-primary/20 to-primary/1 border border-primary/20 rounded-md p-8 sm:p-10 lg:p-12"
whileHover={{
borderColor: "rgba(119, 128, 217, 0.5)",
}}
transition={{
duration: 0.2,
ease: "easeOut",
}}
>
<div className="grid lg:grid-cols-2 gap-8 lg:gap-12 items-center">
{/* Content */}
<div className="order-1 text-left">
{post.formattedDate && (
<div className="text-base font-medium tracking-[-0.9px] text-black mb-4">
{post.formattedDate}
</div>
)}
<h2 className="text-3xl sm:text-4xl lg:text-4xl font-medium tracking-[-1.5px] text-black mb-4 group-hover:text-[var(--secondary)] transition-colors text-left">
<span className="font-sans">{post.title}</span>
</h2>
{post.summary && (
<p className="text-base sm:text-base font-mono font-normal tracking-[-0.9px] text-black/70 mb-6 text-left">
{post.summary}
</p>
)}
{post.author && (
<div className="flex items-center gap-3">
{post.author.image ? (
<div className="relative w-12 h-12 rounded overflow-hidden shrink-0">
<Image
src={urlFor(post.author.image).width(80).url()}
alt={post.author.name || "Author"}
fill
className="object-cover"
/>
</div>
) : (
<div className="w-12 h-12 rounded-full bg-[var(--secondary)]/20 shrink-0" />
)}
<div>
{post.author.name && (
<div className="text-lg font-mono font-semibold tracking-wider text-primary uppercase">
{post.author.name}
</div>
)}
{post.author.title && (
<div className="text-sm font-mono font-normal tracking-wider text-[#28327D] uppercase">
{post.author.title}
</div>
)}
</div>
</div>
)}
</div>
{/* Image */}
<div className="relative aspect-[18/9] w-full overflow-hidden rounded-lg bg-black/5 order-2">
{post.mainImage ? (
<Image
src={urlFor(post.mainImage).width(800).url()}
alt={post.title}
fill
className="object-cover"
/>
) : post.mainImageUrl ? (
<Image
src={post.mainImageUrl}
alt={post.title}
fill
className="object-cover"
/>
) : (
<div className="w-full h-full bg-gradient-to-br from-[var(--secondary)]/20 to-black/10" />
)}
</div>
</div>
</motion.div>
</Link>
</motion.div>
);
}

View file

@ -0,0 +1,68 @@
import React from "react";
import { Button } from "@katanemo/ui";
import Link from "next/link";
import { NetworkAnimation } from "./NetworkAnimation";
export function Hero() {
return (
<section className="relative pt-8 sm:pt-12 lg:pt-1 pb-6 px-4 sm:px-6 lg:px-8 overflow-hidden">
<div className="max-w-[81rem] mx-auto relative">
<div className="hidden lg:block absolute inset-0 pointer-events-none ">
<NetworkAnimation />
</div>
<div className="lg:hidden absolute inset-0 pointer-events-none">
<NetworkAnimation className="!w-[300px] !h-[300px] left-82! top-1! opacity-90! " />
</div>
<div className="max-w-3xl mb-3 sm:mb-4 relative z-10">
{/* Version Badge */}
<div className="mb-4 sm:mb-6">
<div className="inline-flex flex-wrap items-center gap-1.5 sm:gap-2 px-3 sm:px-4 py-1 rounded-full bg-[rgba(185,191,255,0.4)] border border-[var(--secondary)] shadow backdrop-blur">
<span className="text-xs sm:text-sm font-medium text-black/65">
v0.4
</span>
<span className="text-xs sm:text-sm font-medium text-black ">
</span>
<span className="text-xs sm:text-sm font-[600] tracking-[-0.6px]! text-black leading-tight">
<span className="hidden sm:inline">
Unified /v1/responses API with state management
</span>
<span className="sm:hidden">Unified /v1/responses API</span>
</span>
</div>
</div>
{/* Main Heading */}
<h1 className="text-4xl sm:text-4xl md:text-5xl lg:text-7xl font-normal leading-tight tracking-tighter text-black flex flex-col gap-0 sm:-space-y-2 lg:-space-y-3">
<span className="font-sans">Delivery Infrastructure </span>
<span className="font-sans font-medium text-[var(--secondary)]">
for Agentic Apps
</span>
</h1>
</div>
{/* Subheading with CTA Buttons */}
<div className="max-w-7xl relative z-10">
<p className="text-base sm:text-lg md:text-xl lg:text-[22px] font-sans font-[400] tracking-[-1.0px] sm:tracking-[-1.22px]! text-black max-w-76 sm:max-w-2xl mb-6">
Build agents faster, and deliver them reliably to production - by
offloading the critical plumbing work to Plano.
</p>
{/* CTA Buttons */}
<div className="flex flex-col sm:flex-row items-stretch sm:items-start gap-3 sm:gap-4">
<Button asChild className="w-full sm:w-auto">
<Link href="https://docs.planoai.dev/get_started/quickstart" target="_blank" rel="noopener noreferrer">
Get started
</Link>
</Button>
<Button variant="secondary" asChild className="w-full sm:w-auto">
<Link href="https://docs.planoai.dev" target="_blank" rel="noopener noreferrer">
Documentation
</Link>
</Button>
</div>
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,70 @@
"use client";
import React from "react";
import Image from "next/image";
export function HowItWorksSection() {
return (
<section className="bg-[#1a1a1a] text-white pb-16 sm:pb-20 lg:pb-28 sm:pt-0 pt-20">
<div className="max-w-312 mx-auto sm:pl-0">
<div className="flex flex-col gap-8 sm:gap-12 lg:gap-16">
{/* Header and Description */}
<div className="max-w-4xl lg:-ml-[102px] lg:pl-[102px] sm:pl-0 pl-4">
<h2 className="font-sans font-normal text-xl sm:text-2xl lg:text-3xl tracking-[-1.6px] sm:tracking-[-2px]! text-white leading-[1.03] mb-6 sm:mb-8">
One configuration file to orchestrate
</h2>
<div className="text-white w-100 sm:w-full text-sm sm:text-lg lg:text-lg">
<p className="mb-0">
Plano offers a delightful developer experience with a simple
configuration file that describes the types of prompts your
agentic app supports, a set of APIs that need to be plugged in
for agentic scenarios (including retrieval queries) and your
choice of LLMs.
</p>
</div>
</div>
{/* Large Diagram - Scrollable on mobile, normal on desktop */}
{/* Mobile: Full-width scrollable container that extends to viewport edges */}
<div
className="mt-5 lg:hidden relative left-1/2 right-1/2 -ml-[50vw] -mr-[50vw] w-screen overflow-x-auto overflow-y-visible"
style={{
scrollbarWidth: "none",
msOverflowStyle: "none",
WebkitOverflowScrolling: "touch",
}}
>
<style jsx>{`
.diagram-scroll-container::-webkit-scrollbar {
display: none;
}
`}</style>
<div className="diagram-scroll-container inline-block">
<Image
src="/HowItWorks.svg"
alt="How Plano Works Diagram"
width={1200}
height={600}
className="h-auto"
style={{ width: "1200px", maxWidth: "none", display: "block" }}
priority
/>
</div>
</div>
{/* Desktop: Extends to container edges */}
<div className="hidden lg:block -w-[calc(10%+20px)] -mx-[10px]">
<Image
src="/HowItWorks.svg"
alt="How Plano Works Diagram"
width={10}
height={10}
className="w-full h-auto"
priority
/>
</div>
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,202 @@
"use client";
import React, { useState, useEffect } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { Button } from "@katanemo/ui";
import Link from "next/link";
const carouselData = [
{
id: 1,
category: "LAUNCH FASTER",
title: "Focus on core objectives",
description:
"Building agents is hard enough. The plumbing work shouldn't be. Plano handles routing, observability, and policy hooks as a models-native sidecar—so you can focus on your agent's core product logic and ship to production faster.",
image: "/LaunchFaster.svg",
link: "https://docs.planoai.dev/get_started/quickstart",
},
{
id: 2,
category: "BUILD WITH CHOICE",
title: "Rapidly incorporate LLMs",
description:
"Build with multiple LLMs or model versions with a single unified API. Plano centralizes access controls, offers resiliency for traffic to 100+ LLMs -- all without you having to write a single line of code. Use existing libraries and proxy traffic through Plano.",
image: "/BuildWithChoice.svg",
link: "https://docs.planoai.dev/concepts/llm_providers/llm_providers",
},
{
id: 3,
category: "RICH LEARNING SIGNALS",
title: "Hyper-rich agent traces and logs",
description:
"Knowing when agents fail or delight users is a critical signal that feeds into the reinforcement learning and optimization cycle. Plano makes this trivial by sampling hyper-rich information traces from live production agentic interactions so that you can improve agent performance faster.",
image: "/Telemetry.svg",
link: "https://docs.planoai.dev/guides/observability/observability.html",
},
{
id: 4,
category: "SHIP CONFIDENTLY",
title: "Centrally apply guardrail policies",
description:
"Plano comes built-in with a state-of-the-art guardrail model you can use for things like jailbreak detection. But you can easily extend those capabilities via plano's agent filter chain to apply custom policy checks in a centralized way and keep users engaged on topics relevant to your requirements.",
image: "/ShipConfidently.svg",
link: "https://docs.planoai.dev/guides/prompt_guard.html",
},
{
id: 5,
category: "SCALABLE ARCHITECTURE",
title: "Protocol-Native Infrastructure",
description:
"Plano's sidecar deployment model avoids library-based abstractions - operating as a protocol-native data plane that integrates seamlessly with your existing agents via agentic APIs (like v1/responses). This decouples your core agent logic from plumbing concerns - run it alongside any framework without code changes, vendor lock-in, or performance overhead.",
image: "/Contextual.svg",
link: "https://docs.planoai.dev/concepts/tech_overview/tech_overview.html",
},
];
export function IdeaToAgentSection() {
const [currentSlide, setCurrentSlide] = useState(0);
const [isAutoPlaying, setIsAutoPlaying] = useState(true);
// Auto-advance slides
useEffect(() => {
if (!isAutoPlaying) return;
const interval = setInterval(() => {
setCurrentSlide((prev) => (prev + 1) % carouselData.length);
}, 10000); // 10 seconds per slide
return () => clearInterval(interval);
}, [isAutoPlaying]);
const handleSlideClick = (index: number) => {
setCurrentSlide(index);
setIsAutoPlaying(false);
// Resume auto-play after 10 seconds
setTimeout(() => setIsAutoPlaying(true), 10000);
};
return (
<section className="relative py-12 sm:py-16 lg:py-24 px-4 sm:px-6 lg:px-[102px]">
<div className="max-w-[81rem] mx-auto">
{/* Main Heading */}
<h2 className="font-sans font-normal text-2xl sm:text-3xl lg:text-4xl tracking-[-2px] sm:tracking-[-2.96px]! text-black mb-6 sm:mb-8 lg:mb-10">
Idea to agent without overhead
</h2>
{/* Progress Indicators */}
<div className="flex gap-1.5 sm:gap-2 mb-4 sm:mb-6 lg:mb-6 w-full">
{carouselData.map((_, index) => (
<button
key={index}
onClick={() => handleSlideClick(index)}
className={`relative h-1.5 sm:h-2 rounded-full overflow-hidden transition-all duration-300 hover:opacity-80 ${
index === currentSlide
? "flex-1 sm:w-16 md:w-20 lg:w-[292px]"
: "flex-1 sm:w-16 md:w-20 lg:w-[293px]"
}`}
>
{/* Background */}
<div className="absolute inset-0 bg-black/6 rounded-full" />
{/* Active Progress */}
{index === currentSlide && (
<motion.div
className="absolute inset-0 bg-[#7780d9] rounded-full"
initial={{ width: 0 }}
animate={{ width: "100%" }}
transition={{ duration: 10, ease: "linear" }}
key={currentSlide}
/>
)}
{/* Completed State */}
{index < currentSlide && (
<div className="absolute inset-0 bg-purple-200/90 rounded-full" />
)}
</button>
))}
</div>
{/* Carousel Content - Fixed height to prevent layout shift */}
<div className="relative h-[500px] sm:h-[550px] md:h-[600px] lg:h-[500px]">
<AnimatePresence mode="wait">
<motion.div
key={currentSlide}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.4, ease: "easeInOut" }}
className="absolute inset-0"
>
<div className="flex flex-col lg:flex-row lg:justify-between lg:items-center lg:gap-12 h-full">
{/* Left Content */}
<div className="flex-1 order-1 lg:order-1 flex flex-col justify-center">
<div className="max-w-[692px] mt-0 lg:mt-0">
{/* Category */}
<p className="font-mono font-bold text-[#2a3178] text-sm sm:text-base lg:text-xl tracking-[1.44px] sm:tracking-[1.92px]! mb-3 sm:mb-4 leading-[1.102]">
{carouselData[currentSlide].category}
</p>
{/* Title */}
<h3 className="font-sans font-medium text-[#9797ea] text-2xl sm:text-3xl lg:text-5xl tracking-tight sm:tracking-[-2.96px]! mb-4 sm:mb-6 lg:mb-7">
{carouselData[currentSlide].title}
</h3>
{/* Description */}
<div className="text-black text-sm sm:text-base lg:text-lg max-w-full lg:max-w-140">
<p className="mb-0">
{carouselData[currentSlide].description}
</p>
</div>
<Button asChild className="mt-6 sm:mt-8 w-full sm:w-auto">
<Link href={carouselData[currentSlide].link}>
Learn more
</Link>
</Button>
</div>
</div>
{/* Image - Show below on mobile, right side on desktop */}
{carouselData[currentSlide].image && (
<div className="flex lg:hidden shrink-0 w-full justify-center items-center mb-6 sm:mb-8 order-0 lg:order-2">
<img
src={carouselData[currentSlide].image}
alt={carouselData[currentSlide].category}
className={`w-full h-auto object-contain ${
carouselData[currentSlide].image === "/Telemetry.svg"
? "max-w-md sm:max-w-lg max-h-[300px] sm:max-h-[350px]"
: "max-w-sm sm:max-w-md max-h-[250px] sm:max-h-[300px]"
}`}
/>
</div>
)}
{/* Right Image - Desktop only */}
{carouselData[currentSlide].image && (
<div
className={`hidden lg:flex shrink-0 justify-end items-center order-2 ${
carouselData[currentSlide].image === "/Telemetry.svg"
? "w-[500px] xl:w-[600px]"
: "w-[400px] xl:w-[500px]"
}`}
>
<img
src={carouselData[currentSlide].image}
alt={carouselData[currentSlide].category}
className={`w-full h-auto object-contain ${
carouselData[currentSlide].image === "/Telemetry.svg"
? "max-h-[550px]"
: "max-h-[450px]"
}`}
/>
</div>
)}
</div>
</motion.div>
</AnimatePresence>
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,54 @@
import React from "react";
import Image from "next/image";
export function IntroSection() {
return (
<section className="relative bg-[#1a1a1a] text-white py-20 px-6 lg:px-[102px]">
<div className="max-w-324 mx-auto">
<div className="flex flex-col lg:flex-row gap-12">
{/* Left Content */}
<div className="flex-1 mt-2">
{/* Heading */}
<p className="font-mono font-bold text-primary-light text-xl tracking-[1.92px]! mb-4 leading-[1.102]">
WHY PLANO?
</p>
<h2 className="font-sans font-medium tracking-[-1.92px]! text-[#9797ea] text-4xl leading-[1.102] mb-6 max-w-[633px]">
Deliver prototypes to production
<span className="italic">fast.</span>
</h2>
{/* Body Text */}
<div className="text-white text-sm sm:text-base lg:text-lg max-w-[713px]">
<p className="mb-0">
Plano is a models-native proxy and dataplane for agents that
handles critical plumbing work in AI - agent routing and
orchestration, rich agentic traces, guardrail hooks, and smart
model routing APIs for LLMs. Use any language, AI framework, and
deliver agents to productions quickly with Plano.
</p>
<p className="mb-0 mt-4">
Developers can focus more on core product logic of agents.
Product teams can accelerate feedback loops for reinforcement
learning. Engineering teams can standardize policies and access
controls across every agent and LLM for safer, more reliable
scaling.
</p>
</div>
</div>
{/* Right Diagram */}
<div className="flex-1 relative w-full">
<Image
src="/IntroDiagram.svg"
alt="Network Path Diagram"
width={800}
height={600}
className="w-full h-auto"
priority
/>
</div>
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,69 @@
import React from "react";
import Image from "next/image";
const customerLogos = [
{
name: "HuggingFace",
src: "/logos/huggingface.svg",
},
{
name: "T-Mobile",
src: "/logos/tmobile.svg",
},
{
name: "HP",
src: "/logos/hp.svg",
},
{
name: "SanDisk",
src: "/logos/sandisk.svg",
},
{
name: "Chase",
src: "/logos/chase.svg",
},
];
export function LogoCloud() {
return (
<section className="relative py-6 sm:py-8 px-4 sm:px-6 lg:px-8 bg-transparent">
<div className="max-w-[81rem] mx-auto">
<div className="grid grid-cols-2 md:grid-cols-3 lg:flex lg:flex-row lg:justify-center lg:items-center gap-4 sm:gap-6 md:gap-8 lg:gap-0 place-items-center">
{customerLogos.map((logo, index) => {
const isLast = index === customerLogos.length - 1;
const isTMobile = index === 1; // T-Mobile is before HP
const isHP = index === 2; // HP is in center
const isSanDisk = index === 3; // SanDisk is after HP
// Custom spacing for logos around HP on large screens
let spacingClass = "lg:mx-6 xl:mx-8"; // Default spacing
if (isTMobile) {
spacingClass = "lg:mr-3 xl:mr-4 lg:ml-6 xl:ml-8"; // Smaller gap to HP
} else if (isHP) {
spacingClass = "lg:mx-3 xl:mx-4"; // Smaller gaps on both sides
} else if (isSanDisk) {
spacingClass = "lg:ml-3 xl:ml-4 lg:mr-6 xl:mr-8"; // Smaller gap from HP
}
return (
<div
key={logo.name}
className={`flex items-center justify-center opacity-60 hover:opacity-80 transition-opacity duration-300 w-full max-w-32 sm:max-w-40 md:max-w-48 h-10 sm:h-12 md:h-16 mx-auto ${spacingClass} ${
isLast ? "col-span-2 md:col-span-3 lg:col-span-none" : ""
}`}
>
<Image
src={logo.src}
alt={`${logo.name} logo`}
width={128}
height={40}
className="w-full h-full object-contain filter grayscale hover:grayscale-0 transition-all duration-300"
/>
</div>
);
})}
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,206 @@
"use client";
import React, { useId } from "react";
import { motion } from "framer-motion";
// Define the grid of squares with their positions and colors
const squares = [
// Column 1 (x=3)
{ x: 3, y: 3, color: "#B0B7FF", col: 0, row: 0 },
{ x: 3, y: 6, color: "#B0B7FF", col: 0, row: 1 },
{ x: 3, y: 9, color: "#B0B7FF", col: 0, row: 2 },
{ x: 3, y: 12, color: "#ABB2FA", col: 0, row: 3 },
{ x: 3, y: 15, color: "#ABB2FA", col: 0, row: 4 },
{ x: 3, y: 18, color: "#ABB2FA", col: 0, row: 5 },
{ x: 3, y: 21, color: "#969FF4", col: 0, row: 6 },
// Column 2 (x=6)
{ x: 6, y: 3, color: "#B0B7FF", col: 1, row: 0 },
{ x: 6, y: 6, color: "#B0B7FF", col: 1, row: 1 },
{ x: 6, y: 9, color: "#ABB2FA", col: 1, row: 2 },
{ x: 6, y: 12, color: "#ABB2FA", col: 1, row: 3 },
{ x: 6, y: 15, color: "#ABB2FA", col: 1, row: 4 },
{ x: 6, y: 18, color: "#969FF4", col: 1, row: 5 },
{ x: 6, y: 21, color: "#969FF4", col: 1, row: 6 },
// Column 3 (x=9)
{ x: 9, y: 3, color: "#B0B7FF", col: 2, row: 0 },
{ x: 9, y: 6, color: "#ABB2FA", col: 2, row: 1 },
{ x: 9, y: 9, color: "#ABB2FA", col: 2, row: 2 },
{ x: 9, y: 12, color: "#ABB2FA", col: 2, row: 3 },
{ x: 9, y: 15, color: "#969FF4", col: 2, row: 4 },
{ x: 9, y: 18, color: "#969FF4", col: 2, row: 5 },
{ x: 9, y: 21, color: "#969FF4", col: 2, row: 6 },
// Column 4 (x=12)
{ x: 12, y: 3, color: "#ABB2FA", col: 3, row: 0 },
{ x: 12, y: 6, color: "#ABB2FA", col: 3, row: 1 },
{ x: 12, y: 9, color: "#ABB2FA", col: 3, row: 2 },
{ x: 12, y: 12, color: "#969FF4", col: 3, row: 3 },
{ x: 12, y: 15, color: "#969FF4", col: 3, row: 4 },
{ x: 12, y: 18, color: "#969FF4", col: 3, row: 5 },
{ x: 12, y: 21, color: "#969FF4", col: 3, row: 6 },
// Column 5 (x=15)
{ x: 15, y: 3, color: "#ABB2FA", col: 4, row: 0 },
{ x: 15, y: 6, color: "#ABB2FA", col: 4, row: 1 },
{ x: 15, y: 9, color: "#969FF4", col: 4, row: 2 },
{ x: 15, y: 12, color: "#969FF4", col: 4, row: 3 },
{ x: 15, y: 15, color: "#969FF4", col: 4, row: 4 },
{ x: 15, y: 18, color: "#969FF4", col: 4, row: 5 },
{ x: 15, y: 21, color: "#969FF4", col: 4, row: 6 },
// Column 6 (x=18)
{ x: 18, y: 3, color: "#ABB2FA", col: 5, row: 0 },
{ x: 18, y: 6, color: "#969FF4", col: 5, row: 1 },
{ x: 18, y: 9, color: "#969FF4", col: 5, row: 2 },
{ x: 18, y: 12, color: "#969FF4", col: 5, row: 3 },
{ x: 18, y: 15, color: "#969FF4", col: 5, row: 4 },
{ x: 18, y: 18, color: "#969FF4", col: 5, row: 5 },
{ x: 18, y: 21, color: "#969FF4", col: 5, row: 6 },
// Column 7 (x=21)
{ x: 21, y: 3, color: "#969FF4", col: 6, row: 0 },
{ x: 21, y: 6, color: "#969FF4", col: 6, row: 1 },
{ x: 21, y: 9, color: "#969FF4", col: 6, row: 2 },
{ x: 21, y: 12, color: "#969FF4", col: 6, row: 3 },
{ x: 21, y: 15, color: "#969FF4", col: 6, row: 4 },
{ x: 21, y: 18, color: "#969FF4", col: 6, row: 5 },
{ x: 21, y: 21, color: "#969FF4", col: 6, row: 6 },
];
interface NetworkAnimationProps {
className?: string;
}
// Deterministic seeded random number generator for consistent SSR/client values
function seededRandom(seed: number): number {
const x = Math.sin(seed) * 10000;
return x - Math.floor(x);
}
// Round to fixed precision to avoid floating-point precision differences
function roundToPrecision(value: number, precision: number = 10): number {
return Math.round(value * Math.pow(10, precision)) / Math.pow(10, precision);
}
// Generate deterministic random values based on index
function getDeterministicValues(index: number) {
const seed1 = index * 0.1;
const seed2 = index * 0.2;
const seed3 = index * 0.3;
const seed4 = index * 0.4;
const seed5 = index * 0.5;
const seed6 = index * 0.6;
return {
duration: roundToPrecision(3 + seededRandom(seed1) * 3, 10), // 3-6 seconds
peakOpacity: roundToPrecision(0.7 + seededRandom(seed2) * 0.3, 10),
baseOpacity: roundToPrecision(0.3 + seededRandom(seed3) * 0.2, 10),
midOpacity: roundToPrecision(0.5 + seededRandom(seed4) * 0.2, 10),
baseBrightness: roundToPrecision(0.85 + seededRandom(seed5) * 0.15, 10),
peakBrightness: roundToPrecision(1.0 + seededRandom(seed6) * 0.2, 10),
};
}
export function NetworkAnimation({ className }: NetworkAnimationProps) {
// Generate unique IDs for gradient and mask to avoid conflicts when multiple instances exist
const gradientId = useId().replace(/:/g, "-");
const maskId = useId().replace(/:/g, "-");
return (
<div className="absolute inset-0 pointer-events-none opacity-100">
<motion.div
className={`absolute
top-[9%] right-[-3%] w-[380px] h-[380px] ${className || ""}`}
initial={{
rotate: 9, // Start at the same rotation as animation to prevent flicker
}}
animate={{
rotate: [9, 10, 9], // Slight breathing rotation
}}
transition={{
duration: 8,
repeat: Infinity,
ease: "easeInOut",
}}
>
<svg
width="100%"
height="100%"
viewBox="0 0 32 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
{/* Gradient mask: transparent at bottom, opaque at top */}
<linearGradient id={gradientId} x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stopColor="white" stopOpacity="1" />
<stop offset="50%" stopColor="white" stopOpacity="0.5" />
<stop offset="100%" stopColor="white" stopOpacity="0" />
</linearGradient>
<mask id={maskId}>
<rect width="26" height="26" fill={`url(#${gradientId})`} />
</mask>
</defs>
<g mask={`url(#${maskId})`}>
{/* Outer border */}
<rect width="26" height="26" fill="#7780D9" />
{/* Inner background */}
<rect x="2" y="2" width="22" height="22" fill="#B9BFFF" />
{/* Animated squares with wave effect */}
{squares.map((square, index) => {
// Use deterministic values based on index for SSR/client consistency
const {
duration,
peakOpacity,
baseOpacity,
midOpacity,
baseBrightness,
peakBrightness,
} = getDeterministicValues(index);
return (
<motion.path
key={`square-${index}`}
d={`M${square.x} ${square.y}H${square.x + 2}V${square.y + 2}H${square.x}V${square.y}Z`}
fill={square.color}
initial={{
opacity: roundToPrecision(baseOpacity, 10),
filter: `brightness(${roundToPrecision(baseBrightness, 10)})`,
}}
animate={{
opacity: [
roundToPrecision(baseOpacity, 10),
roundToPrecision(midOpacity, 10),
roundToPrecision(peakOpacity, 10),
roundToPrecision(midOpacity, 10),
roundToPrecision(baseOpacity, 10),
],
filter: [
`brightness(${roundToPrecision(baseBrightness, 10)})`,
`brightness(${roundToPrecision((baseBrightness + peakBrightness) / 2, 10)})`,
`brightness(${roundToPrecision(peakBrightness, 10)})`,
`brightness(${roundToPrecision((baseBrightness + peakBrightness) / 2, 10)})`,
`brightness(${roundToPrecision(baseBrightness, 10)})`,
],
}}
transition={{
duration: roundToPrecision(duration, 10),
delay: 0, // No delay - instant start
repeat: Infinity,
ease: "easeInOut",
repeatDelay: 0, // No pause between cycles
}}
/>
);
})}
</g>
</svg>
</motion.div>
</div>
);
}

View file

@ -0,0 +1,125 @@
import { PortableText as SanityPortableText } from "@portabletext/react";
import Image from "next/image";
import { urlFor } from "@/lib/sanity";
import type { PortableTextBlock } from "@portabletext/types";
interface PortableTextProps {
content: PortableTextBlock[];
}
const components = {
types: {
image: ({ value }: any) => {
if (!value?.asset) return null;
const imageUrl = urlFor(value);
const asset = value.asset;
// Get natural dimensions if available from metadata
const dimensions = asset.metadata?.dimensions;
const width = dimensions?.width || 1000;
const height = dimensions?.height || 562;
const aspectRatio = dimensions ? height / width : 0.5625; // Default to 16:9 if no dimensions
return (
<div className="my-6 lg:my-8">
<div className="max-w-3xl mx-auto">
<div className="relative w-full overflow-hidden rounded-lg bg-black/5">
<div
className="relative w-full"
style={{ paddingBottom: `${aspectRatio * 100}%` }}
>
<Image
src={imageUrl.width(Math.min(width, 1000)).url()}
alt={value.alt || "Blog image"}
fill
className="object-contain"
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 768px, 1000px"
/>
</div>
</div>
{value.alt && (
<p className="mt-2 text-sm text-black/60 text-center">
{value.alt}
</p>
)}
</div>
</div>
);
},
},
block: {
h1: (props: any) => (
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-normal leading-tight tracking-tighter text-black mt-8 mb-4 first:mt-0">
<span className="font-sans">{props.children}</span>
</h1>
),
h2: (props: any) => (
<h2 className="text-3xl sm:text-4xl lg:text-5xl font-normal leading-tight tracking-tighter text-black mt-8 mb-4 first:mt-0">
<span className="font-sans">{props.children}</span>
</h2>
),
h3: (props: any) => (
<h3 className="text-2xl sm:text-3xl lg:text-4xl font-normal leading-tight tracking-tighter text-black mt-6 mb-3 first:mt-0">
<span className="font-sans">{props.children}</span>
</h3>
),
h4: (props: any) => (
<h4 className="text-xl sm:text-2xl lg:text-3xl font-normal leading-tight tracking-tighter text-black mt-6 mb-3 first:mt-0">
<span className="font-sans">{props.children}</span>
</h4>
),
normal: (props: any) => (
<p className="text-base sm:text-lg font-sans font-[400] tracking-[-0.5px] text-black/80 mb-4 leading-relaxed">
{props.children}
</p>
),
blockquote: (props: any) => (
<blockquote className="border-l-4 border-[var(--secondary)] pl-6 py-2 my-6 italic text-black/70">
{props.children}
</blockquote>
),
},
list: {
bullet: (props: any) => (
<ul className="list-disc list-inside mb-4 space-y-2 text-base sm:text-lg font-sans font-[400] tracking-[-0.5px] text-black/80">
{props.children}
</ul>
),
number: (props: any) => (
<ol className="list-decimal list-inside mb-4 space-y-2 text-base sm:text-lg font-sans font-[400] tracking-[-0.5px] text-black/80">
{props.children}
</ol>
),
},
listItem: {
bullet: (props: any) => <li className="ml-4">{props.children}</li>,
number: (props: any) => <li className="ml-4">{props.children}</li>,
},
marks: {
strong: ({ children }: { children: React.ReactNode }) => (
<strong className="font-semibold text-black">{children}</strong>
),
em: ({ children }: { children: React.ReactNode }) => (
<em className="italic">{children}</em>
),
link: (props: any) => (
<a
href={props.value?.href || "#"}
target={props.value?.href?.startsWith("http") ? "_blank" : undefined}
rel={
props.value?.href?.startsWith("http")
? "noopener noreferrer"
: undefined
}
className="text-[var(--secondary)] hover:underline font-medium"
>
{props.children}
</a>
),
},
};
export function PortableText({ content }: PortableTextProps) {
return <SanityPortableText value={content} components={components} />;
}

View file

@ -0,0 +1,46 @@
import React from "react";
import { Button } from "@katanemo/ui";
import Link from "next/link";
interface UnlockPotentialSectionProps {
variant?: "transparent" | "black";
className?: string;
}
export function UnlockPotentialSection({
variant = "transparent",
className = "",
}: UnlockPotentialSectionProps) {
const backgroundClass = variant === "black" ? "bg-[#1a1a1a]" : "";
const textColor = variant === "black" ? "text-white" : "text-black";
return (
<section
className={`relative py-24 px-6 lg:px-[102px]`}
style={{ background: "linear-gradient(to top right, #ffffff, #dcdfff)" }}
>
<div className="max-w-[81rem] mx-auto">
<div className="max-w-4xl">
<h2
className={`font-sans font-normal text-[1.8rem] lg:text-4xl tracking-[-2.55px]! ${textColor} leading-[1.4] mb-8`}
>
Focus on prompting, not plumbing.
<br />
Build with{" "}
<strong className="font-medium text-primary">plano</strong>, get
started in less than a minute.
</h2>
<div className="flex flex-col sm:flex-row gap-5">
<Button asChild>
<Link href="https://docs.planoai.dev/get_started/quickstart">Deploy today</Link>
</Button>
<Button variant="secondaryDark" asChild>
<Link href="https://docs.planoai.dev/get_started/quickstart">Documentation</Link>
</Button>
</div>
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,310 @@
"use client";
import React, { useState } from "react";
import {
ArrowRightIcon,
Network,
Filter,
TrendingUp,
Shield,
Server,
XIcon,
} from "lucide-react";
import {
Button,
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogClose,
} from "@katanemo/ui";
import { motion, AnimatePresence } from "framer-motion";
import Link from "next/link";
interface UseCase {
id: number;
category: string;
title: string;
summary: string;
fullContent: string;
icon: React.ComponentType<{ className?: string }>;
gradient: string;
}
const useCasesData: UseCase[] = [
{
id: 1,
category: "AGENT ORCHESTRATION",
title: "Multi-agent systems without framework lock-in",
summary:
"Seamless routing and orchestration for complex agent interactions",
fullContent:
"Plano manages agent routing and orchestration without framework dependencies, allowing seamless multi-agent interactions. This is ideal for building complex systems like automated customer support or data processing pipelines, where agents hand off tasks efficiently to deliver end-to-end solutions faster.",
icon: Network,
gradient:
"from-[rgba(119,128,217,0.15)] via-[rgba(119,128,217,0.08)] to-[rgba(17,28,132,0.05)]",
},
{
id: 2,
category: "CONTEXT ENGINEERING",
title: "Reusable filters for smarter agents",
summary:
"Inject data, reformulate queries, and enforce policies efficiently",
fullContent:
"Plano's filter chain encourages reuse and decoupling for context engineering tasks like injecting data, reformulating queries, and enforcing policy before calls reach an agent or LLM. This means faster debugging, cleaner architecture, and more accurate, on-policy agents —without bespoke glue code.",
icon: Filter,
gradient:
"from-[rgba(177,184,255,0.15)] via-[rgba(177,184,255,0.08)] to-[rgba(17,28,132,0.05)]",
},
{
id: 3,
category: "REINFORCEMENT LEARNING",
title: "Production signals for continuous improvement",
summary: "Capture rich traces to accelerate training and refinement",
fullContent:
"Plano captures hyper-rich tracing and log samples from production traffic, feeding into reinforcement learning and fine-tuning cycles. This accelerates iteration in areas like recommendation engines, helping teams quickly identify failures, refine prompts, and boost agent effectiveness based on real-user signals.",
icon: TrendingUp,
gradient:
"from-[rgba(185,191,255,0.15)] via-[rgba(185,191,255,0.08)] to-[rgba(17,28,132,0.05)]",
},
{
id: 4,
category: "CENTRALIZED SECURITY",
title: "Built-in guardrails and centralized policies",
summary: "Safe scaling with jailbreak detection and access controls",
fullContent:
"With built-in guardrails, centralized policies, and access controls, Plano ensures safe scaling across LLMs, detecting issues like jailbreak attempts. This is critical for deployments in regulated fields like finance or healthcare, and minimizing risks while standardizing reliability and security of agents.",
icon: Shield,
gradient:
"from-[rgba(119,128,217,0.15)] via-[rgba(119,128,217,0.08)] to-[rgba(17,28,132,0.05)]",
},
{
id: 5,
category: "ON-PREMISES DEPLOYMENT",
title: "Full data control in regulated environments",
summary: "Deploy on private infrastructure without compromising features",
fullContent:
"Plano's lightweight sidecar model deploys effortlessly on your private infrastructure, empowering teams in regulated sectors to maintain full data control while benefiting from unified LLM access, custom filter chains, and production-grade tracing—without compromising on security or scalability.",
icon: Server,
gradient:
"from-[rgba(177,184,255,0.15)] via-[rgba(177,184,255,0.08)] to-[rgba(17,28,132,0.05)]",
},
];
export function UseCasesSection() {
const [selectedUseCase, setSelectedUseCase] = useState<UseCase | null>(null);
return (
<section className="relative py-12 sm:py-16 lg:py-10 px-4 sm:px-6 lg:px-[102px]">
<div className="max-w-[81rem] mx-auto">
{/* Section Header */}
<div className="mb-8 sm:mb-12 lg:mb-14">
{/* USE CASES Badge */}
<div className="mb-4 sm:mb-6">
<div className="inline-flex items-center gap-2 px-3 sm:px-4 py-1 rounded-full bg-[rgba(185,191,255,0.4)] border border-[var(--secondary)] shadow backdrop-blur">
<span className="font-mono font-bold text-[#2a3178] text-xs sm:text-sm tracking-[1.44px] sm:tracking-[1.62px]!">
USE CASES
</span>
</div>
</div>
{/* Main Heading and CTA Button */}
<div className="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-6 sm:gap-6">
<h2 className="font-sans font-normal text-2xl sm:text-3xl lg:text-4xl tracking-[-2px] sm:tracking-[-2.88px]! text-black leading-[1.03]">
What's possible with Plano
</h2>
<Button asChild className="hidden lg:block">
<Link href="https://docs.planoai.dev/get_started/quickstart">
Start building
</Link>
</Button>
</div>
</div>
{/* 5 Card Grid - Horizontal Row */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-4">
{useCasesData.map((useCase) => (
<motion.div
key={useCase.id}
whileHover={{ y: -4 }}
transition={{ duration: 0.2 }}
className="bg-gradient-to-b from-[rgba(177,184,255,0.16)] to-[rgba(17,28,132,0.035)] border-2 border-[rgba(171,178,250,0.27)] rounded-md p-4 sm:p-6 lg:p-6 h-auto sm:h-64 md:h-72 lg:h-90 flex flex-col justify-between cursor-pointer"
onClick={() => setSelectedUseCase(useCase)}
>
{/* Category */}
<div className="mb-4 sm:mb-6">
<p className="font-mono font-bold text-[#2a3178] text-sm sm:text-sm tracking-[1.44px] sm:tracking-[1.92px]! mb-3 sm:mb-4">
{useCase.category}
</p>
{/* Title */}
<h3 className="font-sans font-normal text-black text-lg sm:text-xl lg:text-2xl tracking-[-1.2px]! leading-[1.102]">
{useCase.title}
</h3>
</div>
{/* Learn More Link */}
<div className="mt-auto">
<button className="group flex items-center gap-2 font-mono font-bold text-[var(--primary)] text-sm sm:text-base tracking-[1.44px] sm:tracking-[1.92px]! leading-[1.45] hover:text-[var(--primary-dark)] transition-colors">
LEARN MORE
<ArrowRightIcon className="w-3.5 h-3.5 sm:w-4 sm:h-4 group-hover:translate-x-1 transition-transform" />
</button>
</div>
</motion.div>
))}
</div>
{/* Start building button - Mobile only, appears last */}
<div className="lg:hidden mt-8">
<Button asChild className="w-full">
<Link href="https://docs.planoai.dev/get_started/quickstart">
Start building
</Link>
</Button>
</div>
</div>
{/* Modal */}
<Dialog
open={selectedUseCase !== null}
onOpenChange={(open) => !open && setSelectedUseCase(null)}
>
<AnimatePresence>
{selectedUseCase &&
(() => {
const IconComponent = selectedUseCase.icon;
return (
<DialogContent
key={selectedUseCase.id}
className="max-w-[90rem]! p-0 overflow-hidden"
showCloseButton={false}
>
<motion.div
initial={{ opacity: 0, scale: 0.98, y: 8 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.98, y: 8 }}
transition={{ duration: 0.25, ease: [0.16, 1, 0.3, 1] }}
className="relative"
>
{/* Gradient Background */}
<div
className={`absolute inset-0 bg-gradient-to-br ${selectedUseCase.gradient} opacity-50`}
/>
{/* Decorative Border */}
<div className="absolute inset-0 border-2 border-[rgba(171,178,250,0.3)] rounded-lg pointer-events-none" />
{/* Custom Close Button */}
<DialogClose className="absolute top-4 right-4 z-50 rounded-xs opacity-70 hover:opacity-100 transition-opacity focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[rgba(171,178,250,0.5)] bg-white/80 backdrop-blur-sm p-2 hover:bg-white/90">
<XIcon className="w-5 h-5 text-[#2a3178]" />
<span className="sr-only">Close</span>
</DialogClose>
{/* Content Container */}
<div className="relative z-10 p-5 sm:p-8 md:p-10 lg:p-14">
{/* Header Section with Icon */}
<DialogHeader className="mb-4">
<div className="flex flex-col sm:flex-row sm:items-start gap-4 sm:gap-8 mb-8">
{/* Icon Container - hidden on mobile */}
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
transition={{
duration: 0.3,
ease: [0.16, 1, 0.3, 1],
delay: 0.1,
}}
className="hidden sm:flex shrink-0 w-14 h-14 sm:w-16 sm:h-16 rounded-xl bg-gradient-to-br from-[rgba(119,128,217,0.2)] to-[rgba(17,28,132,0.1)] border-2 border-[rgba(171,178,250,0.4)] items-center justify-center shadow-lg backdrop-blur-sm mx-0"
>
<IconComponent className="w-8 h-8 text-[#2a3178]" />
</motion.div>
{/* Title Section */}
<div className="flex-1 text-left mt-4 sm:mt-0">
<motion.p
initial={{ opacity: 0, x: -8 }}
animate={{ opacity: 1, x: 0 }}
transition={{
duration: 0.3,
ease: [0.16, 1, 0.3, 1],
delay: 0.15,
}}
className="font-mono font-bold text-[#2a3178] text-xs tracking-[1.62px]! mb-1 uppercase"
>
USE CASE
</motion.p>
<motion.div
initial={{ opacity: 0, x: -8 }}
animate={{ opacity: 1, x: 0 }}
transition={{
duration: 0.3,
ease: [0.16, 1, 0.3, 1],
delay: 0.2,
}}
>
<DialogTitle className="font-sans font-medium text-2xl sm:text-3xl lg:text-4xl xl:text-4xl tracking-[-1.5px]! text-black leading-[1.1] mb-4">
{selectedUseCase.title}
</DialogTitle>
<div className="inline-flex items-center px-3 py-1 rounded-full bg-[rgba(185,191,255,0.3)] border border-[rgba(171,178,250,0.4)] backdrop-blur-sm">
<span className="font-mono font-bold text-[#2a3178] text-xs tracking-[1.44px]!">
{selectedUseCase.category}
</span>
</div>
</motion.div>
</div>
</div>
</DialogHeader>
<motion.div
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
transition={{
duration: 0.3,
ease: [0.16, 1, 0.3, 1],
delay: 0.3,
}}
className="mb-10"
>
<DialogDescription className="text-[#494949] text-base lg:text-base xl:text-lg leading-relaxed max-w-none mb-0">
{selectedUseCase.fullContent}
</DialogDescription>
</motion.div>
{/* Footer with CTA - mobile friendly */}
<motion.div
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
transition={{
duration: 0.3,
ease: [0.16, 1, 0.3, 1],
delay: 0.35,
}}
className="flex flex-col sm:flex-row items-stretch sm:items-center justify-between gap-4 pt-8 border-t border-[rgba(171,178,250,0.2)]"
>
{/* "Ready to get started?" is now first in column on mobile */}
<div className="flex items-center gap-2 text-sm text-neutral-500 justify-center sm:justify-start order-0">
<span>Ready to get started?</span>
</div>
<div className="flex flex-col sm:flex-row gap-3 w-full sm:w-auto order-1">
<Button asChild className="w-full sm:w-auto">
<Link
href="https://docs.planoai.dev/get_started/quickstart"
className="flex items-center gap-2"
>
Start building
<ArrowRightIcon className="w-4 h-4" />
</Link>
</Button>
</div>
</motion.div>
</div>
</motion.div>
</DialogContent>
);
})()}
</AnimatePresence>
</Dialog>
</section>
);
}

View file

@ -0,0 +1,210 @@
"use client";
import React, { useState } from "react";
import Image from "next/image";
import { motion, AnimatePresence } from "framer-motion";
import { Button } from "@katanemo/ui";
const verticalCarouselData = [
{
id: 1,
category: "INTRODUCTION",
title: "",
description: [
"Plano is a models-native data plane for AI agents - a framework-friendly, protocol-native fabric that lets you focus on what really matters: your agents' product logic.",
"Plano takes over the plumbing work that slows teams down when handling and processing prompts, including detecting and blocking jailbreaks, routing tasks to the right model or agent for better accuracy, applying context engineering hooks, and centralizing observability across agentic interactions.",
],
diagram: "/IntroDiagram.svg",
},
{
id: 2,
category: "OPEN SOURCE",
title: "",
description: [
"No lock-in. No black boxes. Just an open, intelligent fabric for building more reliable agentic AI applications.",
"Built by engineers with roots in the Envoy ecosystem, Plano brings production-grade reliability to agent traffic and prompt orchestration—while staying fully extensible. Shape it, extend it, and integrate it into your existing workflows without being forced into a rigid framework or a single provider.",
],
diagram: "/OpenSource.svg",
},
{
id: 3,
category: "BUILT ON ENVOY",
title: "",
description: [
"Plano is built on Envoy and runs as a self-contained sidecar alongside your application servers. It extends Envoy's HTTP connection management, filtering, and telemetry specifically for prompt and LLM traffic—so you get production-grade routing, policy enforcement, and observability out of the box.",
"Use Plano with any application language or framework, and connect it to any LLM provider.",
],
diagram: "/BuiltOnEnvoy.svg",
},
{
id: 4,
category: "PURPOSE-BUILT",
title: "",
description: [
"Unlike generic API gateways, Plano is purpose-built for agent workloads, where prompts are the unit of work.",
"Plano treats prompts as first-class traffic: it understands prompt/response flows, tool calls, model selection, and multi-agent handoffs. That means routing, policy enforcement, and observability are optimized for agent execution—not retrofitted from traditional API infrastructure—so your AI applications stay fast, reliable, and easy to evolve.",
],
diagram: "/PurposeBuilt.svg",
},
{
id: 5,
category: "PROGRAMMABLE ARCHITECTURE",
title: "",
description: [
'As agent workloads move beyond prototypes, teams end up scattering critical logic across apps: compliance checks, context "patches," provider-specific quirks, etc. That glue code gets duplicated across agents, is hard to audit, and slows iteration because every policy or workflow change requires touching application code and redeploying.',
"Plano keeps that logic in one place with a programmable Agent Filter Chain—hooks that can inspect, mutate, or terminate prompt traffic early, turning common steps (policy enforcement, jailbreak checks, context engineering, tool gating, routing hints) into reusable building blocks.",
],
diagram: "/PromptRouting.svg",
},
];
export function VerticalCarouselSection() {
const [activeSlide, setActiveSlide] = useState(0);
const handleSlideClick = (index: number) => {
setActiveSlide(index);
};
return (
<section className="relative bg-[#1a1a1a] text-white pt-20 pb-0 lg:pb-4 px-4 sm:px-6 lg:px-[102px] h-auto sm:h-[650px]">
<div className="max-w-324 mx-auto">
{/* Main Heading */}
<h2 className="font-sans font-normal text-2xl sm:text-3xl lg:text-4xl tracking-[-2px] sm:tracking-[-2.88px]! text-white leading-[1.03] mb-8 sm:mb-12 lg:mb-12 max-w-4xl">
Under the hood
</h2>
{/* Mobile: Horizontal Scroller Navigation */}
<div className="lg:hidden mb-8 -mx-4 sm:mx-0 px-4 sm:px-0">
<div
className="relative overflow-x-auto pb-2"
style={{
scrollbarWidth: "none",
msOverflowStyle: "none",
}}
>
<style jsx>{`
.hide-scrollbar::-webkit-scrollbar {
display: none;
}
`}</style>
<div className="flex gap-4 min-w-max hide-scrollbar">
{verticalCarouselData.map((item, index) => (
<button
key={item.id}
onClick={() => handleSlideClick(index)}
className={`relative px-4 py-2 rounded transition-all duration-300 whitespace-nowrap ${
index === activeSlide
? "bg-[#6363d2]/90 text-[#f9faff]"
: "bg-[#6363d2]/10 text-[rgba(182,188,255,0.71)] hover:bg-[#6363d2]/15"
}`}
>
<span className="font-mono font-bold text-sm tracking-[1.44px]!">
{item.category}
</span>
</button>
))}
</div>
</div>
</div>
{/* Desktop: Vertical Carousel Layout */}
<div className="flex flex-col lg:flex-row lg:items-start">
{/* Left Sidebar Navigation - Desktop Only */}
<div className="hidden lg:block lg:w-72 shrink-0 lg:pt-0">
<div className="relative space-y-6">
<motion.div
className="absolute left-0 top-0 w-2 h-4 bg-[#6363d2] z-10 rounded-xs"
animate={{
y: activeSlide * 52 + 6, // Each item is ~28px text + 24px gap = 52px, +10px to center smaller rectangle
}}
transition={{
type: "spring",
stiffness: 300,
damping: 30,
duration: 0.6,
}}
/>
{verticalCarouselData.map((item, index) => (
<div
key={item.id}
onClick={() => handleSlideClick(index)}
className="cursor-pointer relative pl-6 transition-all duration-300"
>
{/* Category Text */}
<span
className={`font-mono font-bold text-lg tracking-[1.69px]! transition-colors duration-300 ${
index === activeSlide
? "text-[#acb3fe]"
: "text-[rgba(172,179,254,0.71)]"
}`}
>
{item.category}
</span>
</div>
))}
</div>
</div>
{/* Right Content Area - Fixed height to prevent layout shift */}
<div className="flex-1 h-[600px] sm:h-[650px] lg:h-[600px] relative lg:-ml-8">
<AnimatePresence mode="wait">
<motion.div
key={activeSlide}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.4, ease: "easeInOut" }}
className="w-full h-full"
>
<div className="flex flex-col lg:flex-row gap-6 sm:gap-8 lg:gap-12 items-start h-full">
{/* Diagram - Above on mobile, Right Side on desktop */}
<div className="w-full lg:flex-1 flex items-center justify-center lg:justify-start order-first lg:order-last shrink-0">
<div className="relative w-full max-w-full sm:max-w-md lg:max-w-[600px] aspect-4/3">
<Image
src={verticalCarouselData[activeSlide].diagram}
alt={verticalCarouselData[activeSlide].category}
fill
className="object-contain object-top"
priority
/>
</div>
</div>
{/* Text Content */}
<div className="flex-1 max-w-2xl order-last lg:order-first flex flex-col justify-start">
{/* Title
<h3 className="font-sans font-medium text-primary text-xl sm:text-2xl lg:text-[34px] tracking-[-1px]! leading-[1.03] mb-4 sm:mb-6">
{verticalCarouselData[activeSlide].title}
</h3> */}
{/* Description */}
<div className="text-white text-sm sm:text-base lg:text-lg max-w-full lg:max-w-md -mt-0.5">
{verticalCarouselData[activeSlide].description.map(
(paragraph, index) => (
<p
key={index}
className={
index <
verticalCarouselData[activeSlide].description
.length -
1
? "mb-4"
: "mb-0"
}
>
{paragraph}
</p>
),
)}
</div>
</div>
</div>
</motion.div>
</AnimatePresence>
</div>
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,67 @@
import React from "react";
import Image from "next/image";
export function ResearchBenchmarks() {
return (
<section className="relative py-12 sm:py-16 lg:py-20 px-4 sm:px-6 lg:px-[102px] bg-[#1a1a1a] border-b-2 border-white/10">
<div className="max-w-[81rem] mx-auto">
{/* Section Header */}
<div className="mb-8 sm:mb-12 lg:mb-6">
{/* BENCHMARKS Label */}
<div className="mb-4 sm:mb-2">
<div className="font-mono font-bold text-[#9797ea] text-sm sm:text-base lg:text-xl tracking-[1.44px] sm:tracking-[1.92px]! leading-[1.502]">
BENCHMARKS
</div>
</div>
{/* Title */}
<h2 className="text-4xl sm:text-4xl md:text-5xl lg:text-4xl font-medium leading-tight tracking-[-0.06em]! text-white">
<span className="font-sans">
Production excellence, outperforming frontier LLMs
</span>
</h2>
</div>
{/* Benchmarks Image */}
{/* Mobile: Full-width scrollable container that extends to viewport edges */}
<div
className="mt-5 lg:hidden relative left-1/2 right-1/2 -ml-[50vw] -mr-[50vw] w-screen overflow-x-auto overflow-y-visible"
style={{
scrollbarWidth: "none",
msOverflowStyle: "none",
WebkitOverflowScrolling: "touch",
}}
>
<style jsx>{`
.benchmarks-scroll-container::-webkit-scrollbar {
display: none;
}
`}</style>
<div className="benchmarks-scroll-container inline-block pl-4 sm:pl-6">
<Image
src="/Benchmarks.svg"
alt="Benchmarks"
width={1200}
height={600}
className="h-auto"
style={{ width: "1200px", maxWidth: "none", display: "block" }}
priority
/>
</div>
</div>
{/* Desktop: Normal display */}
<div className="hidden lg:block w-full">
<Image
src="/Benchmarks.svg"
alt="Benchmarks"
width={1200}
height={600}
className="w-full h-auto"
priority
/>
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,46 @@
import React from "react";
import { Button } from "@katanemo/ui";
import Link from "next/link";
export function ResearchCTA() {
return (
<section className="relative pt-16 sm:pt-20 lg:pt-24 pb-12 sm:pb-16 lg:pb-20 px-4 sm:px-6 lg:px-[102px] bg-[#1a1a1a]">
<div className="max-w-[81rem] mx-auto relative z-10">
<div className="max-w-4xl">
{/* Main Heading */}
<h1 className="text-4xl sm:text-4xl md:text-5xl lg:text-5xl font-medium leading-tight tracking-[-0.06em]! text-white -ml-1 mb-3 mt-4">
<span className="font-sans">
Meet Plano-Orchestrator. Our latest models.
</span>
</h1>
</div>
{/* Description with CTA Buttons */}
<div className="max-w-5xl">
<p className="leading-relaxed sm:text-lg md:text-lg lg:text-[18px] font-sans font-normal text-white/90 mb-6">
Plano-Orchestrator is a family of state-of-the-art routing and
orchestration models that decides which agent(s) or LLM(s) should
handle each request, and in what sequence. Built for multi-agent
orchestration systems, Plano-Orchestrator excels at analyzing user
intent and conversation context to make precise routing and
orchestration decisions.
</p>
{/* CTA Buttons */}
<div className="flex flex-col sm:flex-row items-stretch sm:items-start gap-3 sm:gap-4">
<Button asChild className="w-full sm:w-auto">
<Link href="https://huggingface.co/katanemo">
Download Plano models
</Link>
</Button>
<Button variant="secondary" asChild className="w-full sm:w-auto">
<Link href="https://docs.planoai.dev">
Get Started with Plano
</Link>
</Button>
</div>
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,157 @@
"use client";
import React from "react";
import { motion } from "framer-motion";
import { MessagesSquare, GitFork, Route, RefreshCw } from "lucide-react";
interface Capability {
id: number;
title: string;
description: string;
}
const capabilitiesData: Capability[] = [
{
id: 1,
title: "Multi-turn Understanding",
description:
"Makes routing decisions based on full conversation history, maintaining contextual awareness across extended dialogues with evolving user needs.",
},
{
id: 2,
title: "Multi-Intent Detection",
description:
"Identifies when a single user message requires multiple agents simultaneously, enabling parallel/sequential routing to fulfill complex requests",
},
{
id: 3,
title: "Content-Dependency Routing",
description:
"Correctly interprets ambiguous or referential messages by leveraging prior conversation context for accurate routing decisions.",
},
{
id: 4,
title: "Conversational-Flow Handling",
description:
"Understands diverse interaction patterns including follow-ups, clarifications, confirmations, and corrections within ongoing conversations.",
},
];
export function ResearchCapabilities() {
return (
<section className="relative py-12 sm:py-16 lg:py-20 px-4 sm:px-6 lg:px-[102px] bg-[#1a1a1a]">
<div className="max-w-[81rem] mx-auto">
{/* Section Header */}
<div className="mb-8 sm:mb-12 lg:mb-10">
{/* PLANO-4B CAPABILITIES Label */}
<div className="mb-2 sm:mb-1">
<div className="font-mono font-bold text-[#9797ea] text-sm sm:text-base lg:text-xl tracking-[1.44px] sm:tracking-[1.92px]! leading-[1.502]">
PLANO-ORCHESTRATOR CAPABILITIES
</div>
</div>
{/* Title */}
<h2 className="text-4xl sm:text-4xl md:text-5xl lg:text-4xl font-medium leading-tight tracking-[-0.06em]! text-white mb-4">
<span className="font-sans">
Accurately route with confidence with no compromise
</span>
</h2>
<p className="text-white/90 w-full sm:w-[75%] text-sm sm:text-base leading-relaxed">
Designed for real-world deployments, it delivers strong performance
across general conversations, coding tasks, and long-context
multi-turn conversations, while remaining efficient enough for
low-latency production environments.
</p>
</div>
{/* Mobile: Icon card above title/description, stacked vertically */}
<div className="lg:hidden grid grid-cols-1 gap-8">
{capabilitiesData.map((capability) => {
// Map each capability to its icon
const iconMap: Record<
number,
React.ComponentType<{ className?: string }>
> = {
1: MessagesSquare, // Multi-turn Understanding
2: GitFork, // Multi-Intent Detection
3: Route, // Content-Dependency Routing
4: RefreshCw, // Conversational-Flow Handling
};
const Icon = iconMap[capability.id];
return (
<div key={capability.id} className="flex flex-col">
{/* Icon Card */}
<motion.div
whileHover={{ y: -4 }}
transition={{ duration: 0.2 }}
className="bg-gradient-to-b from-[rgba(177,184,255,0.16)] to-[rgba(17,28,132,0.035)] border-2 border-[rgba(171,178,250,0.27)] rounded-md p-6 h-40 flex items-center justify-center mb-4"
>
{Icon && <Icon className="w-24 h-24 text-[#9797ea]" />}
</motion.div>
{/* Title */}
<h3 className="font-sans font-medium text-white text-xl tracking-[-1.2px]! leading-[1.102] mb-3">
{capability.title}
</h3>
{/* Description */}
<p className="text-white/90 text-base leading-relaxed">
{capability.description}
</p>
</div>
);
})}
</div>
{/* Desktop: Icon cards separate from titles/descriptions */}
<div className="hidden lg:grid lg:grid-cols-4 gap-6 mb-6">
{capabilitiesData.map((capability) => {
// Map each capability to its icon
const iconMap: Record<
number,
React.ComponentType<{ className?: string }>
> = {
1: MessagesSquare, // Multi-turn Understanding
2: GitFork, // Multi-Intent Detection
3: Route, // Content-Dependency Routing
4: RefreshCw, // Conversational-Flow Handling
};
const Icon = iconMap[capability.id];
return (
<motion.div
key={capability.id}
whileHover={{ y: -4 }}
transition={{ duration: 0.2 }}
className="bg-gradient-to-b from-[rgba(177,184,255,0.16)] to-[rgba(17,28,132,0.035)] border-2 border-[rgba(171,178,250,0.27)] rounded-md p-6 h-52 flex items-center justify-center"
>
{Icon && <Icon className="w-24 h-24 text-[#9797ea]" />}
</motion.div>
);
})}
</div>
{/* Desktop: Titles and Descriptions Below Boxes */}
<div className="hidden lg:grid lg:grid-cols-4 gap-6">
{capabilitiesData.map((capability) => (
<div key={capability.id}>
{/* Title */}
<h3 className="font-sans font-medium text-white text-2xl tracking-[-1.2px]! leading-[1.102] mb-4">
{capability.title}
</h3>
{/* Description */}
<p className="text-white/90 text-base leading-relaxed">
{capability.description}
</p>
</div>
))}
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,111 @@
"use client";
import React from "react";
import Image from "next/image";
import { Check } from "lucide-react";
import { motion } from "framer-motion";
interface ModelFeature {
text: string;
}
interface Model {
id: number;
name: string;
logo: string;
features: ModelFeature[];
}
const modelsData: Model[] = [
{
id: 1,
name: "Plano-4B",
logo: "/Plano4B-Logo.svg",
features: [
{ text: "Optimized for production routing with sub-100ms latency" },
{ text: "84-87% accuracy on long-context scenarios" },
{ text: "Cost-effective model selection at scale" },
{ text: "Seamless agent orchestration capabilities" },
{ text: "Frontier-level performance at fraction of cost" },
],
},
{
id: 2,
name: "Plano-30B-A3B",
logo: "/Plano30B-Logo.svg",
features: [
{ text: "Advanced routing intelligence for complex workflows" },
{ text: "Enhanced context understanding and preservation" },
{ text: "Superior accuracy for multi-agent coordination" },
{ text: "Enterprise-grade performance and reliability" },
{ text: "Scalable architecture for high-throughput systems" },
],
},
];
export function ResearchFamily() {
return (
<section className="relative py-16 sm:py-20 lg:py-24 px-4 sm:px-6 lg:px-[102px] bg-white">
<div className="max-w-[81rem] mx-auto">
{/* Section Header */}
<div className="mb-8 sm:mb-12 lg:mb-10">
{/* PLANO FAMILY Label */}
<div className="mb-4 sm:mb-2">
<div className="font-mono font-bold text-[#2A3178] text-sm sm:text-base lg:text-xl tracking-[1.44px] sm:tracking-[1.92px]! leading-[1.502]">
PLANO FAMILY
</div>
</div>
{/* Title */}
<h2 className="text-4xl sm:text-4xl md:text-5xl lg:text-4xl font-medium leading-tight tracking-[-0.06em]! text-black -ml-1">
<span className="font-sans">Plano Models</span>
</h2>
</div>
{/* 2 Card Grid - Side by Side */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
{modelsData.map((model) => (
<motion.div
key={model.id}
whileHover={{ y: -4 }}
transition={{ duration: 0.2 }}
className="bg-gradient-to-b from-[rgba(177,184,255,0.16)] to-[rgba(17,28,132,0.035)] border-2 border-[rgba(171,178,250,0.27)] rounded-md p-6 sm:p-6 lg:p-6 h-72"
>
{/* Empty box - content is below */}
</motion.div>
))}
</div>
{/* Titles and Descriptions Below Boxes */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{modelsData.map((model) => (
<div key={model.id}>
{/* Logo */}
<div className="mb-6">
<Image
src={model.logo}
alt={model.name}
width={200}
height={60}
className="h-12 w-auto"
/>
</div>
{/* Features List */}
<div>
{model.features.map((feature, index) => (
<div key={index} className="flex items-start gap-3 mb-4">
<Check className="w-5 h-5 text-[var(--primary)] flex-shrink-0 mt-0.5" />
<p className="font-mono text-black text-sm sm:text-base tracking-[-0.8px] sm:tracking-[-1.2px]! leading-relaxed">
{feature.text}
</p>
</div>
))}
</div>
</div>
))}
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,49 @@
import React from "react";
interface ResearchItem {
title: string;
description: string;
}
const researchItems: ResearchItem[] = [
{
title: "Model Routing",
description:
"Great agent UX starts with using the best model for a task — fast and cheap when it can be, smarter when it needs to be — and our routing research gives developers the controls to do exactly that. Our policy-based router captures your evals and preferences, while our performance-based router learns from real traffic over time, so you can evolve model choices without retraining.",
},
{
title: "Governance & Learning",
description:
"Building an agent is easy — knowing what it does in production and how to improve it is very hard. Our research focuses on making agent behavior observable and governable: studying how agents respond to real and adversarial traffic, policy changes, and turning signals into learning loops that make agents safer and more effective over time.",
},
{
title: "Agentic Performance",
description:
"Better system performance comes from directing traffic to the right agents for each task or workflow. We build compact orchestration models that manage traffic between agents — ensuring clean handoffs, preserved context, and reliable multi-agent collaboration across distributed systems.",
},
];
export function ResearchGrid() {
return (
<section className="relative py-12 sm:py-16 lg:py-20 px-4 sm:px-6 lg:px-[102px] bg-white">
<div className="max-w-[81rem] mx-auto">
{/* 3 Column Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8 lg:gap-12">
{researchItems.map((item, index) => (
<div key={index} className="flex flex-col">
{/* Title */}
<h3 className="font-sans font-medium text-2xl sm:text-3xl lg:text-3xl tracking-[-1.5px] sm:tracking-[-2px]! text-black leading-[1.1] mb-2 sm:mb-4">
{item.title}
</h3>
{/* Description */}
<p className="text-black text-sm sm:text-base lg:text-lg leading-relaxed">
{item.description}
</p>
</div>
))}
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,58 @@
import React from "react";
import { NetworkAnimation } from "../NetworkAnimation";
import { Button } from "@katanemo/ui";
import Link from "next/link";
export function ResearchHero() {
return (
<section className="relative pt-8 sm:pt-12 lg:pt-1 pb-12 sm:pb-16 lg:pb-20 px-4 sm:px-6 lg:px-[102px] overflow-hidden">
<div className="max-w-[81rem] mx-auto relative">
<div className="hidden lg:block absolute inset-0 pointer-events-none">
<NetworkAnimation className="!w-[500px] !h-[500px] xl:!w-[600px] xl:!h-[600px] 2xl:!w-[570px] 2xl:!h-[540px] !top-[15%]" />
</div>
<div className="lg:hidden absolute inset-0 pointer-events-none">
<NetworkAnimation className="!w-[300px] !h-[300px] left-77! -top-2! opacity-90! " />
</div>
<div className="max-w-3xl relative z-10">
{/* Badge */}
<div className="mb-4 sm:mb-6">
<div className="inline-flex flex-wrap items-center gap-1.5 sm:gap-2 px-3 sm:px-4 py-1 rounded-full bg-[rgba(185,191,255,0.4)] border border-[var(--secondary)] shadow backdrop-blur">
<span className="text-xs sm:text-sm font-medium text-black/65">
New!
</span>
<span className="text-xs sm:text-sm font-medium text-black hidden sm:inline">
</span>
<span className="text-xs sm:text-sm font-[600] tracking-[-0.6px]! text-black leading-tight">
<span className="">Plano Orchestrator models released</span>
</span>
</div>
</div>
{/* Main Heading */}
<h1 className="text-4xl sm:text-4xl md:text-5xl lg:text-7xl font-medium leading-tight tracking-tighter text-black -ml-1 mb-3 mt-4">
<span className="font-sans">Research</span>
</h1>
</div>
{/* Description */}
<div className="max-w-70 sm:max-w-2xl relative z-10">
<p className="text-base sm:text-lg md:text-xl lg:text-[22px] font-sans font-normal tracking-[-1.0px] sm:tracking-[-1.22px]! text-black">
Our applied research focuses on how to deliver agents safely,
efficiently, and with improved real-world performance critical for
any AI application, but work that sits outside of any agent's core
product logic.
</p>
</div>
<div className="flex flex-col sm:flex-row items-stretch sm:items-start gap-3 sm:gap-4 mt-6 sm:mt-8 relative z-10">
<Button asChild className="w-full sm:w-auto">
<Link href="https://huggingface.co/katanemo">
Available on Hugging Face
</Link>
</Button>
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,50 @@
import React from "react";
import Image from "next/image";
export function ResearchTimeline() {
return (
<section className="relative py-12 sm:py-16 lg:py-16 px-4 sm:px-6 lg:px-[102px] bg-white border-b border-gray-200">
<div className="max-w-[81rem] mx-auto">
{/* Timeline Image */}
{/* Mobile: Full-width scrollable container that extends to viewport edges */}
<div
className="mt-5 lg:hidden relative left-1/2 right-1/2 -ml-[50vw] -mr-[50vw] w-screen overflow-x-auto overflow-y-visible"
style={{
scrollbarWidth: "none",
msOverflowStyle: "none",
WebkitOverflowScrolling: "touch",
}}
>
<style jsx>{`
.timeline-scroll-container::-webkit-scrollbar {
display: none;
}
`}</style>
<div className="timeline-scroll-container inline-block pl-4 sm:pl-6">
<Image
src="/Timeline.svg"
alt="Research Timeline"
width={1200}
height={600}
className="h-auto"
style={{ width: "1200px", maxWidth: "none", display: "block" }}
priority
/>
</div>
</div>
{/* Desktop: Normal display */}
<div className="hidden lg:block w-full">
<Image
src="/Timeline.svg"
alt="Research Timeline"
width={1200}
height={600}
className="w-full h-auto"
priority
/>
</div>
</div>
</section>
);
}

View file

@ -0,0 +1,7 @@
export { ResearchHero } from "./ResearchHero";
export { ResearchGrid } from "./ResearchGrid";
export { ResearchTimeline } from "./ResearchTimeline";
export { ResearchCTA } from "./ResearchCTA";
export { ResearchCapabilities } from "./ResearchCapabilities";
export { ResearchBenchmarks } from "./ResearchBenchmarks";
export { ResearchFamily } from "./ResearchFamily";

View file

@ -0,0 +1,59 @@
import { createFlowDiagram, FlowStep } from "@/utils/asciiBuilder";
/**
* Easy-to-use diagram templates that automatically handle spacing
* Perfect for non-coders who just want to define their flow
*/
// Example: Simple 3-step process
export const createSimpleProcess = (steps: string[]) => {
return createFlowDiagram({
title: "Process Flow",
width: 60,
steps: steps.map((label) => ({
label,
type: "regular" as const,
shadow: true,
})),
});
};
// Example: Create a nested container diagram
export const createNestedDiagram = (
title: string,
innerContent: FlowStep[],
width: number = 70,
) => {
return createFlowDiagram({
title,
width,
steps: innerContent,
});
};
// Pre-built templates
export const templates = {
simpleFlow: createSimpleProcess(["Start", "Process", "End"]),
apiFlow: createFlowDiagram({
title: "API Request Flow",
width: 65,
steps: [
{ label: "Client Request", type: "regular", shadow: true },
{ label: "API Gateway", type: "container", shadow: true },
{ label: "Process", type: "inner", shadow: true },
{ label: "Response", type: "regular", shadow: true },
],
}),
dataPipeline: createFlowDiagram({
title: "Data Pipeline",
width: 70,
steps: [
{ label: "Input Data", type: "regular", shadow: true },
{ label: "Transform", type: "inner", shadow: true },
{ label: "Validate", type: "regular", shadow: true },
{ label: "Store", type: "regular", shadow: true },
],
}),
};

View file

@ -0,0 +1,82 @@
/**
* Programmatic ASCII Diagram Builder
*
* For non-coders: Define your diagram structure with simple objects,
* and the system will automatically generate the ASCII art.
*/
interface DiagramStep {
id: string;
label: string;
type: "input" | "inner" | "regular";
position: { x: number; y: number };
}
interface DiagramFlow {
from: string;
to: string;
arrow: "right" | "down" | "left" | "up";
label?: string;
}
interface DiagramConfig {
title: string;
steps: DiagramStep[];
flows: DiagramFlow[];
}
// Example: Define diagram using simple objects
export const myFlow: DiagramConfig = {
title: "User Registration Flow",
steps: [
{ id: "start", label: "User", type: "input", position: { x: 0, y: 0 } },
{
id: "step1",
label: "Validate Email",
type: "inner",
position: { x: 2, y: 0 },
},
{
id: "step2",
label: "Create Account",
type: "regular",
position: { x: 2, y: 1 },
},
{
id: "step3",
label: "Send Welcome",
type: "regular",
position: { x: 2, y: 2 },
},
],
flows: [
{ from: "start", to: "step1", arrow: "right" },
{ from: "step1", to: "step2", arrow: "down" },
{ from: "step2", to: "step3", arrow: "down" },
],
};
/**
* Convert diagram config to ASCII string
*
* Usage:
* import { buildDiagram } from './ascii-builder';
* const ascii = buildDiagram(myFlow);
*/
export const buildDiagram = (config: DiagramConfig): string => {
// This function would programmatically build the ASCII
// For now, return a placeholder
let result = "";
result += `╔═ ${config.title} ══╗\n`;
result += `║ Placeholder for programmatic generation ║\n`;
result += `╚════════════════════════════════════╝\n`;
// TODO: Implement automatic ASCII generation from config
// This would:
// 1. Layout boxes based on positions
// 2. Add arrows based on flows
// 3. Add shadows automatically
// 4. Handle different box types
return result;
};

View file

@ -0,0 +1,84 @@
export const diagrams = {
intentDetection: ` ╔═ Intent Detection ═════════════════════════════╗
agent Cognition
Action
Confirm action?
Execute Action
`,
dataFlow: ` ╔═ Data Pipeline ═════════════════════════════╗
Input Process Transform
Store (DB)
`,
microservices: ` ╔═ Microservices Architecture ════════════════════╗
Client API API Gateway
Service A Service B
Database
`,
simpleFlow: `╔════════════╗ ╔════════════╗ ╔════════════╗
Step 1 Step 2 Step 3
`,
infrastructureLayer: ` ╔═ plano ════════════════════════════════════════╗
client Safety Guardrails
Multi-Agent Workflows
Unified LLM Access
`,
};
export type DiagramKey = keyof typeof diagrams;

View file

@ -0,0 +1,20 @@
import { createClient } from "@sanity/client";
import imageUrlBuilder from "@sanity/image-url";
import type { SanityImageSource } from "@sanity/image-url/lib/types/types";
const projectId = process.env.NEXT_PUBLIC_SANITY_PROJECT_ID;
const dataset = process.env.NEXT_PUBLIC_SANITY_DATASET;
const apiVersion = process.env.NEXT_PUBLIC_SANITY_API_VERSION;
export const client = createClient({
projectId,
dataset,
apiVersion,
useCdn: true, // Set to false if statically generating pages, using ISR or using the on-demand revalidation API
});
const builder = imageUrlBuilder(client);
export function urlFor(source: SanityImageSource) {
return builder.image(source);
}

View file

@ -0,0 +1,424 @@
/**
* ASCII Diagram Builder - Auto-spacing and formatting utilities
*
* This module provides utilities to ensure consistent spacing across ASCII diagrams
* similar to the intent detection diagram pattern.
*/
interface BoxDimensions {
label: string;
width: number;
height: number;
}
/**
* Calculates proper padding to center content within a container width
*/
export function calculateCenterPadding(
contentWidth: number,
containerWidth: number,
): number {
return Math.floor((containerWidth - contentWidth) / 2);
}
/**
* Creates a horizontal arrow between two positions
*/
export function createArrow(
length: number,
direction: "→" | "↓" | "↑" | "←" = "→",
): string {
return direction.repeat(length);
}
/**
* Builds a box with specified dimensions, label, and box type
*/
export function buildBox(
label: string,
type: "container" | "inner" | "regular" = "regular",
shadow: boolean = true,
width?: number,
): string[] {
const actualWidth = width || Math.max(label.length + 4, 12);
const paddedLabel = label
.padStart(Math.floor((actualWidth - 2 + label.length) / 2), " ")
.padEnd(actualWidth - 2, " ");
const symbols = {
container: { tl: "╔", tr: "╗", bl: "╚", br: "╝", h: "═", v: "║" },
inner: { tl: "┏", tr: "┓", bl: "┗", br: "┛", h: "━", v: "┃" },
regular: { tl: "┌", tr: "┐", bl: "└", br: "┘", h: "─", v: "│" },
};
const s = symbols[type];
const shadowChar = "░";
const lines = [
s.tl + s.h.repeat(actualWidth - 2) + s.tr + (shadow ? shadowChar : ""),
s.v + paddedLabel + s.v + (shadow ? shadowChar : ""),
s.bl + s.h.repeat(actualWidth - 2) + s.br + (shadow ? shadowChar : ""),
];
if (shadow) {
lines.push(" " + shadowChar.repeat(actualWidth));
}
return lines;
}
/**
* Fixes spacing in an existing diagram by analyzing and adjusting alignment
*/
export function fixDiagramSpacing(diagram: string): string {
const lines = diagram.split("\n");
if (lines.length === 0) return diagram;
// Find the container boundaries (look for ╔ and ╚ markers)
let containerStart = -1;
let containerEnd = -1;
let containerWidth = 0;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.includes("╔═") && line.includes("╗")) {
containerStart = i;
containerWidth = line.length;
}
if (line.includes("╚") && line.includes("╝")) {
containerEnd = i;
}
}
if (containerStart === -1 || containerEnd === -1) {
return diagram; // Can't fix if no container found
}
// The intent detection pattern shows:
// Line 2: title line with ╔═ {title} ═{fill}╗
// Lines 3-19: content with ║ on sides
// Line 20: bottom ╚══════╝
// Line 21: shadow line
// For intent detection, the container content width is about 60 chars
// Total line width including borders is about 68-70
// Content starts around position 26
// Detect pattern by looking at first content line
const firstContentLine = lines[containerStart + 1];
if (!firstContentLine) return diagram;
const leftPadding = firstContentLine.indexOf("║");
const rightPadding = containerWidth - firstContentLine.lastIndexOf("║") - 1;
// Now standardize all internal lines
const fixedLines = [...lines];
for (let i = containerStart + 1; i < containerEnd; i++) {
const line = lines[i];
const shadowIndex = line.indexOf("░");
if (line.trim().startsWith("║")) {
// This is a content line inside the container
// Standardize the padding
const content = extractContainerContent(line);
fixedLines[i] = padContainerLine(content, containerWidth, leftPadding);
}
}
return fixedLines.join("\n");
}
function extractContainerContent(line: string): string {
// Extract content between ║ characters
const startIdx = line.indexOf("║");
const endIdx = line.lastIndexOf("║");
if (startIdx === -1 || endIdx === -1 || startIdx === endIdx) return line;
return line.substring(startIdx + 1, endIdx);
}
function padContainerLine(
content: string,
containerWidth: number,
targetLeftPad: number,
): string {
const padding = " ".repeat(targetLeftPad);
const contentLength = content.length;
const rightPadding = containerWidth - targetLeftPad - contentLength - 2; // -2 for two ║
const rightPad = rightPadding > 0 ? " ".repeat(rightPadding) : "";
return padding + "║" + content + "║" + rightPad + "░";
}
/**
* Creates a simple flow diagram programmatically
* Usage:
* ```ts
* const diagram = createFlowDiagram({
* title: "My Process",
* width: 60,
* steps: [
* { label: "Step 1", type: "regular" },
* { label: "Step 2", type: "inner" },
* { label: "Step 3", type: "regular" }
* ]
* });
* ```
*/
export interface FlowStep {
label: string;
type?: "container" | "inner" | "regular";
shadow?: boolean;
}
export interface FlowDiagramConfig {
title: string;
width?: number;
steps: FlowStep[];
layout?: "vertical" | "horizontal";
externalElements?: FlowStep[]; // Elements outside the container (like "agent")
}
export function createFlowDiagram(config: FlowDiagramConfig): string {
const layout = config.layout || "vertical";
if (layout === "horizontal") {
return createHorizontalFlow(config);
} else {
return createVerticalFlow(config);
}
}
function createVerticalFlow(config: FlowDiagramConfig): string {
const width = config.width || 60;
const hasExternal =
config.externalElements && config.externalElements.length > 0;
// Build external elements first
let externalBoxes: string[] = [];
let externalWidth = 0;
if (hasExternal) {
externalWidth = 20;
for (const extEl of config.externalElements!) {
const extWidth = Math.max(extEl.label.length + 4, 12);
const extBoxLines = buildBox(
extEl.label,
extEl.type || "regular",
extEl.shadow !== false,
extWidth,
);
for (const extLine of extBoxLines) {
externalBoxes.push(" ".repeat(2) + extLine);
}
// Add vertical arrow if not last
if (
extEl !== config.externalElements![config.externalElements!.length - 1]
) {
const arrowPad = 2 + Math.floor(extWidth / 2);
externalBoxes.push(" ".repeat(arrowPad) + "▼");
}
}
}
const titleLine = hasExternal
? ` ╔═ ${config.title} ${"═".repeat(Math.max(0, width - config.title.length - 5))}`
: `╔═ ${config.title} ${"═".repeat(Math.max(0, width - config.title.length - 5))}`;
const lines: string[] = [];
lines.push(titleLine);
// Find max step width
const maxStepWidth = Math.max(...config.steps.map((s) => s.label.length), 20);
const stepWidth = maxStepWidth + 4;
// Build internal steps
const internalLines: string[] = [];
for (let i = 0; i < config.steps.length; i++) {
const step = config.steps[i];
const boxLines = buildBox(
step.label,
step.type || "regular",
step.shadow !== false,
stepWidth,
);
// Center each box
const leftPadding = calculateCenterPadding(stepWidth, width);
for (const boxLine of boxLines) {
internalLines.push(" ".repeat(leftPadding) + boxLine);
}
// Add vertical arrow between steps (except last)
if (i < config.steps.length - 1) {
const arrowPad = calculateCenterPadding(1, width);
internalLines.push(" ".repeat(arrowPad) + "│");
internalLines.push(" ".repeat(arrowPad) + "▼");
}
}
// Combine external and internal elements
const maxHeight = Math.max(externalBoxes.length, internalLines.length);
for (let row = 0; row < maxHeight; row++) {
let line = "";
// External part
if (row < externalBoxes.length) {
line += externalBoxes[row];
// Add connecting arrow on middle row
if (row === Math.floor(externalBoxes.length / 2)) {
line += "░".repeat(6) + "─".repeat(10) + "─▶║─";
} else {
line += "░".repeat(6) + " ".repeat(10) + " ║ ";
}
} else if (hasExternal) {
line += " ".repeat(externalWidth);
if (row < internalLines.length) {
line += "░".repeat(6) + " ".repeat(10) + " ║ ";
}
} else {
line += " ".repeat(externalWidth);
}
// Internal container part
if (row < internalLines.length) {
line += internalLines[row];
} else {
line += " ".repeat(width);
}
line += "║░";
lines.push(line);
}
// Close container
const bottomPadding = hasExternal ? " ".repeat(externalWidth + 16) : "";
const bottomLine = bottomPadding + "╚" + "═".repeat(width - 1) + "╝░";
lines.push(bottomLine);
const shadowLine =
(hasExternal ? " ".repeat(externalWidth + 17) : " ") + "░".repeat(width);
lines.push(shadowLine);
return lines.join("\n");
}
function createHorizontalFlow(config: FlowDiagramConfig): string {
const width = config.width || 70;
const hasExternal =
config.externalElements && config.externalElements.length > 0;
const lines: string[] = [];
// Calculate step widths
const maxStepWidth = Math.max(...config.steps.map((s) => s.label.length), 16);
const stepWidth = maxStepWidth + 4;
const arrowGap = 12;
const totalStepWidth =
config.steps.length * stepWidth + (config.steps.length - 1) * arrowGap;
const containerPadding = Math.max(
4,
Math.floor((width - totalStepWidth) / 2),
);
// Build internal boxes matrix
const boxMatrix: string[][] = [];
let maxHeight = 0;
for (const step of config.steps) {
const boxLines = buildBox(
step.label,
step.type || "regular",
step.shadow !== false,
stepWidth,
);
boxMatrix.push(boxLines);
maxHeight = Math.max(maxHeight, boxLines.length);
}
// Title line - position based on external elements
const titleLeftPad = hasExternal ? 26 : 26;
const titleRepeatCount = Math.max(0, width - config.title.length - 5);
const titleLine =
" ".repeat(titleLeftPad) +
`╔═ ${config.title} ${"═".repeat(titleRepeatCount)}`;
lines.push(titleLine);
// Build external box for rendering
let externalBoxLines: string[] = [];
if (hasExternal) {
const extEl = config.externalElements![0];
const extWidth = Math.max(extEl.label.length + 4, 16);
externalBoxLines = buildBox(
extEl.label,
extEl.type || "regular",
extEl.shadow !== false,
extWidth,
);
}
// Render content rows
for (let row = 0; row < maxHeight; row++) {
let line = "";
// External elements on left (if present)
if (hasExternal) {
const extRow = row < externalBoxLines.length ? row : -1;
if (extRow >= 0) {
line += " " + externalBoxLines[extRow];
// Add connecting arrow on middle row
if (row === Math.floor(externalBoxLines.length / 2)) {
line += "░".repeat(5) + "─".repeat(8) + "─▶║─";
} else {
line += "░".repeat(5) + " ".repeat(8) + " ║ ";
}
} else {
line += " ".repeat(26) + "║ ";
}
} else {
line += " ".repeat(26) + "║ ";
}
// Internal container boxes with proper padding
line += " ".repeat(containerPadding);
for (let i = 0; i < boxMatrix.length; i++) {
const boxLines = boxMatrix[i];
const boxLine =
row < boxLines.length
? boxLines[row]
: " ".repeat(stepWidth + (config.steps[i].shadow !== false ? 1 : 0));
line += boxLine;
// Add horizontal arrow between boxes
if (i < boxMatrix.length - 1) {
if (row === Math.floor(maxHeight / 2)) {
line += "─".repeat(arrowGap) + "►";
} else {
line += " ".repeat(arrowGap + 1);
}
}
}
// Right padding and border
const usedWidth = containerPadding + totalStepWidth;
const rightPad = Math.max(0, width - usedWidth);
line += " ".repeat(rightPad);
line += "║░";
lines.push(line);
}
// Close container
const bottomLine = " ".repeat(26) + "╚" + "═".repeat(width - 1) + "╝░";
lines.push(bottomLine);
const shadowLine = " ".repeat(27) + "░".repeat(width);
lines.push(shadowLine);
return lines.join("\n");
}

19
apps/www/tsconfig.json Normal file
View file

@ -0,0 +1,19 @@
{
"extends": "@katanemo/tsconfig/nextjs.json",
"compilerOptions": {
"jsx": "react-jsx",
"paths": {
"@/*": ["./src/*"],
"@katanemo/ui": ["../../packages/ui/src"]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts",
"**/*.mts"
],
"exclude": ["node_modules"]
}

17607
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more