Increase small text to 12px (#114)

* fix: increase small text to 12px

* fix: use initiative CTA label

* refactor: use Tailwind text-xs utility

* fix: make homepage banner dismissible

* fix: update Discord links and banner text

* fix: refresh Discord invite links
This commit is contained in:
Jinho Jang
2026-07-23 20:58:59 +09:00
committed by GitHub
parent dc6b664fc6
commit 3e36fc9790
93 changed files with 423 additions and 338 deletions
@@ -18,7 +18,7 @@ const createListingDoc = (
description: 'Funded work.',
breadcrumbLabel: 'RFPs',
submitCtaLabel: 'Submit',
submitCtaHref: 'https://discord.gg/logosnetwork',
submitCtaHref: 'https://discord.gg/Ykv4eZyHUJ',
submitCtaExternal: true,
defaultView: 'grid',
pageSize: 12,
@@ -26,7 +26,7 @@ const createListingDoc = (
nextLabel: 'Next',
bottomCtaTitle: 'Have a build idea?',
bottomCtaLabel: 'Submit',
bottomCtaHref: 'https://discord.gg/logosnetwork',
bottomCtaHref: 'https://discord.gg/Ykv4eZyHUJ',
bottomCtaExternal: true,
...overrides,
})
@@ -51,7 +51,7 @@ export function BookAction({
className="inline-flex min-w-[150px] items-center justify-between gap-4 rounded-xl bg-brand-off-white px-4 py-3 text-brand-dark-green transition-colors hover:bg-gray-01 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-off-white"
>
<span className="flex flex-col">
<span className="font-mono text-[10px] font-semibold uppercase leading-[1.35]">
<span className="font-mono text-xs font-semibold uppercase leading-[1.35]">
{label}
</span>
<span className="font-mono text-[9px] leading-[1.35] opacity-60">
@@ -28,12 +28,8 @@ function ColorSwatch({
<div
className={`absolute right-[9px] bottom-[9px] left-[9px] overflow-hidden ${textColor === 'white' ? 'text-white' : 'text-black'}`}
>
<p className="truncate text-[10px] leading-[1.2] md:text-[16px]">
{name}
</p>
<p className="truncate text-[10px] leading-[1.2] md:text-[16px]">
{hex}
</p>
<p className="truncate text-xs leading-[1.2] md:text-[16px]">{name}</p>
<p className="truncate text-xs leading-[1.2] md:text-[16px]">{hex}</p>
</div>
</div>
)
@@ -52,7 +52,7 @@ export function Buttons() {
</h2>
<div className="grid grid-cols-1 items-start gap-8 sm:grid-cols-2 lg:grid-cols-4">
<div className="flex flex-col items-start gap-3">
<p className="font-mono text-[10px] leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
<p className="font-mono text-xs leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
Primary
</p>
<Button variant="primary" href={EXTERNAL_URLS.docs}>
@@ -60,7 +60,7 @@ export function Buttons() {
</Button>
</div>
<div className="flex flex-col items-start gap-3">
<p className="font-mono text-[10px] leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
<p className="font-mono text-xs leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
Secondary
</p>
<Button variant="secondary" href={EXTERNAL_URLS.docs}>
@@ -68,7 +68,7 @@ export function Buttons() {
</Button>
</div>
<div className="flex flex-col items-start gap-3">
<p className="font-mono text-[10px] leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
<p className="font-mono text-xs leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
Tertiary
</p>
<Button variant="tertiary" href={EXTERNAL_URLS.docs}>
@@ -76,7 +76,7 @@ export function Buttons() {
</Button>
</div>
<div className="flex flex-col items-start gap-3">
<p className="font-mono text-[10px] leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
<p className="font-mono text-xs leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
Link
</p>
<Button variant="link" href={EXTERNAL_URLS.docs}>
@@ -248,7 +248,7 @@ export function ViewToggles() {
</h2>
<div className="grid grid-cols-1 items-start gap-8 sm:grid-cols-2">
<div className="flex flex-col items-start gap-3">
<p className="font-mono text-[10px] leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
<p className="font-mono text-xs leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
Grid active (default on /rfps)
</p>
<ViewToggle
@@ -258,7 +258,7 @@ export function ViewToggles() {
/>
</div>
<div className="flex flex-col items-start gap-3">
<p className="font-mono text-[10px] leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
<p className="font-mono text-xs leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
List active (default on /ideas)
</p>
<ViewToggle
@@ -282,7 +282,7 @@ export function Paginations() {
</h2>
<div className="flex flex-col gap-8">
<div className="flex flex-col items-start gap-3">
<p className="font-mono text-[10px] leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
<p className="font-mono text-xs leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
3 pages · current 1
</p>
<Pagination
@@ -292,7 +292,7 @@ export function Paginations() {
/>
</div>
<div className="flex flex-col items-start gap-3">
<p className="font-mono text-[10px] leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
<p className="font-mono text-xs leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
5 pages · current 3
</p>
<Pagination
@@ -302,7 +302,7 @@ export function Paginations() {
/>
</div>
<div className="flex flex-col items-start gap-3">
<p className="font-mono text-[10px] leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
<p className="font-mono text-xs leading-[1.3] font-medium text-brand-dark-green uppercase opacity-50">
10 pages · current 5 · ellipsis collapse
</p>
<Pagination
@@ -211,7 +211,7 @@ function MetaBlock({
function SameAsDesktopTag() {
return (
<span className="inline-flex h-[24px] items-center justify-center rounded-full bg-brand-yellow px-2.5 text-[10px] font-medium leading-[1.3] text-black uppercase">
<span className="inline-flex h-[24px] items-center justify-center rounded-full bg-brand-yellow px-2.5 text-xs font-medium leading-[1.3] text-black uppercase">
Same as desktop
</span>
)
@@ -24,10 +24,7 @@ export function Community({
return (
<section className="border-t border-brand-dark-green/10 pt-6 pb-25">
<ContentWidth className="flex w-full flex-col gap-10">
<SectionHeading
number={data.number}
heading={data.heading}
/>
<SectionHeading number={data.number} heading={data.heading} />
<div className="flex flex-col">
{communityLinks.map((item, index) => (
<a
@@ -43,11 +40,9 @@ export function Community({
<span className="font-sans font-medium">
{String(index + 1).padStart(2, '0')}
</span>
<span className="font-display">
{data.items[item.key]}
</span>
<span className="font-display">{data.items[item.key]}</span>
</span>
<span className="inline-flex items-center gap-1 border-b border-brand-dark-green/50 pb-0.5 font-mono text-[10px] leading-[1.35] font-semibold whitespace-nowrap uppercase">
<span className="inline-flex items-center gap-1 border-b border-brand-dark-green/50 pb-0.5 font-mono text-xs leading-[1.35] font-semibold whitespace-nowrap uppercase">
{data.cta}
<ButtonArrowIcon />
</span>
@@ -18,7 +18,7 @@ export function Hero({ heading, intro }: HeroProps) {
{heading}
</h1>
</LambdaLockup>
<p className="absolute top-[126px] left-3 max-w-[342px] whitespace-pre-line font-mono text-[10px] leading-[1.3] md:top-[90px] md:left-[calc(50%+6px)] md:max-w-[345px]">
<p className="absolute top-[126px] left-3 max-w-[342px] whitespace-pre-line font-mono text-xs leading-[1.3] md:top-[90px] md:left-[calc(50%+6px)] md:max-w-[345px]">
{intro}
</p>
</ContentWidth>
@@ -199,7 +199,7 @@ describe('LambdaPrizePage support section driven from data', () => {
}),
expect.objectContaining({
label: 'Connect with Logos',
href: 'https://discord.gg/logosnetwork',
href: 'https://discord.gg/Ykv4eZyHUJ',
}),
])
})
@@ -42,7 +42,7 @@ export function AboutProgramme({
</Button>
</div>
</div>
<p className="mx-auto w-full max-w-[345px] text-center font-sans text-[12px] leading-[1.2] font-medium text-brand-dark-green">
<p className="mx-auto w-full max-w-[345px] text-center font-sans text-xs leading-[1.2] font-medium text-brand-dark-green">
{copy.body}
</p>
<div className="flex flex-col gap-3 text-brand-dark-green">
@@ -21,7 +21,7 @@ export function TertiaryCta({
<Link
href={href}
{...(isExternal ? { target: '_blank', rel: 'noopener noreferrer' } : {})}
className={`inline-flex cursor-pointer items-center gap-1 border-b pb-0.5 font-mono text-[10px] font-semibold uppercase leading-[1.35] ${
className={`inline-flex cursor-pointer items-center gap-1 border-b pb-0.5 font-mono text-xs font-semibold uppercase leading-[1.35] ${
tone === 'light'
? 'border-brand-off-white/50 text-brand-off-white'
: 'border-brand-dark-green/50 text-brand-dark-green'
@@ -5,7 +5,7 @@ import type { LambdaPrizePageCopy } from './types'
function SupportLabel({ children }: { children: string }) {
return (
<span className="inline-flex items-center border-b border-brand-dark-green/20 pb-0.5 font-mono text-[10px] leading-[1.35] font-semibold text-brand-dark-green/70 uppercase">
<span className="inline-flex items-center border-b border-brand-dark-green/20 pb-0.5 font-mono text-xs leading-[1.35] font-semibold text-brand-dark-green/70 uppercase">
{children}
</span>
)
@@ -172,7 +172,7 @@ function EventPill({
interactive?: boolean
}) {
const baseClassName =
'block rounded-lg border border-brand-dark-green/50 p-2 font-mono text-[10px] font-medium uppercase leading-[1.3]'
'block rounded-lg border border-brand-dark-green/50 p-2 font-mono text-xs font-medium uppercase leading-[1.3]'
const content = <span className="line-clamp-2">{event.calendarTitle}</span>
return interactive && event.link ? (
@@ -231,7 +231,7 @@ function MonthSelect({
aria-label={label}
value={value}
onChange={(event) => onChange(Number(event.target.value))}
className="h-full w-full cursor-pointer appearance-none rounded-full border border-transparent bg-brand-off-white py-0 pl-6 pr-10 font-mono text-[10px] font-semibold uppercase leading-[1.35] text-brand-dark-green"
className="h-full w-full cursor-pointer appearance-none rounded-full border border-transparent bg-brand-off-white py-0 pl-6 pr-10 font-mono text-xs font-semibold uppercase leading-[1.35] text-brand-dark-green"
>
{MONTHS.map((month, index) => (
<option key={month} value={index}>
@@ -263,7 +263,7 @@ function YearSelect({
aria-label={label}
value={value}
onChange={(event) => onChange(Number(event.target.value))}
className="h-full w-full cursor-pointer appearance-none rounded-full border border-transparent bg-brand-off-white py-0 pl-6 pr-10 font-mono text-[10px] font-semibold uppercase leading-[1.35] text-brand-dark-green"
className="h-full w-full cursor-pointer appearance-none rounded-full border border-transparent bg-brand-off-white py-0 pl-6 pr-10 font-mono text-xs font-semibold uppercase leading-[1.35] text-brand-dark-green"
>
{years.map((year) => (
<option key={year} value={year}>
@@ -302,7 +302,7 @@ function NavButtons({
<button
type="button"
onClick={onToday}
className="flex h-[31px] w-[54px] cursor-pointer items-center justify-center rounded-full border border-brand-dark-green/30 bg-brand-off-white font-mono text-[10px] font-semibold uppercase leading-[1.35]"
className="flex h-[31px] w-[54px] cursor-pointer items-center justify-center rounded-full border border-brand-dark-green/30 bg-brand-off-white font-mono text-xs font-semibold uppercase leading-[1.35]"
>
{todayLabel}
</button>
@@ -513,7 +513,7 @@ export function EventsCalendar({
{WEEKDAYS.map((day) => (
<span
key={day}
className="flex items-center justify-center font-mono text-[10px] font-semibold uppercase leading-[1.35]"
className="flex items-center justify-center font-mono text-xs font-semibold uppercase leading-[1.35]"
>
{day}
</span>
@@ -35,7 +35,7 @@ function Dot() {
function UnderlineLabel({ children }: { children: string }) {
return (
<span className="font-mono text-[10px] font-semibold uppercase leading-[1.35] text-brand-dark-green underline decoration-brand-dark-green/50 underline-offset-[3px]">
<span className="font-mono text-xs font-semibold uppercase leading-[1.35] text-brand-dark-green underline decoration-brand-dark-green/50 underline-offset-[3px]">
{children}
</span>
)
+3 -3
View File
@@ -45,7 +45,7 @@ export default async function ManifestoPage({
const data = findSection<ManifestoCopySection>(
page.sections,
'manifestoCopy',
'manifesto.copy',
'manifesto.copy'
)
const moreLinks = data.more.map((label, index) => ({
@@ -63,7 +63,7 @@ export default async function ManifestoPage({
<span className="block">{data.headingLine2}</span>
</span>
</h1>
<p className="font-mono-body mx-auto mt-6 w-[102px] text-center text-[10px] leading-[1.3] tracking-[0px] desktop:absolute desktop:top-[426px] desktop:left-1/2 desktop:mt-0 desktop:-translate-x-1/2">
<p className="font-mono-body mx-auto mt-6 w-[102px] text-center text-xs leading-[1.3] tracking-[0px] desktop:absolute desktop:top-[426px] desktop:left-1/2 desktop:mt-0 desktop:-translate-x-1/2">
{data.author.map((line) => (
<span key={line} className="block">
{line}
@@ -118,7 +118,7 @@ export default async function ManifestoPage({
))}
</div>
<aside className="font-mono-body mt-12 text-[10px] leading-[1.3] tracking-[0px] desktop:absolute desktop:top-[2995px] desktop:left-0 desktop:mt-0 desktop:h-[88px] desktop:w-[306px] desktop:text-left">
<aside className="font-mono-body mt-12 text-xs leading-[1.3] tracking-[0px] desktop:absolute desktop:top-[2995px] desktop:left-0 desktop:mt-0 desktop:h-[88px] desktop:w-[306px] desktop:text-left">
<h2 className="font-bold">{data.moreHeading}</h2>
<div className="mt-3 space-y-3 desktop:mt-[12px] desktop:space-y-[12px]">
{moreLinks.map((item) => (
@@ -91,7 +91,7 @@ export function BlogHero({
{ href: '#podcasts', label: copy.navPodcasts },
].map((item) => {
const className =
'inline-flex cursor-pointer items-center gap-1 font-mono text-[10px] font-semibold uppercase leading-[1.35] transition-opacity hover:opacity-70'
'inline-flex cursor-pointer items-center gap-1 font-mono text-xs font-semibold uppercase leading-[1.35] transition-opacity hover:opacity-70'
return (
<a key={item.href} href={item.href} className={className}>
@@ -102,7 +102,7 @@ export function BlogHero({
})}
<a
href={copy.navBroadcastHref}
className="inline-flex cursor-pointer items-center gap-1 font-mono text-[10px] font-semibold uppercase leading-[1.35] transition-opacity hover:opacity-70"
className="inline-flex cursor-pointer items-center gap-1 font-mono text-xs font-semibold uppercase leading-[1.35] transition-opacity hover:opacity-70"
>
<ArrowIcon direction="down" />
{copy.navBroadcast}
@@ -196,7 +196,7 @@ export function GallerySection({ articles }: { articles: BlogArticleRow[] }) {
/>
</div>
<div className="flex items-baseline justify-between gap-6">
<p className="max-w-[170px] font-sans text-[12px] font-medium leading-[1.2] tracking-normal md:text-[14px]">
<p className="max-w-[170px] font-sans text-xs font-medium leading-[1.2] tracking-normal md:text-[14px]">
{article.title}
</p>
<div className="text-mono-s shrink-0 text-brand-dark-green md:text-right">
@@ -299,7 +299,7 @@ export function BroadcastSection({
<div className="absolute left-3 top-3 flex w-[calc(100%-24px)] flex-col gap-6 desktop:h-[380px] desktop:w-[453px] desktop:justify-between desktop:gap-0">
<div className="flex items-center gap-25.5">
<LogosMark size={6} className="shrink-0 text-brand-off-white" />
<p className="font-mono text-[10px] font-medium uppercase leading-[1.3] text-brand-off-white">
<p className="font-mono text-xs font-medium uppercase leading-[1.3] text-brand-off-white">
{copy.media}
</p>
</div>
@@ -308,7 +308,7 @@ export function BroadcastSection({
<h2 className="w-[185px] font-sans text-[24px] leading-[1.1] tracking-[-0.01em] text-brand-off-white">
{copy.broadcastHeading}
</h2>
<p className="font-mono text-[10px] leading-[1.3] text-brand-off-white desktop:w-full">
<p className="font-mono text-xs leading-[1.3] text-brand-off-white desktop:w-full">
{copy.broadcastDescription}
</p>
</div>
@@ -325,7 +325,7 @@ export function BroadcastSection({
</div>
<div className="absolute left-3 right-3 bottom-3 top-[292px] overflow-hidden rounded-[100px] bg-accent-tan text-brand-dark-green transition-colors group-hover:bg-brand-yellow desktop:left-auto desktop:right-3 desktop:bottom-auto desktop:top-3 desktop:h-[382px] desktop:w-[702px]">
<span className="absolute left-1/2 top-1/2 inline-flex -translate-x-1/2 -translate-y-1/2 items-center gap-1 font-mono text-[10px] font-semibold uppercase leading-[1.35]">
<span className="absolute left-1/2 top-1/2 inline-flex -translate-x-1/2 -translate-y-1/2 items-center gap-1 font-mono text-xs font-semibold uppercase leading-[1.35]">
{copy.broadcastCta}
<ArrowIcon />
</span>
@@ -59,7 +59,7 @@ export function TextLink({
href={href}
aria-label={label}
className={cn(
'cursor-pointer font-mono text-[10px] font-semibold leading-[1.35] uppercase underline underline-offset-[3px] transition-opacity hover:opacity-70',
'cursor-pointer font-mono text-xs font-semibold leading-[1.35] uppercase underline underline-offset-[3px] transition-opacity hover:opacity-70',
tone === 'light'
? 'text-brand-off-white decoration-brand-off-white/50'
: 'text-brand-dark-green decoration-brand-dark-green/50',
@@ -73,7 +73,7 @@ export function TextLink({
export function UnderlineLabel({ children }: { children: ReactNode }) {
return (
<span className="font-mono text-[10px] font-semibold uppercase leading-[1.35] text-brand-dark-green underline decoration-brand-dark-green/50 underline-offset-[3px]">
<span className="font-mono text-xs font-semibold uppercase leading-[1.35] text-brand-dark-green underline decoration-brand-dark-green/50 underline-offset-[3px]">
{children}
</span>
)
@@ -151,7 +151,7 @@ export function SectionCta({ href, label }: { href: string; label: string }) {
const className =
'flex h-[84px] w-full cursor-pointer items-center justify-center rounded-xl border border-brand-dark-green text-brand-dark-green transition-colors hover:bg-brand-yellow'
const content = (
<span className="inline-flex items-center gap-1 font-mono text-[10px] font-semibold uppercase leading-[1.35]">
<span className="inline-flex items-center gap-1 font-mono text-xs font-semibold uppercase leading-[1.35]">
{label}
<ArrowIcon />
</span>
@@ -63,7 +63,7 @@ function PodcastHero({
<div className="absolute left-3 top-3 flex h-[268px] w-[calc(100%-24px)] max-w-[345px] min-w-0 flex-col justify-between text-brand-off-white xl:h-[380px] xl:w-[453px] xl:max-w-[453px]">
<div className="flex items-center gap-25.5">
<LogosMark size={6} className="shrink-0" />
<span className="font-mono text-[10px] font-medium uppercase leading-[1.3]">
<span className="font-mono text-xs font-medium uppercase leading-[1.3]">
{copy.media}
</span>
</div>
@@ -86,7 +86,7 @@ function PodcastHero({
</div>
</div>
<div className="absolute left-3 top-[397px] flex h-[290px] w-[calc(100%-24px)] items-center justify-center rounded-[100px] bg-accent-tan text-brand-dark-green xl:hidden">
<span className="inline-flex items-center gap-1 font-mono text-[10px] font-semibold uppercase leading-[1.35]">
<span className="inline-flex items-center gap-1 font-mono text-xs font-semibold uppercase leading-[1.35]">
{copy.seeAllEpisodes}
<ArrowIcon />
</span>
@@ -52,7 +52,7 @@ function HeroAnchorLink({
className="inline-flex cursor-pointer items-center justify-center text-brand-dark-green"
>
<span className="inline-flex items-center gap-1">
<span className="border-b border-brand-dark-green/50 pb-0.5 font-mono text-[10px] leading-[1.35] font-semibold whitespace-nowrap uppercase">
<span className="border-b border-brand-dark-green/50 pb-0.5 font-mono text-xs leading-[1.35] font-semibold whitespace-nowrap uppercase">
{children}
</span>
<ButtonArrowIcon />
@@ -76,7 +76,7 @@ export default async function NodeProgramPage({
const data = findSection<NodeProgrammeCopySection>(
page.sections,
'nodeProgrammeCopy',
'nodeProgramme.copy',
'nodeProgramme.copy'
)
return (
+2 -2
View File
@@ -31,7 +31,7 @@ function PodcastIntro({ copy }: { copy: PodcastIntroCopy }) {
<span className="inline-flex size-3.75 shrink-0 rotate-180 items-center justify-center">
<ButtonArrowIcon />
</span>
<span className="font-mono text-[10px] leading-[1.3] font-medium uppercase">
<span className="font-mono text-xs leading-[1.3] font-medium uppercase">
{copy.backToMedia}
</span>
</Link>
@@ -80,7 +80,7 @@ export default async function LogosPodcastPage({
const data = findSection<PodcastCopySection>(
page.sections,
'podcastCopy',
'podcast.copy',
'podcast.copy'
)
return (
+25 -25
View File
@@ -11,7 +11,7 @@
--display: var(--next-font-display), Georgia, serif;
--mono: var(--next-font-mono), monospace;
--public-sans:
var(--next-font-sans), "Public Sans", ui-sans-serif, system-ui, sans-serif;
var(--next-font-sans), 'Public Sans', ui-sans-serif, system-ui, sans-serif;
position: relative;
min-height: 100vh;
@@ -22,13 +22,13 @@
}
.page::before {
content: "";
content: '';
position: absolute;
top: -767px;
left: 50%;
width: 2565px;
height: 3206px;
background: url("/campaigns/ukdebt/page-bg.webp") center / cover no-repeat;
background: url('/campaigns/ukdebt/page-bg.webp') center / cover no-repeat;
filter: blur(157px);
transform: translateX(-50%);
pointer-events: none;
@@ -36,10 +36,10 @@
}
.page::after {
content: "";
content: '';
position: absolute;
inset: 0;
background: url("/campaigns/ukdebt/paper.webp") center / cover no-repeat;
background: url('/campaigns/ukdebt/paper.webp') center / cover no-repeat;
mix-blend-mode: multiply;
opacity: 0.2;
pointer-events: none;
@@ -68,12 +68,12 @@
.ctaSection::after,
.sourcesStrip::after,
.campaignFooter::after {
content: "";
content: '';
position: absolute;
inset: 0;
z-index: 1;
border-radius: inherit;
background: url("/campaigns/ukdebt/paper.webp") center / cover no-repeat;
background: url('/campaigns/ukdebt/paper.webp') center / cover no-repeat;
mix-blend-mode: multiply;
opacity: 0.42;
pointer-events: none;
@@ -102,14 +102,14 @@
}
.hero::after {
content: "";
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 50%;
z-index: 1;
width: 100vw;
background: url("/campaigns/ukdebt/paper-wrinkles.webp") center / cover
background: url('/campaigns/ukdebt/paper-wrinkles.webp') center / cover
no-repeat;
opacity: 0.38;
pointer-events: none;
@@ -154,7 +154,7 @@
}
.heroFigure::before {
content: "";
content: '';
position: absolute;
top: 273px;
left: 0;
@@ -478,7 +478,7 @@
z-index: 0;
background:
linear-gradient(0deg, rgba(21, 37, 33, 0.72), rgba(21, 37, 33, 0.18)),
url("/campaigns/ukdebt/card-bg.webp") center / cover;
url('/campaigns/ukdebt/card-bg.webp') center / cover;
filter: blur(45px);
opacity: 0.85;
transform: scale(1.08);
@@ -613,7 +613,7 @@
padding: 0;
background:
linear-gradient(180deg, rgba(15, 17, 16, 0.55), rgba(15, 17, 16, 0.7)),
url("/campaigns/ukdebt/spend-bg.webp") center / cover no-repeat;
url('/campaigns/ukdebt/spend-bg.webp') center / cover no-repeat;
}
.spendPanel .panelBackdrop {
@@ -931,7 +931,7 @@
.historyPanel::before,
.historyPanel::after {
content: "";
content: '';
position: absolute;
pointer-events: none;
}
@@ -942,7 +942,7 @@
left: 50%;
z-index: -1;
width: 100vw;
background-image: url("/campaigns/ukdebt/paper.webp");
background-image: url('/campaigns/ukdebt/paper.webp');
background-position: center;
background-size: cover;
background-repeat: no-repeat;
@@ -970,7 +970,7 @@
.historyColumns::before,
.historyColumns::after {
content: "";
content: '';
position: absolute;
left: -12px;
right: -12px;
@@ -1233,21 +1233,21 @@
z-index: 0;
width: 2226px;
height: 2783px;
background: url("/campaigns/ukdebt/page-bg.webp") center / cover no-repeat;
background: url('/campaigns/ukdebt/page-bg.webp') center / cover no-repeat;
filter: blur(242.883px);
opacity: 1;
transform: translateX(-974px);
}
.ctaSection::before {
content: "";
content: '';
position: absolute;
top: 50%;
left: 50%;
z-index: 0;
width: 3682px;
height: 4602.5px;
background: url("/campaigns/ukdebt/cta-bg.webp") center / cover no-repeat;
background: url('/campaigns/ukdebt/cta-bg.webp') center / cover no-repeat;
filter: blur(204.775px);
transform: translate(calc(-50% + 639.5px), calc(-50% - 40.5px)) rotate(90deg);
}
@@ -1310,7 +1310,7 @@
}
.ctaButtonSecondary::after {
content: "";
content: '';
position: absolute;
right: 0;
bottom: 0;
@@ -1344,7 +1344,7 @@
border: 1px solid rgba(255, 255, 255, 0.65);
border-radius: 4px;
font: inherit;
font-size: 10px;
font-size: 12px;
text-transform: uppercase;
}
@@ -1378,7 +1378,7 @@
grid-column: 1 / -1;
margin: 0;
color: #fff;
font-size: 10px;
font-size: 12px;
line-height: 1.2;
text-align: center;
text-transform: uppercase;
@@ -1503,7 +1503,7 @@
.footerNav strong,
.footerBuilt {
font-family: var(--mono);
font-size: 10px;
font-size: 12px;
line-height: 1.3;
color: inherit;
}
@@ -2287,7 +2287,7 @@
border-top: 1px solid rgba(255, 255, 255, 0.9);
background:
linear-gradient(180deg, rgba(15, 17, 16, 0.55), rgba(15, 17, 16, 0.7)),
url("/campaigns/ukdebt/spend-bg.webp") center / cover no-repeat;
url('/campaigns/ukdebt/spend-bg.webp') center / cover no-repeat;
}
.spendPanel .panelBackdrop {
@@ -2369,7 +2369,7 @@
.spendBubble span {
margin-top: 3px;
font-size: 10px;
font-size: 12px;
}
.zeroSection {
@@ -2741,7 +2741,7 @@
.ctaSignup input,
.ctaSignup button {
height: 28px;
font-size: 10px;
font-size: 12px;
}
.ctaSignup input {
@@ -22,7 +22,10 @@ import L from 'leaflet'
import MarkerClusterGroup from 'react-leaflet-cluster'
import 'leaflet/dist/leaflet.css'
import type { ActiveCircleMarker, ActiveCircleUpcomingEvent } from '@/lib/active-circles'
import type {
ActiveCircleMarker,
ActiveCircleUpcomingEvent,
} from '@/lib/active-circles'
import { submitNewsletterSignup } from '@/lib/newsletter-signup'
const DEFAULT_CENTER: [number, number] = [20, 0]
@@ -56,7 +59,7 @@ const yellowMarkerIcon = L.divIcon({
function clusterIconCreator(cluster: { getChildCount: () => number }) {
const count = cluster.getChildCount()
return L.divIcon({
html: `<div style="display:flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:9999px;background-color:#ffd328;color:#152521;font-size:10px;font-weight:500;">${count}</div>`,
html: `<div style="display:flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:9999px;background-color:#ffd328;color:#152521;font-size:12px;font-weight:500;">${count}</div>`,
className: 'logos-circle-cluster',
iconSize: L.point(32, 32, true),
})
@@ -119,8 +122,12 @@ function EventPopupContent({
{event.name}
</h3>
<div className="flex flex-col gap-0.5">
<span className="text-mono-s block text-brand-dark-green">{date}</span>
<span className="text-mono-s block text-brand-dark-green">{time}</span>
<span className="text-mono-s block text-brand-dark-green">
{date}
</span>
<span className="text-mono-s block text-brand-dark-green">
{time}
</span>
{location ? (
<span className="text-mono-s block truncate text-gray-05">
{location}
@@ -133,7 +140,12 @@ function EventPopupContent({
if (event.eventUrl) {
return (
<a href={event.eventUrl} target="_blank" rel="noopener noreferrer" className={cardClass}>
<a
href={event.eventUrl}
target="_blank"
rel="noopener noreferrer"
className={cardClass}
>
{content}
</a>
)
@@ -145,7 +157,9 @@ function EventPopupContent({
function NoEventPopupContent({ marker }: { marker: ActiveCircleMarker }) {
const t = useTranslations('circlesMap')
const [email, setEmail] = useState('')
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle')
const [status, setStatus] = useState<
'idle' | 'loading' | 'success' | 'error'
>('idle')
const [errorMsg, setErrorMsg] = useState('')
const handleSubmit = async (e: FormEvent) => {
@@ -171,7 +185,9 @@ function NoEventPopupContent({ marker }: { marker: ActiveCircleMarker }) {
<div className="pr-6 font-sans text-[18px] leading-[1.15]">
{t('subscribedHeading')}
</div>
<div className="text-mono-s mt-1 text-gray-05">{t('subscribedBody')}</div>
<div className="text-mono-s mt-1 text-gray-05">
{t('subscribedBody')}
</div>
</div>
)
}
@@ -322,7 +338,9 @@ function TouchGestureHandling({ hint }: { hint: string }) {
if (event.touches.length < 2) map.dragging.disable()
}
container.addEventListener('touchstart', handleTouchStart, { passive: true })
container.addEventListener('touchstart', handleTouchStart, {
passive: true,
})
container.addEventListener('touchmove', handleTouchMove, { passive: true })
container.addEventListener('touchend', handleTouchEnd, { passive: true })
container.addEventListener('touchcancel', handleTouchEnd, { passive: true })
@@ -397,10 +415,13 @@ function DesktopScrollZoomGate() {
(entries) => {
if (!entries.some((entry) => entry.isIntersecting)) return
setShowHint(true)
hintTimeout = setTimeout(() => setShowHint(false), SCROLL_ZOOM_HINT_DURATION_MS)
hintTimeout = setTimeout(
() => setShowHint(false),
SCROLL_ZOOM_HINT_DURATION_MS
)
observer.disconnect()
},
{ threshold: 0.35 },
{ threshold: 0.35 }
)
observer.observe(map.getContainer())
@@ -508,7 +529,8 @@ export default function CirclesWorldMap({
minWidth={0}
maxWidth={480}
closeButton
autoPan>
autoPan
>
{upcomingEvent ? (
<EventPopupContent event={upcomingEvent} locale={locale} />
) : (
@@ -30,7 +30,7 @@ function HeroBackLink({ eyebrow }: { eyebrow: string }) {
<span className="inline-flex size-3.75 shrink-0 rotate-180 items-center justify-center">
<ButtonArrowIcon />
</span>
<span className="font-mono text-[10px] leading-[1.3] font-medium uppercase">
<span className="font-mono text-xs leading-[1.3] font-medium uppercase">
{eyebrow}
</span>
</Link>
@@ -22,7 +22,7 @@ export function JourneySection({
href={link.href}
className="flex h-[71px] cursor-pointer flex-col items-start justify-between rounded-xl bg-brand-dark-green p-3 text-brand-off-white md:h-[83px]"
>
<span className="font-mono text-[10px] font-semibold leading-[1.35]">
<span className="font-mono text-xs font-semibold leading-[1.35]">
{(index + 1).toString().padStart(2, '0')}
</span>
<span className="inline-flex items-center gap-1 text-subhead-sans">
@@ -55,7 +55,7 @@ function ImageOverlayPanel({ panel }: { panel: ActionPanel }) {
{panel.title}
</h3>
{panel.description ? (
<p className="font-mono text-[10px] leading-[1.3] text-brand-off-white max-w-[219px] md:max-w-[380px]">
<p className="font-mono text-xs leading-[1.3] text-brand-off-white max-w-[219px] md:max-w-[380px]">
{panel.description}
</p>
) : null}
@@ -83,7 +83,7 @@ function OfficeHoursPanel({ data }: { data: OfficeHours }) {
<h3 className="font-sans text-[18px] font-normal leading-[1.15] tracking-[-0.18px] text-brand-dark-green">
{data.title}
</h3>
<p className="font-mono text-[10px] leading-[1.3] text-brand-dark-green max-w-[380px]">
<p className="font-mono text-xs leading-[1.3] text-brand-dark-green max-w-[380px]">
{data.description}
</p>
</div>
@@ -75,7 +75,7 @@ export function BuildersHubDetailLayout({
<span className="inline-flex size-3.75 shrink-0 rotate-180 items-center justify-center">
<ButtonArrowIcon />
</span>
<span className="font-mono text-[10px] font-medium leading-[1.3] uppercase">
<span className="font-mono text-xs font-medium leading-[1.3] uppercase">
{backLabel}
</span>
</Link>
@@ -86,7 +86,7 @@ export function BuildersHubDetailLayout({
<div className="flex items-center gap-3">
<LogosMark size={28} className="text-brand-dark-green shrink-0" />
{eyebrow ? (
<span className="font-mono text-[10px] font-medium leading-[1.3] text-brand-dark-green/70 uppercase">
<span className="font-mono text-xs font-medium leading-[1.3] text-brand-dark-green/70 uppercase">
{eyebrow}
</span>
) : null}
@@ -105,7 +105,7 @@ export function BuildersHubDetailLayout({
<section className="border-t border-brand-dark-green/10">
<div className="mx-auto max-w-360 px-3 py-12 grid gap-12 md:grid-cols-3">
<div className="md:col-span-2">
<h2 className="font-mono text-[10px] font-medium leading-[1.3] text-brand-dark-green/70 uppercase mb-4">
<h2 className="font-mono text-xs font-medium leading-[1.3] text-brand-dark-green/70 uppercase mb-4">
About
</h2>
<div className="font-sans text-[16px] leading-[1.5] text-brand-dark-green space-y-4 max-w-[60ch]">
@@ -134,13 +134,13 @@ export function BuildersHubDetailLayout({
{meta && meta.length > 0 ? (
<aside className="md:col-span-1">
<h2 className="font-mono text-[10px] font-medium leading-[1.3] text-brand-dark-green/70 uppercase mb-4">
<h2 className="font-mono text-xs font-medium leading-[1.3] text-brand-dark-green/70 uppercase mb-4">
Details
</h2>
<dl className="space-y-4">
{meta.map((item, i) => (
<div key={i}>
<dt className="font-mono text-[10px] leading-[1.3] text-brand-dark-green/60 uppercase">
<dt className="font-mono text-xs leading-[1.3] text-brand-dark-green/60 uppercase">
{item.label}
</dt>
<dd className="font-sans text-[14px] leading-[1.4] text-brand-dark-green mt-1">
@@ -35,7 +35,7 @@ export function BuildersHubHero({ hero }: Props) {
{/* Eyebrow — desktop center / mobile right */}
{hero.description ? (
<p className="font-mono text-[10px] leading-[1.3] text-black absolute top-6 left-[203px] w-[178px] md:left-[50%] md:translate-x-[6px] md:w-[226px]">
<p className="font-mono text-xs leading-[1.3] text-black absolute top-6 left-[203px] w-[178px] md:left-[50%] md:translate-x-[6px] md:w-[226px]">
{hero.description}
</p>
) : null}
@@ -61,14 +61,14 @@ export function BuildersHubListingHeader({
{backHref ? (
<Link
href={backHref}
className="absolute top-[-20px] left-0 inline-flex items-center gap-2 font-mono text-[10px] leading-[1.3] text-brand-dark-green uppercase hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-dark-green"
className="absolute top-[-20px] left-0 inline-flex items-center gap-2 font-mono text-xs leading-[1.3] text-brand-dark-green uppercase hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-dark-green"
>
<span aria-hidden="true"></span>
<span>{backLabel}</span>
</Link>
) : null}
{!backHref && eyebrow ? (
<p className="absolute top-0 left-1/2 -translate-x-1/2 font-mono text-[10px] leading-[1.3] text-brand-dark-green uppercase">
<p className="absolute top-0 left-1/2 -translate-x-1/2 font-mono text-xs leading-[1.3] text-brand-dark-green uppercase">
{eyebrow}
</p>
) : null}
@@ -83,7 +83,7 @@ export function BuildersHubListingHeader({
<div className="hidden md:col-span-3 md:col-start-7 md:block">
{description ? (
<p className="max-w-[342px] font-mono text-[10px] leading-[1.3] text-brand-dark-green">
<p className="max-w-[342px] font-mono text-xs leading-[1.3] text-brand-dark-green">
{description}
</p>
) : null}
@@ -105,7 +105,7 @@ export function BuildersHubListingHeader({
{mobileCopy ? (
<p
className={`${mobileDescriptionMarginClass} font-mono text-[10px] leading-[1.3] text-brand-dark-green md:hidden`}
className={`${mobileDescriptionMarginClass} font-mono text-xs leading-[1.3] text-brand-dark-green md:hidden`}
>
{mobileCopy}
</p>
@@ -61,7 +61,7 @@ function OverviewRow({ index, link }: { index: number; link: OverviewLink }) {
) : null}
</span>
</div>
<p className="font-mono text-[10px] leading-[1.3] text-brand-dark-green">
<p className="font-mono text-xs leading-[1.3] text-brand-dark-green">
{link.description}
</p>
</div>
@@ -79,7 +79,7 @@ function OverviewRow({ index, link }: { index: number; link: OverviewLink }) {
</div>
{/* Description — middle column (start col 7) */}
<p className="absolute top-3 left-[50%] translate-x-[6px] w-[345px] font-mono text-[10px] leading-[1.3] text-brand-dark-green">
<p className="absolute top-3 left-[50%] translate-x-[6px] w-[345px] font-mono text-xs leading-[1.3] text-brand-dark-green">
{link.description}
</p>
@@ -99,7 +99,7 @@ function OverviewRow({ index, link }: { index: number; link: OverviewLink }) {
function OverviewCtaLabel({ children }: { children: string }) {
return (
<span className="inline-flex items-center justify-center text-brand-dark-green">
<span className="font-mono text-[10px] leading-[1.35] font-semibold uppercase whitespace-nowrap border-b border-brand-dark-green/50 pb-0.5">
<span className="font-mono text-xs leading-[1.35] font-semibold uppercase whitespace-nowrap border-b border-brand-dark-green/50 pb-0.5">
{children}
</span>
</span>
@@ -68,7 +68,7 @@ function ResourceRow({
<span className="ml-3 font-display">{resource.title}</span>
</p>
<span className="absolute top-3 right-3 inline-flex items-center justify-center text-brand-dark-green">
<span className="font-mono text-[10px] leading-[1.35] font-semibold uppercase whitespace-nowrap border-b border-brand-dark-green/50 pb-0.5">
<span className="font-mono text-xs leading-[1.35] font-semibold uppercase whitespace-nowrap border-b border-brand-dark-green/50 pb-0.5">
{resource.ctaLabel}
</span>
</span>
@@ -84,11 +84,11 @@ function ResourceRow({
{resource.title}
</span>
</div>
<p className="absolute top-3 left-[50%] translate-x-[6px] w-[312px] font-mono text-[10px] leading-[1.3] text-brand-dark-green">
<p className="absolute top-3 left-[50%] translate-x-[6px] w-[312px] font-mono text-xs leading-[1.3] text-brand-dark-green">
{resource.description}
</p>
<span className="absolute top-3 left-[83.33%] translate-x-[2px] inline-flex items-center justify-center text-brand-dark-green">
<span className="font-mono text-[10px] leading-[1.35] font-semibold uppercase whitespace-nowrap border-b border-brand-dark-green/50 pb-0.5">
<span className="font-mono text-xs leading-[1.35] font-semibold uppercase whitespace-nowrap border-b border-brand-dark-green/50 pb-0.5">
{resource.ctaLabel}
</span>
</span>
@@ -48,7 +48,7 @@ export function IdeaCard({ idea }: Props) {
</div>
) : null}
<p className="absolute left-4 bottom-4 w-[186px] font-mono text-[10px] leading-[1.3] text-brand-dark-green">
<p className="absolute left-4 bottom-4 w-[186px] font-mono text-xs leading-[1.3] text-brand-dark-green">
{blurb}{' '}
<span className="opacity-70">/ Idea by @{idea.submitter.handle}</span>
</p>
@@ -45,21 +45,21 @@ export function IdeaRow({ index, idea }: Props) {
href={detailHref}
className="inline-flex cursor-pointer items-center justify-center justify-self-end border border-brand-dark-green/50 px-3 py-2 text-brand-dark-green focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-brand-dark-green"
>
<span className="font-mono text-[10px] leading-[1.35] font-semibold uppercase whitespace-nowrap">
<span className="font-mono text-xs leading-[1.35] font-semibold uppercase whitespace-nowrap">
{ctaLabel}
</span>
<span
aria-hidden="true"
className="ml-1 font-mono text-[10px] leading-none"
className="ml-1 font-mono text-xs leading-none"
>
</span>
</Link>
<p className="min-w-0 font-mono text-[10px] leading-[1.3] text-brand-dark-green">
<p className="min-w-0 font-mono text-xs leading-[1.3] text-brand-dark-green">
{mobileDescription}
</p>
{rewardLines.length > 0 ? (
<p className="w-[83px] justify-self-end font-mono text-[10px] leading-[1.3] text-brand-dark-green">
<p className="w-[83px] justify-self-end font-mono text-xs leading-[1.3] text-brand-dark-green">
{rewardLines.map((line) => (
<span key={line} className="block">
{line}
@@ -82,13 +82,13 @@ export function IdeaRow({ index, idea }: Props) {
{idea.title}
</Link>
</div>
<p className="min-w-0 flex-1 font-mono text-[10px] leading-[1.3] text-brand-dark-green">
<p className="min-w-0 flex-1 font-mono text-xs leading-[1.3] text-brand-dark-green">
<span className="block truncate">{description}</span>
<span className="block truncate">{submitter}</span>
</p>
<div className="flex shrink-0 items-start gap-3">
{rewardLines.length > 0 ? (
<span className="w-[107px] font-mono text-[10px] leading-[1.3] text-brand-dark-green">
<span className="w-[107px] font-mono text-xs leading-[1.3] text-brand-dark-green">
{rewardLines.map((line) => (
<span key={line} className="block">
{line}
@@ -102,7 +102,7 @@ export function IdeaRow({ index, idea }: Props) {
href={detailHref}
className="inline-flex cursor-pointer items-center justify-center text-brand-dark-green focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-brand-dark-green"
>
<span className="font-mono text-[10px] leading-[1.35] font-semibold uppercase whitespace-nowrap border-b border-brand-dark-green/50 pb-0.5">
<span className="font-mono text-xs leading-[1.35] font-semibold uppercase whitespace-nowrap border-b border-brand-dark-green/50 pb-0.5">
{ctaLabel}
</span>
</Link>
@@ -26,7 +26,7 @@ export function RelatedLinksList({
if (items.length === 0) return null
return (
<>
<h2 className="font-mono text-[10px] font-medium leading-[1.3] text-brand-dark-green/70 uppercase mb-4">
<h2 className="font-mono text-xs font-medium leading-[1.3] text-brand-dark-green/70 uppercase mb-4">
{heading}
</h2>
<ul className="space-y-2">
@@ -31,7 +31,7 @@ export function RfpCard({ rfp }: Props) {
{rfp.title}
</h3>
<span className="mt-[14.2px] inline-flex items-center justify-center text-brand-dark-green">
<span className="font-mono text-[10px] leading-[1.35] font-semibold uppercase whitespace-nowrap border-b border-brand-dark-green/50 pb-0.5">
<span className="font-mono text-xs leading-[1.35] font-semibold uppercase whitespace-nowrap border-b border-brand-dark-green/50 pb-0.5">
Learn More
</span>
</span>
@@ -54,7 +54,7 @@ export function RfpCard({ rfp }: Props) {
) : null}
{/* Description */}
<p className="absolute left-4 bottom-4 w-[186px] font-mono text-[10px] leading-[1.3] text-brand-dark-green">
<p className="absolute left-4 bottom-4 w-[186px] font-mono text-xs leading-[1.3] text-brand-dark-green">
{blurb}
</p>
</Link>
@@ -35,15 +35,15 @@ export function RfpListRow({ index, rfp }: Props) {
<span className="ml-3 font-display">{rfp.title}</span>
</p>
<span className="inline-flex items-center justify-center justify-self-end border border-brand-dark-green/50 px-3 py-2 text-brand-dark-green">
<span className="font-mono text-[10px] leading-[1.35] font-semibold uppercase whitespace-nowrap">
<span className="font-mono text-xs leading-[1.35] font-semibold uppercase whitespace-nowrap">
Learn More
</span>
</span>
<p className="font-mono text-[10px] leading-[1.3] text-brand-dark-green">
<p className="font-mono text-xs leading-[1.3] text-brand-dark-green">
{blurb}
</p>
{rewardLines.length > 0 ? (
<p className="w-[83px] justify-self-end font-mono text-[10px] leading-[1.3] text-brand-dark-green">
<p className="w-[83px] justify-self-end font-mono text-xs leading-[1.3] text-brand-dark-green">
{rewardLines.map((line) => (
<span key={line} className="block">
{line}
@@ -65,12 +65,12 @@ export function RfpListRow({ index, rfp }: Props) {
{rfp.title}
</span>
</div>
<p className="min-w-0 flex-1 truncate font-mono text-[10px] leading-[1.3] text-brand-dark-green">
<p className="min-w-0 flex-1 truncate font-mono text-xs leading-[1.3] text-brand-dark-green">
{blurb}
</p>
<div className="flex shrink-0 items-start gap-3">
{rewardLines.length > 0 ? (
<span className="w-[107px] font-mono text-[10px] leading-[1.3] text-brand-dark-green">
<span className="w-[107px] font-mono text-xs leading-[1.3] text-brand-dark-green">
{rewardLines.map((line) => (
<span key={line} className="block">
{line}
@@ -81,7 +81,7 @@ export function RfpListRow({ index, rfp }: Props) {
<span className="w-[107px]" />
)}
<span className="inline-flex items-center justify-center text-brand-dark-green">
<span className="font-mono text-[10px] leading-[1.35] font-semibold uppercase whitespace-nowrap border-b border-brand-dark-green/50 pb-0.5">
<span className="font-mono text-xs leading-[1.35] font-semibold uppercase whitespace-nowrap border-b border-brand-dark-green/50 pb-0.5">
Learn More
</span>
</span>
@@ -31,7 +31,7 @@ export function BuildersHubSectionHeader({
{/* Desktop layout — absolute, matches Figma x-coords */}
<div className="absolute inset-0 hidden md:block">
{eyebrow ? (
<p className="font-mono text-[10px] leading-[1.3] text-black absolute top-[3px] left-[50%] translate-x-[6px] w-[226px]">
<p className="font-mono text-xs leading-[1.3] text-black absolute top-[3px] left-[50%] translate-x-[6px] w-[226px]">
{eyebrow}
</p>
) : null}
@@ -53,7 +53,7 @@ export function BuildersHubSectionHeader({
{/* Mobile layout — eyebrow + CTA stacked on the right side */}
<div className="absolute top-0 right-3 flex flex-col items-start gap-6 md:hidden w-[178px] text-right">
{eyebrow ? (
<p className="font-mono text-[10px] leading-[1.3] text-black w-full">
<p className="font-mono text-xs leading-[1.3] text-black w-full">
{eyebrow}
</p>
) : null}
@@ -44,7 +44,7 @@ function InitiativeCard({ initiative }: { initiative: CircleInitiative }) {
</div>
<span className="absolute right-3 top-3 inline-flex items-center gap-1 rounded-xl bg-brand-off-white px-3 py-2 text-brand-dark-green">
<span className="font-mono text-[10px] font-semibold uppercase leading-[1.35]">
<span className="font-mono text-xs font-semibold uppercase leading-[1.35]">
{initiative.ctaLabel}
</span>
<ArrowIcon />
@@ -65,66 +65,66 @@ function DetailHero({
return (
<section className="relative h-auto min-h-[291px] bg-brand-off-white px-3 pt-10 md:h-[334px] md:pb-0">
<ContentWidth className="relative h-full">
<SmartLink
href={circle.detailBackLink.href}
className="absolute left-3 top-[-20px] inline-flex items-center gap-1 px-0 py-2 text-brand-dark-green"
>
<ArrowIcon direction="left" />
<span className="font-mono text-[10px] font-semibold uppercase leading-[1.35]">
{circle.detailBackLink.label}
</span>
</SmartLink>
<SmartLink
href={circle.detailBackLink.href}
className="absolute left-3 top-[-20px] inline-flex items-center gap-1 px-0 py-2 text-brand-dark-green"
>
<ArrowIcon direction="left" />
<span className="font-mono text-xs font-semibold uppercase leading-[1.35]">
{circle.detailBackLink.label}
</span>
</SmartLink>
<div className="flex items-center gap-3 md:absolute md:left-3 md:top-10">
<CircleLogo size="large" />
<h1 className="font-display text-[30px] leading-none text-brand-dark-green md:text-[36px]">
{circle.name}
</h1>
</div>
<div className="mt-10 grid gap-10 md:absolute md:left-[calc(50%+6px)] md:top-10 md:mt-0 md:w-[345px] md:gap-7">
<div className="flex flex-col items-start gap-3">
<p className="text-mono-s max-w-[369px] text-brand-dark-green md:max-w-[342px]">
{circle.description}
</p>
<Button
href={circle.joinUrl}
variant="secondary"
className="md:hidden"
{...(isExternalHref(circle.joinUrl)
? { target: '_blank', rel: 'noopener noreferrer' }
: {})}
>
{settings.detailJoinCtaLabel}
</Button>
<div className="flex items-center gap-3 md:absolute md:left-3 md:top-10">
<CircleLogo size="large" />
<h1 className="font-display text-[30px] leading-none text-brand-dark-green md:text-[36px]">
{circle.name}
</h1>
</div>
<dl className="text-mono-s w-full text-brand-dark-green">
{stats.map(([label, value]) => (
<div
key={label}
className="grid grid-cols-[83px_minmax(0,1fr)] gap-3 border-t border-brand-dark-green/10 py-1.5 md:grid-cols-[107px_minmax(0,1fr)]"
>
<dt className="font-mono text-[10px] font-medium uppercase leading-[1.3]">
{label}
</dt>
<dd className="min-w-0 break-words">{value}</dd>
</div>
))}
</dl>
</div>
<div className="mt-10 grid gap-10 md:absolute md:left-[calc(50%+6px)] md:top-10 md:mt-0 md:w-[345px] md:gap-7">
<div className="flex flex-col items-start gap-3">
<p className="text-mono-s max-w-[369px] text-brand-dark-green md:max-w-[342px]">
{circle.description}
</p>
<Button
href={circle.joinUrl}
variant="secondary"
className="hidden md:absolute md:left-[calc(83.333%+2px)] md:top-10 md:mt-0 md:inline-flex"
{...(isExternalHref(circle.joinUrl)
? { target: '_blank', rel: 'noopener noreferrer' }
: {})}
>
{settings.detailJoinCtaLabel}
</Button>
<Button
href={circle.joinUrl}
variant="secondary"
className="md:hidden"
{...(isExternalHref(circle.joinUrl)
? { target: '_blank', rel: 'noopener noreferrer' }
: {})}
>
{settings.detailJoinCtaLabel}
</Button>
</div>
<dl className="text-mono-s w-full text-brand-dark-green">
{stats.map(([label, value]) => (
<div
key={label}
className="grid grid-cols-[83px_minmax(0,1fr)] gap-3 border-t border-brand-dark-green/10 py-1.5 md:grid-cols-[107px_minmax(0,1fr)]"
>
<dt className="font-mono text-xs font-medium uppercase leading-[1.3]">
{label}
</dt>
<dd className="min-w-0 break-words">{value}</dd>
</div>
))}
</dl>
</div>
<Button
href={circle.joinUrl}
variant="secondary"
className="hidden md:absolute md:left-[calc(83.333%+2px)] md:top-10 md:mt-0 md:inline-flex"
{...(isExternalHref(circle.joinUrl)
? { target: '_blank', rel: 'noopener noreferrer' }
: {})}
>
{settings.detailJoinCtaLabel}
</Button>
</ContentWidth>
</section>
)
@@ -230,7 +230,7 @@ function SectionShell({
<ContentWidth>
<div className="flex flex-col gap-3 px-3">
<div className="flex justify-start md:justify-end">
<h2 className="font-mono text-[10px] font-medium uppercase leading-[1.3] text-brand-dark-green">
<h2 className="font-mono text-xs font-medium uppercase leading-[1.3] text-brand-dark-green">
{title}
</h2>
</div>
@@ -299,7 +299,7 @@ function InitiativeCard({ initiative }: { initiative: CircleInitiative }) {
</div>
<span className="absolute right-3 top-3 inline-flex items-center gap-1 rounded-xl bg-brand-off-white px-3 py-2 text-brand-dark-green">
<span className="font-mono text-[10px] font-semibold uppercase leading-[1.35]">
<span className="font-mono text-xs font-semibold uppercase leading-[1.35]">
{initiative.ctaLabel}
</span>
<ArrowIcon />
@@ -46,7 +46,7 @@ export function AfformPageIntro({ text }: Props) {
.filter(Boolean)
return (
<div className="mx-auto max-w-[40em] space-y-4 text-balance font-mono text-[10px] leading-[1.3]">
<div className="mx-auto max-w-[40em] space-y-4 text-balance font-mono text-xs leading-[1.3]">
{paragraphs.map((paragraph, index) => (
<p key={index}>{renderInlineLinks(paragraph)}</p>
))}
@@ -15,7 +15,10 @@ import {
} from 'react'
import { Button } from '@/components/ui/button'
import { buildFormSchema, MAX_TEXT_LENGTH } from '@/lib/civicrm/contactFormSchema'
import {
buildFormSchema,
MAX_TEXT_LENGTH,
} from '@/lib/civicrm/contactFormSchema'
import { HEAR_ABOUT_FORM_KEY } from '@/lib/civicrm/hear-about-field'
import type {
AfformConfig,
@@ -267,7 +270,9 @@ export function ConnectFormSection({
if (!el) return
const rect = el.getBoundingClientRect()
const top =
window.scrollY + rect.top - Math.max(0, (window.innerHeight - rect.height) / 2)
window.scrollY +
rect.top -
Math.max(0, (window.innerHeight - rect.height) / 2)
window.scrollTo({ top: Math.max(0, top), behavior: 'smooth' })
el.focus({ preventScroll: true })
}
@@ -353,7 +358,7 @@ export function ConnectFormSection({
<h3 className="mb-4 font-sans text-[24px] leading-[1.1] tracking-[-0.24px] text-brand-dark-green">
{confirmationMessage}
</h3>
<p className="mx-auto max-w-[40em] text-balance font-mono text-[10px] leading-[1.3] text-brand-dark-green/80">
<p className="mx-auto max-w-[40em] text-balance font-mono text-xs leading-[1.3] text-brand-dark-green/80">
{t('successBody')}
</p>
</motion.div>
@@ -475,7 +480,7 @@ export function ConnectFormSection({
type="button"
onClick={handleRemoveChatRow(index)}
disabled={loadingState}
className="shrink-0 self-center font-mono text-[10px] leading-[1.3] text-brand-dark-green/70 hover:text-brand-dark-green"
className="shrink-0 self-center font-mono text-xs leading-[1.3] text-brand-dark-green/70 hover:text-brand-dark-green"
aria-label={t('removeChatRow', { index: index + 1 })}
>
{t('remove')}
@@ -484,7 +489,7 @@ export function ConnectFormSection({
</div>
))}
{hasError('chat') ? (
<p className="font-mono text-[10px] font-semibold text-red-600">
<p className="font-mono text-xs font-semibold text-red-600">
{t('chatNameRequired')}
</p>
) : null}
@@ -492,7 +497,7 @@ export function ConnectFormSection({
type="button"
onClick={handleAddChatRow}
disabled={loadingState}
className="text-left font-mono text-[10px] leading-[1.3] text-brand-dark-green/70 hover:text-brand-dark-green"
className="text-left font-mono text-xs leading-[1.3] text-brand-dark-green/70 hover:text-brand-dark-green"
aria-label={t('addChatRow')}
>
{t('addAnother')}
@@ -537,7 +542,7 @@ export function ConnectFormSection({
const isChecked = value === true
return (
<div key={field.formKey} className="w-full">
<label className="inline-flex cursor-pointer items-start font-mono text-[10px] leading-[1.3]">
<label className="inline-flex cursor-pointer items-start font-mono text-xs leading-[1.3]">
<input
className="sr-only"
type="checkbox"
@@ -590,7 +595,7 @@ export function ConnectFormSection({
{!isOverLimit &&
hasFieldError &&
REQUIRED_FIELDS.has(field.formKey) ? (
<p className="mt-2 font-mono text-[10px] font-semibold text-red-600">
<p className="mt-2 font-mono text-xs font-semibold text-red-600">
{t('fieldRequired', { field: label.toLowerCase() })}
</p>
) : null}
@@ -606,8 +611,7 @@ export function ConnectFormSection({
values = [values[0], '']
}
const canAddRow =
field.formKey !== 'website' ||
values.length < MAX_WEBSITE_ROWS
field.formKey !== 'website' || values.length < MAX_WEBSITE_ROWS
return (
<div key={field.formKey} className="w-full space-y-3">
<FieldLabel>{label}</FieldLabel>
@@ -627,7 +631,7 @@ export function ConnectFormSection({
type="button"
onClick={handleRemoveRepeatable(field.formKey, index)}
disabled={loadingState}
className="shrink-0 self-center font-mono text-[10px] leading-[1.3] text-brand-dark-green/70 hover:text-brand-dark-green"
className="shrink-0 self-center font-mono text-xs leading-[1.3] text-brand-dark-green/70 hover:text-brand-dark-green"
aria-label={t('removeFieldRow', {
field: label,
index: index + 1,
@@ -643,7 +647,7 @@ export function ConnectFormSection({
type="button"
onClick={handleAddRepeatable(field.formKey)}
disabled={loadingState}
className="text-left font-mono text-[10px] leading-[1.3] text-brand-dark-green/70 hover:text-brand-dark-green"
className="text-left font-mono text-xs leading-[1.3] text-brand-dark-green/70 hover:text-brand-dark-green"
aria-label={t('addFieldRow', { field: label })}
>
{t('addAnother')}
@@ -677,7 +681,7 @@ export function ConnectFormSection({
{!isOverLimit &&
hasFieldError &&
REQUIRED_FIELDS.has(field.formKey) ? (
<p className="mt-2 font-mono text-[10px] font-semibold text-red-600">
<p className="mt-2 font-mono text-xs font-semibold text-red-600">
{field.formKey === 'email'
? t('emailInvalid')
: t('fieldRequired', { field: label.toLowerCase() })}
@@ -691,7 +695,7 @@ export function ConnectFormSection({
<motion.p
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="font-mono text-[10px] font-semibold text-red-600"
className="font-mono text-xs font-semibold text-red-600"
>
{serverError}
</motion.p>
@@ -717,7 +721,7 @@ export function ConnectFormSection({
<div className="flex flex-col gap-6 pt-4 md:flex-row md:items-end md:justify-between">
{pagePrivacy ? (
<div className="max-w-[50em]">
<p className="text-balance font-mono text-[10px] leading-[1.3] text-brand-dark-green/80">
<p className="text-balance font-mono text-xs leading-[1.3] text-brand-dark-green/80">
{pagePrivacyLink && pagePrivacy.includes('Privacy Policy') ? (
<>
{pagePrivacy.split('Privacy Policy')[0]}
@@ -16,7 +16,7 @@ export function FieldError({ visible, children }: Props) {
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.3 }}
className="mt-2 font-mono text-[10px] leading-[1.3] font-semibold text-red-600"
className="mt-2 font-mono text-xs leading-[1.3] font-semibold text-red-600"
>
{children}
</motion.p>
@@ -14,7 +14,7 @@ export function FieldLabel({ htmlFor, children, required, className }: Props) {
<label
htmlFor={htmlFor}
className={cn(
'mb-1.5 block font-mono text-[10px] leading-[1.3] text-brand-dark-green',
'mb-1.5 block font-mono text-xs leading-[1.3] text-brand-dark-green',
className
)}
>
@@ -32,19 +32,20 @@ export function TextInput({
const isOverLimit = count > maxLength
return (
<div className={cn('w-full', wrapperClassName)}>
{label ? (
<FieldLabel htmlFor={id}>{label}</FieldLabel>
) : null}
{label ? <FieldLabel htmlFor={id}>{label}</FieldLabel> : null}
<input
id={id}
value={value}
aria-invalid={error || isOverLimit || undefined}
className={cn(inputClassName, (error || isOverLimit) && 'border-red-600')}
className={cn(
inputClassName,
(error || isOverLimit) && 'border-red-600'
)}
{...props}
/>
{isOverLimit ? (
<div
className="mt-1 flex items-center gap-2 font-mono text-[10px] leading-[1.3] font-semibold text-red-600"
className="mt-1 flex items-center gap-2 font-mono text-xs leading-[1.3] font-semibold text-red-600"
aria-live="polite"
>
{overLimitMessage ? <p>{overLimitMessage}</p> : null}
@@ -27,9 +27,7 @@ export function TextareaInput({
const isOverLimit = count > maxLength
return (
<div className="w-full">
{label ? (
<FieldLabel htmlFor={id}>{label}</FieldLabel>
) : null}
{label ? <FieldLabel htmlFor={id}>{label}</FieldLabel> : null}
<textarea
id={id}
value={value}
@@ -41,7 +39,7 @@ export function TextareaInput({
{...props}
/>
<div
className="mt-1 flex items-center gap-2 font-mono text-[10px] leading-[1.3]"
className="mt-1 flex items-center gap-2 font-mono text-xs leading-[1.3]"
aria-live="polite"
>
{isOverLimit && overLimitMessage ? (
@@ -99,15 +99,15 @@ function CardBody({
</div>
</div>
<div className="flex w-full max-w-[339px] items-baseline gap-10">
<p className="min-h-[51px] w-[169.5px] shrink-0 break-words font-sans text-[12px] leading-[1.2] font-medium text-brand-dark-green desktop:text-body-sans desktop:font-normal">
<p className="min-h-[51px] w-[169.5px] shrink-0 break-words font-sans text-xs leading-[1.2] font-medium text-brand-dark-green desktop:text-body-sans desktop:font-normal">
{title}
</p>
<div className="shrink-0">
<p className="font-mono-body text-[10px] leading-[1.3] font-normal text-brand-dark-green desktop:text-eyebrow">
<p className="font-mono-body text-xs leading-[1.3] font-normal text-brand-dark-green desktop:text-eyebrow">
{date}
</p>
{author ? (
<p className="font-mono-body text-[10px] leading-[1.3] font-normal text-brand-dark-green desktop:text-eyebrow">
<p className="font-mono-body text-xs leading-[1.3] font-normal text-brand-dark-green desktop:text-eyebrow">
{author}
</p>
) : null}
@@ -144,7 +144,7 @@ export default function BlogSection({ data, articles }: Props) {
{(data.label || data.eyebrow || data.cta) && (
<div className="contents lg:flex lg:items-center lg:justify-between">
{data.label ? (
<p className="font-mono-body absolute top-6 right-[169px] left-3 text-[10px] leading-[1.3] font-normal text-brand-dark-green lg:static lg:right-auto lg:w-auto lg:text-mono-s">
<p className="font-mono-body absolute top-6 right-[169px] left-3 text-xs leading-[1.3] font-normal text-brand-dark-green lg:static lg:right-auto lg:w-auto lg:text-mono-s">
{data.label}
</p>
) : null}
@@ -122,7 +122,7 @@ export default function CivilSocietyAccordion({
<p className="font-sans text-[14px] leading-[1.2]">
{item.body}
</p>
<div className="flex flex-col gap-4 font-mono text-[10px] leading-[1.3] lg:gap-[20px]">
<div className="flex flex-col gap-4 font-mono text-xs leading-[1.3] lg:gap-[20px]">
{item.facts.map((fact, index) => (
<p key={fact}>
<FactText
@@ -50,7 +50,7 @@ function PathCardView({ card }: { card: PathCard }) {
<span className="inline-flex shrink-0 items-center justify-center rounded-xl bg-brand-off-white px-3 py-2 text-brand-dark-green backdrop-blur-[5px] transition-colors duration-300 ease-out group-hover/path-card:bg-accent-steel-teal group-focus-visible/path-card:bg-accent-steel-teal lg:px-[clamp(8px,0.8vw,12px)] desktop:px-3">
<span className="inline-flex items-center gap-1">
<span className="font-mono text-[10px] leading-[1.35] font-semibold whitespace-nowrap uppercase lg:text-[clamp(8px,0.7vw,10px)] desktop:text-[10px]">
<span className="font-mono text-xs leading-[1.35] font-semibold whitespace-nowrap uppercase">
{card.cta}
</span>
<ButtonArrowIcon />
@@ -69,7 +69,9 @@ interface FeatureCardsSectionProps {
data: HomeChoosePathSection
}
export default function FeatureCardsSection({ data }: FeatureCardsSectionProps) {
export default function FeatureCardsSection({
data,
}: FeatureCardsSectionProps) {
const cards: PathCard[] = [
{
key: 'build',
@@ -111,7 +113,7 @@ export default function FeatureCardsSection({ data }: FeatureCardsSectionProps)
{data.title}
</SectionHeadingReveal>
<div className="font-mono-body mx-auto flex w-[351.5px] max-w-[calc(100vw-24px)] flex-col gap-[13px] text-[10px] leading-[1.3] text-brand-dark-green lg:mx-0 lg:w-[226px] lg:gap-4 lg:text-mono-s">
<div className="font-mono-body mx-auto flex w-[351.5px] max-w-[calc(100vw-24px)] flex-col gap-[13px] text-xs leading-[1.3] text-brand-dark-green lg:mx-0 lg:w-[226px] lg:gap-4 lg:text-mono-s">
<p>{data.kicker}</p>
<p>{data.body}</p>
</div>
@@ -13,10 +13,13 @@ import type { SocialProofStats } from '@/lib/social-proof-stats'
function StatCardView({ card }: { card: HomeStatCard }) {
return (
<article className="hidden h-full w-full min-w-0 rounded-[20px] border border-brand-dark-green bg-brand-off-white text-brand-dark-green md:grid md:grid-cols-1">
<div aria-hidden className="col-start-1 row-start-1 aspect-square w-full" />
<div
aria-hidden
className="col-start-1 row-start-1 aspect-square w-full"
/>
<div className="col-start-1 row-start-1 flex min-w-0 flex-col gap-4 p-4 xl:gap-[23px] xl:p-5">
<span className="inline-flex w-fit items-center rounded-[4px] border border-brand-dark-green px-[11px] py-1.5">
<span className="font-sans text-[12px] leading-[1.15] tracking-[-0.01em]">
<span className="font-sans text-xs leading-[1.15] tracking-[-0.01em]">
{card.label}
</span>
</span>
@@ -47,7 +50,7 @@ function MobileStatRowView({
<p className="w-full font-sans text-[18px] leading-[1.15] font-normal tracking-[-0.18px] [text-box-edge:cap_alphabetic] [text-box-trim:trim-both]">
{card.value} {card.label}
</p>
<p className="font-mono-body w-full text-[10px] leading-[1.3] font-normal tracking-normal [text-box-edge:cap_alphabetic] [text-box-trim:trim-both]">
<p className="font-mono-body w-full text-xs leading-[1.3] font-normal tracking-normal [text-box-edge:cap_alphabetic] [text-box-trim:trim-both]">
{card.body}
</p>
</div>
@@ -65,7 +65,7 @@ export default function StartBuildingSection({
<h2 className="font-display text-[30px] leading-none tracking-[-0.03em] lg:text-[36px]">
{data.title}
</h2>
<p className="font-sans text-[12px] leading-[1.2] lg:w-[254px]">
<p className="font-sans text-xs leading-[1.2] lg:w-[254px]">
{data.body}
</p>
</div>
@@ -58,7 +58,7 @@ export default function UseCasesSection({
{data.headline}
</SectionHeadingReveal>
</div>
<SectionHeadingReveal className="font-mono-body mt-[80px] text-center text-[10px] leading-[1.3] tracking-normal whitespace-nowrap lg:mt-0 lg:hidden">
<SectionHeadingReveal className="font-mono-body mt-[80px] text-center text-xs leading-[1.3] tracking-normal whitespace-nowrap lg:mt-0 lg:hidden">
{data.eyebrow}
</SectionHeadingReveal>
<p className="text-mono-s hidden w-full lg:block">
@@ -80,7 +80,7 @@ export default function UseCasesSection({
}
</h3>
<div className="absolute right-[10px] bottom-[11px] left-[15px] flex items-end justify-between gap-3 lg:static">
<p className="font-mono-body w-[186px] text-[10px] leading-[1.3] lg:max-w-[186px]">
<p className="font-mono-body w-[186px] text-xs leading-[1.3] lg:max-w-[186px]">
{
data[
card.key as 'secure' | 'money' | 'archives' | 'donations'
@@ -203,10 +203,10 @@ describe('MovementPageView content-driven copy', () => {
initiatives: [],
resources: [],
locale: 'en',
}),
})
)
expect(html).toContain(
'Logos is a movement of builders, activists, and community organisers rebuilding civil society.',
'Logos is a movement of builders, activists, and community organisers rebuilding civil society.'
)
})
@@ -220,7 +220,7 @@ describe('MovementPageView content-driven copy', () => {
initiatives: [],
resources: [],
locale: 'en',
}),
})
)
expect(html).toContain('Join an Activist Circle')
})
@@ -235,7 +235,7 @@ describe('MovementPageView content-driven copy', () => {
initiatives: [],
resources: [],
locale: 'en',
}),
})
)
expect(html).toContain('Become an Activist Builder')
})
@@ -250,11 +250,47 @@ describe('MovementPageView content-driven copy', () => {
initiatives: [],
resources: [],
locale: 'en',
}),
})
)
expect(html).toContain('Activism in Action')
})
it('renders the initiative CTA label from content', () => {
const html = renderToStaticMarkup(
createElement(MovementPageView, {
data: fixture,
circlesSettings: circlesSettings as never,
mapMarkers: [],
upcomingEvents: [],
initiatives: [
{
schemaVersion: 1,
slug: 'digital-escape-egress',
status: 'published',
circleSlug: 'london',
href: 'https://example.com/proposal',
image: {
src: '/initiative.webp',
alt: '',
width: 720,
height: 480,
},
featured: false,
language: 'en',
locationLabel: 'London',
title: 'Digital IDs knowledge hub',
description: 'An initiative description.',
ctaLabel: 'Read the proposal',
},
],
resources: [],
locale: 'en',
})
)
expect(html).toContain('Read the proposal')
})
it('renders find.title from data prop', () => {
const html = renderToStaticMarkup(
createElement(MovementPageView, {
@@ -265,7 +301,7 @@ describe('MovementPageView content-driven copy', () => {
initiatives: [],
resources: [],
locale: 'en',
}),
})
)
expect(html).toContain('Find a Circle near you.')
})
@@ -26,8 +26,8 @@ function IssueCard({ initiative }: { initiative: CircleInitiative }) {
aria-hidden="true"
className="absolute right-3 top-3 inline-flex items-center gap-1 rounded-xl bg-brand-off-white px-3 py-2 text-brand-dark-green pointer-events-none"
>
<span className="font-mono text-[10px] font-semibold uppercase leading-[1.35]">
View issue
<span className="font-mono text-xs font-semibold uppercase leading-[1.35]">
{initiative.ctaLabel}
</span>
<ArrowIcon />
</span>
@@ -33,7 +33,7 @@ const ctaToneClass: Record<CtaTone, string> = {
export function Cta({ href, label, tone = 'primary', className }: CtaProps) {
const isExternal = href.startsWith('http')
const classes = `inline-flex cursor-pointer items-center justify-center gap-1 font-mono text-[10px] font-semibold leading-[1.35] uppercase backdrop-blur-[5px] transition-opacity hover:opacity-70 ${ctaToneClass[tone]} ${className ?? ''}`
const classes = `inline-flex cursor-pointer items-center justify-center gap-1 font-mono text-xs font-semibold leading-[1.35] uppercase backdrop-blur-[5px] transition-opacity hover:opacity-70 ${ctaToneClass[tone]} ${className ?? ''}`
const content = (
<>
<span
@@ -135,7 +135,7 @@ export function SectionHeader({
<p
className={cn(
'text-mono-s max-w-[456px] md:col-span-3 md:col-start-7',
descriptionClassName,
descriptionClassName
)}
>
{description}
@@ -12,7 +12,10 @@ export function isExternalHref(href: string): boolean {
return /^https?:\/\//.test(href)
}
export function TextLink({ href, children }: LinkItem & { children: ReactNode }) {
export function TextLink({
href,
children,
}: LinkItem & { children: ReactNode }) {
if (isExternalHref(href)) {
return (
<a
@@ -35,7 +38,7 @@ export function TextLink({ href, children }: LinkItem & { children: ReactNode })
export function CtaLink({ label, href }: LinkItem) {
const className =
'inline-flex cursor-pointer items-center gap-1 rounded-[4px] font-mono text-[10px] font-semibold uppercase leading-[1.35] text-brand-dark-green'
'inline-flex cursor-pointer items-center gap-1 rounded-[4px] font-mono text-xs font-semibold uppercase leading-[1.35] text-brand-dark-green'
const content = (
<>
<span>{label}</span>
@@ -65,7 +68,7 @@ export function CtaLink({ label, href }: LinkItem) {
export function LinkButton({ label, href }: LinkItem) {
const className =
'inline-flex cursor-pointer items-center gap-1 border-b border-brand-dark-green/50 pb-0.5 font-mono text-[10px] font-semibold uppercase leading-[1.35] text-brand-dark-green'
'inline-flex cursor-pointer items-center gap-1 border-b border-brand-dark-green/50 pb-0.5 font-mono text-xs font-semibold uppercase leading-[1.35] text-brand-dark-green'
const content = (
<>
<span>{label}</span>
@@ -81,7 +81,7 @@ export function DeveloperProgramsSection({
}`}
>
<h4 className="w-[249px] text-h4-sans">{rfp.title}</h4>
<span className="absolute top-[83px] left-4 font-mono text-[10px] font-semibold uppercase underline underline-offset-[3px]">
<span className="absolute top-[83px] left-4 font-mono text-xs font-semibold uppercase underline underline-offset-[3px]">
{rfp.ctaLabel ?? data.rfpsTitle}
</span>
<p className="absolute bottom-4 left-4 w-[186px] text-mono-s">
@@ -12,7 +12,7 @@ import { Link } from '@/i18n/navigation'
*
* Layout matches Figma exactly:
* - w-[226px], py-20, gap-1 (4px in Figma)
* - text-mono-s (Fira Mono Regular 10px) for inactive items
* - text-mono-s (Fira Mono Regular 12px) for inactive items
* - dot (h-2 w-3 rounded-full) + text-eyebrow for the active item
* - sticky top-0 from xl upward (matches the gap-122 desktop frame)
*/
@@ -65,7 +65,9 @@ function OverviewMediaPanelActions({
}
return (
<div className={`flex items-baseline gap-1.5${className ? ` ${className}` : ''}`}>
<div
className={`flex items-baseline gap-1.5${className ? ` ${className}` : ''}`}
>
{cta ? (
<Button
{...resolveBasecampInstallCtaLinkProps(cta)}
@@ -124,7 +126,9 @@ export function OverviewMediaPanel({
const footerMarker = footerLabel ?? (isCompact ? eyebrow : undefined)
const copyBody = (
<div className={`flex w-full min-w-0 flex-col gap-3 break-words${copyBodyClassName ? ` ${copyBodyClassName}` : ''}`}>
<div
className={`flex w-full min-w-0 flex-col gap-3 break-words${copyBodyClassName ? ` ${copyBodyClassName}` : ''}`}
>
<h2 className="text-h4-sans md:w-[377px]">
{hasMobileTitle ? (
<>
@@ -136,7 +140,7 @@ export function OverviewMediaPanel({
)}
</h2>
{mobileBody !== undefined && mobileBody.length > 0 ? (
<div className="flex max-w-full flex-col gap-3 text-[12px] leading-[1.2] font-medium text-brand-dark-green md:hidden">
<div className="flex max-w-full flex-col gap-3 text-xs leading-[1.2] font-medium text-brand-dark-green md:hidden">
{mobileBody.map((paragraph) => (
<p key={paragraph}>{paragraph}</p>
))}
@@ -144,7 +148,7 @@ export function OverviewMediaPanel({
) : null}
{body.length > 0 ? (
<div
className={`max-w-full flex-col gap-3 text-[12px] leading-[1.2] font-medium text-brand-dark-green md:w-[485px] ${
className={`max-w-full flex-col gap-3 text-xs leading-[1.2] font-medium text-brand-dark-green md:w-[485px] ${
hasMobileBody ? 'hidden md:flex' : 'flex'
}`}
>
@@ -1,11 +1,7 @@
import { TechDetailHero } from '@acid-info/logos-ui'
import type { HeroSection } from '@repo/content/schemas'
import {
Button,
ButtonArrowIcon,
type ButtonVariant,
} from '@/components/ui'
import { Button, ButtonArrowIcon, type ButtonVariant } from '@/components/ui'
import { Link } from '@/i18n/navigation'
import { resolveBasecampInstallCtaLinkProps } from '@/lib/basecamp-release-links'
@@ -53,7 +49,7 @@ export default function TechStackDetailHero({
<span className="inline-flex size-3.75 shrink-0 rotate-180 items-center justify-center">
<ButtonArrowIcon />
</span>
<span className="font-mono text-[10px] leading-[1.3] font-medium uppercase">
<span className="font-mono text-xs leading-[1.3] font-medium uppercase">
{data.eyebrow}
</span>
</Link>
@@ -38,7 +38,7 @@ function StackItemCta({
className={`inline-flex items-center justify-center rounded-xl bg-brand-dark-green px-3 py-2 text-brand-off-white backdrop-blur-[5px] ${className}`}
>
<span className="inline-flex items-center gap-1">
<span className="font-mono text-[10px] leading-[1.35] font-semibold whitespace-nowrap uppercase">
<span className="font-mono text-xs leading-[1.35] font-semibold whitespace-nowrap uppercase">
{children}
</span>
{icon}
@@ -234,7 +234,7 @@ function HoverStackItem({
key={detail.title}
className="flex h-[50px] items-center justify-center rounded-[18px] border border-brand-dark-green/50 px-2 text-brand-dark-green"
>
<p className="text-center font-mono text-[10px] leading-[1.3] font-medium uppercase">
<p className="text-center font-mono text-xs leading-[1.3] font-medium uppercase">
{detail.title}
</p>
</div>
@@ -248,10 +248,10 @@ function HoverStackItem({
key={detail.title}
className="rounded-[18px] border border-brand-dark-green/50 px-4 py-3 text-left text-brand-dark-green"
>
<p className="font-mono text-[10px] leading-[1.25] font-semibold tracking-[0.08em] uppercase">
<p className="font-mono text-xs leading-[1.25] font-semibold tracking-[0.08em] uppercase">
{detail.title}
</p>
<p className="mt-1.5 font-mono text-[10px] leading-[1.25]">
<p className="mt-1.5 font-mono text-xs leading-[1.25]">
{detail.body}
</p>
</div>
@@ -267,12 +267,7 @@ function HoverStackItem({
}
return (
<Link
href={href}
target={target}
rel={rel}
className={containerClassName}
>
<Link href={href} target={target} rel={rel} className={containerClassName}>
{content}
</Link>
)
@@ -40,7 +40,7 @@ export default function TechOverviewModular({ data }: Props) {
</h2>
{data.body && data.body.length > 0 ? (
<div className="mt-15 flex w-full flex-col gap-3 text-left text-[12px] leading-[1.2] font-medium text-brand-dark-green lg:mt-10">
<div className="mt-15 flex w-full flex-col gap-3 text-left text-xs leading-[1.2] font-medium text-brand-dark-green lg:mt-10">
{data.body.map((paragraph) => (
<p key={paragraph}>{paragraph}</p>
))}
@@ -5,6 +5,7 @@ import Image from 'next/image'
import type { ReactNode } from 'react'
import type { HomepageHighlight } from '@repo/content/schemas'
import { XIcon } from '@acid-info/logos-ui'
import { IconMask } from '@/components/icons/icon-mask'
import { ExternalLink } from '@/components/ui/external-link'
@@ -40,36 +41,53 @@ function HighlightLink({
export function HomepageHighlightCard({
data,
onDismiss,
}: {
data: HomepageHighlight
onDismiss: () => void
}) {
return (
<HighlightLink
href={data.cta.href}
<div
className={clsx(
'group absolute z-10 flex cursor-pointer rounded-[6px] transition-opacity hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2',
'top-2 left-3 w-[calc(100vw-24px)] max-w-none items-center gap-3 bg-gray-01 py-0.5 pr-1 pl-0.5 text-brand-dark-green focus-visible:outline-brand-dark-green',
'md:left-[119px] md:w-[calc(50vw-137px)] md:max-w-[345px] md:items-start md:gap-2 md:bg-gray-06 md:p-1 md:text-brand-off-white md:focus-visible:outline-brand-off-white'
'absolute top-2 left-3 z-10 w-[calc(100vw-24px)] max-w-none rounded-[6px] bg-gray-01 text-brand-dark-green',
'md:left-[119px] md:w-[calc(50vw-137px)] md:max-w-[345px] md:bg-gray-06 md:text-brand-off-white'
)}
>
<span className="relative h-[65px] w-[65px] shrink-0 overflow-hidden rounded-[4px] md:h-11 md:w-[37px]">
<Image
src={data.image.src}
alt={data.image.alt}
fill
sizes="(max-width: 767px) 65px, 37px"
className="object-cover"
/>
</span>
<span className="flex min-w-0 flex-1 flex-col items-start justify-center gap-[3px] py-1 md:justify-start md:py-0">
<span className="text-mono-s block w-full text-brand-dark-green md:text-brand-off-white">
{data.body}
<HighlightLink
href={data.cta.href}
className={clsx(
'group flex cursor-pointer items-center gap-3 rounded-[6px] py-0.5 pr-7 pl-0.5 transition-opacity hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-dark-green',
'md:items-start md:gap-2 md:p-1 md:focus-visible:outline-brand-off-white'
)}
>
<span className="relative h-[65px] w-[65px] shrink-0 overflow-hidden rounded-[4px] md:h-11 md:w-[37px]">
<Image
src={data.image.src}
alt={data.image.alt}
fill
sizes="(max-width: 767px) 65px, 37px"
className="object-cover"
/>
</span>
<span className="flex items-center gap-1 font-mono text-[10px] leading-[1.35] font-semibold text-brand-dark-green uppercase md:text-brand-off-white">
{data.cta.label}
<ArrowIcon />
<span className="flex min-w-0 flex-1 flex-col items-start justify-center gap-[3px] py-1 md:justify-start md:py-0">
<span className="block w-full font-mono-body text-[10px] leading-[1.3] text-brand-dark-green md:text-brand-off-white">
{data.body}
</span>
<span className="flex items-center gap-1 font-mono text-[10px] leading-[1.35] font-semibold text-brand-dark-green uppercase md:text-brand-off-white">
{data.cta.label}
<ArrowIcon />
</span>
</span>
</span>
</HighlightLink>
</HighlightLink>
<button
type="button"
onClick={onDismiss}
aria-label={data.dismissAriaLabel}
className="absolute top-1 right-1 z-10 inline-flex size-5 cursor-pointer items-center justify-center rounded-full border border-current transition-opacity hover:opacity-70 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2"
>
<XIcon size={12} />
</button>
</div>
)
}
@@ -57,10 +57,14 @@ export default function SiteHeaderClient({
null
)
const [hasPassedHero, setHasPassedHero] = useState(false)
const [isHomepageHighlightDismissed, setIsHomepageHighlightDismissed] =
useState(false)
const pathname = usePathname()
const normalizedPathname = pathname.replace(/\/$/, '') || ROUTES.home
const showHomepageHighlight =
normalizedPathname === ROUTES.home && homepageHighlight?.enabled === true
normalizedPathname === ROUTES.home &&
homepageHighlight?.enabled === true &&
!isHomepageHighlightDismissed
const usesHeroHeaderTone =
normalizedPathname === ROUTES.home ||
@@ -138,7 +142,10 @@ export default function SiteHeaderClient({
)}
>
{showHomepageHighlight ? (
<HomepageHighlightCard data={homepageHighlight} />
<HomepageHighlightCard
data={homepageHighlight}
onDismiss={() => setIsHomepageHighlightDismissed(true)}
/>
) : null}
<a
@@ -188,7 +195,10 @@ export default function SiteHeaderClient({
)}
>
{showHomepageHighlight ? (
<HomepageHighlightCard data={homepageHighlight} />
<HomepageHighlightCard
data={homepageHighlight}
onDismiss={() => setIsHomepageHighlightDismissed(true)}
/>
) : null}
<a
+1 -1
View File
@@ -93,7 +93,7 @@ export const EXTERNAL_URLS = {
// Social
twitter: 'https://twitter.com/logos_network',
twitterDevs: 'https://x.com/logos_devs',
discord: 'https://discord.gg/logosnetwork',
discord: 'https://discord.gg/Ykv4eZyHUJ',
youtube: 'https://youtube.com/@logos_network',
github: 'https://github.com/logos-co',
+1 -1
View File
@@ -48,7 +48,7 @@ const repoPressArticlePaths = [
'packages/content/src/schemas/press.ts',
].map((path) => join(repoRoot, path))
const jobsHref = 'https://free.technology/jobs'
const discordHref = 'https://discord.gg/logosnetwork'
const discordHref = 'https://discord.gg/Ykv4eZyHUJ'
const onboardingCalendarHref = 'https://cal.com/team/logos-onboarding/intro'
const logosDocsHref = 'https://docs.logos.co/'
const communityIdeasHref = 'https://github.com/logos-co/ideas'
@@ -17,5 +17,5 @@
"featured": false,
"order": 6,
"submittedAt": "2026-03-04T00:00:00Z",
"discussionUrl": "https://discord.gg/logosnetwork"
"discussionUrl": "https://discord.gg/Ykv4eZyHUJ"
}
@@ -17,5 +17,5 @@
"featured": false,
"order": 7,
"submittedAt": "2026-03-12T00:00:00Z",
"discussionUrl": "https://discord.gg/logosnetwork"
"discussionUrl": "https://discord.gg/Ykv4eZyHUJ"
}
@@ -16,5 +16,5 @@
"featured": false,
"order": 2,
"submittedAt": "2026-01-22T00:00:00Z",
"discussionUrl": "https://discord.gg/logosnetwork"
"discussionUrl": "https://discord.gg/Ykv4eZyHUJ"
}
@@ -16,5 +16,5 @@
"featured": false,
"order": 5,
"submittedAt": "2026-02-26T00:00:00Z",
"discussionUrl": "https://discord.gg/logosnetwork"
"discussionUrl": "https://discord.gg/Ykv4eZyHUJ"
}
@@ -17,5 +17,5 @@
"featured": false,
"order": 3,
"submittedAt": "2026-02-09T00:00:00Z",
"discussionUrl": "https://discord.gg/logosnetwork"
"discussionUrl": "https://discord.gg/Ykv4eZyHUJ"
}
@@ -17,5 +17,5 @@
"featured": false,
"order": 4,
"submittedAt": "2026-02-18T00:00:00Z",
"discussionUrl": "https://discord.gg/logosnetwork"
"discussionUrl": "https://discord.gg/Ykv4eZyHUJ"
}
@@ -17,5 +17,5 @@
"featured": true,
"order": 1,
"submittedAt": "2026-01-04T00:00:00Z",
"discussionUrl": "https://discord.gg/logosnetwork"
"discussionUrl": "https://discord.gg/Ykv4eZyHUJ"
}
+2 -2
View File
@@ -7,7 +7,7 @@
"breadcrumbLabel": "Ideas",
"submitCta": {
"label": "Submit an idea",
"href": "https://discord.gg/logosnetwork",
"href": "https://discord.gg/Ykv4eZyHUJ",
"external": true
},
"defaultView": "list",
@@ -20,7 +20,7 @@
"title": "We want your ideas.",
"cta": {
"label": "Submit an idea",
"href": "https://discord.gg/logosnetwork",
"href": "https://discord.gg/Ykv4eZyHUJ",
"external": true
}
}
+2 -2
View File
@@ -7,7 +7,7 @@
"breadcrumbLabel": "RFPs",
"submitCta": {
"label": "Submit an RFP",
"href": "https://discord.gg/logosnetwork",
"href": "https://discord.gg/Ykv4eZyHUJ",
"external": true
},
"defaultView": "grid",
@@ -20,7 +20,7 @@
"title": "Have a build idea worth funding?",
"cta": {
"label": "Submit an RFP",
"href": "https://discord.gg/logosnetwork",
"href": "https://discord.gg/Ykv4eZyHUJ",
"external": true
}
}
@@ -3,7 +3,7 @@
"slug": "attack-resistant-public-registries",
"status": "published",
"reward": { "amount": 3000, "currency": "USDC", "xp": 1200 },
"applyUrl": "https://discord.gg/logosnetwork",
"applyUrl": "https://discord.gg/Ykv4eZyHUJ",
"tags": ["registry", "censorship-resistance", "consensus"],
"image": {
"src": "/cms/builders-hub/rfps/attack-resistant-public-registries/cover.webp",
@@ -3,7 +3,7 @@
"slug": "build-a-dex",
"status": "published",
"reward": { "amount": 5000, "currency": "USDC", "xp": 1500 },
"applyUrl": "https://discord.gg/logosnetwork",
"applyUrl": "https://discord.gg/Ykv4eZyHUJ",
"tags": ["defi", "trading", "ux"],
"image": {
"src": "/cms/builders-hub/rfps/build-a-dex/cover.webp",
@@ -3,7 +3,7 @@
"slug": "community-governance-tooling",
"status": "published",
"reward": { "amount": 1800, "currency": "USDC", "xp": 600 },
"applyUrl": "https://discord.gg/logosnetwork",
"applyUrl": "https://discord.gg/Ykv4eZyHUJ",
"tags": ["governance", "circles", "voting"],
"image": {
"src": "/cms/builders-hub/rfps/community-governance-tooling/cover.webp",
@@ -3,7 +3,7 @@
"slug": "decentralised-archives",
"status": "published",
"reward": { "amount": 2000, "currency": "USDC", "xp": 800 },
"applyUrl": "https://discord.gg/logosnetwork",
"applyUrl": "https://discord.gg/Ykv4eZyHUJ",
"tags": ["archives", "preservation", "codex"],
"image": {
"src": "/cms/builders-hub/rfps/decentralised-archives/cover.webp",
@@ -3,7 +3,7 @@
"slug": "integrate-fileverse",
"status": "published",
"reward": { "amount": 1500, "currency": "USDC", "xp": 500 },
"applyUrl": "https://discord.gg/logosnetwork",
"applyUrl": "https://discord.gg/Ykv4eZyHUJ",
"tags": ["files", "collaboration", "integration"],
"image": {
"src": "/cms/builders-hub/rfps/integrate-fileverse/cover.webp",
@@ -3,7 +3,7 @@
"slug": "private-financial-networks",
"status": "published",
"reward": { "amount": 4000, "currency": "USDC", "xp": 1500 },
"applyUrl": "https://discord.gg/logosnetwork",
"applyUrl": "https://discord.gg/Ykv4eZyHUJ",
"tags": ["payments", "privacy", "circles"],
"image": {
"src": "/cms/builders-hub/rfps/private-financial-networks/cover.webp",
@@ -3,7 +3,7 @@
"slug": "secure-decentralised-frontends",
"status": "published",
"reward": { "amount": 2500, "currency": "USDC", "xp": 1000 },
"applyUrl": "https://discord.gg/logosnetwork",
"applyUrl": "https://discord.gg/Ykv4eZyHUJ",
"tags": ["frontend", "privacy", "infrastructure"],
"image": {
"src": "/cms/builders-hub/rfps/secure-decentralised-frontends/cover.webp",
+6 -6
View File
@@ -12,7 +12,7 @@
"secondaryCtas": [
{
"label": "Join Discord",
"href": "https://discord.gg/logosnetwork",
"href": "https://discord.gg/Ykv4eZyHUJ",
"external": true
},
{
@@ -174,7 +174,7 @@
],
"cta": {
"label": "Add to calendar",
"href": "https://discord.gg/logosnetwork",
"href": "https://discord.gg/Ykv4eZyHUJ",
"external": true
}
},
@@ -208,7 +208,7 @@
"description": "Chat with us and get real time support.",
"cta": {
"label": "Join",
"href": "https://discord.gg/logosnetwork",
"href": "https://discord.gg/Ykv4eZyHUJ",
"external": true
}
},
@@ -274,7 +274,7 @@
"seeAllCta": { "label": "Explore RFPs", "href": "/builders-hub/rfps" },
"submitCta": {
"label": "Submit an RFP",
"href": "https://discord.gg/logosnetwork",
"href": "https://discord.gg/Ykv4eZyHUJ",
"external": true
},
"displayCount": 8,
@@ -301,7 +301,7 @@
"seeAllCta": { "label": "See all ideas", "href": "/builders-hub/ideas" },
"submitCta": {
"label": "Submit an idea",
"href": "https://discord.gg/logosnetwork",
"href": "https://discord.gg/Ykv4eZyHUJ",
"external": true
},
"displayCount": 7
@@ -357,7 +357,7 @@
"description": "Talk to Logos core contributors.",
"cta": {
"label": "Join",
"href": "https://discord.gg/logosnetwork",
"href": "https://discord.gg/Ykv4eZyHUJ",
"external": true
}
},
@@ -9,7 +9,7 @@
"timezone": "America/Sao_Paulo",
"memberCount": 38,
"discordChannel": "circle-florianopolis",
"discordUrl": "https://discord.gg/logosnetwork",
"discordUrl": "https://discord.gg/Ykv4eZyHUJ",
"forumUrl": "https://forum.logos.co/",
"joinUrl": "/circles#resources",
"image": {
+1 -1
View File
@@ -9,7 +9,7 @@
"timezone": "Europe/London",
"memberCount": 112,
"discordChannel": "circle-london",
"discordUrl": "https://discord.gg/logosnetwork",
"discordUrl": "https://discord.gg/Ykv4eZyHUJ",
"forumUrl": "https://forum.logos.co/",
"joinUrl": "/circles#resources",
"image": {
+1 -1
View File
@@ -8,7 +8,7 @@
"timezone": "Europe/Lisbon",
"memberCount": 47,
"discordChannel": "circle-porto",
"discordUrl": "https://discord.gg/logosnetwork",
"discordUrl": "https://discord.gg/Ykv4eZyHUJ",
"forumUrl": "https://forum.logos.co/",
"joinUrl": "/circles#resources",
"image": {
+1 -1
View File
@@ -146,7 +146,7 @@
"label": "Connect with Logos",
"body": "Join the community channels for implementation support and feedback.",
"action": "Connect",
"href": "https://discord.gg/logosnetwork"
"href": "https://discord.gg/Ykv4eZyHUJ"
}
]
}
+1 -1
View File
@@ -30,7 +30,7 @@
},
{
"label": "Discord",
"href": "https://discord.gg/logosnetwork",
"href": "https://discord.gg/Ykv4eZyHUJ",
"external": true
},
{
+3 -2
View File
@@ -19,6 +19,7 @@
"homepageHighlight": {
"enabled": true,
"body": "Testnet v0.2 is live for experimentation. Introducing improvements to the entire stack.",
"dismissAriaLabel": "Dismiss announcement",
"cta": {
"label": "Learn More",
"href": "https://blog.logos.co/article/testnet-v02-live"
@@ -71,7 +72,7 @@
{ "label": "Events", "href": "https://luma.com/logosevents" },
{
"label": "Join Community",
"href": "https://discord.gg/logosnetwork"
"href": "https://discord.gg/Ykv4eZyHUJ"
},
{ "label": "Install Basecamp", "href": "/basecamp" },
{ "label": "Work with us", "href": "https://free.technology/jobs" }
@@ -127,7 +128,7 @@
{
"label": "Socials",
"links": [
{ "label": "Discord", "href": "https://discord.gg/logosnetwork" },
{ "label": "Discord", "href": "https://discord.gg/Ykv4eZyHUJ" },
{ "label": "X", "href": "https://twitter.com/logos_network" },
{
"label": "YouTube",
+1 -1
View File
@@ -14,7 +14,7 @@
],
"social": {
"twitter": "https://twitter.com/logos_network",
"discord": "https://discord.gg/logosnetwork",
"discord": "https://discord.gg/Ykv4eZyHUJ",
"youtube": "https://youtube.com/@logos_network",
"github": "https://github.com/logos-co"
}
+1
View File
@@ -17,6 +17,7 @@ export type NavLink = z.infer<typeof navLinkSchema>
export const homepageHighlightSchema = z.object({
enabled: z.boolean(),
body: z.string().min(1),
dismissAriaLabel: z.string().min(1),
cta: navLinkSchema,
image: mediaRefSchema,
})
+2 -2
View File
@@ -153,7 +153,7 @@
@utility text-eyebrow {
font-family: var(--font-mono);
font-weight: 500; /* Fira Code Medium */
font-size: 0.625rem; /* 10px */
font-size: 0.75rem; /* 12px */
line-height: 1.3;
letter-spacing: 0;
text-transform: uppercase;
@@ -162,7 +162,7 @@
@utility text-mono-s {
font-family: var(--font-mono-body);
font-weight: 400; /* Fira Mono Regular */
font-size: 0.625rem; /* 10px */
font-size: 0.75rem; /* 12px */
line-height: 1.3;
letter-spacing: 0;
}
+1 -1
View File
@@ -100,7 +100,7 @@ export function Button(props: ButtonProps) {
)
const isLink = variant === 'link'
const labelClass = `font-mono text-[10px] leading-[1.35] font-semibold uppercase whitespace-nowrap ${
const labelClass = `font-mono text-xs leading-[1.35] font-semibold uppercase whitespace-nowrap ${
isLink ? 'border-b border-brand-dark-green/50 pb-0.5' : ''
}`
+4 -4
View File
@@ -118,7 +118,7 @@ export function Card({
</div>
{description && (
<p
className={`max-w-[222px] text-center font-mono text-[10px] leading-[1.3] text-brand-dark-green transition-opacity duration-200 ${revealClass}`}
className={`max-w-[222px] text-center font-mono text-xs leading-[1.3] text-brand-dark-green transition-opacity duration-200 ${revealClass}`}
>
{description}
</p>
@@ -149,7 +149,7 @@ function CardCTA({
const className =
'absolute top-3 right-3 z-10 inline-flex items-center rounded-xl bg-brand-dark-green px-3 py-2 backdrop-blur-[5px]'
const content = (
<span className="font-mono text-[10px] leading-[1.35] font-semibold text-brand-off-white uppercase">
<span className="font-mono text-xs leading-[1.35] font-semibold text-brand-off-white uppercase">
{label}
</span>
)
@@ -194,10 +194,10 @@ export function CardInfo({
: 'flex flex-col gap-0.5'
}
>
<p className="font-mono text-[10px] leading-[1.3] font-medium text-brand-dark-green uppercase">
<p className="font-mono text-xs leading-[1.3] font-medium text-brand-dark-green uppercase">
{label}
</p>
<p className="font-mono text-[10px] leading-[1.3] text-brand-dark-green">
<p className="font-mono text-xs leading-[1.3] text-brand-dark-green">
{description}
</p>
</div>
@@ -240,7 +240,7 @@ function ActionCard({
</span>
</div>
<div className="flex items-end justify-between gap-4">
<p className="max-w-[326px] font-sans text-[12px] font-medium leading-[1.2]">
<p className="max-w-[326px] font-sans text-xs font-medium leading-[1.2]">
{description}
</p>
</div>
@@ -278,7 +278,7 @@ function MenuCard({
<p className="mr-[54px] max-w-[148px] font-sans text-[14px] leading-[1.2]">
{label}
</p>
<p className="font-sans text-[12px] font-medium leading-[1.2] text-brand-off-white/50">
<p className="font-sans text-xs font-medium leading-[1.2] text-brand-off-white/50">
{description}
</p>
{imageNodes.length > 0 && (
+3 -3
View File
@@ -32,7 +32,7 @@ export function Table({
</div>
<div className="flex flex-1 items-start gap-6">
{subtitle && (
<p className="max-w-[226px] font-mono text-[10px] leading-[1.3] text-brand-dark-green">
<p className="max-w-[226px] font-mono text-xs leading-[1.3] text-brand-dark-green">
{subtitle}
</p>
)}
@@ -85,12 +85,12 @@ export function TableRow({
</div>
{/* Description — 464/1440 */}
<div className="hidden flex-[464] font-mono text-[10px] leading-[1.3] text-brand-dark-green md:block [&>p]:leading-[1.3]">
<div className="hidden flex-[464] font-mono text-xs leading-[1.3] text-brand-dark-green md:block [&>p]:leading-[1.3]">
{description}
</div>
{/* Reward — fixed 107px */}
<div className="hidden w-[107px] shrink-0 font-mono text-[10px] leading-[1.3] text-brand-dark-green md:block [&>p]:leading-[1.3]">
<div className="hidden w-[107px] shrink-0 font-mono text-xs leading-[1.3] text-brand-dark-green md:block [&>p]:leading-[1.3]">
{reward}
</div>