Compare commits

..

2 Commits

Author SHA1 Message Date
SeekingGamer
dbda554d28 fix(style): Seperate CSS style to src\styles 2026-05-13 13:46:21 +08:00
SeekingGamer
93049e9044 style: Seperate and Reformat inline style into css seperate files 2026-05-13 11:48:22 +08:00
24 changed files with 2921 additions and 477 deletions

View File

@@ -1,4 +1,11 @@
---
import type { Translations } from '../i18n/translations'
export interface Props {
t: Translations['preview']
}
const { t } = Astro.props
const slides = [
"/assets/preview-phone.png",
"/assets/preview-phone.png",
@@ -6,68 +13,56 @@ const slides = [
]
---
<section class="bg-[#fef0eb] w-full flex flex-col gap-[60px] items-center pt-16 lg:pt-[120px] px-4 lg:px-[130px] overflow-hidden">
<!-- Heading -->
<div class="flex flex-col gap-[40px] items-start overflow-clip w-full max-w-[940px] mx-auto">
<p class="font-bold text-[#1a1a1a] text-[32px] md:text-[40px] lg:text-[48px] text-center tracking-[-1.16px] leading-[1.2] w-full">
A Familiar App Experience, Reimagined with a Modern Look
<section class="app-preview">
<div class="app-preview__header">
<p class="app-preview__title">
{t.title}
</p>
<p class="font-normal text-[#7a726d] text-[18px] text-center tracking-[-0.33px] leading-[1.5] w-full">
TalkPro keeps the communication experience familiar while refining the visual layer with updated icons, colors, spacing, and interface details.
<p class="app-preview__description">
{t.description}
</p>
</div>
<!-- Carousel -->
<div class="flex gap-[20px] items-end justify-center shrink-0 w-full" id="carousel">
<!-- Left phone (hidden on mobile) -->
<div class="hidden lg:block relative h-[396px] w-[336px] opacity-20 shrink-0 overflow-hidden pointer-events-none transition-opacity duration-300">
<img id="phone-left" alt="" class="absolute h-[175.34%] left-0 max-w-none top-[-0.03%] w-full transition-opacity duration-300" src={slides[slides.length - 1]} />
<div class="app-preview__carousel" id="carousel">
<div class="app-preview__side-phone">
<img id="phone-left" alt="" class="app-preview__phone-image" src={slides[slides.length - 1]} />
</div>
<!-- Prev button (hidden on mobile) -->
<div class="hidden lg:flex items-end self-stretch shrink-0">
<div class="flex items-center justify-center h-full">
<button id="btn-prev" class="bg-[#f08458] flex items-center justify-center rounded-[9999px] size-[48px] hover:bg-[#e07a3b] active:scale-95 transition-all shrink-0 cursor-pointer">
<img alt="Previous" class="block size-[24px]" src="/assets/preview-arrow-left.svg" />
<div class="app-preview__control-wrap">
<div class="app-preview__control-inner">
<button id="btn-prev" class="app-preview__button">
<img alt={t.previous} class="app-preview__button-icon" src="/assets/preview-arrow-left.svg" />
</button>
</div>
</div>
<!-- Center phone -->
<div class="relative w-full lg:w-[459px] aspect-[459/542] lg:aspect-auto lg:h-[542px] shrink-0 overflow-hidden pointer-events-none">
<img id="phone-center" alt="TalkPro app preview" class="absolute h-[175.34%] left-0 max-w-none top-[-0.03%] w-full transition-opacity duration-300" src={slides[0]} />
<div class="app-preview__center-phone">
<img id="phone-center" alt={t.phoneAlt} class="app-preview__phone-image" src={slides[0]} />
</div>
<!-- Next button (hidden on mobile) -->
<div class="hidden lg:flex items-end self-stretch shrink-0">
<div class="flex items-center justify-center h-full">
<button id="btn-next" class="bg-[#f08458] flex items-center justify-center rounded-[9999px] size-[48px] hover:bg-[#e07a3b] active:scale-95 transition-all shrink-0 cursor-pointer">
<img alt="Next" class="block size-[24px] rotate-180" src="/assets/preview-arrow-right.svg" />
<div class="app-preview__control-wrap">
<div class="app-preview__control-inner">
<button id="btn-next" class="app-preview__button">
<img alt={t.next} class="app-preview__button-icon app-preview__button-icon--next" src="/assets/preview-arrow-right.svg" />
</button>
</div>
</div>
<!-- Right phone (hidden on mobile) -->
<div class="hidden lg:block relative h-[396px] w-[336px] opacity-20 shrink-0 overflow-hidden pointer-events-none transition-opacity duration-300">
<img id="phone-right" alt="" class="absolute h-[175.34%] left-0 max-w-none top-[-0.03%] w-full transition-opacity duration-300" src={slides[1]} />
<div class="app-preview__side-phone">
<img id="phone-right" alt="" class="app-preview__phone-image" src={slides[1]} />
</div>
</div>
</section>
<script>
const slides: string[] = (window as any).__carouselSlides || [];
// Read slides injected via data attribute
const carousel = document.getElementById('carousel')!;
const allSlides: string[] = JSON.parse(carousel.dataset.slides || '[]');
const leftImg = document.getElementById('phone-left') as HTMLImageElement;
const leftImg = document.getElementById('phone-left') as HTMLImageElement;
const centerImg = document.getElementById('phone-center') as HTMLImageElement;
const rightImg = document.getElementById('phone-right') as HTMLImageElement;
const btnPrev = document.getElementById('btn-prev')!;
const btnNext = document.getElementById('btn-next')!;
const rightImg = document.getElementById('phone-right') as HTMLImageElement;
const btnPrev = document.getElementById('btn-prev')!;
const btnNext = document.getElementById('btn-next')!;
let current = 0;
@@ -77,9 +72,9 @@ const slides = [
[leftImg, centerImg, rightImg].forEach(img => img && (img.style.opacity = '0'));
setTimeout(() => {
current = mod(next, allSlides.length);
if (leftImg) leftImg.src = allSlides[mod(current - 1, allSlides.length)];
if (leftImg) leftImg.src = allSlides[mod(current - 1, allSlides.length)];
if (centerImg) centerImg.src = allSlides[current];
if (rightImg) rightImg.src = allSlides[mod(current + 1, allSlides.length)];
if (rightImg) rightImg.src = allSlides[mod(current + 1, allSlides.length)];
[leftImg, centerImg, rightImg].forEach(img => img && (img.style.opacity = '1'));
}, 200);
}

View File

@@ -1,47 +1,44 @@
---
const halftone = "/assets/core-halftone-bg.png";
const iconPrivate = "/assets/core-icon-private.png";
const iconGroups = "/assets/core-icon-groups.png";
const iconChannels = "/assets/core-icon-channels.png";
const iconVoice = "/assets/core-icon-voice.png";
const iconVideo = "/assets/core-icon-video.png";
const iconMedia = "/assets/core-icon-media.png";
import type { Translations } from '../i18n/translations'
const cards = [
{ img: iconPrivate, title: 'Private Messaging', desc: 'Stay connected through fast and familiar one-on-one conversations.' },
{ img: iconGroups, title: 'Group Chats', desc: 'Create spaces for friends, teams, communities, and shared discussions.' },
{ img: iconChannels, title: 'Channels', desc: 'Follow updates, announcements, and content from the people or communities you care about.' },
{ img: iconVoice, title: 'Voice Calls', desc: 'Talk in real time whenever messages are not enough.' },
{ img: iconVideo, title: 'Video Calls', desc: 'Connect face-to-face with a simple and reliable video call experience.' },
{ img: iconMedia, title: 'Media Sharing', desc: 'Share photos, videos, files, and updates in your conversations.' },
export interface Props {
t: Translations['core']
}
const { t } = Astro.props
const halftone = "/assets/core-halftone-bg.png";
const icons = [
"/assets/core-icon-private.png",
"/assets/core-icon-groups.png",
"/assets/core-icon-channels.png",
"/assets/core-icon-voice.png",
"/assets/core-icon-video.png",
"/assets/core-icon-media.png",
]
---
<section id="features" class="relative w-full flex flex-col gap-[60px] items-center py-16 lg:py-[120px] overflow-hidden">
<!-- Background halftone -->
<img alt="" class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 h-[1319px] w-[2363px] object-cover pointer-events-none opacity-20" src={halftone} />
<section id="features" class="features">
<img alt="" class="features__bg" src={halftone} />
<!-- Section header -->
<div class="relative flex flex-col gap-[24px] items-center justify-end overflow-clip w-full max-w-[1280px] mx-auto px-4 lg:px-[180px]">
<div class="bg-white border border-[#fbbfa3] flex items-center justify-center px-[24px] py-[12px] rounded-[9999px] shrink-0">
<span class="font-bold text-[#f08458] text-[14px] text-center tracking-[-0.04px] whitespace-nowrap leading-normal">CORE FEATURES</span>
<div class="features__header">
<div class="section-eyebrow">
<span class="section-eyebrow__text">{t.eyebrow}</span>
</div>
<p class="font-bold text-[#1a1a1a] text-[32px] md:text-[40px] lg:text-[48px] text-center tracking-[-1.16px] leading-[1.2] w-full">Everything You Need to Communicate</p>
<p class="font-normal text-[#7a726d] text-[18px] text-center tracking-[-0.33px] leading-[1.5] w-full">
Different identities, different conversations, and different privacy levels should not be forced into one flat interface. TalkPro lets them exist in order inside one platform.
<p class="features__title">{t.title}</p>
<p class="features__description">
{t.description}
</p>
</div>
<!-- Card grid -->
<div class="relative grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-[22px] w-full max-w-[1280px] mx-auto px-4 lg:px-0">
{cards.map(card => (
<div class="bg-[rgba(255,255,255,0.78)] flex flex-col gap-[16px] items-center p-[32px] rounded-[30px]">
<div class="relative shrink-0 size-[160px] overflow-hidden">
<img alt={card.title} class="absolute inset-0 max-w-none size-full object-contain" src={card.img} />
<div class="features__grid">
{t.cards.map((card, index) => (
<div class="feature-card">
<div class="feature-card__icon-frame">
<img alt={card.title} class="feature-card__icon" src={icons[index]} />
</div>
<div class="flex flex-col gap-[12px] items-start text-center w-full">
<p class="font-bold text-[#2e2a28] text-[24px] tracking-[-0.5px] leading-normal w-full">{card.title}</p>
<p class="font-normal text-[#7a726d] text-[15px] tracking-[-0.13px] leading-[1.5] w-full">{card.desc}</p>
<div class="feature-card__copy">
<p class="feature-card__title">{card.title}</p>
<p class="feature-card__description">{card.desc}</p>
</div>
</div>
))}

View File

@@ -1,4 +1,11 @@
---
import type { Translations } from '../i18n/translations'
export interface Props {
t: Translations['download']
}
const { t } = Astro.props
const bgPattern = "/assets/cta-bg-pattern.svg";
const talkproLogo = "/assets/cta-talkpro-logo.svg";
const androidIcon = "/assets/cta-android-icon.svg";
@@ -6,54 +13,50 @@ const appleIcon = "/assets/cta-apple-icon.svg";
const phoneArt = "/assets/cta-phone-art.png";
---
<section id="download" class="relative bg-white border-t border-[#eec8b8] w-full flex items-center justify-center overflow-hidden min-h-[400px] lg:h-[600px]">
<!-- Background pattern -->
<img alt="" class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 h-[923px] w-full max-w-[1920px] pointer-events-none" src={bgPattern} />
<section id="download" class="download-cta">
<img alt="" class="download-cta__pattern" src={bgPattern} />
<div class="relative flex flex-col lg:flex-row items-center gap-8 lg:gap-0 w-full max-w-[1280px] mx-auto px-4 lg:px-0 py-12 lg:py-0">
<!-- Left: download panel -->
<div class="flex flex-1 flex-col gap-[36px] items-start justify-center min-w-0 overflow-clip">
<div class="bg-white border border-[#fbbfa3] flex items-center justify-center px-[24px] py-[12px] rounded-[9999px] shrink-0">
<span class="font-bold text-[#f08458] text-[14px] text-center tracking-[-0.04px] whitespace-nowrap leading-normal">DOWNLOAD</span>
<div class="download-cta__inner">
<div class="download-cta__content">
<div class="section-eyebrow">
<span class="section-eyebrow__text">{t.eyebrow}</span>
</div>
<div class="flex flex-col gap-[16px] items-start w-full">
<div class="flex gap-[20px] items-start shrink-0 flex-wrap">
<p class="font-bold text-[#1a1a1a] text-[32px] md:text-[40px] lg:text-[48px] tracking-[-1.16px] leading-[1.2] whitespace-nowrap">Download</p>
<div class="relative shrink-0 h-[72px] w-[188px]">
<img alt="TalkPro" class="absolute inset-0 block max-w-none size-full" src={talkproLogo} />
<div class="download-cta__copy">
<div class="download-cta__heading">
<p class="download-cta__title">{t.title}</p>
<div class="download-cta__logo-frame">
<img alt={t.logoAlt} class="download-cta__logo" src={talkproLogo} />
</div>
</div>
<p class="font-normal text-[#7a726d] text-[18px] tracking-[-0.33px] leading-[1.5] max-w-[542px]">
Download TalkPro and experience a cleaner, simpler, and more modern way to stay connected.
<p class="download-cta__description">
{t.description}
</p>
</div>
<!-- Store badges -->
<div class="flex flex-wrap gap-[16px] items-center overflow-clip shrink-0 w-full">
<div class="bg-[#f28a4b] border border-[#c5834e] flex gap-[8px] h-[70px] items-center overflow-clip px-[16px] py-[12px] rounded-[20px] w-full sm:w-[260px] shrink-0">
<img alt="Android" class="block shrink-0 size-[44px]" src={androidIcon} />
<div class="flex flex-col gap-[3px] items-start overflow-clip shrink-0 whitespace-nowrap">
<p class="font-semibold text-[#ffd6bc] text-[11px] tracking-[0.05px] leading-normal">ANDROID</p>
<p class="font-semibold text-white text-[15px] tracking-[-0.13px] leading-normal">APK Coming Soon</p>
<div class="store-badges">
<div class="store-badge store-badge--android">
<img alt={t.androidAlt} class="store-badge__icon" src={androidIcon} />
<div class="store-badge__copy">
<p class="store-badge__platform">{t.android}</p>
<p class="store-badge__label">{t.androidCta}</p>
</div>
</div>
<div class="bg-[#383838] border border-[#141414] flex gap-[8px] h-[70px] items-center overflow-clip px-[16px] py-[12px] rounded-[20px] w-full sm:w-[260px] shrink-0">
<div class="bg-[#151515] flex items-center justify-center rounded-[12px] shrink-0 size-[44px]">
<img alt="Apple" class="block h-[27px] w-[22px]" src={appleIcon} />
<div class="store-badge store-badge--ios">
<div class="store-badge__icon-frame">
<img alt={t.appleAlt} class="store-badge__apple-icon" src={appleIcon} />
</div>
<div class="flex flex-col gap-[3px] items-start overflow-clip shrink-0 whitespace-nowrap">
<p class="font-semibold text-[#ccc] text-[11px] tracking-[0.05px] leading-normal">IOS</p>
<p class="font-semibold text-white text-[15px] tracking-[-0.13px] leading-normal">Coming on App Store</p>
<div class="store-badge__copy">
<p class="store-badge__platform">{t.ios}</p>
<p class="store-badge__label">{t.iosCta}</p>
</div>
</div>
</div>
</div>
<!-- Right: phone art (hidden on mobile) -->
<div class="hidden lg:block relative shrink-0 h-[510px] w-[418px]">
<div class="absolute inset-0 overflow-hidden pointer-events-none">
<img alt="TalkPro on phone" class="absolute h-[136.1%] left-[3.8%] max-w-none top-[-18.05%] w-[92.43%]" src={phoneArt} />
<div class="download-cta__phone">
<div class="download-cta__phone-crop">
<img alt={t.phoneAlt} class="download-cta__phone-image" src={phoneArt} />
</div>
</div>
</div>

View File

@@ -1,64 +1,44 @@
---
import type { Translations } from '../i18n/translations'
export interface Props {
t: Translations['experience']
}
const { t } = Astro.props
const images = ["/assets/exp-card-1.png", "/assets/exp-card-2.png", "/assets/exp-card-3.png"]
const imageClasses = ['experience-card__image--one', 'experience-card__image--two', 'experience-card__image--three']
---
<section id="experience" class="bg-white w-full flex flex-col items-center justify-center py-16 lg:py-[120px]">
<div class="flex flex-col gap-[40px] items-center justify-center w-full max-w-[1008px] mx-auto px-4 lg:px-0">
<p class="font-bold text-[#1a1a1a] text-[32px] md:text-[40px] lg:text-[48px] text-center tracking-[-1.16px] leading-[1.2] w-full">
A Cleaner, More Comfortable Messaging Experience
<section id="experience" class="experience">
<div class="experience__inner">
<p class="experience__title">
{t.title}
</p>
<div class="flex flex-col items-start w-full">
<!-- 3 cards row -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 w-full">
<!-- Card 1: Clear Interface -->
<div class="bg-gradient-to-b from-[#fef0eb] to-white flex flex-col gap-[36px] items-center overflow-clip pb-[36px] px-[36px] rounded-tl-[30px] rounded-tr-[30px] w-full">
<div class="relative h-[232px] shrink-0 w-full">
<div class="absolute inset-0 overflow-hidden pointer-events-none">
<img alt="Clear interface screenshot" class="absolute h-[298.5%] left-0 max-w-none top-[-58.58%] w-full" src="/assets/exp-card-1.png" />
</div>
</div>
<div class="flex flex-col gap-[16px] items-start overflow-clip text-center w-full">
<p class="font-semibold text-[#0d0d0d] text-[24px] tracking-[-0.47px] leading-[1.4] w-full">Clear Interface</p>
<p class="font-medium text-[#7a726d] text-[16px] tracking-[-0.18px] leading-[1.5] w-full">A clean layout that makes conversations easy to follow.</p>
</div>
</div>
<!-- Card 2: Smooth Navigation -->
<div class="bg-gradient-to-b from-[#fef0eb] to-white flex flex-col gap-[36px] items-center overflow-clip pb-[36px] px-[36px] rounded-tl-[30px] rounded-tr-[30px] w-full">
<div class="bg-[#ffeddf] flex flex-col items-start w-full">
<div class="relative h-[232px] shrink-0 w-full">
<div class="absolute inset-0 overflow-hidden pointer-events-none">
<img alt="Smooth navigation screenshot" class="absolute h-[411.28%] left-[-5.95%] max-w-none top-[-335.6%] w-[137.79%]" src="/assets/exp-card-2.png" />
<div class="experience__body">
<div class="experience__grid">
{t.cards.map((card, index) => (
<div class="experience-card">
<div class={`experience-card__media ${index > 0 ? 'experience-card__media--tinted' : ''}`}>
<div class="experience-card__media-crop">
<img
alt={card.alt}
class={`experience-card__image ${imageClasses[index]}`}
src={images[index]}
/>
</div>
</div>
</div>
<div class="flex flex-col gap-[16px] items-start overflow-clip text-center w-full">
<p class="font-semibold text-[#0d0d0d] text-[24px] tracking-[-0.47px] leading-[1.4] w-full">Smooth Navigation</p>
<p class="font-medium text-[#7a726d] text-[16px] tracking-[-0.18px] leading-[1.5] w-full">Move between chats, groups, and channels with familiar controls.</p>
</div>
</div>
<!-- Card 3: Refined Visual Design -->
<div class="bg-gradient-to-b from-[#fef0eb] to-white flex flex-col gap-[36px] items-center overflow-clip pb-[36px] px-[36px] rounded-tl-[30px] rounded-tr-[30px] w-full">
<div class="bg-[#ffeddf] flex flex-col h-[232px] items-start overflow-clip w-full">
<div class="flex-1 min-h-0 relative w-full">
<div class="absolute inset-0 overflow-hidden pointer-events-none">
<img alt="Refined visual design screenshot" class="absolute h-[298.5%] left-0 max-w-none top-[-99.23%] w-full" src="/assets/exp-card-3.png" />
</div>
<div class="experience-card__copy">
<p class="experience-card__title">{card.title}</p>
<p class="experience-card__description">{card.desc}</p>
</div>
</div>
<div class="flex flex-col gap-[16px] items-start overflow-clip text-center w-full">
<p class="font-semibold text-[#0d0d0d] text-[24px] tracking-[-0.47px] leading-[1.4] w-full">Refined Visual Design</p>
<p class="font-medium text-[#7a726d] text-[16px] tracking-[-0.18px] leading-[1.5] w-full">Modern icons, colors, and interface details create a more polished experience.</p>
</div>
</div>
))}
</div>
<!-- Footer caption -->
<p class="font-normal text-[#7a726d] text-[18px] text-center tracking-[-0.33px] leading-[1.5] w-full mt-0">
TalkPro is designed with clarity in mind. Every screen is built to help users focus on their conversations, reduce distractions, and move naturally between chats, groups, channels, and calls.
<p class="experience__caption">
{t.caption}
</p>
</div>
</div>

View File

@@ -1,65 +1,66 @@
---
import type { Translations } from '../i18n/translations'
export interface Props {
t: Translations['footer']
}
const { t } = Astro.props
const logoFull = "/assets/footer-logo.png";
const androidIcon = "/assets/footer-android-icon.svg";
const appleIcon = "/assets/footer-apple-icon.svg";
---
<footer class="bg-[#fef0eb] w-full flex flex-col items-center justify-center py-16 lg:py-[120px]">
<div class="flex flex-col gap-[36px] items-start w-full max-w-[1280px] mx-auto px-4 lg:px-0">
<!-- Top row -->
<div class="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-10 lg:gap-0 w-full">
<!-- Brand col -->
<div class="flex flex-col gap-[24px] items-start overflow-clip shrink-0">
<div class="relative h-[64px] w-[220px]">
<img alt="TalkPro" class="absolute inset-0 max-w-none object-cover size-full pointer-events-none" src={logoFull} />
<footer class="site-footer">
<div class="site-footer__inner">
<div class="site-footer__top">
<div class="site-footer__brand">
<div class="site-footer__logo-frame">
<img alt={t.logoAlt} class="site-footer__logo" src={logoFull} />
</div>
<p class="font-normal text-[#7a726d] text-[14px] tracking-[-0.09px] leading-[1.5] max-w-[320px]">
TalkPro is a modern communication app designed for messaging, group conversations, channels, voice calls, and video calls.
<p class="site-footer__description">
{t.description}
</p>
<!-- Store badges -->
<div class="flex flex-wrap gap-[16px] items-center overflow-clip shrink-0 w-full">
<div class="bg-[#f28a4b] border border-[#c5834e] flex gap-[8px] h-[70px] items-center overflow-clip px-[16px] py-[12px] rounded-[20px] w-full sm:w-[260px] shrink-0">
<img alt="Android" class="block shrink-0 size-[44px]" src={androidIcon} />
<div class="flex flex-col gap-[3px] items-start overflow-clip shrink-0 whitespace-nowrap">
<p class="font-semibold text-[#ffd6bc] text-[11px] tracking-[0.05px] leading-normal">ANDROID</p>
<p class="font-semibold text-white text-[15px] tracking-[-0.13px] leading-normal">APK Coming Soon</p>
<div class="store-badges">
<div class="store-badge store-badge--android">
<img alt="Android" class="store-badge__icon" src={androidIcon} />
<div class="store-badge__copy">
<p class="store-badge__platform">{t.android}</p>
<p class="store-badge__label">{t.androidCta}</p>
</div>
</div>
<div class="bg-[#383838] border border-[#141414] flex gap-[8px] h-[70px] items-center overflow-clip px-[16px] py-[12px] rounded-[20px] w-full sm:w-[260px] shrink-0">
<div class="bg-[#151515] flex items-center justify-center rounded-[12px] shrink-0 size-[44px]">
<img alt="Apple" class="block h-[27px] w-[22px]" src={appleIcon} />
<div class="store-badge store-badge--ios">
<div class="store-badge__icon-frame">
<img alt="Apple" class="store-badge__apple-icon" src={appleIcon} />
</div>
<div class="flex flex-col gap-[3px] items-start overflow-clip shrink-0 whitespace-nowrap">
<p class="font-semibold text-[#ccc] text-[11px] tracking-[0.05px] leading-normal">IOS</p>
<p class="font-semibold text-white text-[15px] tracking-[-0.13px] leading-normal">Coming on App Store</p>
<div class="store-badge__copy">
<p class="store-badge__platform">{t.ios}</p>
<p class="store-badge__label">{t.iosCta}</p>
</div>
</div>
</div>
</div>
<!-- Link cols -->
<div class="flex gap-[32px] items-center leading-normal shrink-0">
<div class="flex flex-col gap-[24px] items-start overflow-clip w-[160px]">
<a href="#download" class="font-normal text-[#4a4a4a] text-[14px] whitespace-nowrap hover:text-[#f28a4b] transition-colors">Download</a>
<a href="#features" class="font-normal text-[#4a4a4a] text-[14px] whitespace-nowrap hover:text-[#f28a4b] transition-colors">Features</a>
<a href="#" class="font-normal text-[#4a4a4a] text-[14px] whitespace-nowrap hover:text-[#f28a4b] transition-colors">About</a>
<div class="site-footer__links">
<div class="site-footer__link-column">
<a href="#download" class="site-footer__link">{t.links.download}</a>
<a href="#features" class="site-footer__link">{t.links.features}</a>
<a href="#" class="site-footer__link">{t.links.about}</a>
</div>
<div class="flex flex-col gap-[24px] items-start overflow-clip w-[160px]">
<p class="font-medium text-[#4a4a4a] text-[14px] whitespace-nowrap">Contact</p>
<p class="font-normal text-[#4a4a4a] text-[14px] whitespace-nowrap">email@hotmail.com</p>
<p class="font-normal text-[#4a4a4a] text-[14px] whitespace-nowrap">+01 123 45562334</p>
<div class="site-footer__link-column">
<p class="site-footer__text site-footer__text--heading">{t.links.contact}</p>
<p class="site-footer__text">{t.email}</p>
<p class="site-footer__text">{t.phone}</p>
</div>
</div>
</div>
<!-- Divider -->
<div class="w-full h-px bg-[#e3d9d1]"></div>
<div class="site-footer__divider"></div>
<!-- Bottom row -->
<div class="flex gap-[20px] items-center overflow-clip w-full">
<p class="font-normal text-[#7a726d] text-[14px] tracking-[-0.09px] whitespace-nowrap leading-normal">© 2026 TalkPro. All rights reserved.</p>
<div class="flex-1 min-w-0"></div>
<p class="font-normal text-[#7a726d] text-[14px] tracking-[-0.09px] whitespace-nowrap leading-normal">Terms of Use · Privacy Policy · Support</p>
<div class="site-footer__bottom">
<p class="site-footer__legal">{t.copyright}</p>
<div class="site-footer__spacer"></div>
<p class="site-footer__legal">{t.legal}</p>
</div>
</div>
</footer>

View File

@@ -1,72 +1,110 @@
---
import { getLocalePath, languageLabels, languageNames, languages, type Lang, type Translations } from '../i18n/translations'
export interface Props {
lang: Lang
t: Translations['header']
}
const { lang, t } = Astro.props
const logoIcon = "/assets/header-logo-icon.png";
const logoWordmark = "/assets/header-logo-wordmark.svg";
const globeIcon = "/assets/header-globe.svg";
const navItems = [
{ href: '#hero', label: t.nav.home },
{ href: '#features', label: t.nav.features },
{ href: '#experience', label: t.nav.experience },
{ href: '#use-cases', label: t.nav.useCases },
{ href: '#reliability', label: t.nav.reliability },
]
const languageOptions = languages.map(item => ({
lang: item,
href: getLocalePath(item),
label: `${languageLabels[item]} - ${languageNames[item]}`,
}))
---
<header id="site-header" class="bg-white border-b border-[#e3d9d1] w-full sticky top-0 z-50">
<!-- Main bar -->
<div class="flex items-center w-full max-w-[1280px] mx-auto px-4 lg:px-6 h-[72px] gap-6">
<!-- Logo -->
<div class="flex flex-1 items-center min-w-0">
<a href="/" class="relative h-[42px] w-[143px] shrink-0 block">
<div class="absolute h-[42px] left-0 top-0 w-[53px] overflow-hidden">
<img alt="TalkPro icon" class="absolute h-[126.98%] left-0 max-w-none top-[-13.49%] w-full" src={logoIcon} />
<header id="site-header" class="site-header">
<div class="site-header__bar">
<div class="site-header__brand">
<a href={getLocalePath(lang)} class="site-logo">
<div class="site-logo__icon-frame">
<img alt={t.logoIconAlt} class="site-logo__icon" src={logoIcon} />
</div>
<div class="absolute inset-[26.97%_0_7.92%_45.45%]">
<img alt="TalkPro" class="absolute block inset-0 max-w-none size-full" src={logoWordmark} />
<div class="site-logo__wordmark-frame">
<img alt={t.logoAlt} class="site-logo__wordmark" src={logoWordmark} />
</div>
</a>
</div>
<!-- Desktop nav -->
<nav class="hidden lg:flex items-center gap-[32px] shrink-0" aria-label="Main navigation">
<a href="#hero" class="font-semibold text-[14px] text-[#f28a4b] tracking-[-0.09px] whitespace-nowrap leading-normal" data-nav-link>Home</a>
<a href="#features" class="font-semibold text-[14px] text-[#7a726d] tracking-[-0.09px] whitespace-nowrap leading-normal hover:text-[#f28a4b] transition-colors" data-nav-link>Features</a>
<a href="#experience" class="font-semibold text-[14px] text-[#7a726d] tracking-[-0.09px] whitespace-nowrap leading-normal hover:text-[#f28a4b] transition-colors" data-nav-link>Experience</a>
<a href="#use-cases" class="font-semibold text-[14px] text-[#7a726d] tracking-[-0.09px] whitespace-nowrap leading-normal hover:text-[#f28a4b] transition-colors" data-nav-link>Use Cases</a>
<a href="#reliability" class="font-semibold text-[14px] text-[#7a726d] tracking-[-0.09px] whitespace-nowrap leading-normal hover:text-[#f28a4b] transition-colors" data-nav-link>Reliability</a>
<nav class="site-nav" aria-label={t.navLabel}>
{navItems.map((item, index) => (
<a href={item.href} class={`site-nav__link ${index === 0 ? 'is-active' : ''}`} data-nav-link>{item.label}</a>
))}
</nav>
<!-- Actions -->
<div class="flex flex-1 gap-[12px] items-center justify-end min-w-0">
<!-- Language button (desktop only) -->
<button class="hidden lg:flex border border-[rgba(46,42,40,0.3)] gap-[8px] h-[43px] items-center justify-center pl-[12px] pr-[16px] rounded-[17px] shrink-0 hover:border-[#f28a4b] transition-colors">
<img alt="Language" class="block size-[26px] object-contain" src={globeIcon} />
<span class="font-semibold text-[14px] text-[#2e2a28] tracking-[-0.09px] whitespace-nowrap leading-[14px]">EN</span>
</button>
<!-- Download button (desktop only) -->
<a href="#download" class="hidden lg:flex bg-[#f28a4b] items-center justify-center px-[22px] py-[13px] rounded-[17px] shrink-0 hover:bg-[#e07a3b] transition-colors">
<span class="font-bold text-[14px] text-white leading-normal whitespace-nowrap">Download</span>
<div class="site-header__actions">
<div class="language-switcher">
<button
id="language-toggle"
class="language-switcher__button"
type="button"
aria-label={t.languageAlt}
aria-expanded="false"
aria-controls="language-menu"
>
<img alt="" class="language-switcher__icon" src={globeIcon} />
<span class="language-switcher__current">{languageLabels[lang]}</span>
</button>
<div id="language-menu" class="language-switcher__menu is-hidden" aria-hidden="true">
{languageOptions.map(option => (
<a
href={option.href}
class={`language-switcher__option ${option.lang === lang ? 'is-active' : ''}`}
aria-current={option.lang === lang ? 'page' : undefined}
>
{option.label}
</a>
))}
</div>
</div>
<a href="#download" class="site-header__download">
<span class="site-header__download-label">{t.download}</span>
</a>
<!-- Hamburger toggle (mobile only) -->
<button
id="menu-toggle"
class="lg:hidden flex flex-col justify-center gap-[5px] w-[40px] h-[40px] p-[8px] shrink-0"
class="menu-toggle"
type="button"
aria-label="Open menu"
aria-label={t.openMenu}
aria-expanded="false"
aria-controls="mobile-nav"
data-open-label={t.openMenu}
data-close-label={t.closeMenu}
>
<span id="bar-1" class="block w-full h-[2px] bg-[#2e2a28] rounded-sm transition-all duration-[240ms] origin-center"></span>
<span id="bar-2" class="block w-full h-[2px] bg-[#2e2a28] rounded-sm transition-all duration-[240ms]"></span>
<span id="bar-3" class="block w-full h-[2px] bg-[#2e2a28] rounded-sm transition-all duration-[240ms] origin-center"></span>
<span id="bar-1" class="menu-toggle__bar"></span>
<span id="bar-2" class="menu-toggle__bar"></span>
<span id="bar-3" class="menu-toggle__bar"></span>
</button>
</div>
</div>
<!-- Mobile nav drawer -->
<div id="mobile-nav" class="hidden lg:!hidden border-t border-[#e3d9d1] bg-white" aria-hidden="true">
<ul class="flex flex-col px-6 py-4 list-none m-0 p-0 px-6 py-4">
<li><a href="#hero" class="block py-4 font-semibold text-[16px] text-[#2e2a28] border-b border-[#e3d9d1]" data-nav-link>Home</a></li>
<li><a href="#features" class="block py-4 font-semibold text-[16px] text-[#2e2a28] border-b border-[#e3d9d1]" data-nav-link>Features</a></li>
<li><a href="#experience" class="block py-4 font-semibold text-[16px] text-[#2e2a28] border-b border-[#e3d9d1]" data-nav-link>Experience</a></li>
<li><a href="#use-cases" class="block py-4 font-semibold text-[16px] text-[#2e2a28] border-b border-[#e3d9d1]" data-nav-link>Use Cases</a></li>
<li><a href="#reliability" class="block py-4 font-semibold text-[16px] text-[#2e2a28]" data-nav-link>Reliability</a></li>
<li class="mt-4 mb-2">
<a href="#download" class="block text-center bg-[#f28a4b] text-white font-bold text-[15px] py-[14px] px-6 rounded-[17px] hover:bg-[#e07a3b] transition-colors">
Download
<div id="mobile-nav" class="mobile-nav is-hidden" aria-hidden="true">
<ul class="mobile-nav__list">
{navItems.map((item, index) => (
<li><a href={item.href} class={`mobile-nav__link ${index === navItems.length - 1 ? 'mobile-nav__link--last' : ''}`} data-nav-link>{item.label}</a></li>
))}
<li class="mobile-nav__languages">
{languages.map(item => (
<a href={getLocalePath(item)} class={`mobile-nav__language-link ${item === lang ? 'is-active' : ''}`} aria-current={item === lang ? 'page' : undefined}>
{languageNames[item]}
</a>
))}
</li>
<li class="mobile-nav__download-item">
<a href="#download" class="mobile-nav__download">
{t.download}
</a>
</li>
</ul>
@@ -75,17 +113,32 @@ const globeIcon = "/assets/header-globe.svg";
<script>
const toggle = document.getElementById('menu-toggle') as HTMLButtonElement;
const nav = document.getElementById('mobile-nav') as HTMLDivElement;
const bar1 = document.getElementById('bar-1') as HTMLSpanElement;
const bar2 = document.getElementById('bar-2') as HTMLSpanElement;
const bar3 = document.getElementById('bar-3') as HTMLSpanElement;
const nav = document.getElementById('mobile-nav') as HTMLDivElement;
const bar1 = document.getElementById('bar-1') as HTMLSpanElement;
const bar2 = document.getElementById('bar-2') as HTMLSpanElement;
const bar3 = document.getElementById('bar-3') as HTMLSpanElement;
const languageToggle = document.getElementById('language-toggle') as HTMLButtonElement | null;
const languageMenu = document.getElementById('language-menu') as HTMLDivElement | null;
function closeLanguageMenu() {
if (!languageToggle || !languageMenu) return;
languageToggle.setAttribute('aria-expanded', 'false');
languageMenu.classList.add('is-hidden');
languageMenu.setAttribute('aria-hidden', 'true');
}
function openLanguageMenu() {
if (!languageToggle || !languageMenu) return;
languageToggle.setAttribute('aria-expanded', 'true');
languageMenu.classList.remove('is-hidden');
languageMenu.removeAttribute('aria-hidden');
}
function openMenu() {
toggle.setAttribute('aria-expanded', 'true');
toggle.setAttribute('aria-label', 'Close menu');
nav.classList.remove('hidden');
toggle.setAttribute('aria-label', toggle.dataset.closeLabel || 'Close menu');
nav.classList.remove('is-hidden');
nav.removeAttribute('aria-hidden');
// Animate to X
bar1.style.transform = 'translateY(7px) rotate(45deg)';
bar2.style.opacity = '0';
bar3.style.transform = 'translateY(-7px) rotate(-45deg)';
@@ -93,10 +146,9 @@ const globeIcon = "/assets/header-globe.svg";
function closeMenu() {
toggle.setAttribute('aria-expanded', 'false');
toggle.setAttribute('aria-label', 'Open menu');
nav.classList.add('hidden');
toggle.setAttribute('aria-label', toggle.dataset.openLabel || 'Open menu');
nav.classList.add('is-hidden');
nav.setAttribute('aria-hidden', 'true');
// Reset bars
bar1.style.transform = '';
bar2.style.opacity = '';
bar3.style.transform = '';
@@ -106,11 +158,23 @@ const globeIcon = "/assets/header-globe.svg";
toggle.getAttribute('aria-expanded') === 'true' ? closeMenu() : openMenu();
});
// Close when any nav link is clicked
languageToggle?.addEventListener('click', event => {
event.stopPropagation();
languageToggle.getAttribute('aria-expanded') === 'true' ? closeLanguageMenu() : openLanguageMenu();
});
languageMenu?.addEventListener('click', event => event.stopPropagation());
document.addEventListener('click', closeLanguageMenu);
document.addEventListener('keydown', event => {
if (event.key === 'Escape') closeLanguageMenu();
});
nav.querySelectorAll('a').forEach(a => a.addEventListener('click', closeMenu));
// Close when resized past mobile breakpoint
window.addEventListener('resize', () => {
if (window.innerWidth >= 1024) closeMenu();
if (window.innerWidth < 1024) closeLanguageMenu();
});
</script>

View File

@@ -1,57 +1,56 @@
---
import type { Translations } from '../i18n/translations'
export interface Props {
t: Translations['hero']
}
const { t } = Astro.props
const heroBg = "/assets/hero-bg.png";
const phoneMockup = "/assets/hero-phone.png";
---
<section id="hero" class="relative w-full flex items-start justify-center min-h-[600px] lg:h-[891px] overflow-hidden">
<img alt="" class="absolute inset-0 max-w-none object-cover size-full pointer-events-none" src={heroBg} />
<section id="hero" class="hero">
<img alt="" class="hero__bg" src={heroBg} />
<div class="relative flex flex-col-reverse lg:flex-row gap-[40px] items-start w-full max-w-[1280px] mx-auto px-4 lg:px-0 h-full">
<!-- Phone mockup -->
<div class="hidden lg:flex flex-1 items-center min-w-0 pt-[60px] h-full">
<div class="relative w-full" style="aspect-ratio: 673/1108;">
<div class="absolute inset-0 overflow-hidden pointer-events-none">
<img alt="TalkPro app on iPhone" class="absolute h-[114.36%] left-[-2.67%] max-w-none top-[-7.18%] w-[105.35%]" src={phoneMockup} />
<div class="hero__inner">
<div class="hero__phone-column">
<div class="hero__phone-frame">
<div class="hero__phone-crop">
<img alt={t.phoneAlt} class="hero__phone" src={phoneMockup} />
</div>
</div>
</div>
<!-- Hero copy -->
<div class="flex flex-col gap-[60px] h-full items-start justify-center overflow-clip shrink-0 w-full lg:w-[660px] py-8 lg:py-[80px]">
<!-- Pill -->
<div class="bg-white border border-[#f08458] flex items-center overflow-clip px-[16px] py-[12px] rounded-[999px] shrink-0">
<p class="font-bold text-[#0d0d0d] text-[14px] tracking-[-0.09px] leading-normal">✦&nbsp; Available on iOS and Android</p>
<div class="hero__content">
<div class="hero__badge">
<p class="hero__badge-text">{t.badge}</p>
</div>
<div class="flex flex-col gap-[24px] items-start shrink-0 w-full">
<div class="font-bold text-[#2e2a28] text-[40px] md:text-[56px] lg:text-[72px] tracking-[-1.61px] w-full">
<p class="leading-[1.1] mb-0">A Modern Way to</p>
<p class="leading-[1.1]">Stay Connected</p>
<div class="hero__copy">
<div class="hero__title">
<p class="hero__title-line">{t.titleLine1}</p>
<p class="hero__title-line">{t.titleLine2}</p>
</div>
<p class="font-normal text-[#7a726d] text-[18px] tracking-[-0.33px] leading-[1.5] w-full">
TalkPro is a modern messaging app designed for clear, simple, and reliable communication. From private chats to group conversations, channels, voice calls, and video calls, TalkPro helps people stay connected in one familiar experience.
<p class="hero__description">
{t.description}
</p>
<div class="flex flex-wrap gap-[14px] items-center overflow-clip shrink-0">
<a href="#download" class="bg-[#f28a4b] flex items-center justify-center overflow-clip px-[24px] py-[14px] rounded-[17px] shrink-0 hover:bg-[#e07a3b] transition-colors">
<span class="font-bold text-white text-[15px] tracking-[-0.13px] leading-normal">Download TalkPro ↓</span>
<div class="hero__actions">
<a href="#download" class="hero__button hero__button--primary">
<span class="hero__button-label">{t.download}</span>
</a>
<a href="#features" class="bg-[rgba(255,255,255,0.55)] border border-[#e3d9d1] flex items-center justify-center overflow-clip px-[24px] py-[14px] rounded-[17px] shrink-0 hover:bg-white transition-colors">
<span class="font-bold text-[#2e2a28] text-[15px] tracking-[-0.13px] leading-normal">Explore Features →</span>
<a href="#features" class="hero__button hero__button--secondary">
<span class="hero__button-label">{t.explore}</span>
</a>
</div>
</div>
<!-- Tags -->
<div class="flex flex-wrap gap-[10px] items-center overflow-clip shrink-0">
<div class="bg-[rgba(255,255,255,0.68)] border border-white flex items-center overflow-clip px-[14px] py-[9px] rounded-[999px] shrink-0">
<span class="font-bold text-[#7a726d] text-[14px] tracking-[-0.09px] whitespace-nowrap leading-normal">Identity Layer</span>
</div>
<div class="bg-[rgba(255,255,255,0.68)] border border-white flex items-center overflow-clip px-[14px] py-[9px] rounded-[999px] shrink-0">
<span class="font-bold text-[#7a726d] text-[14px] tracking-[-0.09px] whitespace-nowrap leading-normal">AI Native Messaging</span>
</div>
<div class="bg-[rgba(255,255,255,0.68)] border border-white flex items-center overflow-clip px-[14px] py-[9px] rounded-[999px] shrink-0">
<span class="font-bold text-[#7a726d] text-[14px] tracking-[-0.09px] whitespace-nowrap leading-normal">Adaptive Privacy</span>
</div>
<div class="hero__tags">
{t.tags.map(tag => (
<div class="hero__tag">
<span class="hero__tag-text">{tag}</span>
</div>
))}
</div>
</div>
</div>

View File

@@ -1,96 +1,58 @@
---
import type { Translations } from '../i18n/translations'
export interface Props {
t: Translations['trust']
}
const { t } = Astro.props
const iconClasses = [
'trust-card__icon--one',
'trust-card__icon--two',
'trust-card__icon--three',
'trust-card__icon--four',
]
---
<section id="reliability" class="bg-white w-full flex flex-col items-center justify-center py-16 px-4 lg:p-[120px]">
<div class="flex flex-col gap-[40px] items-start w-full max-w-[1280px] mx-auto">
<!-- Header -->
<div class="flex flex-col gap-[24px] items-start overflow-clip w-full">
<div class="bg-white border border-[#fbbfa3] flex items-center justify-center px-[24px] py-[12px] rounded-[9999px] shrink-0">
<span class="font-bold text-[#f08458] text-[14px] text-center tracking-[-0.04px] whitespace-nowrap leading-normal">RELIABILITY</span>
<section id="reliability" class="trust">
<div class="trust__inner">
<div class="trust__header">
<div class="section-eyebrow">
<span class="section-eyebrow__text">{t.eyebrow}</span>
</div>
<p class="font-bold text-[#1a1a1a] text-[32px] md:text-[40px] lg:text-[48px] tracking-[-1.16px] leading-[1.2] w-full">Built with User Trust in Mind</p>
<p class="font-normal text-[#7a726d] text-[18px] tracking-[-0.33px] leading-[1.5] w-full">
TalkPro is designed with a privacy-conscious approach and a focus on dependable communication. The app keeps the user experience simple while supporting the core communication features people expect from a modern messaging platform.
<p class="trust__title">{t.title}</p>
<p class="trust__description">
{t.description}
</p>
</div>
<!-- 4-column feature row -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:flex lg:gap-[24px] lg:items-center gap-8 justify-center w-full">
<!-- Card 1: Privacy-Conscious Design -->
<div class="flex flex-1 flex-col gap-[16px] items-center justify-end min-w-0 p-[24px] rounded-[30px]">
<div class="relative shrink-0 size-[128px]">
<div class="absolute inset-0 overflow-hidden pointer-events-none">
<img alt="" class="absolute h-[174.55%] left-[-31.48%] max-w-none top-[7.04%] w-[312.73%]" src="/assets/trust-icon-sprite.png" />
<div class="trust__grid">
{t.cards.map((card, index) => (
<>
<div class="trust-card">
<div class="trust-card__icon-frame">
<div class="trust-card__icon-crop">
<img
alt=""
class={`trust-card__icon ${iconClasses[index]}`}
src={index === 3 ? "/assets/trust-icon-improvement.png" : "/assets/trust-icon-sprite.png"}
/>
</div>
</div>
<div class="trust-card__copy">
<p class="trust-card__title">{card.title}</p>
<p class="trust-card__description">{card.desc}</p>
</div>
</div>
</div>
<div class="flex flex-col gap-[8px] items-start w-full">
<p class="font-semibold text-[#0d0d0d] text-[16px] leading-[22px] w-full">Privacy-Conscious Design</p>
<p class="font-medium text-[#7a726d] text-[15px] leading-[1.5] w-full">Built with careful consideration for user communication and data handling.</p>
</div>
</div>
<!-- Divider -->
<div class="hidden lg:block relative h-[118px] shrink-0 w-0">
<div class="absolute inset-[0_-0.5px]">
<img alt="" class="block max-w-none size-full" src="/assets/trust-divider.svg" />
</div>
</div>
<!-- Card 2: Minimal and Focused -->
<div class="flex flex-1 flex-col gap-[16px] items-center justify-end min-w-0 p-[24px] rounded-[30px]">
<div class="relative shrink-0 size-[128px]">
<div class="absolute inset-0 overflow-hidden pointer-events-none">
<img alt="" class="absolute h-[187.32%] left-[-164.72%] max-w-none top-[3.1%] w-[335.61%]" src="/assets/trust-icon-sprite.png" />
</div>
</div>
<div class="flex flex-col gap-[8px] items-start w-full">
<p class="font-semibold text-[#0d0d0d] text-[16px] leading-[22px] w-full">Minimal and Focused</p>
<p class="font-medium text-[#7a726d] text-[15px] leading-[1.5] w-full">Designed around essential messaging features without unnecessary complexity.</p>
</div>
</div>
<!-- Divider -->
<div class="hidden lg:block relative h-[118px] shrink-0 w-0">
<div class="absolute inset-[0_-0.5px]">
<img alt="" class="block max-w-none size-full" src="/assets/trust-divider.svg" />
</div>
</div>
<!-- Card 3: Reliable Experience -->
<div class="flex flex-1 flex-col gap-[16px] items-center justify-end min-w-0 p-[24px] rounded-[30px]">
<div class="relative shrink-0 size-[128px]">
<div class="absolute inset-0 overflow-hidden pointer-events-none">
<img alt="" class="absolute h-[211.46%] left-[-187.93%] max-w-none top-[-105.62%] w-[378.86%]" src="/assets/trust-icon-sprite.png" />
</div>
</div>
<div class="flex flex-col gap-[8px] items-start w-full">
<p class="font-semibold text-[#0d0d0d] text-[16px] leading-[22px] w-full">Reliable Experience</p>
<p class="font-medium text-[#7a726d] text-[15px] leading-[1.5] w-full">Focused on providing a stable and familiar communication experience.</p>
</div>
</div>
<!-- Divider -->
<div class="hidden lg:block relative h-[118px] shrink-0 w-0">
<div class="absolute inset-[0_-0.5px]">
<img alt="" class="block max-w-none size-full" src="/assets/trust-divider.svg" />
</div>
</div>
<!-- Card 4: Continuous Improvement -->
<div class="flex flex-1 flex-col gap-[16px] items-center justify-end min-w-0 p-[24px] rounded-[30px]">
<div class="relative shrink-0 size-[128px]">
<div class="absolute inset-0 overflow-hidden pointer-events-none">
<img alt="" class="absolute left-[4.14%] max-w-none size-full top-0" src="/assets/trust-icon-improvement.png" />
</div>
</div>
<div class="flex flex-col gap-[8px] items-start w-full">
<p class="font-semibold text-[#0d0d0d] text-[16px] leading-[22px] w-full">Continuous Improvement</p>
<p class="font-medium text-[#7a726d] text-[15px] leading-[1.5] w-full">TalkPro will continue to improve its interface, features, and overall user experience.</p>
</div>
</div>
{index < t.cards.length - 1 && (
<div class="trust__divider">
<div class="trust__divider-frame">
<img alt="" class="trust__divider-image" src="/assets/trust-divider.svg" />
</div>
</div>
)}
</>
))}
</div>
</div>
</section>

View File

@@ -1,36 +1,35 @@
---
const rows = [
{ title: 'Personal Conversations', desc: 'Message friends, family, and close contacts in a simple private chat experience.' },
{ title: 'Communities', desc: 'Join group conversations and stay active in shared interest spaces.' },
{ title: 'Teams and Projects', desc: 'Coordinate discussions, updates, and quick decisions in group chats.' },
{ title: 'News and Updates', desc: 'Follow channels for announcements, information, and community content.' },
]
import type { Translations } from '../i18n/translations'
export interface Props {
t: Translations['useCases']
}
const { t } = Astro.props
---
<section id="use-cases" class="bg-[#fef0eb] w-full flex items-start justify-center py-16 lg:py-[120px] px-4 lg:px-[130px]">
<div class="flex flex-col lg:flex-row lg:gap-[40px] lg:items-center gap-8 w-full max-w-[1280px] mx-auto">
<!-- Left: heading -->
<div class="flex flex-col gap-[24px] items-start overflow-clip shrink-0 w-full lg:w-[540px] lg:shrink-0">
<div class="bg-white border border-[#fbbfa3] flex items-center justify-center px-[24px] py-[12px] rounded-[9999px] shrink-0">
<span class="font-bold text-[#f08458] text-[14px] text-center tracking-[-0.04px] whitespace-nowrap leading-normal">USE CASES</span>
<section id="use-cases" class="use-cases">
<div class="use-cases__inner">
<div class="use-cases__copy">
<div class="section-eyebrow">
<span class="section-eyebrow__text">{t.eyebrow}</span>
</div>
<p class="font-bold text-[#1a1a1a] text-[32px] md:text-[40px] lg:text-[48px] tracking-[-1.16px] leading-[1.2] w-full">
Made for Personal, Social, and Community Communication
<p class="use-cases__title">
{t.title}
</p>
<p class="font-normal text-[#7a726d] text-[18px] tracking-[-0.33px] leading-[1.5] w-full">
With separate spaces for every context, TalkPro keeps your personal, social, and professional communications distinct and organized.
<p class="use-cases__description">
{t.description}
</p>
</div>
<!-- Right: rows -->
<div class="flex flex-1 flex-col items-start min-w-0 overflow-clip rounded-[30px] gap-px">
{rows.map(row => (
<div class="bg-[#faede8] flex flex-col sm:flex-row sm:h-[120px] items-stretch overflow-clip w-full shrink-0">
<div class="bg-[#f08458] flex items-center px-[24px] sm:px-[36px] py-[16px] sm:py-[24px] shrink-0 w-full sm:w-[300px]">
<p class="flex-1 font-semibold text-[18px] sm:text-[20px] text-white tracking-[-0.6px] leading-normal min-w-0">{row.title}</p>
<div class="use-cases__rows">
{t.rows.map(row => (
<div class="use-case-row">
<div class="use-case-row__title-cell">
<p class="use-case-row__title">{row.title}</p>
</div>
<div class="bg-white flex flex-1 items-center min-w-0 px-[24px] sm:px-[36px] py-[16px] sm:py-[24px]">
<p class="font-medium text-[#7a726d] text-[15px] leading-[1.5] flex-1 min-w-0">{row.desc}</p>
<div class="use-case-row__description-cell">
<p class="use-case-row__description">{row.desc}</p>
</div>
</div>
))}

View File

@@ -1,83 +1,61 @@
---
const underline = "/assets/why-underline.svg";
const iconSimple = "/assets/why-icon-simple.svg";
const iconFamiliar = "/assets/why-icon-familiar.svg";
const iconConn = "/assets/why-icon-connected.svg";
const iconModern = "/assets/why-icon-modern.svg";
import type { Translations } from '../i18n/translations'
export interface Props {
t: Translations['why']
}
const { t } = Astro.props
const underline = "/assets/why-underline.svg";
const icons = [
"/assets/why-icon-simple.svg",
"/assets/why-icon-familiar.svg",
"/assets/why-icon-connected.svg",
"/assets/why-icon-modern.svg",
]
const iconClasses = ['why-card__icon--square', 'why-card__icon--familiar', 'why-card__icon--square', 'why-card__icon--modern']
---
<section class="bg-white w-full flex flex-col items-center justify-center py-16 lg:py-[120px]">
<div class="flex flex-col gap-[40px] items-start w-full max-w-[1280px] mx-auto px-4 lg:px-0">
<!-- Header row -->
<div class="flex flex-col lg:flex-row gap-[36px] items-start overflow-clip w-full">
<!-- Left: pill + heading + description -->
<div class="flex flex-1 flex-col gap-[36px] items-start min-w-0">
<div class="bg-white border border-[#fbbfa3] flex items-center justify-center px-[24px] py-[12px] rounded-[9999px] shrink-0">
<span class="font-bold text-[#f08458] text-[14px] text-center tracking-[-0.04px] whitespace-nowrap leading-normal">WHY TALKPRO</span>
<section class="why">
<div class="why__inner">
<div class="why__intro">
<div class="why__copy">
<div class="section-eyebrow">
<span class="section-eyebrow__text">{t.eyebrow}</span>
</div>
<div class="flex flex-col gap-[24px] items-start w-full">
<div class="font-bold text-[#1a1a1a] text-[32px] md:text-[40px] lg:text-[48px] tracking-[-1.16px] w-full">
<p class="leading-[1.2] mb-0">Designed for the Way</p>
<p class="leading-[1.2]">People Communicate Today</p>
<div class="why__text">
<div class="why__title">
<p class="why__title-line">{t.titleLine1}</p>
<p class="why__title-line">{t.titleLine2}</p>
</div>
<!-- Underline decoration -->
<div class="relative h-0 w-[295.5px] shrink-0">
<div class="absolute inset-[-0.5px_0]">
<img alt="" class="block max-w-none size-full" src={underline} />
<div class="why__underline">
<div class="why__underline-frame">
<img alt="" class="why__underline-image" src={underline} />
</div>
</div>
<p class="font-normal text-[#7a726d] text-[18px] tracking-[-0.33px] leading-[1.5] w-full">
Communication today happens across personal conversations, communities, work groups, and content channels. TalkPro brings these essential communication experiences together in a simple and familiar interface, making it easier for users to connect, share, and stay updated.
<p class="why__description">
{t.description}
</p>
</div>
</div>
<!-- Right: illustration -->
<div class="hidden lg:block relative shrink-0 size-[480px]">
<img alt="People communicating with TalkPro" class="absolute inset-0 size-full object-contain" src="/assets/why-illustration.png" />
<div class="why__illustration">
<img alt={t.illustrationAlt} class="why__illustration-image" src="/assets/why-illustration.png" />
</div>
</div>
<!-- 2×2 card grid -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 w-full">
<div class="bg-[#fef0eb] border border-[#e8e4de] flex gap-[24px] h-auto md:h-[152px] items-center min-w-0 overflow-clip p-[36px] rounded-[30px]">
<div class="bg-[#f08458] aspect-square h-[80px] flex items-center justify-center overflow-clip rounded-[9999px] shrink-0">
<img alt="" class="block size-[44px]" src={iconSimple} />
<div class="why__grid">
{t.cards.map((card, index) => (
<div class="why-card">
<div class="why-card__icon-frame">
<img alt="" class={`why-card__icon ${iconClasses[index]}`} src={icons[index]} />
</div>
<div class="why-card__copy">
<p class="why-card__title">{card.title}</p>
<p class="why-card__description">{card.desc}</p>
</div>
</div>
<div class="flex flex-1 flex-col gap-[12px] items-start min-w-0 overflow-clip">
<p class="font-semibold text-[#0d0d0d] text-[24px] tracking-[-0.47px] leading-[20px] w-full">Simple</p>
<p class="font-medium text-[#7a726d] text-[16px] tracking-[-0.18px] leading-[1.5] w-full">An easy-to-use experience designed for everyday communication.</p>
</div>
</div>
<div class="bg-[#fef0eb] border border-[#e8e4de] flex gap-[24px] h-auto md:h-[152px] items-center min-w-0 overflow-clip p-[36px] rounded-[30px]">
<div class="bg-[#f08458] aspect-square h-[80px] flex items-center justify-center overflow-clip rounded-[9999px] shrink-0">
<img alt="" class="block" style="width:38px;height:40px;" src={iconFamiliar} />
</div>
<div class="flex flex-1 flex-col gap-[12px] items-start min-w-0 overflow-clip">
<p class="font-semibold text-[#0d0d0d] text-[24px] tracking-[-0.47px] leading-[20px] w-full">Familiar</p>
<p class="font-medium text-[#7a726d] text-[16px] tracking-[-0.18px] leading-[1.5] w-full">A messaging structure that feels natural from the first use.</p>
</div>
</div>
<div class="bg-[#fef0eb] border border-[#e8e4de] flex gap-[24px] h-auto md:h-[152px] items-center min-w-0 overflow-clip p-[36px] rounded-[30px]">
<div class="bg-[#f08458] aspect-square h-[80px] flex items-center justify-center overflow-clip rounded-[9999px] shrink-0">
<img alt="" class="block size-[44px]" src={iconConn} />
</div>
<div class="flex flex-1 flex-col gap-[12px] items-start min-w-0 overflow-clip">
<p class="font-semibold text-[#0d0d0d] text-[24px] tracking-[-0.47px] leading-[20px] w-full">Connected</p>
<p class="font-medium text-[#7a726d] text-[16px] tracking-[-0.18px] leading-[1.5] w-full">Private chats, groups, channels, voice, and video in one app.</p>
</div>
</div>
<div class="bg-[#fef0eb] border border-[#e8e4de] flex gap-[24px] h-auto md:h-[152px] items-center min-w-0 overflow-clip p-[36px] rounded-[30px]">
<div class="bg-[#f08458] aspect-square h-[80px] flex items-center justify-center overflow-clip rounded-[9999px] shrink-0">
<img alt="" class="block" style="width:24px;height:44px;" src={iconModern} />
</div>
<div class="flex flex-1 flex-col gap-[12px] items-start min-w-0 overflow-clip">
<p class="font-semibold text-[#0d0d0d] text-[24px] tracking-[-0.47px] leading-[20px] w-full">Modern</p>
<p class="font-medium text-[#7a726d] text-[16px] tracking-[-0.18px] leading-[1.5] w-full">A refined interface with clean visuals and smooth interaction.</p>
</div>
</div>
))}
</div>
</div>
</section>

415
src/i18n/translations.ts Normal file
View File

@@ -0,0 +1,415 @@
export const languages = ['en', 'zh-cn', 'zh-tw'] as const
export type Lang = (typeof languages)[number]
export const defaultLang: Lang = 'en'
export const languageLabels: Record<Lang, string> = {
en: 'EN',
'zh-cn': '简',
'zh-tw': '繁',
}
export const languageNames: Record<Lang, string> = {
en: 'English',
'zh-cn': '简体中文',
'zh-tw': '繁體中文',
}
export function isLang(value: string | undefined): value is Lang {
return Boolean(value && languages.includes(value as Lang))
}
export function getLocalePath(lang: Lang) {
return lang === defaultLang ? '/' : `/${lang}/`
}
export const translations = {
en: {
meta: {
title: 'Talk Pro - One User. Multiple Worlds.',
description: 'Talk Pro is a modern messaging app for private chats, group conversations, channels, voice and video calls.',
},
header: {
navLabel: 'Main navigation',
logoIconAlt: 'TalkPro icon',
logoAlt: 'TalkPro',
languageAlt: 'Language',
openMenu: 'Open menu',
closeMenu: 'Close menu',
nav: {
home: 'Home',
features: 'Features',
experience: 'Experience',
useCases: 'Use Cases',
reliability: 'Reliability',
},
download: 'Download',
},
hero: {
phoneAlt: 'TalkPro app on iPhone',
badge: '✦ Available on iOS and Android',
titleLine1: 'A Modern Way to',
titleLine2: 'Stay Connected',
description: 'TalkPro is a modern messaging app designed for clear, simple, and reliable communication. From private chats to group conversations, channels, voice calls, and video calls, TalkPro helps people stay connected in one familiar experience.',
download: 'Download TalkPro ↓',
explore: 'Explore Features →',
tags: ['Identity Layer', 'AI Native Messaging', 'Adaptive Privacy'],
},
why: {
eyebrow: 'WHY TALKPRO',
titleLine1: 'Designed for the Way',
titleLine2: 'People Communicate Today',
description: 'Communication today happens across personal conversations, communities, work groups, and content channels. TalkPro brings these essential communication experiences together in a simple and familiar interface, making it easier for users to connect, share, and stay updated.',
illustrationAlt: 'People communicating with TalkPro',
cards: [
{ title: 'Simple', desc: 'An easy-to-use experience designed for everyday communication.' },
{ title: 'Familiar', desc: 'A messaging structure that feels natural from the first use.' },
{ title: 'Connected', desc: 'Private chats, groups, channels, voice, and video in one app.' },
{ title: 'Modern', desc: 'A refined interface with clean visuals and smooth interaction.' },
],
},
core: {
eyebrow: 'CORE FEATURES',
title: 'Everything You Need to Communicate',
description: 'Different identities, different conversations, and different privacy levels should not be forced into one flat interface. TalkPro lets them exist in order inside one platform.',
cards: [
{ title: 'Private Messaging', desc: 'Stay connected through fast and familiar one-on-one conversations.' },
{ title: 'Group Chats', desc: 'Create spaces for friends, teams, communities, and shared discussions.' },
{ title: 'Channels', desc: 'Follow updates, announcements, and content from the people or communities you care about.' },
{ title: 'Voice Calls', desc: 'Talk in real time whenever messages are not enough.' },
{ title: 'Video Calls', desc: 'Connect face-to-face with a simple and reliable video call experience.' },
{ title: 'Media Sharing', desc: 'Share photos, videos, files, and updates in your conversations.' },
],
},
experience: {
title: 'A Cleaner, More Comfortable Messaging Experience',
cards: [
{ title: 'Clear Interface', desc: 'A clean layout that makes conversations easy to follow.', alt: 'Clear interface screenshot' },
{ title: 'Smooth Navigation', desc: 'Move between chats, groups, and channels with familiar controls.', alt: 'Smooth navigation screenshot' },
{ title: 'Refined Visual Design', desc: 'Modern icons, colors, and interface details create a more polished experience.', alt: 'Refined visual design screenshot' },
],
caption: 'TalkPro is designed with clarity in mind. Every screen is built to help users focus on their conversations, reduce distractions, and move naturally between chats, groups, channels, and calls.',
},
useCases: {
eyebrow: 'USE CASES',
title: 'Made for Personal, Social, and Community Communication',
description: 'With separate spaces for every context, TalkPro keeps your personal, social, and professional communications distinct and organized.',
rows: [
{ title: 'Personal Conversations', desc: 'Message friends, family, and close contacts in a simple private chat experience.' },
{ title: 'Communities', desc: 'Join group conversations and stay active in shared interest spaces.' },
{ title: 'Teams and Projects', desc: 'Coordinate discussions, updates, and quick decisions in group chats.' },
{ title: 'News and Updates', desc: 'Follow channels for announcements, information, and community content.' },
],
},
trust: {
eyebrow: 'RELIABILITY',
title: 'Built with User Trust in Mind',
description: 'TalkPro is designed with a privacy-conscious approach and a focus on dependable communication. The app keeps the user experience simple while supporting the core communication features people expect from a modern messaging platform.',
cards: [
{ title: 'Privacy-Conscious Design', desc: 'Built with careful consideration for user communication and data handling.' },
{ title: 'Minimal and Focused', desc: 'Designed around essential messaging features without unnecessary complexity.' },
{ title: 'Reliable Experience', desc: 'Focused on providing a stable and familiar communication experience.' },
{ title: 'Continuous Improvement', desc: 'TalkPro will continue to improve its interface, features, and overall user experience.' },
],
},
preview: {
title: 'A Familiar App Experience, Reimagined with a Modern Look',
description: 'TalkPro keeps the communication experience familiar while refining the visual layer with updated icons, colors, spacing, and interface details.',
phoneAlt: 'TalkPro app preview',
previous: 'Previous',
next: 'Next',
},
download: {
eyebrow: 'DOWNLOAD',
title: 'Download',
logoAlt: 'TalkPro',
description: 'Download TalkPro and experience a cleaner, simpler, and more modern way to stay connected.',
android: 'ANDROID',
androidCta: 'APK Coming Soon',
ios: 'IOS',
iosCta: 'Coming on App Store',
androidAlt: 'Android',
appleAlt: 'Apple',
phoneAlt: 'TalkPro on phone',
},
footer: {
logoAlt: 'TalkPro',
description: 'TalkPro is a modern communication app designed for messaging, group conversations, channels, voice calls, and video calls.',
links: {
download: 'Download',
features: 'Features',
about: 'About',
contact: 'Contact',
},
email: 'email@hotmail.com',
phone: '+01 123 45562334',
android: 'ANDROID',
androidCta: 'APK Coming Soon',
ios: 'IOS',
iosCta: 'Coming on App Store',
copyright: '© 2026 TalkPro. All rights reserved.',
legal: 'Terms of Use · Privacy Policy · Support',
},
},
'zh-cn': {
meta: {
title: 'Talk Pro - 一个用户,多重场景。',
description: 'Talk Pro 是一款现代通讯应用,支持私聊、群组对话、频道、语音通话和视频通话。',
},
header: {
navLabel: '主导航',
logoIconAlt: 'TalkPro 图标',
logoAlt: 'TalkPro',
languageAlt: '语言',
openMenu: '打开菜单',
closeMenu: '关闭菜单',
nav: {
home: '首页',
features: '功能',
experience: '体验',
useCases: '使用场景',
reliability: '可靠性',
},
download: '下载',
},
hero: {
phoneAlt: 'iPhone 上的 TalkPro 应用',
badge: '✦ 支持 iOS 和 Android',
titleLine1: '以现代方式',
titleLine2: '保持连接',
description: 'TalkPro 是一款现代通讯应用专为清晰、简单、可靠的沟通而设计。从私聊到群组对话、频道、语音通话和视频通话TalkPro 帮助用户在熟悉的体验中保持连接。',
download: '下载 TalkPro ↓',
explore: '探索功能 →',
tags: ['身份分层', 'AI 原生通讯', '自适应隐私'],
},
why: {
eyebrow: '为什么选择 TALKPRO',
titleLine1: '为当代人们的',
titleLine2: '沟通方式而设计',
description: '如今的沟通发生在私人对话、社区、工作群组和内容频道之间。TalkPro 将这些核心沟通体验整合到简单且熟悉的界面中,让用户更轻松地连接、分享并掌握动态。',
illustrationAlt: '使用 TalkPro 沟通的人们',
cards: [
{ title: '简单', desc: '为日常沟通打造的易用体验。' },
{ title: '熟悉', desc: '从第一次使用起就自然顺手的通讯结构。' },
{ title: '连接', desc: '私聊、群组、频道、语音和视频集中在一个应用中。' },
{ title: '现代', desc: '清爽界面、干净视觉和流畅交互。' },
],
},
core: {
eyebrow: '核心功能',
title: '沟通所需,一应俱全',
description: '不同身份、不同对话和不同隐私等级不应被塞进单一扁平界面。TalkPro 让它们在同一平台中有序存在。',
cards: [
{ title: '私密消息', desc: '通过快速且熟悉的一对一对话保持联系。' },
{ title: '群组聊天', desc: '为朋友、团队、社区和共同讨论创建专属空间。' },
{ title: '频道', desc: '关注你关心的人或社区发布的动态、公告和内容。' },
{ title: '语音通话', desc: '当文字不够时,随时进行实时沟通。' },
{ title: '视频通话', desc: '通过简单可靠的视频通话体验面对面连接。' },
{ title: '媒体分享', desc: '在对话中分享照片、视频、文件和动态。' },
],
},
experience: {
title: '更清晰、更舒适的通讯体验',
cards: [
{ title: '清晰界面', desc: '干净布局,让对话更容易阅读和跟进。', alt: '清晰界面截图' },
{ title: '顺畅导航', desc: '用熟悉的操作在聊天、群组和频道之间切换。', alt: '顺畅导航截图' },
{ title: '精致视觉设计', desc: '现代图标、配色和界面细节,带来更 polished 的体验。', alt: '精致视觉设计截图' },
],
caption: 'TalkPro 以清晰为核心进行设计。每个界面都帮助用户专注于对话,减少干扰,并自然地在聊天、群组、频道和通话之间移动。',
},
useCases: {
eyebrow: '使用场景',
title: '适合个人、社交和社区沟通',
description: '通过为每种情境提供独立空间TalkPro 让个人、社交和专业沟通保持清晰有序。',
rows: [
{ title: '个人对话', desc: '以简单的私聊体验联系朋友、家人和亲近联系人。' },
{ title: '社区', desc: '加入群组对话,并在共同兴趣空间中保持活跃。' },
{ title: '团队和项目', desc: '在群组聊天中协调讨论、更新和快速决策。' },
{ title: '新闻和更新', desc: '关注频道,获取公告、资讯和社区内容。' },
],
},
trust: {
eyebrow: '可靠性',
title: '以用户信任为核心构建',
description: 'TalkPro 采用注重隐私的设计思路,并专注于可靠沟通。应用保持简单体验,同时支持现代通讯平台应具备的核心功能。',
cards: [
{ title: '注重隐私的设计', desc: '谨慎考虑用户沟通和数据处理方式。' },
{ title: '简洁聚焦', desc: '围绕核心通讯功能设计,避免不必要的复杂度。' },
{ title: '可靠体验', desc: '专注提供稳定且熟悉的沟通体验。' },
{ title: '持续改进', desc: 'TalkPro 将持续优化界面、功能和整体用户体验。' },
],
},
preview: {
title: '熟悉的应用体验,以现代视觉重新呈现',
description: 'TalkPro 保留熟悉的沟通体验,同时通过更新的图标、颜色、间距和界面细节优化视觉层。',
phoneAlt: 'TalkPro 应用预览',
previous: '上一张',
next: '下一张',
},
download: {
eyebrow: '下载',
title: '下载',
logoAlt: 'TalkPro',
description: '下载 TalkPro体验更清晰、更简单、更现代的连接方式。',
android: 'ANDROID',
androidCta: 'APK 即将推出',
ios: 'IOS',
iosCta: '即将上线 App Store',
androidAlt: 'Android',
appleAlt: 'Apple',
phoneAlt: '手机上的 TalkPro',
},
footer: {
logoAlt: 'TalkPro',
description: 'TalkPro 是一款现代通讯应用,专为消息、群组对话、频道、语音通话和视频通话而设计。',
links: {
download: '下载',
features: '功能',
about: '关于',
contact: '联系',
},
email: 'email@hotmail.com',
phone: '+01 123 45562334',
android: 'ANDROID',
androidCta: 'APK 即将推出',
ios: 'IOS',
iosCta: '即将上线 App Store',
copyright: '© 2026 TalkPro. 版权所有。',
legal: '使用条款 · 隐私政策 · 支持',
},
},
'zh-tw': {
meta: {
title: 'Talk Pro - 一個使用者,多重場景。',
description: 'Talk Pro 是一款現代通訊應用,支援私聊、群組對話、頻道、語音通話和視訊通話。',
},
header: {
navLabel: '主導覽',
logoIconAlt: 'TalkPro 圖示',
logoAlt: 'TalkPro',
languageAlt: '語言',
openMenu: '開啟選單',
closeMenu: '關閉選單',
nav: {
home: '首頁',
features: '功能',
experience: '體驗',
useCases: '使用情境',
reliability: '可靠性',
},
download: '下載',
},
hero: {
phoneAlt: 'iPhone 上的 TalkPro 應用',
badge: '✦ 支援 iOS 和 Android',
titleLine1: '以現代方式',
titleLine2: '保持連結',
description: 'TalkPro 是一款現代通訊應用專為清晰、簡單、可靠的溝通而設計。從私聊到群組對話、頻道、語音通話和視訊通話TalkPro 協助使用者在熟悉的體驗中保持連結。',
download: '下載 TalkPro ↓',
explore: '探索功能 →',
tags: ['身份分層', 'AI 原生通訊', '自適應隱私'],
},
why: {
eyebrow: '為什麼選擇 TALKPRO',
titleLine1: '為當代人們的',
titleLine2: '溝通方式而設計',
description: '如今的溝通發生在私人對話、社群、工作群組和內容頻道之間。TalkPro 將這些核心溝通體驗整合到簡單且熟悉的介面中,讓使用者更輕鬆地連結、分享並掌握動態。',
illustrationAlt: '使用 TalkPro 溝通的人們',
cards: [
{ title: '簡單', desc: '為日常溝通打造的易用體驗。' },
{ title: '熟悉', desc: '從第一次使用起就自然順手的通訊結構。' },
{ title: '連結', desc: '私聊、群組、頻道、語音和視訊集中在一個應用中。' },
{ title: '現代', desc: '清爽介面、乾淨視覺和流暢互動。' },
],
},
core: {
eyebrow: '核心功能',
title: '溝通所需,一應俱全',
description: '不同身份、不同對話和不同隱私等級不應被塞進單一扁平介面。TalkPro 讓它們在同一平台中有序存在。',
cards: [
{ title: '私密訊息', desc: '透過快速且熟悉的一對一對話保持聯繫。' },
{ title: '群組聊天', desc: '為朋友、團隊、社群和共同討論建立專屬空間。' },
{ title: '頻道', desc: '關注你在意的人或社群發布的動態、公告和內容。' },
{ title: '語音通話', desc: '當文字不夠時,隨時進行即時溝通。' },
{ title: '視訊通話', desc: '透過簡單可靠的視訊通話體驗面對面連結。' },
{ title: '媒體分享', desc: '在對話中分享照片、影片、檔案和動態。' },
],
},
experience: {
title: '更清晰、更舒適的通訊體驗',
cards: [
{ title: '清晰介面', desc: '乾淨布局,讓對話更容易閱讀和跟進。', alt: '清晰介面截圖' },
{ title: '順暢導覽', desc: '用熟悉的操作在聊天、群組和頻道之間切換。', alt: '順暢導覽截圖' },
{ title: '精緻視覺設計', desc: '現代圖示、配色和介面細節,帶來更精緻的體驗。', alt: '精緻視覺設計截圖' },
],
caption: 'TalkPro 以清晰為核心進行設計。每個畫面都協助使用者專注於對話,減少干擾,並自然地在聊天、群組、頻道和通話之間移動。',
},
useCases: {
eyebrow: '使用情境',
title: '適合個人、社交和社群溝通',
description: '透過為每種情境提供獨立空間TalkPro 讓個人、社交和專業溝通保持清晰有序。',
rows: [
{ title: '個人對話', desc: '以簡單的私聊體驗聯繫朋友、家人和親近聯絡人。' },
{ title: '社群', desc: '加入群組對話,並在共同興趣空間中保持活躍。' },
{ title: '團隊和專案', desc: '在群組聊天中協調討論、更新和快速決策。' },
{ title: '新聞和更新', desc: '關注頻道,取得公告、資訊和社群內容。' },
],
},
trust: {
eyebrow: '可靠性',
title: '以使用者信任為核心建構',
description: 'TalkPro 採用注重隱私的設計思路,並專注於可靠溝通。應用保持簡單體驗,同時支援現代通訊平台應具備的核心功能。',
cards: [
{ title: '注重隱私的設計', desc: '謹慎考量使用者溝通和資料處理方式。' },
{ title: '簡潔聚焦', desc: '圍繞核心通訊功能設計,避免不必要的複雜度。' },
{ title: '可靠體驗', desc: '專注提供穩定且熟悉的溝通體驗。' },
{ title: '持續改進', desc: 'TalkPro 將持續優化介面、功能和整體使用者體驗。' },
],
},
preview: {
title: '熟悉的應用體驗,以現代視覺重新呈現',
description: 'TalkPro 保留熟悉的溝通體驗,同時透過更新的圖示、顏色、間距和介面細節優化視覺層。',
phoneAlt: 'TalkPro 應用預覽',
previous: '上一張',
next: '下一張',
},
download: {
eyebrow: '下載',
title: '下載',
logoAlt: 'TalkPro',
description: '下載 TalkPro體驗更清晰、更簡單、更現代的連結方式。',
android: 'ANDROID',
androidCta: 'APK 即將推出',
ios: 'IOS',
iosCta: '即將上線 App Store',
androidAlt: 'Android',
appleAlt: 'Apple',
phoneAlt: '手機上的 TalkPro',
},
footer: {
logoAlt: 'TalkPro',
description: 'TalkPro 是一款現代通訊應用,專為訊息、群組對話、頻道、語音通話和視訊通話而設計。',
links: {
download: '下載',
features: '功能',
about: '關於',
contact: '聯絡',
},
email: 'email@hotmail.com',
phone: '+01 123 45562334',
android: 'ANDROID',
androidCta: 'APK 即將推出',
ios: 'IOS',
iosCta: '即將上線 App Store',
copyright: '© 2026 TalkPro. 版權所有。',
legal: '使用條款 · 隱私權政策 · 支援',
},
},
} as const
export type Translations = (typeof translations)[Lang]
export function getTranslations(lang: Lang): Translations {
return translations[lang]
}

View File

@@ -3,16 +3,23 @@ import '../styles/global.css'
export interface Props {
title?: string
description?: string
lang?: string
}
const { title = 'Talk Pro — One User. Multiple Worlds.' } = Astro.props
const {
title = 'Talk Pro - One User. Multiple Worlds.',
description = 'Talk Pro is a modern messaging app for private chats, group conversations, channels, voice and video calls.',
lang = 'en',
} = Astro.props
---
<!doctype html>
<html lang="en">
<html lang={lang}>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Talk Pro is a modern messaging app for private chats, group conversations, channels, voice and video calls." />
<meta name="description" content={description} />
<title>{title}</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
@@ -25,7 +32,6 @@ const { title = 'Talk Pro — One User. Multiple Worlds.' } = Astro.props
const header = document.getElementById('site-header');
const getOffset = () => header ? header.offsetHeight : 0;
// Smooth scroll with header offset
document.querySelectorAll('a[href^="#"]').forEach(link => {
link.addEventListener('click', e => {
const href = link.getAttribute('href');
@@ -38,7 +44,6 @@ const { title = 'Talk Pro — One User. Multiple Worlds.' } = Astro.props
});
});
// Active nav highlighting via IntersectionObserver
const navLinks = document.querySelectorAll('[data-nav-link]');
const sections = Array.from(navLinks)
.map(l => document.querySelector(l.getAttribute('href') ?? ''))
@@ -52,8 +57,7 @@ const { title = 'Talk Pro — One User. Multiple Worlds.' } = Astro.props
if (!visible) return;
navLinks.forEach(link => {
const active = link.getAttribute('href') === `#${visible.target.id}`;
link.classList.toggle('!text-[#f28a4b]', active);
link.classList.toggle('text-[#7a726d]', !active);
link.classList.toggle('is-active', active);
});
}, { rootMargin: '-30% 0px -60% 0px', threshold: 0 });
sections.forEach(s => observer.observe(s));

View File

@@ -0,0 +1,37 @@
---
import Base from '../../layouts/Base.astro'
import Header from '../../components/Header.astro'
import Hero from '../../components/Hero.astro'
import WhyTalkPro from '../../components/WhyTalkPro.astro'
import CoreSystem from '../../components/CoreSystem.astro'
import Experience from '../../components/Experience.astro'
import UseCases from '../../components/UseCases.astro'
import Trust from '../../components/Trust.astro'
import AppPreview from '../../components/AppPreview.astro'
import DownloadCTA from '../../components/DownloadCTA.astro'
import Footer from '../../components/Footer.astro'
import { defaultLang, getTranslations, isLang, languages } from '../../i18n/translations'
export function getStaticPaths() {
return languages
.filter(lang => lang !== defaultLang)
.map(lang => ({ params: { lang } }))
}
const currentLang = Astro.params.lang
const lang = isLang(currentLang) ? currentLang : defaultLang
const t = getTranslations(lang)
---
<Base lang={lang} title={t.meta.title} description={t.meta.description}>
<Header lang={lang} t={t.header} />
<Hero t={t.hero} />
<WhyTalkPro t={t.why} />
<CoreSystem t={t.core} />
<Experience t={t.experience} />
<UseCases t={t.useCases} />
<Trust t={t.trust} />
<AppPreview t={t.preview} />
<DownloadCTA t={t.download} />
<Footer t={t.footer} />
</Base>

View File

@@ -10,17 +10,21 @@ import Trust from '../components/Trust.astro'
import AppPreview from '../components/AppPreview.astro'
import DownloadCTA from '../components/DownloadCTA.astro'
import Footer from '../components/Footer.astro'
import { defaultLang, getTranslations } from '../i18n/translations'
const lang = defaultLang
const t = getTranslations(lang)
---
<Base>
<Header />
<Hero />
<WhyTalkPro />
<CoreSystem />
<Experience />
<UseCases />
<Trust />
<AppPreview />
<DownloadCTA />
<Footer />
<Base lang={lang} title={t.meta.title} description={t.meta.description}>
<Header lang={lang} t={t.header} />
<Hero t={t.hero} />
<WhyTalkPro t={t.why} />
<CoreSystem t={t.core} />
<Experience t={t.experience} />
<UseCases t={t.useCases} />
<Trust t={t.trust} />
<AppPreview t={t.preview} />
<DownloadCTA t={t.download} />
<Footer t={t.footer} />
</Base>

241
src/styles/download.css Normal file
View File

@@ -0,0 +1,241 @@
.download-cta {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: 400px;
overflow: hidden;
background: #fff;
border-top: 1px solid #eec8b8;
}
.download-cta__pattern {
position: absolute;
top: 50%;
left: 50%;
width: 100%;
max-width: 1920px;
height: 923px;
pointer-events: none;
transform: translate(-50%, -50%);
}
.download-cta__inner {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
max-width: 1280px;
gap: 32px;
margin: 0 auto;
padding: 48px 16px;
}
.download-cta__content {
display: flex;
flex: 1;
flex-direction: column;
align-items: flex-start;
justify-content: center;
min-width: 0;
gap: 36px;
overflow: clip;
}
.download-cta__copy {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
gap: 16px;
}
.download-cta__heading {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
flex-shrink: 0;
gap: 20px;
}
.download-cta__title {
margin: 0;
font-size: 32px;
font-weight: 700;
line-height: 1.2;
color: #1a1a1a;
white-space: nowrap;
}
.download-cta__logo-frame {
position: relative;
flex-shrink: 0;
width: 188px;
height: 72px;
}
.download-cta__logo {
position: absolute;
inset: 0;
display: block;
width: 100%;
max-width: none;
height: 100%;
}
.download-cta__description {
max-width: 542px;
margin: 0;
font-size: 18px;
font-weight: 400;
line-height: 1.5;
color: #7a726d;
}
.store-badges {
display: flex;
flex-wrap: wrap;
align-items: center;
flex-shrink: 0;
width: 100%;
gap: 16px;
overflow: clip;
}
.store-badge {
display: flex;
align-items: center;
flex-shrink: 0;
width: 100%;
height: 70px;
gap: 8px;
padding: 12px 16px;
overflow: clip;
border-radius: 20px;
}
.store-badge--android {
background: #f28a4b;
border: 1px solid #c5834e;
}
.store-badge--ios {
background: #383838;
border: 1px solid #141414;
}
.store-badge__icon {
display: block;
flex-shrink: 0;
width: 44px;
height: 44px;
}
.store-badge__icon-frame {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
width: 44px;
height: 44px;
background: #151515;
border-radius: 12px;
}
.store-badge__apple-icon {
display: block;
width: 22px;
height: 27px;
}
.store-badge__copy {
display: flex;
flex-direction: column;
align-items: flex-start;
flex-shrink: 0;
gap: 3px;
overflow: clip;
white-space: nowrap;
}
.store-badge__platform {
margin: 0;
font-size: 11px;
font-weight: 600;
line-height: normal;
letter-spacing: 0.05px;
}
.store-badge--android .store-badge__platform {
color: #ffd6bc;
}
.store-badge--ios .store-badge__platform {
color: #ccc;
}
.store-badge__label {
margin: 0;
font-size: 15px;
font-weight: 600;
line-height: normal;
color: #fff;
}
.download-cta__phone {
position: relative;
display: none;
flex-shrink: 0;
width: 418px;
height: 510px;
}
.download-cta__phone-crop {
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
}
.download-cta__phone-image {
position: absolute;
top: -18.05%;
left: 3.8%;
width: 92.43%;
max-width: none;
height: 136.1%;
}
@media (min-width: 640px) {
.store-badge {
width: 260px;
}
}
@media (min-width: 768px) {
.download-cta__title {
font-size: 40px;
}
}
@media (min-width: 1024px) {
.download-cta {
height: 600px;
}
.download-cta__inner {
flex-direction: row;
gap: 0;
padding: 0;
}
.download-cta__title {
font-size: 48px;
}
.download-cta__phone {
display: block;
}
}

150
src/styles/features.css Normal file
View File

@@ -0,0 +1,150 @@
.features {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
gap: 60px;
padding: 64px 0;
overflow: hidden;
}
.features__bg {
position: absolute;
top: 50%;
left: 50%;
width: 2363px;
height: 1319px;
object-fit: cover;
opacity: 0.2;
pointer-events: none;
transform: translate(-50%, -50%);
}
.features__header {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
width: 100%;
max-width: 1280px;
gap: 24px;
margin: 0 auto;
padding: 0 16px;
overflow: clip;
}
.features__title {
width: 100%;
margin: 0;
font-size: 32px;
font-weight: 700;
line-height: 1.2;
color: #1a1a1a;
text-align: center;
}
.features__description {
width: 100%;
margin: 0;
font-size: 18px;
font-weight: 400;
line-height: 1.5;
color: #7a726d;
text-align: center;
}
.features__grid {
position: relative;
display: grid;
grid-template-columns: minmax(0, 1fr);
width: 100%;
max-width: 1280px;
gap: 22px;
margin: 0 auto;
padding: 0 16px;
}
.feature-card {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
padding: 32px;
background: rgba(255, 255, 255, 0.78);
border-radius: 30px;
}
.feature-card__icon-frame {
position: relative;
flex-shrink: 0;
width: 160px;
height: 160px;
overflow: hidden;
}
.feature-card__icon {
position: absolute;
inset: 0;
width: 100%;
max-width: none;
height: 100%;
object-fit: contain;
}
.feature-card__copy {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
gap: 12px;
text-align: center;
}
.feature-card__title {
width: 100%;
margin: 0;
font-size: 24px;
font-weight: 700;
line-height: normal;
color: #2e2a28;
}
.feature-card__description {
width: 100%;
margin: 0;
font-size: 15px;
font-weight: 400;
line-height: 1.5;
color: #7a726d;
}
@media (min-width: 768px) {
.features__title {
font-size: 40px;
}
.features__grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (min-width: 1024px) {
.features {
padding: 120px 0;
}
.features__header {
padding: 0 180px;
}
.features__title {
font-size: 48px;
}
.features__grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
padding: 0;
}
}

162
src/styles/footer.css Normal file
View File

@@ -0,0 +1,162 @@
.site-footer {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
padding: 64px 0;
background: #fef0eb;
}
.site-footer__inner {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
max-width: 1280px;
gap: 36px;
margin: 0 auto;
padding: 0 16px;
}
.site-footer__top {
display: flex;
flex-direction: column;
width: 100%;
gap: 40px;
}
.site-footer__brand {
display: flex;
flex-direction: column;
align-items: flex-start;
flex-shrink: 0;
gap: 24px;
overflow: clip;
}
.site-footer__logo-frame {
position: relative;
width: 220px;
height: 64px;
}
.site-footer__logo {
position: absolute;
inset: 0;
width: 100%;
max-width: none;
height: 100%;
object-fit: cover;
pointer-events: none;
}
.site-footer__description {
max-width: 320px;
margin: 0;
font-size: 14px;
font-weight: 400;
line-height: 1.5;
color: #7a726d;
}
.site-footer__links {
display: flex;
align-items: center;
flex-shrink: 0;
gap: 32px;
line-height: normal;
}
.site-footer__link-column {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 160px;
gap: 24px;
overflow: clip;
}
.site-footer__link,
.site-footer__text {
margin: 0;
font-size: 14px;
line-height: normal;
color: #4a4a4a;
white-space: nowrap;
}
.site-footer__link {
font-weight: 400;
text-decoration: none;
transition: color 160ms ease;
}
.site-footer__link:hover {
color: #f28a4b;
}
.site-footer__text--heading {
font-weight: 500;
}
.site-footer__divider {
width: 100%;
height: 1px;
background: #e3d9d1;
}
.site-footer__bottom {
display: flex;
flex-direction: column;
width: 100%;
gap: 12px;
overflow: clip;
}
.site-footer__legal {
margin: 0;
font-size: 14px;
font-weight: 400;
line-height: normal;
color: #7a726d;
}
.site-footer__spacer {
display: none;
}
@media (min-width: 768px) {
.site-footer__bottom {
flex-direction: row;
align-items: center;
gap: 20px;
}
.site-footer__legal {
white-space: nowrap;
}
.site-footer__spacer {
display: block;
flex: 1;
min-width: 0;
}
}
@media (min-width: 1024px) {
.site-footer {
padding: 120px 0;
}
.site-footer__inner {
padding: 0;
}
.site-footer__top {
flex-direction: row;
align-items: flex-start;
justify-content: space-between;
gap: 0;
}
}

View File

@@ -1 +1,10 @@
/* UnoCSS handles reset and utilities via astro.config.mjs injectReset */
@import './header.css';
@import './hero.css';
@import './sections.css';
@import './download.css';
@import './footer.css';
@import './why.css';
@import './features.css';
@import './trust.css';
@import './preview.css';

315
src/styles/header.css Normal file
View File

@@ -0,0 +1,315 @@
.site-header {
position: sticky;
top: 0;
z-index: 50;
width: 100%;
background: #fff;
border-bottom: 1px solid #e3d9d1;
}
.site-header__bar {
display: flex;
align-items: center;
width: 100%;
max-width: 1280px;
height: 72px;
gap: 24px;
margin: 0 auto;
padding: 0 16px;
}
.site-header__brand,
.site-header__actions {
display: flex;
flex: 1;
min-width: 0;
}
.site-header__brand {
align-items: center;
}
.site-header__actions {
align-items: center;
justify-content: flex-end;
gap: 12px;
}
.site-logo {
position: relative;
display: block;
flex-shrink: 0;
width: 143px;
height: 42px;
}
.site-logo__icon-frame {
position: absolute;
top: 0;
left: 0;
width: 53px;
height: 42px;
overflow: hidden;
}
.site-logo__icon {
position: absolute;
top: -13.49%;
left: 0;
width: 100%;
max-width: none;
height: 126.98%;
}
.site-logo__wordmark-frame {
position: absolute;
inset: 26.97% 0 7.92% 45.45%;
}
.site-logo__wordmark {
position: absolute;
inset: 0;
display: block;
width: 100%;
max-width: none;
height: 100%;
}
.site-nav {
display: none;
align-items: center;
flex-shrink: 0;
gap: 32px;
}
.site-nav__link {
font-size: 14px;
font-weight: 600;
line-height: normal;
color: #7a726d;
text-decoration: none;
white-space: nowrap;
transition: color 160ms ease;
}
.site-nav__link:hover,
.site-nav__link.is-active {
color: #f28a4b;
}
.language-switcher {
position: relative;
display: none;
flex-shrink: 0;
}
.language-switcher__button {
display: flex;
align-items: center;
justify-content: center;
height: 43px;
gap: 8px;
padding: 0 16px 0 12px;
background: #fff;
border: 1px solid rgba(46, 42, 40, 0.3);
border-radius: 17px;
cursor: pointer;
transition: border-color 160ms ease;
}
.language-switcher__button:hover,
.language-switcher__button[aria-expanded='true'] {
border-color: #f28a4b;
}
.language-switcher__icon {
display: block;
width: 26px;
height: 26px;
object-fit: contain;
}
.language-switcher__current {
font-size: 14px;
font-weight: 600;
line-height: 14px;
color: #2e2a28;
white-space: nowrap;
}
.language-switcher__menu {
position: absolute;
top: 52px;
right: 0;
z-index: 60;
width: 240px;
overflow: hidden;
background: #fff;
border: 1px solid #e3d9d1;
border-radius: 18px;
box-shadow: 0 16px 40px rgba(46, 42, 40, 0.16);
}
.language-switcher__menu.is-hidden {
display: none;
}
.language-switcher__option {
display: block;
padding: 18px 24px;
font-size: 18px;
font-weight: 600;
line-height: normal;
color: #7a726d;
text-decoration: none;
transition: background-color 160ms ease, color 160ms ease;
}
.language-switcher__option:hover {
color: #f28a4b;
background: #fef0eb;
}
.language-switcher__option.is-active {
color: #2e2a28;
background: #f8f3ee;
}
.site-header__download {
display: none;
align-items: center;
justify-content: center;
flex-shrink: 0;
padding: 13px 22px;
background: #f28a4b;
border-radius: 17px;
text-decoration: none;
transition: background-color 160ms ease;
}
.site-header__download:hover {
background: #e07a3b;
}
.site-header__download-label {
font-size: 14px;
font-weight: 700;
line-height: normal;
color: #fff;
white-space: nowrap;
}
.menu-toggle {
display: flex;
flex-shrink: 0;
flex-direction: column;
justify-content: center;
width: 40px;
height: 40px;
gap: 5px;
padding: 8px;
background: transparent;
border: 0;
cursor: pointer;
}
.menu-toggle__bar {
display: block;
width: 100%;
height: 2px;
background: #2e2a28;
border-radius: 2px;
transform-origin: center;
transition: transform 240ms ease, opacity 240ms ease;
}
.mobile-nav {
background: #fff;
border-top: 1px solid #e3d9d1;
}
.mobile-nav.is-hidden {
display: none;
}
.mobile-nav__list {
display: flex;
flex-direction: column;
padding: 16px 24px;
margin: 0;
list-style: none;
}
.mobile-nav__link {
display: block;
padding: 16px 0;
font-size: 16px;
font-weight: 600;
color: #2e2a28;
text-decoration: none;
border-bottom: 1px solid #e3d9d1;
}
.mobile-nav__link--last {
border-bottom: 0;
}
.mobile-nav__languages {
display: flex;
align-items: center;
gap: 16px;
padding: 16px 0;
border-top: 1px solid #e3d9d1;
}
.mobile-nav__language-link {
font-size: 15px;
font-weight: 600;
color: #2e2a28;
text-decoration: none;
}
.mobile-nav__language-link.is-active {
color: #f28a4b;
}
.mobile-nav__download-item {
margin: 16px 0 8px;
}
.mobile-nav__download {
display: block;
padding: 14px 24px;
font-size: 15px;
font-weight: 700;
color: #fff;
text-align: center;
text-decoration: none;
background: #f28a4b;
border-radius: 17px;
transition: background-color 160ms ease;
}
.mobile-nav__download:hover {
background: #e07a3b;
}
@media (min-width: 1024px) {
.site-header__bar {
padding: 0 24px;
}
.site-nav,
.language-switcher,
.site-header__download {
display: flex;
}
.menu-toggle {
display: none;
}
.mobile-nav {
display: none !important;
}
}

237
src/styles/hero.css Normal file
View File

@@ -0,0 +1,237 @@
.hero {
position: relative;
display: flex;
align-items: flex-start;
justify-content: center;
width: 100%;
min-height: 600px;
overflow: hidden;
}
.hero__bg {
position: absolute;
inset: 0;
width: 100%;
max-width: none;
height: 100%;
object-fit: cover;
pointer-events: none;
}
.hero__inner {
position: relative;
display: flex;
flex-direction: column-reverse;
align-items: flex-start;
width: 100%;
max-width: 1280px;
height: 100%;
gap: 40px;
margin: 0 auto;
padding: 0 16px;
}
.hero__phone-column {
display: none;
}
.hero__phone-frame {
position: relative;
width: 100%;
aspect-ratio: 673 / 1108;
}
.hero__phone-crop {
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
}
.hero__phone {
position: absolute;
top: -7.18%;
left: -2.67%;
width: 105.35%;
max-width: none;
height: 114.36%;
}
.hero__content {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
flex-shrink: 0;
width: 100%;
height: 100%;
gap: 60px;
padding: 32px 0;
overflow: clip;
}
.hero__badge {
display: flex;
align-items: center;
flex-shrink: 0;
padding: 12px 16px;
overflow: clip;
background: #fff;
border: 1px solid #f08458;
border-radius: 999px;
}
.hero__badge-text {
margin: 0;
font-size: 14px;
font-weight: 700;
line-height: normal;
color: #0d0d0d;
}
.hero__copy {
display: flex;
flex-direction: column;
align-items: flex-start;
flex-shrink: 0;
width: 100%;
gap: 24px;
}
.hero__title {
width: 100%;
font-size: 40px;
font-weight: 700;
line-height: 1.1;
color: #2e2a28;
}
.hero__title-line {
margin: 0;
line-height: 1.1;
}
.hero__description {
width: 100%;
margin: 0;
font-size: 18px;
font-weight: 400;
line-height: 1.5;
color: #7a726d;
}
.hero__actions {
display: flex;
flex-wrap: wrap;
align-items: center;
flex-shrink: 0;
gap: 14px;
overflow: clip;
}
.hero__button {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
padding: 14px 24px;
overflow: clip;
border-radius: 17px;
text-decoration: none;
transition: background-color 160ms ease;
}
.hero__button--primary {
background: #f28a4b;
}
.hero__button--primary:hover {
background: #e07a3b;
}
.hero__button--secondary {
background: rgba(255, 255, 255, 0.55);
border: 1px solid #e3d9d1;
}
.hero__button--secondary:hover {
background: #fff;
}
.hero__button-label {
font-size: 15px;
font-weight: 700;
line-height: normal;
white-space: nowrap;
}
.hero__button--primary .hero__button-label {
color: #fff;
}
.hero__button--secondary .hero__button-label {
color: #2e2a28;
}
.hero__tags {
display: flex;
flex-wrap: wrap;
align-items: center;
flex-shrink: 0;
gap: 10px;
overflow: clip;
}
.hero__tag {
display: flex;
align-items: center;
flex-shrink: 0;
padding: 9px 14px;
overflow: clip;
background: rgba(255, 255, 255, 0.68);
border: 1px solid #fff;
border-radius: 999px;
}
.hero__tag-text {
font-size: 14px;
font-weight: 700;
line-height: normal;
color: #7a726d;
white-space: nowrap;
}
@media (min-width: 768px) {
.hero__title {
font-size: 56px;
}
}
@media (min-width: 1024px) {
.hero {
height: 891px;
}
.hero__inner {
flex-direction: row;
padding: 0;
}
.hero__phone-column {
display: flex;
align-items: center;
flex: 1;
min-width: 0;
height: 100%;
padding-top: 60px;
}
.hero__content {
width: 660px;
padding: 80px 0;
}
.hero__title {
font-size: 72px;
}
}

158
src/styles/preview.css Normal file
View File

@@ -0,0 +1,158 @@
.app-preview {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
gap: 60px;
padding: 64px 16px 0;
overflow: hidden;
background: #fef0eb;
}
.app-preview__header {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
max-width: 940px;
gap: 40px;
margin: 0 auto;
overflow: clip;
}
.app-preview__title {
width: 100%;
margin: 0;
font-size: 32px;
font-weight: 700;
line-height: 1.2;
color: #1a1a1a;
text-align: center;
}
.app-preview__description {
width: 100%;
margin: 0;
font-size: 18px;
font-weight: 400;
line-height: 1.5;
color: #7a726d;
text-align: center;
}
.app-preview__carousel {
display: flex;
align-items: flex-end;
justify-content: center;
flex-shrink: 0;
width: 100%;
gap: 20px;
}
.app-preview__side-phone {
position: relative;
display: none;
flex-shrink: 0;
width: 336px;
height: 396px;
overflow: hidden;
opacity: 0.2;
pointer-events: none;
transition: opacity 300ms ease;
}
.app-preview__phone-image {
position: absolute;
top: -0.03%;
left: 0;
width: 100%;
max-width: none;
height: 175.34%;
transition: opacity 300ms ease;
}
.app-preview__control-wrap {
display: none;
align-items: flex-end;
align-self: stretch;
flex-shrink: 0;
}
.app-preview__control-inner {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.app-preview__button {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
width: 48px;
height: 48px;
background: #f08458;
border: 0;
border-radius: 9999px;
cursor: pointer;
transition: background-color 160ms ease, transform 160ms ease;
}
.app-preview__button:hover {
background: #e07a3b;
}
.app-preview__button:active {
transform: scale(0.95);
}
.app-preview__button-icon {
display: block;
width: 24px;
height: 24px;
}
.app-preview__button-icon--next {
transform: rotate(180deg);
}
.app-preview__center-phone {
position: relative;
flex-shrink: 0;
width: 100%;
aspect-ratio: 459 / 542;
overflow: hidden;
pointer-events: none;
}
@media (min-width: 768px) {
.app-preview__title {
font-size: 40px;
}
}
@media (min-width: 1024px) {
.app-preview {
padding: 120px 130px 0;
}
.app-preview__title {
font-size: 48px;
}
.app-preview__side-phone,
.app-preview__control-wrap {
display: flex;
}
.app-preview__side-phone {
display: block;
}
.app-preview__center-phone {
width: 459px;
height: 542px;
aspect-ratio: auto;
}
}

331
src/styles/sections.css Normal file
View File

@@ -0,0 +1,331 @@
.experience {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 64px 16px;
background: #fff;
}
.experience__inner {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
max-width: 1008px;
gap: 40px;
margin: 0 auto;
}
.experience__title {
width: 100%;
margin: 0;
font-size: 32px;
font-weight: 700;
line-height: 1.2;
color: #1a1a1a;
text-align: center;
}
.experience__body {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
}
.experience__grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
width: 100%;
gap: 24px;
}
.experience-card {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
gap: 28px;
padding: 0 0 36px;
overflow: hidden;
background: linear-gradient(to bottom, #fef0eb, #fff);
border-radius: 30px 30px 0 0;
}
.experience-card__media {
position: relative;
flex-shrink: 0;
width: 100%;
height: 232px;
overflow: hidden;
}
.experience-card__media--tinted {
display: flex;
flex-direction: column;
align-items: flex-start;
background: #ffeddf;
}
.experience-card__media-crop {
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
}
.experience-card__image {
position: absolute;
max-width: none;
}
.experience-card__image--one {
top: -58.58%;
left: 0;
width: 100%;
height: 298.5%;
}
.experience-card__image--two {
top: -335.6%;
left: -5.95%;
width: 137.79%;
height: 411.28%;
}
.experience-card__image--three {
top: -99.23%;
left: 0;
width: 100%;
height: 298.5%;
}
.experience-card__copy {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
gap: 16px;
max-width: 248px;
padding: 0;
overflow: clip;
text-align: center;
}
.experience-card__title {
width: 100%;
margin: 0;
font-size: 24px;
font-weight: 600;
line-height: 1.4;
letter-spacing: -0.47px;
color: #0d0d0d;
}
.experience-card__description {
width: 100%;
margin: 0;
font-size: 16px;
font-weight: 500;
line-height: 1.5;
letter-spacing: -0.18px;
color: #7a726d;
}
.experience__caption {
width: 100%;
margin: 0;
font-size: 18px;
font-weight: 400;
line-height: 1.5;
color: #7a726d;
text-align: center;
}
.use-cases {
display: flex;
align-items: flex-start;
justify-content: center;
width: 100%;
padding: 64px 16px;
background: #fef0eb;
}
.use-cases__inner {
display: grid;
grid-template-columns: minmax(0, 1fr);
width: 100%;
max-width: 1280px;
gap: 32px;
margin: 0 auto;
}
.use-cases__copy {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
gap: 24px;
overflow: clip;
}
.section-eyebrow {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
padding: 12px 24px;
background: #fff;
border: 1px solid #fbbfa3;
border-radius: 9999px;
}
.section-eyebrow__text {
font-size: 14px;
font-weight: 700;
line-height: normal;
color: #f08458;
text-align: center;
white-space: nowrap;
}
.use-cases__title {
width: 100%;
margin: 0;
font-size: 32px;
font-weight: 700;
line-height: 1.2;
color: #1a1a1a;
}
.use-cases__description {
width: 100%;
margin: 0;
font-size: 18px;
font-weight: 400;
line-height: 1.5;
color: #7a726d;
}
.use-cases__rows {
display: flex;
flex-direction: column;
align-items: stretch;
min-width: 0;
overflow: hidden;
border-radius: 30px;
gap: 1px;
}
.use-case-row {
display: grid;
grid-template-columns: minmax(0, 1fr);
width: 100%;
overflow: hidden;
background: #faede8;
}
.use-case-row__title-cell,
.use-case-row__description-cell {
display: flex;
align-items: center;
min-width: 0;
padding: 16px 24px;
}
.use-case-row__title-cell {
background: #f08458;
}
.use-case-row__description-cell {
background: #fff;
}
.use-case-row__title {
min-width: 0;
margin: 0;
font-size: 18px;
font-weight: 600;
line-height: normal;
color: #fff;
}
.use-case-row__description {
min-width: 0;
margin: 0;
font-size: 15px;
font-weight: 500;
line-height: 1.5;
color: #7a726d;
}
@media (min-width: 640px) {
.use-case-row {
grid-template-columns: minmax(220px, 300px) minmax(280px, 1fr);
min-height: 120px;
}
.use-case-row__title-cell,
.use-case-row__description-cell {
padding: 24px 36px;
}
.use-case-row__title {
font-size: 20px;
}
}
@media (min-width: 768px) {
.experience__title,
.use-cases__title {
font-size: 40px;
}
}
@media (min-width: 1024px) {
.experience {
padding: 120px 16px;
}
.experience__grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.experience-card {
height: 477px;
}
.experience-card__media {
height: 232px;
}
.experience-card__title {
white-space: nowrap;
}
.experience__title,
.use-cases__title {
font-size: 48px;
}
}
@media (min-width: 1200px) {
.use-cases {
padding: 120px 64px;
}
.use-cases__inner {
grid-template-columns: minmax(420px, 540px) minmax(560px, 1fr);
align-items: center;
gap: 40px;
}
}
@media (min-width: 1440px) {
.use-cases {
padding-right: 130px;
padding-left: 130px;
}
}

192
src/styles/trust.css Normal file
View File

@@ -0,0 +1,192 @@
.trust {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
padding: 64px 16px;
background: #fff;
}
.trust__inner {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
max-width: 1280px;
gap: 40px;
margin: 0 auto;
}
.trust__header {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
gap: 24px;
overflow: clip;
}
.trust__title {
width: 100%;
margin: 0;
font-size: 32px;
font-weight: 700;
line-height: 1.2;
color: #1a1a1a;
}
.trust__description {
width: 100%;
margin: 0;
font-size: 18px;
font-weight: 400;
line-height: 1.5;
color: #7a726d;
}
.trust__grid {
display: grid;
grid-template-columns: minmax(0, 1fr);
align-items: center;
justify-content: center;
width: 100%;
gap: 32px;
}
.trust-card {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
min-width: 0;
gap: 16px;
padding: 24px;
border-radius: 30px;
}
.trust-card__icon-frame {
position: relative;
flex-shrink: 0;
width: 128px;
height: 128px;
}
.trust-card__icon-crop {
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
}
.trust-card__icon {
position: absolute;
max-width: none;
}
.trust-card__icon--one {
top: 7.04%;
left: -31.48%;
width: 312.73%;
height: 174.55%;
}
.trust-card__icon--two {
top: 3.1%;
left: -164.72%;
width: 335.61%;
height: 187.32%;
}
.trust-card__icon--three {
top: -105.62%;
left: -187.93%;
width: 378.86%;
height: 211.46%;
}
.trust-card__icon--four {
top: 0;
left: 4.14%;
width: 100%;
height: 100%;
}
.trust-card__copy {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
gap: 8px;
}
.trust-card__title {
width: 100%;
margin: 0;
font-size: 16px;
font-weight: 600;
line-height: 22px;
color: #0d0d0d;
}
.trust-card__description {
width: 100%;
margin: 0;
font-size: 15px;
font-weight: 500;
line-height: 1.5;
color: #7a726d;
}
.trust__divider {
position: relative;
display: none;
flex-shrink: 0;
width: 0;
height: 118px;
}
.trust__divider-frame {
position: absolute;
inset: 0 -0.5px;
}
.trust__divider-image {
display: block;
width: 100%;
max-width: none;
height: 100%;
}
@media (min-width: 768px) {
.trust__title {
font-size: 40px;
}
.trust__grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (min-width: 1024px) {
.trust {
padding: 120px;
}
.trust__title {
font-size: 48px;
}
.trust__grid {
display: flex;
gap: 24px;
}
.trust-card {
flex: 1;
}
.trust__divider {
display: block;
}
}

211
src/styles/why.css Normal file
View File

@@ -0,0 +1,211 @@
.why {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
padding: 64px 16px;
background: #fff;
}
.why__inner {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
max-width: 1280px;
gap: 40px;
margin: 0 auto;
}
.why__intro {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
gap: 36px;
overflow: clip;
}
.why__copy {
display: flex;
flex: 1;
flex-direction: column;
align-items: flex-start;
min-width: 0;
gap: 36px;
}
.why__text {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
gap: 24px;
}
.why__title {
width: 100%;
font-size: 32px;
font-weight: 700;
color: #1a1a1a;
}
.why__title-line {
margin: 0;
line-height: 1.2;
}
.why__underline {
position: relative;
flex-shrink: 0;
width: 295.5px;
height: 0;
}
.why__underline-frame {
position: absolute;
inset: -0.5px 0;
}
.why__underline-image {
display: block;
width: 100%;
max-width: none;
height: 100%;
}
.why__description {
width: 100%;
margin: 0;
font-size: 18px;
font-weight: 400;
line-height: 1.5;
color: #7a726d;
}
.why__illustration {
position: relative;
display: none;
flex-shrink: 0;
width: 480px;
height: 480px;
}
.why__illustration-image {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: contain;
}
.why__grid {
display: grid;
grid-template-columns: minmax(0, 1fr);
width: 100%;
gap: 24px;
}
.why-card {
display: flex;
align-items: center;
min-width: 0;
gap: 24px;
padding: 36px;
overflow: clip;
background: #fef0eb;
border: 1px solid #e8e4de;
border-radius: 30px;
}
.why-card__icon-frame {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
width: 80px;
height: 80px;
overflow: clip;
background: #f08458;
border-radius: 9999px;
}
.why-card__icon {
display: block;
}
.why-card__icon--square {
width: 44px;
height: 44px;
}
.why-card__icon--familiar {
width: 38px;
height: 40px;
}
.why-card__icon--modern {
width: 24px;
height: 44px;
}
.why-card__copy {
display: flex;
flex: 1;
flex-direction: column;
align-items: flex-start;
min-width: 0;
gap: 12px;
overflow: clip;
}
.why-card__title {
width: 100%;
margin: 0;
font-size: 24px;
font-weight: 600;
line-height: 20px;
color: #0d0d0d;
}
.why-card__description {
width: 100%;
margin: 0;
font-size: 16px;
font-weight: 500;
line-height: 1.5;
color: #7a726d;
}
@media (min-width: 768px) {
.why__title {
font-size: 40px;
}
.why__grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.why-card {
min-height: 152px;
}
}
@media (min-width: 1024px) {
.why {
padding: 120px 0;
}
.why__intro {
flex-direction: row;
}
.why__title {
font-size: 48px;
}
.why__illustration {
display: block;
}
}