diff --git a/docusaurus.config.js b/docusaurus.config.js index 8937ab017a6f..e9a984474754 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -212,7 +212,7 @@ const config = { tagName: 'link', attributes: { rel: 'stylesheet', - href: 'https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&family=Fira+Code:wght@300..700&display=swap" rel="stylesheet', + href: 'https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&family=Fira+Code:wght@300..700&family=IBM+Plex+Mono:wght@400;500;600;700&display=swap" rel="stylesheet', }, }, { diff --git a/package.json b/package.json index 9eaa6417253e..822886f12616 100644 --- a/package.json +++ b/package.json @@ -92,6 +92,7 @@ "i18next-browser-languagedetector": "^7.1.0", "i18next-http-backend": "^2.2.1", "jimp": "0.22.10", + "lenis": "^1.3.26", "lottie-react": "^2.4.1", "marked": "^15.0.7", "minisearch": "^7.2.0", diff --git a/src/components/Accordion/index.tsx b/src/components/Accordion/index.tsx index 3500db4aa231..432c9bcfe854 100644 --- a/src/components/Accordion/index.tsx +++ b/src/components/Accordion/index.tsx @@ -27,6 +27,13 @@ interface AccordionProps { firstOpen?: boolean; fontWeight?: string; fontSize?: string; + /** + * 'pushCore' applies the Push Core landing spec (Figma node 49245:16793): + * 32px item padding, a 12px gap before an open answer, a 1.5px #2d2d32 + * rule and a 32px toggle. Omit it and the accordion renders exactly as it + * does on the other four pages that share this component. + */ + variant?: 'default' | 'pushCore'; } const Accordion: React.FC = ({ @@ -34,7 +41,9 @@ const Accordion: React.FC = ({ firstOpen, fontWeight, fontSize, + variant = 'default', }) => { + const isPushCore = variant === 'pushCore'; const [activeIndex, setActiveIndex] = useState( firstOpen === false ? null : 0 ); @@ -49,22 +58,32 @@ const Accordion: React.FC = ({ return (
{items.map((item, index) => ( - - toggleAccordion(index)}> + + toggleAccordion(index)} + $pushCore={isPushCore} + $open={activeIndex === index} + >

{item.title || item.question}

{activeIndex === index ? ( - + ) : ( - + )}
@@ -107,15 +126,21 @@ const Accordion: React.FC = ({ }; const AccordionSection = styled.div` - border-bottom: 1px solid var(--ifm-color-gray-200); + border-bottom: ${(props) => + props.$pushCore ? '1.5px solid #2d2d32' : '1px solid var(--ifm-color-gray-200)'}; h3 { white-space: pre-wrap; } `; +// In the pushCore spec an item is 32px-padded, but an open one tightens to a +// 12px gap before its answer (Figma: header at y=0, answer at y=44). const AccordionParent = styled.div` - padding: 24px 0; + padding: ${(props) => { + if (!props.$pushCore) return '24px 0'; + return props.$open ? '32px 0 12px 0' : '32px 0'; + }}; display: flex; flex-direction: row; flex: 1; diff --git a/src/components/Home/AgenticScaleSection.tsx b/src/components/Home/AgenticScaleSection.tsx new file mode 100644 index 000000000000..f60af795305e --- /dev/null +++ b/src/components/Home/AgenticScaleSection.tsx @@ -0,0 +1,335 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck +/* eslint-disable */ + +// External Components +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; + +// Internal Components +import { Section } from '@site/src/css/SharedStyling'; +import FeatureCard from '@site/src/components/Home/FeatureCard'; +import useMediaQuery from '@site/src/hooks/useMediaQuery'; + +// Internal Configs +import { device } from '@site/src/config/globals'; +import { AgentFeaturesListA } from '@site/src/config/AgentFeaturesListA'; + +// Import Assets +import RingPattern from '@site/static/assets/website/home/built-to-scale/ring-pattern.png'; +import PushLogoMark from '@site/static/assets/website/home/built-to-scale/push-logo-mark.svg'; + +const FONT_MONO = "'IBM Plex Mono', monospace"; + +// Figma's background plate (Rectangle 42282) is 1403px wide on a 1440px frame, +// i.e. inset by (1440 - 1403) / 2 on each side. It sits at Section level rather +// than inside the page's max-width Content container, so the page gutter can't +// constrain it — that's what makes it read as full-bleed. +const PANEL_INSET = 18.5; + +// Vertical anchors, in design pixels measured from the top of that plate. +const VISUAL_HEIGHT = 726; // image 32 — the slot for the incoming animation +const PINK_CARD_TOP = 177; +const BLEND_TOP = 552; // Rectangle 42285 +const BLEND_HEIGHT = 544; +const BODY_TOP = 743; // Frame 37246 +const ROW_ONE_HEIGHT = 534; +const ROW_TWO_HEIGHT = 418; + +export default function AgenticScaleSection() { + const { t } = useTranslation(); + const isMobile = useMediaQuery(device.mobileL); + + return ( +
+ + {/* Top half: reserved for the animation the design team will supply. + The exported ring artwork stands in for it until then. */} + + + + {/* Blurred wash that melts the artwork above into the card grid below. */} + +
+ ); +} + +// The single gradient plate behind the whole section. Its final stop is the +// page background, so the section dissolves into the page instead of ending on +// a seam. Stops are in design pixels from the top, because everything anchored +// to them (artwork, wash, card rows) is fixed-height too. +const Panel = styled.div` + position: relative; + flex: 1; + margin: 0 ${PANEL_INSET}px; + border-radius: 48px 48px 0 0; + overflow: hidden; + /* Figma's Rectangle 42282 stops, at their design pixel offsets. #fbe9fe is a + single peak at 1207px — not a plateau — so the light stays a narrow band + around the first card row and darkens continuously from there, reaching + #180621 just below the second row (which ends ~1841px). The tail is only + carried far enough to settle on the page colour without banding. */ + background: linear-gradient( + 180deg, + #d548ec 0px, + #d548ec 454px, + #fbe9fe 1207px, + #180621 1894px, + var(--ifm-color-black) 97% + ); + + @media ${device.mobileL} { + margin: 0 12px; + border-radius: 24px 24px 0 0; + /* Same shape as the design, in percentages — the stacked mobile layout's + height varies with copy, so fixed pixel offsets wouldn't line up. */ + background: linear-gradient( + 180deg, + #d548ec 0%, + #d548ec 17%, + #fbe9fe 46%, + #180621 72%, + var(--ifm-color-black) 95% + ); + } +`; + +const TopVisual = styled.div` + position: relative; + width: 100%; + height: ${VISUAL_HEIGHT}px; + + @media ${device.laptop} { + height: 560px; + } + + @media ${device.tablet} { + height: 440px; + } + + @media ${device.mobileL} { + height: 320px; + } +`; + +const RingArtwork = styled.div` + position: absolute; + inset: 0; + background-image: url(${RingPattern}); + background-size: cover; + background-position: center 30%; + border-radius: 48px; + mix-blend-mode: lighten; + pointer-events: none; + + @media ${device.mobileL} { + border-radius: 24px; + } +`; + +const PinkCard = styled.div` + position: absolute; + top: ${PINK_CARD_TOP}px; + left: 50%; + transform: translateX(-50%); + z-index: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 44px; + width: 800px; + max-width: calc(100% - 48px); + padding: 40px; + box-sizing: border-box; + background: var(--ifm-color-custom-pink); + + @media ${device.laptop} { + top: 140px; + gap: 32px; + padding: 32px 24px; + max-width: calc(100% - 48px); + } + + @media ${device.tablet} { + top: 110px; + gap: 24px; + } + + @media ${device.mobileL} { + top: 72px; + gap: 16px; + padding: 24px 16px; + max-width: calc(100% - 32px); + } +`; + +const LogoMark = styled.div` + width: 46px; + height: auto; + display: flex; + + svg { + width: 100%; + height: auto; + } + + @media ${device.mobileL} { + width: 32px; + } +`; + +const BannerHeading = styled.h2` + margin: 0; + text-align: center; + color: var(--ifm-color-white); + font-family: ${FONT_MONO}; + font-weight: 500; + font-size: 38px; + letter-spacing: -0.06em; + line-height: 1.2; + + span { + display: block; + white-space: nowrap; + } + + /* The two lines are set nowrap at full size; below this they no longer fit, + so let them wrap and step the size down instead of overflowing. */ + @media ${device.laptop} { + font-size: 28px; + + span { + white-space: normal; + } + } + + @media ${device.tablet} { + font-size: 22px; + } + + @media ${device.mobileL} { + font-size: 17px; + } +`; + +const BlendWash = styled.div` + position: absolute; + top: ${BLEND_TOP}px; + left: 0; + right: 0; + height: ${BLEND_HEIGHT}px; + z-index: 1; + background: linear-gradient(180deg, #de6ef0 0%, #fae7fe 100%); + filter: blur(50px); + pointer-events: none; + + @media ${device.mobileL} { + top: 300px; + height: 260px; + filter: blur(30px); + } +`; + +const Body = styled.div` + position: relative; + z-index: 2; + padding-top: ${BODY_TOP - VISUAL_HEIGHT}px; + + @media ${device.laptop} { + padding-top: 40px; + } + /* Tail for the gradient to settle onto the page colour. Sized so the gap + from the last card down to the Grid B title lands on Figma's 322px + (node 49233:16551's block ends at 1074, Frame 37236 starts at 1396). */ + padding-bottom: 197px; + + @media ${device.mobileL} { + padding-top: 48px; + padding-bottom: 80px; + } +`; + +const BodyInner = styled.div` + width: 100%; + max-width: 1292px; + margin: 0 auto; + padding: 0 16px; + box-sizing: border-box; + display: flex; + flex-direction: column; + gap: 24px; +`; + +const GridTitle = styled.h2` + margin: 0 0 40px 0; + text-align: center; + color: var(--ifm-color-white); + font-family: ${FONT_MONO}; + font-weight: 500; + font-size: 3rem; + letter-spacing: -0.06em; + line-height: 1.2; + + @media ${device.mobileL} { + margin: 0 0 8px 0; + font-size: 1.75rem; + } +`; + +const CardRow = styled.div` + display: flex; + align-items: stretch; + gap: 24px; + + > * { + ${(props) => (props.$height ? `height: ${props.$height}px;` : '')} + } + + /* Three fixed-height cards need real width; below the laptop breakpoint + they'd squeeze to ~190px, so stack them and let height follow content. */ + @media ${device.laptop} { + flex-direction: column; + + > * { + height: auto; + min-height: 260px; + } + } +`; diff --git a/src/components/Home/BuiltToScaleBanner.tsx b/src/components/Home/BuiltToScaleBanner.tsx new file mode 100644 index 000000000000..bcb1da3db417 --- /dev/null +++ b/src/components/Home/BuiltToScaleBanner.tsx @@ -0,0 +1,118 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck +/* eslint-disable */ + +// External Components +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; + +// Internal Components +import { Content, Section } from '@site/src/css/SharedStyling'; + +// Internal Configs +import { device } from '@site/src/config/globals'; + +// Import Assets +import RingPattern from '@site/static/assets/website/home/built-to-scale/ring-pattern.png'; +import PushLogoMark from '@site/static/assets/website/home/built-to-scale/push-logo-mark.svg'; + +const FONT_MONO = "'IBM Plex Mono', monospace"; + +export default function BuiltToScaleBanner() { + const { t } = useTranslation(); + + return ( +
+ + + + +
+ ); +} + +const BannerWrapper = styled.div` + position: relative; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + border-radius: 48px; + padding: 44px 0; + background: var(--ifm-color-custom-pink); +`; + +const RingBackground = styled.div` + position: absolute; + inset: 0; + background-image: url(${RingPattern}); + background-size: cover; + background-position: center 30%; + mix-blend-mode: lighten; + pointer-events: none; +`; + +const PinkCard = styled.div` + position: relative; + z-index: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 44px; + padding: 40px; + max-width: 800px; + width: 100%; + background: var(--ifm-color-custom-pink); + border-radius: 24px; + + @media ${device.mobileL} { + max-width: 100%; + margin: 0 16px; + } +`; + +const LogoMark = styled.div` + width: 46px; + height: auto; + display: flex; + + svg { + width: 100%; + height: auto; + } +`; + +const Heading = styled.h2` + margin: 0; + text-align: center; + color: var(--ifm-color-white); + font-family: ${FONT_MONO}; + font-weight: 500; + font-size: 38px; + letter-spacing: -0.06em; + line-height: 1.2; + + span { + display: block; + } + + @media ${device.mobileL} { + font-size: 22px; + } +`; diff --git a/src/components/Home/ClosingCTA.tsx b/src/components/Home/ClosingCTA.tsx new file mode 100644 index 000000000000..f1a0a3eaa772 --- /dev/null +++ b/src/components/Home/ClosingCTA.tsx @@ -0,0 +1,132 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck +/* eslint-disable */ + +// React + Web3 Essentials +import useBaseUrl from '@docusaurus/useBaseUrl'; + +// External Components +import { useTranslation } from 'react-i18next'; +import { BsArrowRight } from 'react-icons/bs'; +import styled from 'styled-components'; + +// Internal Components +import { A, Content, H2, ItemV, Section } from '@site/src/css/SharedStyling'; +import useMediaQuery from '@site/src/hooks/useMediaQuery'; + +// Internal Configs +import { device } from '@site/src/config/globals'; + +const FONT_MONO = "'IBM Plex Mono', monospace"; + +export default function ClosingCTA() { + const { t } = useTranslation(); + const isMobile = useMediaQuery(device.mobileL); + + return ( +
+ + {/* Reserved for the dot-matrix hand animation. Held at the design's + footprint so dropping the real asset in needs no layout change. */} + + + +

+ {t('pages.home.closing-cta.title-line1')} +
+ {t('pages.home.closing-cta.title-line2')} +

+ + {t('pages.home.closing-cta.subtitle')} + + + {t('pages.home.closing-cta.cta')} + +
+
+
+ ); +} + +const AnimationSlot = styled.div` + width: 100%; + height: 420px; + + @media ${device.laptop} { + height: 320px; + } + + @media ${device.tablet} { + height: 240px; + } + + @media ${device.mobileL} { + height: 160px; + } +`; + +const CTABody = styled(ItemV)` + align-items: center; + justify-content: center; + gap: 16px; + margin-top: 48px; + + @media ${device.mobileL} { + margin-top: 24px; + } +`; + +const Subtitle = styled.p` + margin: 0; + text-align: center; + font-family: 'DM Sans', sans-serif; + font-size: 1.125rem; + font-weight: 400; + line-height: 1.5; + letter-spacing: -0.36px; + color: var(--ifm-color-white); + + @media ${device.mobileL} { + font-size: 1rem; + } +`; + +const CTAButton = styled(A)` + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + height: 58px; + padding: 16px 32px; + margin-top: 24px; + box-sizing: border-box; + background: var(--ifm-color-custom-pink); + border: 1px solid rgba(255, 255, 255, 0.3); + border-radius: 16px; + color: var(--ifm-color-white); + font-family: 'DM Sans', sans-serif; + font-size: 1.125rem; + font-weight: 600; + line-height: 1rem; + letter-spacing: -0.03em; +`; diff --git a/src/components/Home/FeatureCard.tsx b/src/components/Home/FeatureCard.tsx new file mode 100644 index 000000000000..21d4c5490db2 --- /dev/null +++ b/src/components/Home/FeatureCard.tsx @@ -0,0 +1,135 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck +/* eslint-disable */ + +// External Components +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; + +const FONT_MONO = "'IBM Plex Mono', monospace"; + +export default function FeatureCard({ item }) { + const { t } = useTranslation(); + + if (item.cardStyle === 'divided') { + return ( + + {item.icon && ( + + ); + } + + return ( + + + {t(item.titleKey)} + {t(item.descriptionKey)} + + + ); +} + +const BorderedCard = styled.div` + flex: 1; + display: flex; + flex-direction: column; + justify-content: flex-end; + /* Figma's stroke is a vertical linear gradient — #ffffff at the top to + #eb8afb at the bottom — drawn at 25% opacity, Outside, 1px. Extracted from + the node's alpha channel (alpha 63/255 = 24.7%). + CSS can't put a gradient on a border while honouring border-radius, so the + border area is painted by a border-box gradient layer and the fill by a + padding-box layer on top. Keeping the stops translucent (rather than + pre-flattening them) reproduces Figma's Outside placement, where the + stroke blends with the section gradient behind the card. */ + background: + linear-gradient(#090909, #090909) padding-box, + linear-gradient( + 180deg, + rgba(255, 255, 255, 0.25) 0%, + rgba(235, 138, 251, 0.25) 100% + ) + border-box; + border: 1px solid transparent; + border-radius: 24px; + padding: 32px; + box-sizing: border-box; +`; + +const BorderedTitle = styled.p` + margin: 0; + /* Titles carry their own line breaks, matching the design's wrap points. */ + white-space: pre-line; + font-family: ${FONT_MONO}; + font-weight: 400; + font-size: 2rem; + letter-spacing: -0.06em; + line-height: 1.2; + color: var(--ifm-color-white); +`; + +const BorderedDescription = styled.p` + /* Figma spaces the title and body by 24px (spacing-md), not 16px. */ + margin: 24px 0 0 0; + font-size: 1rem; + letter-spacing: -0.02em; + line-height: 1.5; + color: var(--ifm-color-white); +`; + +const DividedCard = styled.div` + flex: 1; + display: flex; + flex-direction: column; + gap: 8px; + padding: 32px; + border-left: 1px solid #2c2c35; + + &:first-child { + border-left: none; + } +`; + +const IconImage = styled.img` + width: 120px; + height: 120px; +`; + +const CardBody = styled.div` + display: flex; + flex-direction: column; + gap: 8px; +`; + +const DividedTitle = styled.p` + margin: 0; + white-space: pre-line; + font-family: ${FONT_MONO}; + font-weight: 500; + font-size: 2rem; + letter-spacing: -0.06em; + line-height: 1.2; + color: var(--ifm-color-white); +`; + +const DividedDescription = styled.p` + margin: 0; + font-size: 1.125rem; + letter-spacing: -0.02em; + line-height: 1.5; + color: #a9a6b2; +`; diff --git a/src/components/Home/PaidStatsRow.tsx b/src/components/Home/PaidStatsRow.tsx new file mode 100644 index 000000000000..71c931e3cf0b --- /dev/null +++ b/src/components/Home/PaidStatsRow.tsx @@ -0,0 +1,375 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck +/* eslint-disable */ + +// External Components +import Lottie from 'lottie-react'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; + +// Internal Components +import { Content, H2, ItemH, ItemV, Section, Span } from '@site/src/css/SharedStyling'; +import useMediaQuery from '@site/src/hooks/useMediaQuery'; + +// Internal Configs +import { device } from '@site/src/config/globals'; +import { PaidStatsList } from '@site/src/config/PaidStatsList'; + +// Import Assets +import GlowEllipse from '@site/static/assets/website/home/paid-stats/glow-ellipse.svg'; +import instantInteroperability from '@site/static/assets/website/interoperability/instant-interoperability.json'; + +const FONT_MONO = "'IBM Plex Mono', monospace"; + +// Chain marks are exported from Figma at 43.119px and overlap by 11.179px +// (node 49245:16690). Icons the design team hasn't supplied yet are skipped +// rather than crashing the build, so dropping the file in is all that's needed. +const chainIcon = (name) => { + try { + return require( + `@site/static/assets/website/home/paid-stats/${name}.svg` + ).default; + } catch (err) { + return null; + } +}; + +export default function PaidStatsRow() { + const { t } = useTranslation(); + const isMobile = useMediaQuery(device.mobileL); + + return ( +
+ + + + + + {t(PaidStatsList.meta.eyebrow)} + + + + + + {t(PaidStatsList.meta.title)}{' '} + {t(PaidStatsList.meta.titleGradient)} + + + {t(PaidStatsList.meta.paragraph)} + + + + + {/* The lines belong to the stats row, not the section — Figma anchors + Layer_1's box 227px above Frame 37131, so the strands sweep up + behind the heading and settle across the stats. */} + + + + {PaidStatsList.stats.map((stat) => ( + + {t(stat.titleKey)} + + {stat.type === 'text' && ( + {t(stat.valueKey)} + )} + + {stat.type === 'chains' && ( + + + {stat.chains + .map((chain) => ({ ...chain, src: chainIcon(chain.icon) })) + .filter((chain) => chain.src) + .map((chain) => ( + + ))} + + {t(stat.badgeTextKey)} + + )} + + ))} + + + +
+ ); +} + +// Figma's Ellipse 42 is a 587px circle whose blur spills 51.11% past its box, +// so the exported artwork is 1187px square. Centred on the section on both +// axes — the design places its centre on the content block's centre. +const GlowBackground = styled.div` + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + width: 1187px; + height: 1187px; + pointer-events: none; + z-index: 0; + + @media ${device.laptop} { + width: 820px; + height: 820px; + } + + @media ${device.mobileL} { + width: 520px; + height: 520px; + } + + svg { + width: 100%; + height: 100%; + display: block; + } +`; + +// The flowing lines behind this section are the same Lottie the old +// interoperability section used, rather than a flat SVG. +// Positioning context for the lines so they track the stats row rather than +// the section as a whole. +const StatsStage = styled.div` + position: relative; + width: 100%; + margin-top: 100px; + + @media ${device.mobileL} { + margin-top: 48px; + } +`; + +// Anchored to the stats row so the strands keep crossing the stats however the +// copy above reflows. The offset is set from Layer_1's central axis (the +// zero-height vector at y=262.7 in its box), which Figma places ~33% down +// Frame 37131 — the Lottie's own artwork sits slightly higher inside its box +// than Figma's vectors do, so this is 40px lower than a box-to-box match. +const LinesAnimation = styled.div` + position: absolute; + left: 50%; + top: -167px; + transform: translateX(-50%); + width: 1317px; + height: 463px; + max-width: none; + /* Faint in the design — the lines read as texture behind the content. */ + opacity: 0.2; + pointer-events: none; + z-index: 0; + + svg { + width: 100%; + height: 100%; + display: block; + } + + /* The strands are 1317px wide — narrower than that they're mostly cropped + and just add noise behind the stats. */ + @media ${device.laptop} { + display: none; + } +`; + +const Eyebrow = styled(ItemH)` + justify-content: flex-start; + margin-bottom: 16px; + position: relative; + z-index: 1; +`; + +const PaidHeaderRow = styled(ItemV)` + flex-direction: row; + align-items: center; + /* Figma pins the paragraph to the right edge of the 1200px content block + (node 49245:16672 sits at x=806 with w=394). Our container is wider, so + space-between keeps it flush right instead of leaving slack there. */ + justify-content: space-between; + width: 100%; + position: relative; + z-index: 1; + gap: 236px; + + @media ${device.laptop} { + flex-direction: column; + align-items: flex-start; + gap: 24px; + } +`; + +const TitleBlock = styled(H2)` + margin: 0 !important; + flex: 0 0 auto; + max-width: 570px; + + @media ${device.laptop} { + font-size: 2.25rem !important; + max-width: 100%; + } + + @media ${device.tablet} { + font-size: 2rem !important; + } +`; + +const HeaderParagraph = styled.p` + margin: 0; + flex: 0 0 auto; + max-width: 394px; + font-family: 'DM Sans', sans-serif; + font-size: 1.25rem; + font-weight: 400; + line-height: 1.5; + letter-spacing: -0.4px; + color: var(--ifm-color-white); + /* Two fixed lines, per the design's split of this copy. */ + white-space: pre-line; + + @media ${device.mobileL} { + max-width: 100%; + } +`; + +const GradientWord = styled.span` + color: var(--ifm-color-custom-pink); +`; + +// No rule above this row in the design — the stats sit directly on the +// background, 100px below the header block (Frame 37131 at y=234, header 134). +const StatRow = styled(ItemH)` + align-items: flex-start; + justify-content: center; + gap: 151px; + position: relative; + z-index: 1; + + /* Four stats across needs the full width; below that go two-up, then + single column on phones. */ + @media ${device.laptop} { + flex-wrap: wrap; + gap: 48px 32px; + } + + @media ${device.mobileL} { + flex-direction: column; + gap: 32px; + } +`; + +const StatItem = styled(ItemV)` + gap: 24px; + align-items: center; + justify-content: center; + text-align: center; + flex: ${(props) => (props.$fill ? '1 0 0' : '0 0 auto')}; + min-width: 0; + + /* Two-up, then single column. Declared here rather than as a child selector + on the row, which this component's own flex above would override. */ + @media ${device.laptop} { + flex: 1 1 40%; + min-width: 220px; + } + + @media ${device.mobileL} { + flex: 1 1 100%; + width: 100%; + } +`; + +const StatTitle = styled.span` + font-family: 'DM Sans', sans-serif; + font-size: 1rem; + font-weight: 600; + letter-spacing: 0.8px; + line-height: 1.2; + text-transform: uppercase; + text-align: center; + white-space: nowrap; + color: var(--ifm-color-white); + + @media ${device.laptop} { + white-space: normal; + } +`; + +const StatValue = styled.span` + font-family: 'DM Sans', sans-serif; + font-size: 3.25rem; + font-weight: 400; + letter-spacing: -1.04px; + line-height: 1.2; + text-align: center; + white-space: nowrap; + color: var(--ifm-color-white); + + @media ${device.laptop} { + white-space: normal; + } +`; + +const ChainRow = styled(ItemV)` + align-items: center; + justify-content: center; + gap: 8px; +`; + +const ChainIconStack = styled(ItemH)` + justify-content: center; + align-items: center; + flex-wrap: nowrap; +`; + +const ChainIcon = styled.img` + width: 43.119px; + height: 43.119px; + border-radius: 50%; + flex: 0 0 auto; + + &:not(:last-child) { + margin-right: -11.179px; + } +`; + +const MoreChainsBadge = styled.span` + display: inline-flex; + align-items: center; + justify-content: center; + height: 21px; + padding: 0 8px; + box-sizing: border-box; + border-radius: 12px; + border: 1px solid var(--ifm-color-pink-100); + font-family: 'DM Sans', sans-serif; + font-size: 0.5625rem; + font-weight: 700; + letter-spacing: 0.45px; + color: var(--ifm-color-pink-100); + white-space: nowrap; +`; diff --git a/src/components/Home/ProblemNarrative.tsx b/src/components/Home/ProblemNarrative.tsx new file mode 100644 index 000000000000..a2205978862c --- /dev/null +++ b/src/components/Home/ProblemNarrative.tsx @@ -0,0 +1,359 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck +/* eslint-disable */ + +// React + Web3 Essentials +import { useEffect, useRef } from 'react'; + +// External Components +import { gsap } from 'gsap'; +import { ScrollTrigger } from 'gsap/ScrollTrigger'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; + +// Internal Components +import { Content, H2, ItemH, ItemV, Section, Span } from '@site/src/css/SharedStyling'; +import useMediaQuery from '@site/src/hooks/useMediaQuery'; + +// Internal Configs +import GLOBALS, { device } from '@site/src/config/globals'; +import { ProblemNarrativeList } from '@site/src/config/ProblemNarrativeList'; + +gsap.registerPlugin(ScrollTrigger); + +// Hard floor for where a stuck card parks, so it can never tuck under the +// fixed header on short viewports. +const HEADER_OFFSET = GLOBALS.HEADER.HEIGHT + GLOBALS.HEADER.OUTER_MARGIN.DESKTOP.TOP + 24; + +// Breathing room the parked card always keeps below the header, on top of the +// header floor. Centring alone is not enough: on a short laptop viewport +// (~740px) the centred position lands only a few pixels below the header, so +// the stack still reads as glued to the nav. +const MIN_PARK_GAP = 64; + +// A parked card sits vertically centred in the viewport rather than pinned to +// the top, which reads far better when the card is shorter than the screen — +// but never closer to the nav than the gap above, and never so low that the +// card's bottom edge runs off the screen on a short window. +const parkOffset = (cardHeight) => { + if (typeof window === 'undefined') return HEADER_OFFSET; + + const viewport = window.innerHeight; + const centred = Math.round((viewport - cardHeight) / 2); + const preferred = Math.max(HEADER_OFFSET + MIN_PARK_GAP, centred); + const ceiling = Math.max(HEADER_OFFSET, viewport - cardHeight - 24); + + return Math.min(preferred, ceiling); +}; + +// Vertical gap between the cards while they are still stacked in flow. +const CARD_GAP = 48; + +const FONT_MONO = "'IBM Plex Mono', monospace"; + +// Exact 5x5 dot-grid glyph from Figma (node 49322:1879 and its repeats) — red accent +// cells (rounded, 5.739px) and gray filler cells (3.826px) at fixed grid coordinates. +const RED_CELLS = [ + [0, 0], [0, 38.26], [9.57, 9.57], [9.57, 28.7], [19.13, 19.13], + [28.7, 9.57], [28.7, 28.7], [38.26, 0], [38.26, 38.26], +]; +const GRAY_CELLS = [ + [0, 9.57], [0, 19.13], [0, 28.7], + [9.57, 0], [9.57, 19.13], [9.57, 38.26], + [19.13, 0], [19.13, 9.57], [19.13, 28.7], [19.13, 38.26], + [28.7, 0], [28.7, 19.13], [28.7, 38.26], + [38.26, 9.57], [38.26, 19.13], [38.26, 28.7], +]; + +const DotGridIcon = () => ( + +); + +export default function ProblemNarrative() { + const { t } = useTranslation(); + const isMobile = useMediaQuery(device.mobileL); + // Stack only where there's room for it; below this the cards read better + // as a simple vertical list. + const isCompact = useMediaQuery(device.laptop); + + const stageRef = useRef(null); + const cardRefs = useRef([]); + const parkRef = useRef(HEADER_OFFSET); + const setCardRef = (index) => (el) => { + cardRefs.current[index] = el; + }; + + // The stack is pure CSS `position: sticky` in natural document flow: every + // card keeps its own place in the flow, so the section's height is always + // the true sum of its cards and the following section can never ride up + // underneath it. The cards differ by a line or two of wrapped copy though, + // so equalise their heights — otherwise the incoming card is shorter than + // the one it is meant to cover and leaves a sliver showing. + useEffect(() => { + const cards = cardRefs.current.filter(Boolean); + if (cards.length < 2) return undefined; + + const equalize = () => { + cards.forEach((card) => { + card.style.minHeight = ''; + }); + + if (isCompact) { + ScrollTrigger.refresh(); + return; + } + + const tallest = Math.max(...cards.map((card) => card.offsetHeight)); + cards.forEach((card) => { + card.style.minHeight = `${tallest}px`; + }); + + // Park the stack vertically centred for this viewport. Published as a + // custom property so the sticky CSS and the GSAP trigger below always + // read the exact same number. + parkRef.current = parkOffset(tallest); + stageRef.current?.style.setProperty('--stack-top', `${parkRef.current}px`); + + // Heights and offsets just changed, so every trigger needs recomputing. + ScrollTrigger.refresh(); + }; + + equalize(); + + // Re-measure once webfonts land — IBM Plex Mono changes how the story + // copy wraps, and therefore how tall each card is. + if (document.fonts && document.fonts.ready) { + document.fonts.ready.then(equalize); + } + + window.addEventListener('resize', equalize); + return () => { + window.removeEventListener('resize', equalize); + cards.forEach((card) => { + if (card) card.style.minHeight = ''; + }); + }; + }, [isCompact]); + + // Cosmetic only: as the incoming card climbs over the one beneath it, the + // lower card recedes so the stack reads as depth rather than a flat swap. + // This touches transform/opacity exclusively — never layout — so it cannot + // disturb the sticky flow above. + useEffect(() => { + if (isCompact) return undefined; + + const cards = cardRefs.current.filter(Boolean); + if (cards.length < 2 || !stageRef.current) return undefined; + + const ctx = gsap.context(() => { + cards.slice(0, -1).forEach((card) => { + gsap.to(card, { + scale: 0.93, + opacity: 0.45, + ease: 'none', + scrollTrigger: { + trigger: stageRef.current, + // From the moment the first card parks… + start: () => `top top+=${parkRef.current}`, + // …until the stack releases, i.e. the card above is fully covered. + end: () => `bottom top+=${parkRef.current + card.offsetHeight}`, + scrub: true, + invalidateOnRefresh: true, + }, + }); + }); + }, stageRef); + + return () => ctx.revert(); + }, [isCompact]); + + return ( +
+ + +

+ {t(ProblemNarrativeList.meta.titleLine1)} +
+ + {t(ProblemNarrativeList.meta.titleLine2)}{' '} + {t(ProblemNarrativeList.meta.titleGradient)} + +

+ + {t(ProblemNarrativeList.meta.subtitle)} + +
+ + + {ProblemNarrativeList.vignettes.map((vignette, index) => ( + + + + + {t(vignette.story)} + + + + + {vignette.consequences.map((consequence, i) => ( + + + + {t(consequence.text)} + + + ))} + + + + ))} + +
+
+ ); +} + +const NarrativeHeader = styled(ItemV)` + align-items: center; + max-width: 780px; + margin: 0 auto; +`; + +const GradientWord = styled.span` + color: var(--ifm-color-custom-pink); +`; + +// Plain block in normal flow. Deliberately no overflow/transform/filter here: +// any of those would turn this into the sticky containing block and the stack +// would silently stop working. +const Stage = styled.div` + position: relative; + width: 100%; + margin-top: 64px; + + @media ${device.mobileL} { + margin-top: 40px; + } +`; + +// One slot per card, stacked normally. Each sticks at the same offset, so a +// later card climbs over an earlier one and — being later in the DOM — paints +// on top of it without needing any z-index juggling. +const CardSlot = styled.div` + position: sticky; + top: var(--stack-top, ${HEADER_OFFSET}px); + width: 100%; + + &:not(:last-child) { + margin-bottom: ${CARD_GAP}px; + } + + @media ${device.laptop} { + position: static; + top: auto; + + &:not(:last-child) { + margin-bottom: 24px; + } + } +`; + +const VignetteCard = styled(ItemV)` + align-items: ${(props) => (props.align === 'right' ? 'flex-end' : 'flex-start')}; + justify-content: space-between; + gap: 157px; + width: 100%; + padding: 48px; + border-radius: 48px; + background: ${(props) => props.bg}; + box-sizing: border-box; + will-change: transform; + + @media ${device.laptop} { + align-items: flex-start; + justify-content: flex-start; + gap: 48px; + padding: 40px 32px; + min-height: 0 !important; + } + + @media ${device.mobileL} { + gap: 32px; + padding: 28px 20px; + } +`; + +// 465px is the Figma width, but it has to be a cap rather than a fixed width: +// as a fixed width it becomes a min-content floor that inflates the card (and +// then the whole Content column) past the viewport on narrow screens. +const StoryText = styled.div` + display: flex; + align-items: center; + justify-content: center; + width: 100%; + max-width: 465px; + min-width: 0; +`; + +const ConsequenceRow = styled(ItemH)` + gap: 64px; + align-items: flex-start; + width: 100%; + + @media ${device.laptop} { + flex-direction: column; + gap: 24px; + } +`; + +const ConsequenceItem = styled(ItemH)` + flex: 1; + align-items: flex-start; + justify-content: flex-start; + flex-wrap: nowrap; + gap: 24px; + + svg { + flex: 0 0 auto; + } +`; diff --git a/src/components/Home/RecentBlogPosts.js b/src/components/Home/RecentBlogPosts.js index 7c7921dee50b..8ad6438d92b3 100644 --- a/src/components/Home/RecentBlogPosts.js +++ b/src/components/Home/RecentBlogPosts.js @@ -18,7 +18,7 @@ import { Spacer, } from '@site/src/components/reusables/date.tsx'; -const RecentBlogPosts = () => { +const RecentBlogPosts = ({ count = 3 }) => { const { recentBlogs } = useFetchRecentBlogs(); const { t } = useTranslation(); @@ -48,7 +48,7 @@ const RecentBlogPosts = () => { role='list' aria-label={t('pages.home.blog-section.blog-posts-list-aria-label')} > - {recentBlogs?.slice(0, 3).map((postItem, index) => { + {recentBlogs?.slice(0, count).map((postItem, index) => { const blogPostAriaLabel = t( 'pages.home.blog-section.blog-post-aria-label', { diff --git a/src/components/Home/SolutionPanel.tsx b/src/components/Home/SolutionPanel.tsx new file mode 100644 index 000000000000..017f7088eb0e --- /dev/null +++ b/src/components/Home/SolutionPanel.tsx @@ -0,0 +1,117 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck +/* eslint-disable */ + +// External Components +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; + +// Internal Components +import { Content, H2, ItemH, ItemV, Section, Span } from '@site/src/css/SharedStyling'; +import useMediaQuery from '@site/src/hooks/useMediaQuery'; + +// Internal Configs +import { device } from '@site/src/config/globals'; + +const FONT_MONO = "'IBM Plex Mono', monospace"; + +export default function SolutionPanel() { + const { t } = useTranslation(); + const isMobile = useMediaQuery(device.mobileL); + + return ( + + + +

+ {/* Three fixed lines, per Figma. The design's 530px text box wraps + naturally into "Making AI / Universally / accountable"; forcing + the breaks keeps that shape at any container width instead of + depending on where the copy happens to wrap. */} + {t('pages.home.solution-panel.title-prefix')} +
+ {t('pages.home.solution-panel.title-highlight')} +
+ {t('pages.home.solution-panel.title-suffix')} +

+ + {t('pages.home.solution-panel.paragraph')} + +
+ +
+
+ ); +} + +// Figma puts 385px between the bottom of the last problem-narrative card and +// the top of this title (node 49233:16550 at y=2724 vs the card block ending +// at y=2339). The two sections' own paddings already supply 253px of that, so +// this makes up the remaining lead-in. +const SolutionSection = styled(Section)` + margin-top: 132px; + + @media ${device.mobileL} { + margin-top: 40px; + } +`; + +const TextRow = styled(ItemH)` + align-items: center; + gap: 139px; + margin-bottom: 64px; + + h2, + span { + flex: 1; + } + + @media ${device.laptop} { + flex-direction: column; + align-items: flex-start; + gap: 24px; + margin-bottom: 40px; + } + + @media ${device.mobileL} { + margin-bottom: 32px; + } +`; + +const GradientWord = styled.span` + color: var(--ifm-color-custom-pink); +`; + +const SolutionPlaceholder = styled.div` + width: 100%; + height: 635px; + border-radius: 48px; + background: #323232; + + @media ${device.laptop} { + height: 420px; + border-radius: 32px; + } + + @media ${device.mobileL} { + height: 240px; + border-radius: 24px; + } +`; diff --git a/src/components/Home/UniversalStatCallout.tsx b/src/components/Home/UniversalStatCallout.tsx new file mode 100644 index 000000000000..88fe82d7eae9 --- /dev/null +++ b/src/components/Home/UniversalStatCallout.tsx @@ -0,0 +1,142 @@ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck +/* eslint-disable */ + +// React + Web3 Essentials +import useBaseUrl from '@docusaurus/useBaseUrl'; + +// External Components +import { useTranslation } from 'react-i18next'; +import { BsArrowRight } from 'react-icons/bs'; +import styled from 'styled-components'; + +// Internal Components +import { A, ItemH } from '@site/src/css/SharedStyling'; +import useMediaQuery from '@site/src/hooks/useMediaQuery'; + +// Internal Configs +import { device } from '@site/src/config/globals'; + +export default function UniversalStatCallout() { + const { t } = useTranslation(); + const isMobile = useMediaQuery(device.mobileL); + + return ( + + + + {t('pages.home.feature-grid-b.stat-callout.value')} + {t('pages.home.feature-grid-b.stat-callout.value-label')} + + + {t('pages.home.feature-grid-b.stat-callout.text')} + + + + + {t('pages.home.feature-grid-b.stat-callout.cta')} + + + + ); +} + +const CalloutRow = styled(ItemH)` + align-items: center; + justify-content: space-between; + gap: 24px; + margin-top: 24px; + + a { + display: flex; + justify-content: center; + align-items: center; + gap: 12px; + /* Figma gives this button an explicit 58px height. */ + min-height: 58px; + box-sizing: border-box; + } + + @media ${device.laptop} { + flex-direction: column; + align-items: flex-start; + gap: 32px; + } + + @media ${device.mobileL} { + a { + width: 100%; + } + } +`; + +const CalloutLeft = styled(ItemH)` + align-items: center; + justify-content: flex-start; + flex-wrap: wrap; + gap: 24px; +`; + +const GradientText = styled.span` + background: linear-gradient(90deg, #f5f1ff 3.116%, #aa48ec 109.09%); + background-clip: text; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + font-family: 'DM Sans', sans-serif; + font-weight: 600; +`; + +const StatBlock = styled.div` + display: flex; + align-items: flex-end; +`; + +const StatValue = styled(GradientText)` + font-size: 4.8125rem; + letter-spacing: -1.54px; + line-height: 1; +`; + +const StatLabel = styled(GradientText)` + font-size: 1.25rem; + letter-spacing: -0.4px; + /* Figma sets 20px leading on the 20px label — the two lines sit tight. */ + line-height: 20px; + white-space: pre-line; + margin-left: 4px; +`; + +const CalloutText = styled.p` + margin: 0; + font-family: 'DM Sans', sans-serif; + font-weight: 500; + font-size: 1.75rem; + letter-spacing: -0.56px; + line-height: 1.4; + color: var(--ifm-color-white); + /* Two fixed lines, per Figma's split of this sentence. */ + white-space: pre-line; + + @media ${device.tablet} { + font-size: 1.375rem; + } + + @media ${device.mobileL} { + font-size: 1.125rem; + /* Let the sentence reflow rather than forcing the desktop break. */ + white-space: normal; + } +`; diff --git a/src/components/InfoBar.tsx b/src/components/InfoBar.tsx index 750837d7d747..234609834fe0 100644 --- a/src/components/InfoBar.tsx +++ b/src/components/InfoBar.tsx @@ -81,16 +81,18 @@ const BarContainer = styled.div` justify-content: center; gap: 8px; width: 100%; - padding: 0 16px; + padding: 16px; box-sizing: border-box; - height: 58px; + height: 56px; cursor: pointer; background: linear-gradient( 90deg, - #3524ed 0%, + #f898f0 0%, + #e670ee 25%, var(--ifm-color-custom-pink) 50%, - #3524ed 100% + #e670ee 75%, + #f898f0 100% ); /* backdrop-filter: blur(calc(var(--blur-md, 24px) / 2)); */ @@ -203,7 +205,11 @@ const DismissBtn = styled.button` font-size: 18px; cursor: pointer; padding: 0; - height: 48px; + height: 20px; + width: 20px; + display: flex; + align-items: center; + justify-content: center; `; export default InfoBar; diff --git a/src/components/QnA/QnA.tsx b/src/components/QnA/QnA.tsx index 248d7e142855..34b5c4255fee 100644 --- a/src/components/QnA/QnA.tsx +++ b/src/components/QnA/QnA.tsx @@ -30,6 +30,14 @@ interface QnAProps { exploreMoreTextKey?: string; discordUrl?: string; exploreMoreUrl?: string; + titleFontFamily?: string; + titleFontWeight?: string; + /** + * 'pushCore' applies the Push Core landing spec (Figma node 49245:16774): + * 383/793 columns 24px apart, a 321px-wide title, and the larger Discord + * button. Omit it and this renders as it does on the other four pages. + */ + variant?: 'default' | 'pushCore'; faqsList?: Array<{ question: string; section: string; @@ -54,6 +62,9 @@ const QnA: FC = ({ exploreMoreTextKey = 'components.short-faq-snippet.explore-more-text', discordUrl = 'https://discord.com/invite/pushchain', exploreMoreUrl = '/knowledge/faq', + titleFontFamily = 'DM Sans, sans-serif', + titleFontWeight = '600', + variant = 'default', faqsList, getQnAsFunction = getShortFAQsList, }) => { @@ -63,28 +74,32 @@ const QnA: FC = ({ const isMobile = useMediaQuery(device.mobileL); const isLaptop = useMediaQuery(device.laptop); const finalFaqsList = faqsList || getQnAsFunction(); + const isPushCore = variant === 'pushCore'; return (

= ({

-
@@ -292,22 +293,6 @@ function Footer() { -
- - {t('footer.footer-image.alt')} - -
); @@ -380,12 +365,6 @@ const FooterContainer = styled.div` } `; -const ImageContent = styled(Content)` - @media ${device.tablet} { - padding-top: 0px; - padding-bottom: 0px; - } -`; const FooterColumn = styled.div` display: flex; diff --git a/src/segments/Header.tsx b/src/segments/Header.tsx index c741953e56a5..5ee476cf91ba 100644 --- a/src/segments/Header.tsx +++ b/src/segments/Header.tsx @@ -357,16 +357,17 @@ function Header() { to={useBaseUrl('/')} aria-label={t('header.meta.logo-aria-label')} > + {/* Referenced as a served static URL rather than require()d: + this project's webpack turns .svg imports into SVGR React + components, so require(...).default yields a component and + the renders 0x0. */} {t('header.logo.imagealt')} @@ -378,15 +379,12 @@ function Header() { padding='0' > {t('header.logo.imagealt')} @@ -963,11 +961,9 @@ const LanguageItem = styled.div` const HeaderItemH = styled(ItemH)` border-radius: 24px; + box-sizing: border-box; border: 1px solid rgba(171, 70, 248, 0.4); background: rgba(0, 0, 0, 0.5); - // box-shadow: - // 2.788px 2.598px 12px 0 rgba(255, 255, 255, 0.15) inset, - // 1.858px 1.732px 6px 0 rgba(255, 255, 255, 0.15) inset; z-index: 1; &::before { @@ -983,6 +979,22 @@ const HeaderItemH = styled(ItemH)` border-radius: 24px; } + /* Inner highlight from Figma (node 49113:39) — the same inset pair the + footer's newsletter input uses. It has to be its own layer *above* the + ::before glass: as a box-shadow on this element it paints underneath + that backdrop-filter, which blurs the highlight away. Figma stacks it + the same way, as the last child over the blurred fill. */ + &::after { + content: ''; + position: absolute; + inset: 0; + border-radius: 24px; + pointer-events: none; + box-shadow: + 2.788px 2.598px 12px 0 rgba(255, 255, 255, 0.15) inset, + 1.858px 1.732px 6px 0 rgba(255, 255, 255, 0.15) inset; + } + margin: ${({ showAlertBar }) => `${showAlertBar ? 80 : GLOBALS.HEADER.OUTER_MARGIN.DESKTOP.TOP}px ${ GLOBALS.HEADER.OUTER_MARGIN.DESKTOP.RIGHT @@ -1047,7 +1059,23 @@ const HeaderNavItemV = styled(ItemV)` const PushLogoWhiteContainer = styled(ItemV)` display: flex; - max-width: 190px; + max-width: 209px; + flex: 0 0 auto; + /* Figma node 49113:40: the artwork sits in a 50px-tall box with 16px of + padding either side, so the mark starts 28px in from the pill edge. */ + height: 50px; + padding: 0 16px; + box-sizing: border-box; + align-items: center; + justify-content: center; + + img { + object-fit: contain; + /* A global img { max-width: 100% } clamps the mark to its parent, which is + itself sized by the mark — leaving it short of its intrinsic 176px. */ + max-width: none; + flex: 0 0 auto; + } &.light { display: none; } @@ -1055,6 +1083,22 @@ const PushLogoWhiteContainer = styled(ItemV)` const PushLogoBlackContainer = styled(ItemV)` display: none; + flex: 0 0 auto; + /* Figma node 49113:40: the artwork sits in a 50px-tall box with 16px of + padding either side, so the mark starts 28px in from the pill edge. */ + height: 50px; + padding: 0 16px; + box-sizing: border-box; + align-items: center; + justify-content: center; + + img { + object-fit: contain; + /* A global img { max-width: 100% } clamps the mark to its parent, which is + itself sized by the mark — leaving it short of its intrinsic 176px. */ + max-width: none; + flex: 0 0 auto; + } &.light { display: flex; } @@ -1176,7 +1220,10 @@ const MenuTop = styled(ItemV)<{ }>` display: flex; z-index: 9999; - height: ${GLOBALS.HEADER.HEIGHT}px; + /* Fill the pill's content box, not the pill's outer height — the pill now + carries 12px padding, so a fixed HEADER.HEIGHT here overflows it by 24px + and pushes the row off centre. */ + height: 100%; & svg { cursor: pointer; diff --git a/src/theme/Root.js b/src/theme/Root.js index e70f13ed5b1a..26d73a4af48a 100644 --- a/src/theme/Root.js +++ b/src/theme/Root.js @@ -140,7 +140,7 @@ export default function Root({ children }) { {typeof window !== 'undefined' && showAlertBar && ( )} @@ -180,6 +180,6 @@ const Content = styled.div` flex: 1; ${({ isHome }) => isHome && - `background: linear-gradient(90deg, #3524ed 0%,var(--ifm-color-custom-pink) 50%, #3524ed 100%); + `background: linear-gradient(90deg, #f898f0 0%, #e670ee 25%, var(--ifm-color-custom-pink) 50%, #e670ee 75%, #f898f0 100%); `} `; diff --git a/static/assets/website/home/built-to-scale/push-logo-mark.svg b/static/assets/website/home/built-to-scale/push-logo-mark.svg new file mode 100644 index 000000000000..c0505ede45fd --- /dev/null +++ b/static/assets/website/home/built-to-scale/push-logo-mark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/static/assets/website/home/built-to-scale/ring-pattern.png b/static/assets/website/home/built-to-scale/ring-pattern.png new file mode 100644 index 000000000000..8a0fee201296 Binary files /dev/null and b/static/assets/website/home/built-to-scale/ring-pattern.png differ diff --git a/static/assets/website/home/feature-grid-b/universal-access.png b/static/assets/website/home/feature-grid-b/universal-access.png new file mode 100644 index 000000000000..335725fde38b Binary files /dev/null and b/static/assets/website/home/feature-grid-b/universal-access.png differ diff --git a/static/assets/website/home/feature-grid-b/universal-contracts.png b/static/assets/website/home/feature-grid-b/universal-contracts.png new file mode 100644 index 000000000000..4c9916a45c98 Binary files /dev/null and b/static/assets/website/home/feature-grid-b/universal-contracts.png differ diff --git a/static/assets/website/home/feature-grid-b/universal-read-write.png b/static/assets/website/home/feature-grid-b/universal-read-write.png new file mode 100644 index 000000000000..bf68b6614311 Binary files /dev/null and b/static/assets/website/home/feature-grid-b/universal-read-write.png differ diff --git a/static/assets/website/home/paid-stats/arbitrum.svg b/static/assets/website/home/paid-stats/arbitrum.svg new file mode 100644 index 000000000000..1c41b3994b59 --- /dev/null +++ b/static/assets/website/home/paid-stats/arbitrum.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/static/assets/website/home/paid-stats/base.svg b/static/assets/website/home/paid-stats/base.svg new file mode 100644 index 000000000000..a6991fb1f33f --- /dev/null +++ b/static/assets/website/home/paid-stats/base.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/assets/website/home/paid-stats/bnb-chain.svg b/static/assets/website/home/paid-stats/bnb-chain.svg new file mode 100644 index 000000000000..328816da3a4a --- /dev/null +++ b/static/assets/website/home/paid-stats/bnb-chain.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/static/assets/website/home/paid-stats/ethereum.svg b/static/assets/website/home/paid-stats/ethereum.svg new file mode 100644 index 000000000000..3b57f9779122 --- /dev/null +++ b/static/assets/website/home/paid-stats/ethereum.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/static/assets/website/home/paid-stats/glow-ellipse.svg b/static/assets/website/home/paid-stats/glow-ellipse.svg new file mode 100644 index 000000000000..af43ef5a1baf --- /dev/null +++ b/static/assets/website/home/paid-stats/glow-ellipse.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/static/assets/website/home/paid-stats/lines-bg.svg b/static/assets/website/home/paid-stats/lines-bg.svg new file mode 100644 index 000000000000..8ddb6bdae57c --- /dev/null +++ b/static/assets/website/home/paid-stats/lines-bg.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/assets/website/home/paid-stats/solana.svg b/static/assets/website/home/paid-stats/solana.svg new file mode 100644 index 000000000000..1d981097ad06 --- /dev/null +++ b/static/assets/website/home/paid-stats/solana.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/static/assets/website/segments/PushCoreLogoTextBlack.svg b/static/assets/website/segments/PushCoreLogoTextBlack.svg new file mode 100644 index 000000000000..a6f8a623c6cb --- /dev/null +++ b/static/assets/website/segments/PushCoreLogoTextBlack.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/static/assets/website/segments/PushCoreLogoTextWhite.svg b/static/assets/website/segments/PushCoreLogoTextWhite.svg new file mode 100644 index 000000000000..9dcc52f6925d --- /dev/null +++ b/static/assets/website/segments/PushCoreLogoTextWhite.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/static/locales/en/01-translate/03-footer.json b/static/locales/en/01-translate/03-footer.json index e6b4ebda8bc3..125c7520684d 100644 --- a/static/locales/en/01-translate/03-footer.json +++ b/static/locales/en/01-translate/03-footer.json @@ -1,8 +1,8 @@ { "footer": { "email-section": { - "title": "Stay in the loop with Push Chain", - "title-secondary": "news and updates!", + "title": "Want to receive Push Core", + "title-secondary": "news, and updates?", "title-aria-label": "Newsletter subscription section", "section-aria-label": "Push Chain newsletter signup" }, @@ -28,6 +28,10 @@ "help": { "title": "Help", "title-aria-label": "Help navigation" + }, + "products": { + "title": "Products", + "title-aria-label": "Products navigation" } }, "links": { @@ -68,7 +72,9 @@ "reddit": "Reddit", "reddit-title": "Join the Push Chain subreddit", "telegram": "Telegram", - "telegram-title": "Join the Push Chain Telegram" + "telegram-title": "Join the Push Chain Telegram", + "quick-start": "Quick Start", + "quick-start-title": "Get up and running on Push Chain quickly" }, "social-section": { "section-aria-label": "Social media links and legal information", diff --git a/static/locales/en/01-translate/04-01-pages-home.json b/static/locales/en/01-translate/04-01-pages-home.json index ffb4f2ea8850..007a2f098643 100644 --- a/static/locales/en/01-translate/04-01-pages-home.json +++ b/static/locales/en/01-translate/04-01-pages-home.json @@ -10,99 +10,127 @@ "twitter-description": "Transact from any chain. Use any wallet. Pay with any token. No network switching." }, "hero-section": { - "title": "Any Chain, Any App, All Users.\nOne Push Chain.", - "description": "The first Layer 1 built for Universal Apps. \nBuild & Deploy once, onboard users from any chain.", + "title": "Verification for the Agentic Internet.", + "description": "Push Chain verifies if AI agents' work is any good.", "primary-button": "Start Building", "primary-button-title": "Start your builder's journey with Push Chain!", "secondary-button": "Explore Knowledge Base", "secondary-button-title": "Learn and explore Push Chain", - "section-aria-label": "Push Chain hero section - Universal Layer 1 blockchain introduction", + "section-aria-label": "Push Chain hero section - verification layer for the agentic internet", "primary-button-aria-label": "Start building universal apps on Push Chain - Go to developer documentation", "secondary-button-aria-label": "Learn about Push Chain features and concepts in knowledge base", "hero-background-alt": "Push Chain hero background animation showing universal blockchain connectivity", "hero-background-title": "Push Chain - Universal Layer 1 for cross-chain applications", - "schema-headline": "Push Chain - Universal L1 for Apps", - "schema-description": "Deploy once on Push Chain and reach users on any blockchain with universal apps" + "schema-headline": "Push Chain - Verification for the Agentic Internet", + "schema-description": "Push Chain verifies if AI agents' work is any good, settling payment on verdict across any chain", + "title-line1": "Verification for the", + "title-line2": "Agentic Internet." }, - "whatis-section": { - "titleFirst": "A True", - "titleSecondGraditent": "Universal", - "titleThird": "Chain", - "bottomTextFirst": "Deploy Once,", - "bottomTextSecond": "Reach Everywhere", - "bottomLinkText": "Get Started", - "bottomLinkTitle": "Goto Documentation Hub", - "section-aria-label": "What is Push Chain - Universal blockchain explanation", - "animation-alt": "Animation demonstrating Push Chain's universal app deployment across multiple blockchains", - "animation-title": "Push Chain universal deployment visualization - deploy once, reach any chain", - "bottom-link-aria-label": "Navigate to Push Chain documentation to start building universal apps" + "problem-narrative": { + "title-line1": "Letting agents move", + "title-line2": "your money is a", + "titleGradient": "Gamble.", + "subtitle": "Agents can already move money, but nothing checks their work.", + "section-aria-label": "The problem with unverified AI agents moving money", + "vignette1": { + "story": "Alice gives her agent a budget. Her rules are simple: trusted contracts only, a fixed amount per day. But no chain enforces these rules everywhere the agent trades.", + "consequence1": "Rules hold on some chains. When the agent trades somewhere else, they stop applying.", + "consequence2": "One hallucination or rogue call and the money is lost forever." + }, + "vignette2": { + "story": "Chad paid an AI agent to grow his Twitter: He gained 10,000 new followers, but every one was a bot. The payment released the instant the goal was reached.", + "consequence1": "The job was marked done. The work was never evaluated.", + "consequence2": "Irreversible: No reputation hit, No recourse." + } + }, + "solution-panel": { + "title-prefix": "Making AI", + "title-highlight": "Universally", + "title-suffix": "accountable", + "paragraph": "Before your agent acts, it's held to rules it can't break. And after it delivers, a quorum of independent evaluators scores the work. Payment moves only on their verdict, and it moves on any chain.", + "section-aria-label": "How Push Chain makes AI agents universally accountable" }, - "chain-features-section": { - "section-aria-label": "Push Chain innovations and features section", - "header": { - "main-text": "Built on innovations to eliminate fragmentation!", - "other-text": "Push is the only Universal Layer 1 you will ever need!" + "built-to-scale": { + "title-line1": "Built to scale the agentic economy.", + "title-line2": "Whatever you're building, wherever.", + "section-aria-label": "Push Chain is built to scale the agentic economy" + }, + "feature-grid-a": { + "title": "Everything your agent needs, in one place.", + "section-aria-label": "Everything your AI agent needs, in one place", + "card1": { + "title": "Evaluation by\nQuorum", + "description": "A quorum of independent, staked AI judges scores every job against its spec. Payment moves on their verdict, not on claims." + }, + "card2": { + "title": "Pay on\nVerdict", + "description": "Escrow that releases on quality, not claims. Plug Push in as the evaluator on any agent job: the work gets judged, then the money moves." }, - "box1": { - "texttitle": "Any Chain Transactions", - "bodytext": "Push Chain supports transactions from any blockchain. Users can pay gas in any token — No need for bridging.", - "imagealt": "Illustration showing different blockchain logos falling in a pin ball machine.", - "imagetitle": "Supports transactions from any blockchain." + "card3": { + "title": "Unbreakable\nRules", + "description": "Rules your agent can never break: spend caps, allowed contracts, time limits. Enforced at the chain level, no matter what the model decides." }, - "box2": { - "texttitle": "Wallet Abstraction", - "bodytext": "Let any wallet from any chain connect, interact, and transact. Break web3 barriers by using social login or email. User get to decide on Push Chain.", - "imagealt": "Illustration showing Metamask wallet, Phantom Wallet, etc coming out of a big wallet with Push Chain logo on it.", - "imagetitle": "Supports any existing wallets like Metamask, Phantom, etc along with social login" + "card4": { + "title": "Agentic\nWallet", + "description": "A wallet that operates within the guardrails you set. Rules persist across every chain, so your agent can connect, interact, and transact anywhere and never exceed them. One wallet, every chain, no per-chain keys to manage." }, - "box3": { - "texttitle": "100% EVM\nCompatible", - "bodytext": "Deploy with zero on-chain code. Turn your native app into a universal app in minutes.", - "imagealt": "Illustration showing Ethereum Virtual Machine logo spinning and saying 100% EVM Compatibility.", - "imagetitle": "Zero on-chain code changes required, 100% EVM Compatible." + "card5": { + "title": "Identity &\nReputation", + "description": "Your agent keeps one identity everywhere it works. Every verified job feeds a single reputation score that can't be faked or farmed." + } + }, + "feature-grid-b": { + "title": "Everything runs on a\nnetwork that reaches", + "titleGradient": "every other chain.", + "subtitle": "One settlement and execution layer, so any agent and any user can easily participate without bridging.", + "section-aria-label": "Push Chain runs on a network that reaches every other chain", + "card1": { + "title": "Universal\nAccess", + "description": "Supports transactions from any chain. One execution and one settlement layer across every chain. Any token, any chain, all users." }, - "box4": { - "texttitle": "Universal Smart Contracts", - "bodytext": "Build once, run cross chain, multi step experiences with a single, future-proof contract.", - "imagealt": "Illustration showing Ethereum Virtual Maching logo and a an arc revolving around it saying '100% EVM Compatible'", - "imagetitle": "Deploy once, instantly become compatible with all supported chains (EVM or non-EVM)." + "card2": { + "title": "Universal\nContracts", + "description": "Build once, run on every chain. Cross-chain experiences from a single future-proof contract. 100% EVM compatible, zero on-chain code changes." }, - "box5": { - "texttitle": "Universal Fee\nAbstraction", - "bodytext": "Let's users pay gas in any token, on any chain without bridging.", - "imagealt": "Illustration showing different logos of Bitcoin, Ethereum, Solana rotating around Push Chain", - "imagetitle": "Supports any token of any chain for transactions." + "card3": { + "title": "Universal\nRead & Write", + "description": "Trigger, validate, and complete transactions on any chain from your contract or wallet. One call, delivered wherever it points." }, - "box6": { - "texttitle": "Universal Execution Layer", - "bodytext": "Build atomic, composable apps across web3. Create never seen before app experiences, by having multiple users of different chains transact with the same app.", - "imagealt": "Illustration showing different tetris blocks entering a wormhole and Push Chain logo emerging from the other end.", - "imagetitle": "Transactions from any chain finalize on Push Chain, enabling users of any chain to natively use the same app aka Universal Execution Layer." + "stat-callout": { + "value": "5", + "value-label": "mins \nto deploy", + "text": "Push Core verifies if AI agents' work is any good.\nYour first universal app takes minutes.", + "cta": "Start Building", + "cta-title": "Start your builder's journey with Push Chain!", + "cta-aria-label": "Start building universal apps on Push Chain - Go to developer documentation" + } + }, + "paid-stats": { + "eyebrow": "GET P.A.I.D", + "title": "Get Probabilistic AI,", + "titleGradient": "Deterministic", + "paragraph": "Ask one AI twice and you get two answers.\nPush settles every judgement across a quorum of independent evaluators: probabilistic AI in, deterministic verdict out.", + "section-aria-label": "Get Probabilistic AI, Deterministic - Push Chain verdict and settlement stats", + "stat1": { + "title": "Verdict per job", + "value": "1" }, - "box7": { - "texttitle": "Universal\nValidators", - "bodytext": "Trigger, validate, and complete transactions across any chain using your smart contract.", - "tags": { - "title1": "WRITE TO CHAINS" - }, - "imagealt": "Illustration showing tetris blocks in different colors merging and changing.", - "imagetitle": "(Roadmap) Universal Validators allow users to trigger, validate, and complete transactions across any chain using your smart contract." + "stat2": { + "title": "Quorum to finalize", + "value": "2/3" }, - "box8": { - "texttitle": "State Access", - "bodytext": "Access account and state data from other chains in your smart contract.", - "tagText": "COMING SOON", - "tags": { - "title1": "READ FROM CHAINS" - }, - "imagealt": "Illustration showing Push Chain growing in blocks style animation.", - "imagetitle": "(Roadmap) Shared State allows access to account and state data from other chains in your smart contract." + "stat3": { + "title": "Settlement / Execution", + "value": "Universal" }, - "footer": { - "title": "your app's user base by going universal", - "secondary": "with zero effort!", - "ctatext": "Start Building", - "ctatitle": "Deploy once, 10x your userbase. Visit Developer Docs." + "stat4": { + "title": "Supported chains", + "chain1-alt": "Ethereum", + "chain2-alt": "Solana", + "chain3-alt": "BNB Chain", + "more-chains-badge": "More chains soon", + "chain4-alt": "Arbitrum", + "chain5-alt": "Base" } }, "partners-section": { @@ -147,7 +175,7 @@ "blog-section": { "subtitle": "NEWS, DEVLOGS & IDEAS", "subtitle-aria-label": "Blog category information", - "title": "Your Pulse of Push Chain", + "title": "Your Pulse of Push Core", "title-aria-label": "Latest Push Chain blog posts and updates", "explore-link-text": "Explore More Articles", "explore-link-title": "Visit Push Chain blog to read all articles and updates", @@ -160,11 +188,6 @@ "error-text": "Unable to load blog posts at this time", "no-posts-text": "No blog posts available" }, - "trustedby-section": { - "title": "Built by the team trusted by pioneers of web3", - "section-aria-label": "Push Chain trusted by section", - "trusted-by-alt": "Investor - " - }, "featured-section": { "aria-label": "Featured On section", "tag": "FEATURED ON", @@ -225,21 +248,16 @@ } } }, - "ending-section": { - "aria-label": "Build Universal Apps section", - "section-title": "Build Universal Apps.", - "section-subtitle": "Break the silos. Build once, scale on every blockchain.", - "docs-link": { - "text": "Explore Push Chain Docs", - "title": "Explore Push Chain documentation and developer resources", - "aria-label": "Open Push Chain documentation in new tab" - }, - "cta-link": { - "text": "LFG Push Chain", - "title": "Get started with Push Chain - the universal blockchain platform", - "aria-label": "Get started with Push Chain development" - } + "closing-cta": { + "section-aria-label": "Get started with Push Core", + "title-line1": "Agents do the work.", + "title-line2": "Push proves it's good.", + "subtitle": "Guardrails before. Verification after. Payment on the verdict.", + "cta": "Get Started", + "cta-title": "Start your builder's journey with Push Chain!", + "cta-aria-label": "Get started building on Push Chain - Go to developer documentation", + "animation-aria-label": "Push Core verification animation" } } } -} \ No newline at end of file +} diff --git a/static/locales/en/01-translate/05-12-components-home-agent-faq.json b/static/locales/en/01-translate/05-12-components-home-agent-faq.json new file mode 100644 index 000000000000..99c2d39125ad --- /dev/null +++ b/static/locales/en/01-translate/05-12-components-home-agent-faq.json @@ -0,0 +1,69 @@ +{ + "components": { + "home-agent-faq": { + "title": "Frequently Asked Questions", + "title-aria-label": "Frequently asked questions about Push Chain and AI agent verification", + "section-aria-label": "Frequently asked questions about Push Chain", + "discord-link-text": "Ask us on Discord", + "discord-link-title": "Ask us your questions on Discord", + "discord-link-aria-label": "Join the Push Chain Discord community to ask questions", + "accordion-aria-label": "Frequently asked questions accordion", + "answer-aria-label": "Answer to: ", + "explore-more-text": "Explore More FAQs", + "explore-more-title": "Explore more frequently asked questions", + "explore-more-aria-label": "Navigate to the full FAQ page", + "qnas": { + "qna1": { + "question": "What is Push Core?", + "answer": "<1>Push Chain is the verification layer for the agentic internet. Agents are held to rules they can't break while they act, and independent AI evaluators score their work after. Payment settles on the verdict, on any chain, with a universal network underneath." + }, + "qna2": { + "question": "What if the evaluators disagree, or get it wrong?", + "answer": "<1>Verdicts aren't decided by a single evaluator. A quorum of independent, staked AI judges scores each job against its spec, and payment only moves once enough of them agree. Evaluators that consistently misjudge work put their own stake at risk, which keeps their incentives aligned with getting it right." + }, + "qna3": { + "question": "What stops evaluators from colluding or being bribed?", + "answer": "<1>Evaluators stake collateral to participate, and that stake is slashed if they're caught colluding or producing bad-faith verdicts. Combined with requiring quorum agreement across independent evaluators rather than a single judge, collusion has to clear a much higher bar than convincing one party." + }, + "qna4": { + "question": "Can Push verify work that happens offchain, in web2?", + "answer": "<1>Yes. Evaluators score the agent's output against its spec regardless of where the work happened - an API call, a social post, an offchain computation. What Push Chain guarantees is what happens next: the verdict and the payment settlement, which move onchain on any supported chain." + }, + "qna5": { + "question": "Does my agent have to run on Push?", + "answer": "<1>No. Your agent can run anywhere. Push Chain plugs in as the evaluation and settlement layer - you point your agent's payment flow at Push, and the work gets judged and paid out from there, without migrating your agent's own runtime." + }, + "qna6": { + "question": "How does Push fit the existing agent standards?", + "answer": "<1>Push Chain is designed to sit alongside existing agent frameworks and payment standards rather than replace them. It adds a verification and settlement layer on top - your agent keeps using the tools and standards it already does, with Push handling accountability for the outcomes." + } + }, + "faqs": { + "faq1": { + "question": "What is Push Core?", + "answer": "Push Chain is the verification layer for the agentic internet. Agents are held to rules they can't break while they act, and independent AI evaluators score their work after. Payment settles on the verdict, on any chain, with a universal network underneath." + }, + "faq2": { + "question": "What if the evaluators disagree, or get it wrong?", + "answer": "Verdicts aren't decided by a single evaluator. A quorum of independent, staked AI judges scores each job against its spec, and payment only moves once enough of them agree." + }, + "faq3": { + "question": "What stops evaluators from colluding or being bribed?", + "answer": "Evaluators stake collateral to participate, and that stake is slashed if they're caught colluding or producing bad-faith verdicts." + }, + "faq4": { + "question": "Can Push verify work that happens offchain, in web2?", + "answer": "Yes. Evaluators score the agent's output against its spec regardless of where the work happened, and the verdict and payment settlement move onchain on any supported chain." + }, + "faq5": { + "question": "Does my agent have to run on Push?", + "answer": "No. Your agent can run anywhere. Push Chain plugs in as the evaluation and settlement layer without migrating your agent's own runtime." + }, + "faq6": { + "question": "How does Push fit the existing agent standards?", + "answer": "Push Chain sits alongside existing agent frameworks and payment standards, adding a verification and settlement layer on top." + } + } + } + } +} diff --git a/static/locales/en/01-translate/06-03-notifications-info-bar.json b/static/locales/en/01-translate/06-03-notifications-info-bar.json index abc5513dab8b..f28abff69b0e 100644 --- a/static/locales/en/01-translate/06-03-notifications-info-bar.json +++ b/static/locales/en/01-translate/06-03-notifications-info-bar.json @@ -1,9 +1,9 @@ { "notifications": { "info-bar": { - "title": "Push Chain passes Hacken security audit. Zero critical issues found.", - "learn-more-text": "Read More", - "learn-more-title": "Read More", + "title": "Launch on Push Testnet Now — Unlock Rewards for Builders and Early Users.", + "learn-more-text": "Learn More", + "learn-more-title": "Learn More", "dismiss-button-title": "Dismiss announcement", "dismiss-button-aria-label": "Close announcement bar", "container-aria-label": "Site announcement", diff --git a/static/locales/en/translation.json b/static/locales/en/translation.json index ffb58531794a..2af930e8a0fe 100644 --- a/static/locales/en/translation.json +++ b/static/locales/en/translation.json @@ -176,8 +176,8 @@ }, "footer": { "email-section": { - "title": "Stay in the loop with Push Chain", - "title-secondary": "news and updates!", + "title": "Want to receive Push Core", + "title-secondary": "news, and updates?", "title-aria-label": "Newsletter subscription section", "section-aria-label": "Push Chain newsletter signup" }, @@ -203,6 +203,10 @@ "help": { "title": "Help", "title-aria-label": "Help navigation" + }, + "products": { + "title": "Products", + "title-aria-label": "Products navigation" } }, "links": { @@ -243,7 +247,9 @@ "reddit": "Reddit", "reddit-title": "Join the Push Chain subreddit", "telegram": "Telegram", - "telegram-title": "Join the Push Chain Telegram" + "telegram-title": "Join the Push Chain Telegram", + "quick-start": "Quick Start", + "quick-start-title": "Get up and running on Push Chain quickly" }, "social-section": { "section-aria-label": "Social media links and legal information", @@ -280,99 +286,127 @@ "twitter-description": "Transact from any chain. Use any wallet. Pay with any token. No network switching." }, "hero-section": { - "title": "Any Chain, Any App, All Users.\nOne Push Chain.", - "description": "The first Layer 1 built for Universal Apps. \nBuild & Deploy once, onboard users from any chain.", + "title": "Verification for the Agentic Internet.", + "description": "Push Chain verifies if AI agents' work is any good.", "primary-button": "Start Building", "primary-button-title": "Start your builder's journey with Push Chain!", "secondary-button": "Explore Knowledge Base", "secondary-button-title": "Learn and explore Push Chain", - "section-aria-label": "Push Chain hero section - Universal Layer 1 blockchain introduction", + "section-aria-label": "Push Chain hero section - verification layer for the agentic internet", "primary-button-aria-label": "Start building universal apps on Push Chain - Go to developer documentation", "secondary-button-aria-label": "Learn about Push Chain features and concepts in knowledge base", "hero-background-alt": "Push Chain hero background animation showing universal blockchain connectivity", "hero-background-title": "Push Chain - Universal Layer 1 for cross-chain applications", - "schema-headline": "Push Chain - Universal L1 for Apps", - "schema-description": "Deploy once on Push Chain and reach users on any blockchain with universal apps" - }, - "whatis-section": { - "titleFirst": "A True", - "titleSecondGraditent": "Universal", - "titleThird": "Chain", - "bottomTextFirst": "Deploy Once,", - "bottomTextSecond": "Reach Everywhere", - "bottomLinkText": "Get Started", - "bottomLinkTitle": "Goto Documentation Hub", - "section-aria-label": "What is Push Chain - Universal blockchain explanation", - "animation-alt": "Animation demonstrating Push Chain's universal app deployment across multiple blockchains", - "animation-title": "Push Chain universal deployment visualization - deploy once, reach any chain", - "bottom-link-aria-label": "Navigate to Push Chain documentation to start building universal apps" - }, - "chain-features-section": { - "section-aria-label": "Push Chain innovations and features section", - "header": { - "main-text": "Built on innovations to eliminate fragmentation!", - "other-text": "Push is the only Universal Layer 1 you will ever need!" - }, - "box1": { - "texttitle": "Any Chain Transactions", - "bodytext": "Push Chain supports transactions from any blockchain. Users can pay gas in any token — No need for bridging.", - "imagealt": "Illustration showing different blockchain logos falling in a pin ball machine.", - "imagetitle": "Supports transactions from any blockchain." - }, - "box2": { - "texttitle": "Wallet Abstraction", - "bodytext": "Let any wallet from any chain connect, interact, and transact. Break web3 barriers by using social login or email. User get to decide on Push Chain.", - "imagealt": "Illustration showing Metamask wallet, Phantom Wallet, etc coming out of a big wallet with Push Chain logo on it.", - "imagetitle": "Supports any existing wallets like Metamask, Phantom, etc along with social login" - }, - "box3": { - "texttitle": "100% EVM\nCompatible", - "bodytext": "Deploy with zero on-chain code. Turn your native app into a universal app in minutes.", - "imagealt": "Illustration showing Ethereum Virtual Machine logo spinning and saying 100% EVM Compatibility.", - "imagetitle": "Zero on-chain code changes required, 100% EVM Compatible." - }, - "box4": { - "texttitle": "Universal Smart Contracts", - "bodytext": "Build once, run cross chain, multi step experiences with a single, future-proof contract.", - "imagealt": "Illustration showing Ethereum Virtual Maching logo and a an arc revolving around it saying '100% EVM Compatible'", - "imagetitle": "Deploy once, instantly become compatible with all supported chains (EVM or non-EVM)." - }, - "box5": { - "texttitle": "Universal Fee\nAbstraction", - "bodytext": "Let's users pay gas in any token, on any chain without bridging.", - "imagealt": "Illustration showing different logos of Bitcoin, Ethereum, Solana rotating around Push Chain", - "imagetitle": "Supports any token of any chain for transactions." - }, - "box6": { - "texttitle": "Universal Execution Layer", - "bodytext": "Build atomic, composable apps across web3. Create never seen before app experiences, by having multiple users of different chains transact with the same app.", - "imagealt": "Illustration showing different tetris blocks entering a wormhole and Push Chain logo emerging from the other end.", - "imagetitle": "Transactions from any chain finalize on Push Chain, enabling users of any chain to natively use the same app aka Universal Execution Layer." - }, - "box7": { - "texttitle": "Universal\nValidators", - "bodytext": "Trigger, validate, and complete transactions across any chain using your smart contract.", - "tags": { - "title1": "WRITE TO CHAINS" - }, - "imagealt": "Illustration showing tetris blocks in different colors merging and changing.", - "imagetitle": "(Roadmap) Universal Validators allow users to trigger, validate, and complete transactions across any chain using your smart contract." - }, - "box8": { - "texttitle": "State Access", - "bodytext": "Access account and state data from other chains in your smart contract.", - "tagText": "COMING SOON", - "tags": { - "title1": "READ FROM CHAINS" - }, - "imagealt": "Illustration showing Push Chain growing in blocks style animation.", - "imagetitle": "(Roadmap) Shared State allows access to account and state data from other chains in your smart contract." - }, - "footer": { - "title": "your app's user base by going universal", - "secondary": "with zero effort!", - "ctatext": "Start Building", - "ctatitle": "Deploy once, 10x your userbase. Visit Developer Docs." + "schema-headline": "Push Chain - Verification for the Agentic Internet", + "schema-description": "Push Chain verifies if AI agents' work is any good, settling payment on verdict across any chain", + "title-line1": "Verification for the", + "title-line2": "Agentic Internet." + }, + "problem-narrative": { + "title-line1": "Letting agents move", + "title-line2": "your money is a", + "titleGradient": "Gamble.", + "subtitle": "Agents can already move money, but nothing checks their work.", + "section-aria-label": "The problem with unverified AI agents moving money", + "vignette1": { + "story": "Alice gives her agent a budget. Her rules are simple: trusted contracts only, a fixed amount per day. But no chain enforces these rules everywhere the agent trades.", + "consequence1": "Rules hold on some chains. When the agent trades somewhere else, they stop applying.", + "consequence2": "One hallucination or rogue call and the money is lost forever." + }, + "vignette2": { + "story": "Chad paid an AI agent to grow his Twitter: He gained 10,000 new followers, but every one was a bot. The payment released the instant the goal was reached.", + "consequence1": "The job was marked done. The work was never evaluated.", + "consequence2": "Irreversible: No reputation hit, No recourse." + } + }, + "solution-panel": { + "title-prefix": "Making AI", + "title-highlight": "Universally", + "title-suffix": "accountable", + "paragraph": "Before your agent acts, it's held to rules it can't break. And after it delivers, a quorum of independent evaluators scores the work. Payment moves only on their verdict, and it moves on any chain.", + "section-aria-label": "How Push Chain makes AI agents universally accountable" + }, + "built-to-scale": { + "title-line1": "Built to scale the agentic economy.", + "title-line2": "Whatever you're building, wherever.", + "section-aria-label": "Push Chain is built to scale the agentic economy" + }, + "feature-grid-a": { + "title": "Everything your agent needs, in one place.", + "section-aria-label": "Everything your AI agent needs, in one place", + "card1": { + "title": "Evaluation by\nQuorum", + "description": "A quorum of independent, staked AI judges scores every job against its spec. Payment moves on their verdict, not on claims." + }, + "card2": { + "title": "Pay on\nVerdict", + "description": "Escrow that releases on quality, not claims. Plug Push in as the evaluator on any agent job: the work gets judged, then the money moves." + }, + "card3": { + "title": "Unbreakable\nRules", + "description": "Rules your agent can never break: spend caps, allowed contracts, time limits. Enforced at the chain level, no matter what the model decides." + }, + "card4": { + "title": "Agentic\nWallet", + "description": "A wallet that operates within the guardrails you set. Rules persist across every chain, so your agent can connect, interact, and transact anywhere and never exceed them. One wallet, every chain, no per-chain keys to manage." + }, + "card5": { + "title": "Identity &\nReputation", + "description": "Your agent keeps one identity everywhere it works. Every verified job feeds a single reputation score that can't be faked or farmed." + } + }, + "feature-grid-b": { + "title": "Everything runs on a\nnetwork that reaches", + "titleGradient": "every other chain.", + "subtitle": "One settlement and execution layer, so any agent and any user can easily participate without bridging.", + "section-aria-label": "Push Chain runs on a network that reaches every other chain", + "card1": { + "title": "Universal\nAccess", + "description": "Supports transactions from any chain. One execution and one settlement layer across every chain. Any token, any chain, all users." + }, + "card2": { + "title": "Universal\nContracts", + "description": "Build once, run on every chain. Cross-chain experiences from a single future-proof contract. 100% EVM compatible, zero on-chain code changes." + }, + "card3": { + "title": "Universal\nRead & Write", + "description": "Trigger, validate, and complete transactions on any chain from your contract or wallet. One call, delivered wherever it points." + }, + "stat-callout": { + "value": "5", + "value-label": "mins \nto deploy", + "text": "Push Core verifies if AI agents' work is any good.\nYour first universal app takes minutes.", + "cta": "Start Building", + "cta-title": "Start your builder's journey with Push Chain!", + "cta-aria-label": "Start building universal apps on Push Chain - Go to developer documentation" + } + }, + "paid-stats": { + "eyebrow": "GET P.A.I.D", + "title": "Get Probabilistic AI,", + "titleGradient": "Deterministic", + "paragraph": "Ask one AI twice and you get two answers.\nPush settles every judgement across a quorum of independent evaluators: probabilistic AI in, deterministic verdict out.", + "section-aria-label": "Get Probabilistic AI, Deterministic - Push Chain verdict and settlement stats", + "stat1": { + "title": "Verdict per job", + "value": "1" + }, + "stat2": { + "title": "Quorum to finalize", + "value": "2/3" + }, + "stat3": { + "title": "Settlement / Execution", + "value": "Universal" + }, + "stat4": { + "title": "Supported chains", + "chain1-alt": "Ethereum", + "chain2-alt": "Solana", + "chain3-alt": "BNB Chain", + "more-chains-badge": "More chains soon", + "chain4-alt": "Arbitrum", + "chain5-alt": "Base" } }, "partners-section": { @@ -417,7 +451,7 @@ "blog-section": { "subtitle": "NEWS, DEVLOGS & IDEAS", "subtitle-aria-label": "Blog category information", - "title": "Your Pulse of Push Chain", + "title": "Your Pulse of Push Core", "title-aria-label": "Latest Push Chain blog posts and updates", "explore-link-text": "Explore More Articles", "explore-link-title": "Visit Push Chain blog to read all articles and updates", @@ -430,11 +464,6 @@ "error-text": "Unable to load blog posts at this time", "no-posts-text": "No blog posts available" }, - "trustedby-section": { - "title": "Built by the team trusted by pioneers of web3", - "section-aria-label": "Push Chain trusted by section", - "trusted-by-alt": "Investor - " - }, "featured-section": { "aria-label": "Featured On section", "tag": "FEATURED ON", @@ -495,20 +524,15 @@ } } }, - "ending-section": { - "aria-label": "Build Universal Apps section", - "section-title": "Build Universal Apps.", - "section-subtitle": "Break the silos. Build once, scale on every blockchain.", - "docs-link": { - "text": "Explore Push Chain Docs", - "title": "Explore Push Chain documentation and developer resources", - "aria-label": "Open Push Chain documentation in new tab" - }, - "cta-link": { - "text": "LFG Push Chain", - "title": "Get started with Push Chain - the universal blockchain platform", - "aria-label": "Get started with Push Chain development" - } + "closing-cta": { + "section-aria-label": "Get started with Push Core", + "title-line1": "Agents do the work.", + "title-line2": "Push proves it's good.", + "subtitle": "Guardrails before. Verification after. Payment on the verdict.", + "cta": "Get Started", + "cta-title": "Start your builder's journey with Push Chain!", + "cta-aria-label": "Get started building on Push Chain - Go to developer documentation", + "animation-aria-label": "Push Core verification animation" } }, "knowledge": { @@ -1973,6 +1997,71 @@ "description": "Push Chain's universal wallet" } } + }, + "home-agent-faq": { + "title": "Frequently Asked Questions", + "title-aria-label": "Frequently asked questions about Push Chain and AI agent verification", + "section-aria-label": "Frequently asked questions about Push Chain", + "discord-link-text": "Ask us on Discord", + "discord-link-title": "Ask us your questions on Discord", + "discord-link-aria-label": "Join the Push Chain Discord community to ask questions", + "accordion-aria-label": "Frequently asked questions accordion", + "answer-aria-label": "Answer to: ", + "explore-more-text": "Explore More FAQs", + "explore-more-title": "Explore more frequently asked questions", + "explore-more-aria-label": "Navigate to the full FAQ page", + "qnas": { + "qna1": { + "question": "What is Push Core?", + "answer": "<1>Push Chain is the verification layer for the agentic internet. Agents are held to rules they can't break while they act, and independent AI evaluators score their work after. Payment settles on the verdict, on any chain, with a universal network underneath." + }, + "qna2": { + "question": "What if the evaluators disagree, or get it wrong?", + "answer": "<1>Verdicts aren't decided by a single evaluator. A quorum of independent, staked AI judges scores each job against its spec, and payment only moves once enough of them agree. Evaluators that consistently misjudge work put their own stake at risk, which keeps their incentives aligned with getting it right." + }, + "qna3": { + "question": "What stops evaluators from colluding or being bribed?", + "answer": "<1>Evaluators stake collateral to participate, and that stake is slashed if they're caught colluding or producing bad-faith verdicts. Combined with requiring quorum agreement across independent evaluators rather than a single judge, collusion has to clear a much higher bar than convincing one party." + }, + "qna4": { + "question": "Can Push verify work that happens offchain, in web2?", + "answer": "<1>Yes. Evaluators score the agent's output against its spec regardless of where the work happened - an API call, a social post, an offchain computation. What Push Chain guarantees is what happens next: the verdict and the payment settlement, which move onchain on any supported chain." + }, + "qna5": { + "question": "Does my agent have to run on Push?", + "answer": "<1>No. Your agent can run anywhere. Push Chain plugs in as the evaluation and settlement layer - you point your agent's payment flow at Push, and the work gets judged and paid out from there, without migrating your agent's own runtime." + }, + "qna6": { + "question": "How does Push fit the existing agent standards?", + "answer": "<1>Push Chain is designed to sit alongside existing agent frameworks and payment standards rather than replace them. It adds a verification and settlement layer on top - your agent keeps using the tools and standards it already does, with Push handling accountability for the outcomes." + } + }, + "faqs": { + "faq1": { + "question": "What is Push Core?", + "answer": "Push Chain is the verification layer for the agentic internet. Agents are held to rules they can't break while they act, and independent AI evaluators score their work after. Payment settles on the verdict, on any chain, with a universal network underneath." + }, + "faq2": { + "question": "What if the evaluators disagree, or get it wrong?", + "answer": "Verdicts aren't decided by a single evaluator. A quorum of independent, staked AI judges scores each job against its spec, and payment only moves once enough of them agree." + }, + "faq3": { + "question": "What stops evaluators from colluding or being bribed?", + "answer": "Evaluators stake collateral to participate, and that stake is slashed if they're caught colluding or producing bad-faith verdicts." + }, + "faq4": { + "question": "Can Push verify work that happens offchain, in web2?", + "answer": "Yes. Evaluators score the agent's output against its spec regardless of where the work happened, and the verdict and payment settlement move onchain on any supported chain." + }, + "faq5": { + "question": "Does my agent have to run on Push?", + "answer": "No. Your agent can run anywhere. Push Chain plugs in as the evaluation and settlement layer without migrating your agent's own runtime." + }, + "faq6": { + "question": "How does Push fit the existing agent standards?", + "answer": "Push Chain sits alongside existing agent frameworks and payment standards, adding a verification and settlement layer on top." + } + } } }, "notifications": { @@ -1996,9 +2085,9 @@ "container-aria-label": "Push Chain rewards notification" }, "info-bar": { - "title": "Push Chain passes Hacken security audit. Zero critical issues found.", - "learn-more-text": "Read More", - "learn-more-title": "Read More", + "title": "Launch on Push Testnet Now — Unlock Rewards for Builders and Early Users.", + "learn-more-text": "Learn More", + "learn-more-title": "Learn More", "dismiss-button-title": "Dismiss announcement", "dismiss-button-aria-label": "Close announcement bar", "container-aria-label": "Site announcement", diff --git a/yarn.lock b/yarn.lock index 2ed938979a9d..7268917cf0cd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16368,6 +16368,24 @@ __metadata: languageName: node linkType: hard +"lenis@npm:^1.3.26": + version: 1.3.26 + resolution: "lenis@npm:1.3.26" + peerDependencies: + "@nuxt/kit": ">=3.0.0" + react: ">=17.0.0" + vue: ">=3.0.0" + peerDependenciesMeta: + "@nuxt/kit": + optional: true + react: + optional: true + vue: + optional: true + checksum: 10c0/0d523ecd7bbbaac64b86de8e7c6641e4a2299065743def53eade177f42c280d1447d36b0fd7a525b7d69b0a889c1af91e85e48bfeec3851975c4858c0823204e + languageName: node + linkType: hard + "leven@npm:^3.1.0": version: 3.1.0 resolution: "leven@npm:3.1.0" @@ -20241,6 +20259,7 @@ __metadata: i18next-http-backend: "npm:^2.2.1" jest: "npm:^29.7.0" jimp: "npm:0.22.10" + lenis: "npm:^1.3.26" lint-staged: "npm:^15.2.2" lottie-react: "npm:^2.4.1" marked: "npm:^15.0.7"