Compare commits

..

30 Commits

Author SHA1 Message Date
SeekingGamer
74793fbc11 fix(style): fix gaps and pop up screen ui 2026-05-20 11:36:04 +08:00
SeekingGamer
a8229e543e fix(docs): Update Translation ts 2026-05-19 11:30:10 +08:00
SeekingGamer
37055ca74a fix(style):Removed the site link in Downloads astro 2026-05-19 10:59:27 +08:00
SeekingGamer
2a2d5fb9e5 fix(feat): Change styling for responsive layout 2026-05-19 10:51:38 +08:00
SeekingGamer
0220aa5ff8 fix(style): compact reliability row at 1024 2026-05-18 16:03:09 +08:00
SeekingGamer
7f7b44415e fix(style): keep reliability grid at tablet widths 2026-05-18 15:58:05 +08:00
SeekingGamer
61ef7c14de fix(asset): bust cached public assets 2026-05-18 15:39:38 +08:00
b8103ea072 1
All checks were successful
Deploy to talkpro / build-and-sync (push) Successful in 27s
2026-05-18 15:23:09 +08:00
a481c382a6 CI deploy without sudo: tar over ssh when rsync missing
All checks were successful
Deploy to talkpro / build-and-sync (push) Successful in 33s
Remove apt/sudo install step (act runners lack sudo). Use rsync when
available; otherwise clear remote web root and stream dist/ via tar|ssh.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 15:19:16 +08:00
5f9e8db7e5 CI: install rsync and openssh-client before deploy
Some checks failed
Deploy to talkpro / build-and-sync (push) Failing after 11s
Gitea/act runners often lack rsync; apt/apk/dnf install step runs
before ssh/rsync in deploy-talkpro.sh.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 15:17:13 +08:00
fe14ca30ff Fix deploy script: use SSH_OPTS array for ssh mkdir
Some checks failed
Deploy to talkpro / build-and-sync (push) Failing after 31s
Typo SSH[@] left ssh out of the command so the shell tried to run
ubuntu@host as a program (exit 127).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 15:15:31 +08:00
cf9cbb6134 Fix CI: remove optional secret overrides step
Some checks failed
Deploy to talkpro / build-and-sync (push) Failing after 31s
Empty optional secrets made [ -n ... ] && echo fail under set -e.
Job env already defines host, user, and deploy path.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 15:13:48 +08:00
77485eee63 Fix CI deploy: default talkpro host, require only SSH secret
Some checks failed
Deploy to talkpro / build-and-sync (push) Failing after 14s
Gitea workflow no longer needs TALKPRO_HOST secret; defaults match
talkpro VPS. Fail fast with a clear message if TALKPRO_SSH_PRIVATE_KEY
is missing.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 15:06:14 +08:00
6e90a4adb6 Add Gitea Actions deploy workflow for talkpro.info
Some checks failed
Deploy to talkpro / build-and-sync (push) Failing after 18s
Build Astro on push to main/master and rsync dist/ to the marketing
server via SSH. Includes deploy-talkpro.sh, env example, and README.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 15:01:58 +08:00
3933cf42c0 1 2026-05-18 14:58:09 +08:00
df6cff4895 Merge pull request 'fix(style): Changes responsive layout breakpoint' (#8) from finn-staging into main
Reviewed-on: #8
2026-05-18 06:41:21 +00:00
SeekingGamer
7b45ca94a6 fix(style): Changes responsive layout breakpoint 2026-05-18 14:39:56 +08:00
82e3a23df3 Merge pull request 'fix(feat): Refine responsive layout and section spacing' (#7) from finn-staging into main
Reviewed-on: #7
2026-05-15 09:46:01 +00:00
SeekingGamer
c09ba76350 fix(feat): Refine responsive layout and section spacing 2026-05-15 17:44:31 +08:00
66f52a2d6e Merge pull request 'fix(feat): add locales and refine responsive landing page UI' (#6) from finn-staging into main
Reviewed-on: #6
2026-05-15 05:41:46 +00:00
SeekingGamer
ff7e4395ea fix(feat): add locales and refine responsive landing page UI 2026-05-15 13:17:37 +08:00
b6e6178466 Merge pull request 'finn-staging' (#5) from finn-staging into main
Reviewed-on: #5
2026-05-14 10:02:48 +00:00
ce1095088d Merge branch 'main' into finn-staging 2026-05-14 10:02:00 +00:00
SeekingGamer
a8474fd208 fix(feat): Rearrange the element to fix the responsive layout 2026-05-14 17:58:14 +08:00
SeekingGamer
c587df063b fix(feat): Adjust button and cards position when screen size change 2026-05-14 12:03:42 +08:00
SeekingGamer
c7a205e40c fix(feat): Add and Rearrange the img container after screen change 2026-05-14 11:20:49 +08:00
SeekingGamer
92bd81aed4 Merge finn-staging into main 2026-05-13 15:09:28 +08:00
SeekingGamer
33b1f7f9dd fix(style): Change the css styling for different screen size 2026-05-13 14:57:52 +08:00
TerryM
d31a13cbbe Revert "fix(style): Seperate CSS style to src\styles"
This reverts commit dbda554d28.
2026-05-13 14:55:01 +08:00
TerryM
6f8d36140a Revert "style: Seperate and Reformat inline style into css seperate files"
This reverts commit 93049e9044.
2026-05-13 14:55:01 +08:00
42 changed files with 5301 additions and 1548 deletions

10
.env.deploy.example Normal file
View File

@@ -0,0 +1,10 @@
# Copy to .env.deploy for local runs: set -a && source .env.deploy && set +a && ./scripts/deploy-talkpro.sh
#
# Gitea Actions: only this secret is required (Settings → Secrets → Actions):
# TALKPRO_SSH_PRIVATE_KEY = full PEM file contents
# Host/user/path defaults are in .gitea/workflows/deploy-talkpro.yml
TALKPRO_HOST=13.214.179.69
TALKPRO_USER=ubuntu
TALKPRO_REMOTE_ROOT=/home/ubuntu/talkpro
TALKPRO_SSH_KEY_FILE=/absolute/path/to/luis-only.pem

View File

@@ -0,0 +1,57 @@
# Build talk-pro and rsync dist/ to the marketing VPS (talkpro.info).
#
# Required Gitea repo secret (Settings → Secrets → Actions):
# TALKPRO_SSH_PRIVATE_KEY full PEM for ubuntu@talkpro (same as luis-only.pem)
#
# Host/user/path defaults are in the `env:` block below (edit there if needed).
#
# Requires a runner with: node 22+, ssh, ssh-keyscan, tar (rsync optional; no sudo needed).
name: Deploy to talkpro
on:
push:
branches:
- main
- master
workflow_dispatch:
env:
TALKPRO_HOST: "13.214.179.69"
TALKPRO_USER: ubuntu
TALKPRO_REMOTE_ROOT: /home/ubuntu/talkpro
jobs:
build-and-sync:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm
- name: Check deploy secrets
env:
TALKPRO_SSH_PRIVATE_KEY: ${{ secrets.TALKPRO_SSH_PRIVATE_KEY }}
run: |
if [ -z "${TALKPRO_SSH_PRIVATE_KEY}" ]; then
echo "ERROR: Missing Gitea secret TALKPRO_SSH_PRIVATE_KEY"
echo "Add it under Repository → Settings → Secrets (Actions)."
echo "Value: full contents of your ubuntu@talkpro SSH private key (PEM)."
exit 1
fi
- name: Trust host key
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
ssh-keyscan -H "$TALKPRO_HOST" >> ~/.ssh/known_hosts 2>/dev/null || true
- name: Build and deploy to talkpro
env:
TALKPRO_SSH_PRIVATE_KEY: ${{ secrets.TALKPRO_SSH_PRIVATE_KEY }}
run: bash scripts/deploy-talkpro.sh

2
.gitignore vendored
View File

@@ -5,3 +5,5 @@ dist/
.env
.env.*
!.env.example
!.env.deploy.example
.env.deploy

View File

@@ -26,6 +26,28 @@ Open [http://localhost:4321](http://localhost:4321)
| `npm run build` | Build for production into `dist/` |
| `npm run preview` | Preview production build locally |
## Deploy (Gitea Actions → talkpro.info)
Pushes to **`main`** or **`master`** run [`.gitea/workflows/deploy-talkpro.yml`](.gitea/workflows/deploy-talkpro.yml): `npm ci``npm run build``rsync` `dist/` to the marketing server (`/home/ubuntu/talkpro`).
**Repository secret** (Gitea → Settings → Secrets → Actions) — **required**:
| Secret | Value |
|--------|--------|
| `TALKPRO_SSH_PRIVATE_KEY` | Full PEM text of the `ubuntu@talkpro` deploy key |
Host (`13.214.179.69`), user (`ubuntu`), and web root (`/home/ubuntu/talkpro`) are set in the workflow. Optional secrets `TALKPRO_HOST`, `TALKPRO_USER`, `TALKPRO_REMOTE_ROOT` override those defaults.
Manual deploy from this repo:
```bash
cp .env.deploy.example .env.deploy # edit paths
set -a && source .env.deploy && set +a
bash scripts/deploy-talkpro.sh
```
`/api/site-links` (APK / App Store URLs) is still updated via the parent **talkpro** repo: `./scripts/post-talkpro-site-links.sh` on your laptop.
## Project Structure
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 716 KiB

After

Width:  |  Height:  |  Size: 414 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 427 KiB

After

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 602 KiB

After

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 417 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 MiB

After

Width:  |  Height:  |  Size: 473 KiB

View File

@@ -1,6 +1,13 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Icon">
<rect width="44" height="44" rx="12" fill="var(--fill-0, #D55F31)"/>
<path id="Vector" d="M23.8954 10H15.6259C14.728 10 14 10.8028 14 11.793V32.207C14 33.1972 14.728 34 15.6259 34H28.3741C29.272 34 30 33.1972 30 32.207V16.7328C30 16.1165 29.7778 15.5252 29.3827 15.0895L25.3848 10.6807C24.9897 10.245 24.4536 10 23.8947 10H23.8954Z" fill="var(--fill-0, white)"/>
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_9846_29800)">
<path d="M3.79923 9.12891H3.7275C2.80804 9.12891 2.05835 9.88098 2.05835 10.7981V18.0653C2.05835 18.986 2.80804 19.7356 3.7275 19.7356H3.80045C4.71991 19.7356 5.4696 18.9835 5.4696 18.0653V10.798C5.46838 9.88098 4.71753 9.12891 3.79923 9.12891Z" fill="white"/>
<path d="M6.26831 20.8732C6.26831 21.7173 6.95819 22.4048 7.80233 22.4048H9.4416V26.3302C9.4416 27.252 10.1937 28.0017 11.1108 28.0017H11.1825C12.1032 28.0017 12.854 27.2509 12.854 26.3302V22.4048H15.1449V26.3302C15.1449 27.252 15.8994 28.0017 16.8165 28.0017H16.887C17.8077 28.0017 18.5573 27.2509 18.5573 26.3302V22.4048H20.1978C21.0407 22.4048 21.7306 21.7173 21.7306 20.8732V9.39844H6.26831V20.8732Z" fill="white"/>
<path d="M17.8506 2.43795L19.1527 0.428069C19.2364 0.301301 19.1993 0.127973 19.0714 0.045438C18.9447 -0.0382608 18.7713 -0.00356184 18.6887 0.126753L17.3389 2.20603C16.3262 1.79114 15.1951 1.558 14.0006 1.558C12.8049 1.558 11.6762 1.79114 10.6611 2.20603L9.3136 0.126753C9.23112 -0.00356184 9.05651 -0.0382608 8.92858 0.045438C8.80065 0.127917 8.76357 0.301301 8.84727 0.428069L10.1505 2.43795C7.80103 3.58939 6.2168 5.75951 6.2168 8.24886C6.2168 8.4019 6.22639 8.55256 6.23952 8.70199H21.7628C21.7759 8.55256 21.7843 8.4019 21.7843 8.24886C21.7843 5.75951 20.1989 3.58939 17.8506 2.43795ZM10.4016 6.03688C9.98912 6.03688 9.65432 5.70447 9.65432 5.2908C9.65432 4.87713 9.98912 4.54588 10.4016 4.54588C10.8165 4.54588 11.1489 4.87707 11.1489 5.2908C11.1489 5.70453 10.8141 6.03688 10.4016 6.03688ZM17.5983 6.03688C17.1858 6.03688 16.851 5.70447 16.851 5.2908C16.851 4.87713 17.1858 4.54588 17.5983 4.54588C18.012 4.54588 18.3444 4.87707 18.3444 5.2908C18.3444 5.70447 18.012 6.03688 17.5983 6.03688Z" fill="white"/>
<path d="M24.2714 9.12891H24.2021C23.2826 9.12891 22.5305 9.88098 22.5305 10.7981V18.0653C22.5305 18.986 23.2838 19.7356 24.2021 19.7356H24.2726C25.1932 19.7356 25.9418 18.9835 25.9418 18.0653V10.798C25.9418 9.88098 25.1909 9.12891 24.2714 9.12891Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_9846_29800">
<rect width="28" height="28" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 559 B

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -1,4 +1,4 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 1920 923" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg preserveAspectRatio="xMidYMid slice" width="1920" height="923" overflow="visible" style="display: block;" viewBox="0 0 1920 923" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Layer_1" clip-path="url(#clip0_0_4)">
<path id="Vector" d="M12.1851 -29.997L0.00488281 -17.7969L12.1851 -5.59676L24.3653 -17.7969L12.1851 -29.997Z" fill="var(--fill-0, #FFF0E8)"/>
<path id="Vector_2" d="M102.45 -30.0001L90.2725 -17.7969L102.45 -5.59361L114.627 -17.7969L102.45 -30.0001Z" fill="var(--fill-0, #FFF0E8)"/>

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 343 KiB

After

Width:  |  Height:  |  Size: 369 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 284 KiB

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 848 KiB

After

Width:  |  Height:  |  Size: 880 KiB

Binary file not shown.

310
public/site-links-client.js Normal file
View File

@@ -0,0 +1,310 @@
/**
* Mirrors talkpro static site: /api/site-links, APK default, in-app + App Store modals.
* Strings come from #site-links-i18n (JSON) rendered by DownloadCTA.astro.
*/
(function () {
const DEFAULT_APK = 'https://talkspro.xyz/download';
let apkDownloadUrl = DEFAULT_APK;
function getApkDownloadUrl() {
return apkDownloadUrl;
}
function getI18n() {
const el = document.getElementById('site-links-i18n');
if (!el || !el.textContent.trim()) return {};
try {
return JSON.parse(el.textContent);
} catch {
return {};
}
}
function detectInAppBrowser() {
const ua = navigator.userAgent || '';
if (/MicroMessenger/i.test(ua)) return 'wechat';
try {
if (typeof window.WeixinJSBridge !== 'undefined') return 'wechat';
} catch {
/* ignore */
}
if (/QQ\//i.test(ua) && /MQQBrowser/i.test(ua)) return 'qq';
if (/Weibo/i.test(ua)) return 'weibo';
return '';
}
function isIOSDevice() {
const ua = navigator.userAgent || '';
if (/iPhone|iPad|iPod/i.test(ua)) return true;
if (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1) return true;
return false;
}
function isAndroidDevice() {
const ua = navigator.userAgent || '';
return /Android/i.test(ua) && !isIOSDevice();
}
const MODAL_WRAP =
'position:fixed;inset:0;z-index:10050;display:flex;align-items:center;justify-content:center;padding:16px;box-sizing:border-box;';
const MODAL_BACK = 'position:absolute;inset:0;background:rgba(0,0,0,.45);cursor:pointer;';
const MODAL_PANEL =
'position:relative;max-width:420px;width:100%;margin:auto;padding:20px 22px;border-radius:12px;background:#fff;color:#1a1a1a;font:15px/1.45 system-ui,-apple-system,sans-serif;box-shadow:0 12px 40px rgba(0,0,0,.18);';
const MODAL_TITLE = 'margin:0 0 10px;font-size:18px;font-weight:700;line-height:1.25;';
const MODAL_BODY = 'margin:0 0 18px;font-size:14px;color:#444;';
const MODAL_ACTIONS = 'display:flex;flex-wrap:wrap;gap:10px;justify-content:flex-end;';
const BTN =
'cursor:pointer;border-radius:8px;padding:10px 14px;font-size:14px;font-weight:600;border:1px solid #ccc;background:#f5f5f5;color:#1a1a1a;';
const BTN_PRIMARY = 'border-color:#1a6cff;background:#1a6cff;color:#fff;';
const BTN_ORANGE = 'cursor:pointer;border-radius:14px;padding:10px 14px;font-size:14px;font-weight:600;border:1px solid #f28a4b;background:#f28a4b;color:#fff;';
function initInAppBrowserModal() {
if (document.getElementById('inapp-browser-modal')) return;
const wrap = document.createElement('div');
wrap.id = 'inapp-browser-modal';
wrap.setAttribute('role', 'dialog');
wrap.setAttribute('aria-modal', 'true');
wrap.setAttribute('aria-hidden', 'true');
wrap.style.cssText = MODAL_WRAP + 'display:none;';
wrap.innerHTML =
'<div data-inapp-close style="' +
MODAL_BACK +
'"></div>' +
'<div style="' +
MODAL_PANEL +
'">' +
'<h3 id="inapp-modal-title" style="' +
MODAL_TITLE +
'"></h3>' +
'<p id="inapp-modal-body" style="' +
MODAL_BODY +
'"></p>' +
'<div style="' +
MODAL_ACTIONS +
'">' +
'<button type="button" id="inapp-copy-apk" style="' +
BTN +
BTN_PRIMARY +
'"></button>' +
'<button type="button" id="inapp-try-chrome" style="' +
BTN +
'" hidden></button>' +
'<button type="button" id="inapp-got-it" data-inapp-close style="' +
BTN +
'"></button>' +
'</div></div>';
document.body.appendChild(wrap);
const close = () => {
wrap.style.display = 'none';
wrap.setAttribute('aria-hidden', 'true');
};
wrap.querySelectorAll('[data-inapp-close]').forEach((el) => {
el.addEventListener('click', close);
});
const i18n = () => getI18n();
document.getElementById('inapp-copy-apk').addEventListener('click', async () => {
const btn = document.getElementById('inapp-copy-apk');
const dict = i18n();
const done = dict.inapp_browser_copied || 'Copied';
try {
await navigator.clipboard.writeText(getApkDownloadUrl());
const prev = btn.textContent;
btn.textContent = done;
setTimeout(() => {
btn.textContent = dict.inapp_browser_copy || prev;
}, 1600);
} catch {
window.prompt(dict.inapp_browser_copy || 'Copy', getApkDownloadUrl());
}
});
document.getElementById('inapp-try-chrome').addEventListener('click', () => {
const enc = encodeURIComponent(getApkDownloadUrl());
const intent =
getApkDownloadUrl().replace(/^https:/i, 'intent:') +
'#Intent;' +
'scheme=https;action=android.intent.action.VIEW;category=android.intent.category.BROWSABLE;' +
'package=com.android.chrome;S.browser_fallback_url=' +
enc +
';end';
window.location.href = intent;
});
}
function openInAppBrowserModal() {
const modal = document.getElementById('inapp-browser-modal');
if (!modal) return;
const dict = getI18n();
const tryChrome = modal.querySelector('#inapp-try-chrome');
const showChrome = isAndroidDevice() && !!detectInAppBrowser();
if (tryChrome) {
tryChrome.hidden = !showChrome;
tryChrome.setAttribute('aria-hidden', showChrome ? 'false' : 'true');
}
modal.style.display = 'flex';
modal.setAttribute('aria-hidden', 'false');
const titleEl = modal.querySelector('#inapp-modal-title');
const bodyEl = modal.querySelector('#inapp-modal-body');
if (titleEl) titleEl.textContent = dict.inapp_browser_title || '';
if (bodyEl) {
const iosWechat = isIOSDevice() && detectInAppBrowser() === 'wechat';
const bodyKey = iosWechat ? 'inapp_browser_body_ios' : 'inapp_browser_body';
bodyEl.innerHTML =
dict[bodyKey] || dict.inapp_browser_body || '';
}
const copyBtn = modal.querySelector('#inapp-copy-apk');
const gotBtn = modal.querySelector('#inapp-got-it');
if (copyBtn) copyBtn.textContent = dict.inapp_browser_copy || '';
if (tryChrome) tryChrome.textContent = dict.inapp_browser_try_chrome || '';
if (gotBtn) gotBtn.textContent = dict.inapp_browser_got_it || 'OK';
}
function initAppStoreSoonModal() {
if (document.getElementById('app-store-soon-modal')) return;
const wrap = document.createElement('div');
wrap.id = 'app-store-soon-modal';
wrap.setAttribute('role', 'dialog');
wrap.setAttribute('aria-modal', 'true');
wrap.setAttribute('aria-hidden', 'true');
wrap.style.cssText = MODAL_WRAP + 'display:none;';
wrap.innerHTML =
'<div data-app-soon-close style="' +
MODAL_BACK +
'"></div>' +
'<div style="' +
MODAL_PANEL +
'">' +
'<h3 id="app-soon-title" style="' +
MODAL_TITLE +
'"></h3>' +
'<p id="app-soon-body" style="' +
MODAL_BODY +
'"></p>' +
'<div style="' +
MODAL_ACTIONS +
'">' +
'<button type="button" data-app-soon-close style="' +
BTN_ORANGE +
'"></button>' +
'</div></div>';
document.body.appendChild(wrap);
const close = () => {
wrap.style.display = 'none';
wrap.setAttribute('aria-hidden', 'true');
};
wrap.querySelectorAll('[data-app-soon-close]').forEach((el) => {
el.addEventListener('click', close);
});
}
function openAppStoreSoonModal() {
const modal = document.getElementById('app-store-soon-modal');
if (!modal) return;
const dict = getI18n();
const tEl = modal.querySelector('#app-soon-title');
const bEl = modal.querySelector('#app-soon-body');
const ok = modal.querySelector('button[data-app-soon-close]');
if (tEl) tEl.textContent = dict.app_store_soon_title || '';
if (bEl) bEl.innerHTML = dict.app_store_soon_body || '';
if (ok) ok.textContent = dict.app_store_soon_ok || 'OK';
modal.style.display = 'flex';
modal.setAttribute('aria-hidden', 'false');
}
function bindBrowserDownloadLinks() {
document.querySelectorAll('a.store-badge--browser').forEach((a) => {
const openForInApp = (e) => {
if (!detectInAppBrowser()) return;
e.preventDefault();
e.stopPropagation();
openInAppBrowserModal();
};
a.addEventListener('click', openForInApp);
a.addEventListener(
'touchend',
(e) => {
if (!detectInAppBrowser()) return;
e.preventDefault();
openInAppBrowserModal();
},
{ passive: false }
);
});
}
function bindAppStoreAppleBadges() {
document.querySelectorAll('a.store-badge--apple[data-app-soon]').forEach((a) => {
const stopAndOpen = (e) => {
e.preventDefault();
e.stopPropagation();
openAppStoreSoonModal();
};
a.addEventListener('click', stopAndOpen);
a.addEventListener(
'touchend',
(e) => {
e.preventDefault();
e.stopPropagation();
openAppStoreSoonModal();
},
{ passive: false }
);
});
}
function loadSiteLinksThenBind() {
if (window.location.protocol === 'file:') {
bindBrowserDownloadLinks();
bindAppStoreAppleBadges();
return;
}
fetch('/api/site-links', { credentials: 'same-origin' })
.then((r) => {
if (!r.ok) throw new Error('bad status');
return r.json();
})
.then((j) => {
const apk = String(j.apk_download_url || '').trim();
const ios = String(j.app_store_url || '').trim();
if (apk.startsWith('https://')) apkDownloadUrl = apk;
document.querySelectorAll('a.store-badge--browser').forEach((a) => {
if (apk.startsWith('https://')) a.setAttribute('href', apk);
});
document.querySelectorAll('a.store-badge--apple').forEach((a) => {
if (ios.startsWith('https://')) {
a.setAttribute('href', ios);
a.removeAttribute('data-app-soon');
a.setAttribute('rel', 'noopener noreferrer');
a.setAttribute('target', '_blank');
}
});
const meta = document.getElementById('site-links-meta');
if (meta) {
const dict = getI18n();
const u = String(j.updated_at || '').trim();
if (u) {
meta.textContent =
(dict.linksMetaPrefix || 'Store links file updated: ') +
u +
(dict.linksMetaSuffix || ' (GMT+8)');
meta.hidden = false;
} else {
meta.hidden = true;
}
}
})
.catch(() => {
/* keep defaults */
})
.finally(() => {
bindBrowserDownloadLinks();
bindAppStoreAppleBadges();
});
}
initInAppBrowserModal();
initAppStoreSoonModal();
loadSiteLinksThenBind();
})();

71
scripts/deploy-talkpro.sh Executable file
View File

@@ -0,0 +1,71 @@
#!/usr/bin/env bash
# Build Astro dist/ and sync to the Talk Pro marketing host (talkpro.info).
# Used by Gitea Actions and for manual deploys from this repo.
#
# Required (CI): TALKPRO_SSH_PRIVATE_KEY — PEM contents (Gitea secret)
# Optional: TALKPRO_SSH_KEY_FILE — path to PEM (local)
# Defaults match .env.deploy.example / Gitea workflow job env:
# TALKPRO_HOST=13.214.179.69 TALKPRO_USER=ubuntu TALKPRO_REMOTE_ROOT=/home/ubuntu/talkpro
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"
HOST="${TALKPRO_HOST:-13.214.179.69}"
USER="${TALKPRO_USER:-ubuntu}"
REMOTE_ROOT="${TALKPRO_REMOTE_ROOT:-/home/ubuntu/talkpro}"
[[ -n "$HOST" ]] || HOST=13.214.179.69
[[ -n "$USER" ]] || USER=ubuntu
[[ -n "$REMOTE_ROOT" ]] || REMOTE_ROOT=/home/ubuntu/talkpro
KEY_FILE="${TALKPRO_SSH_KEY_FILE:-}"
TMP_KEY=""
cleanup() {
[[ -n "$TMP_KEY" && -f "$TMP_KEY" ]] && rm -f "$TMP_KEY"
}
trap cleanup EXIT
if [[ -n "${TALKPRO_SSH_PRIVATE_KEY:-}" ]]; then
TMP_KEY="$(mktemp)"
chmod 600 "$TMP_KEY"
printf '%s\n' "$TALKPRO_SSH_PRIVATE_KEY" | tr -d '\r' > "$TMP_KEY"
KEY_FILE="$TMP_KEY"
elif [[ -z "$KEY_FILE" || ! -f "$KEY_FILE" ]]; then
echo "ERROR: Set TALKPRO_SSH_PRIVATE_KEY (Gitea secret / env) or TALKPRO_SSH_KEY_FILE (local path)" >&2
exit 1
fi
if [[ ! -s "$KEY_FILE" ]]; then
echo "ERROR: SSH key file is empty — check TALKPRO_SSH_PRIVATE_KEY secret in Gitea" >&2
exit 1
fi
chmod 600 "$KEY_FILE"
SSH_OPTS=(-i "$KEY_FILE" -o BatchMode=yes -o StrictHostKeyChecking=accept-new)
RSYNC_SSH="ssh -i \"$KEY_FILE\" -o BatchMode=yes -o StrictHostKeyChecking=accept-new"
REMOTE="${USER}@${HOST}"
if [[ -f package-lock.json ]]; then
npm ci
else
npm install
fi
npm run build
command -v ssh >/dev/null || { echo "ERROR: ssh not found (install openssh-client)" >&2; exit 127; }
ssh "${SSH_OPTS[@]}" "$REMOTE" "mkdir -p ${REMOTE_ROOT}"
if command -v rsync >/dev/null 2>&1; then
echo "Uploading with rsync..."
rsync -avz --delete \
-e "$RSYNC_SSH" \
dist/ \
"${REMOTE}:${REMOTE_ROOT}/"
else
command -v tar >/dev/null || { echo "ERROR: need rsync or tar on the runner" >&2; exit 127; }
echo "Uploading with tar over ssh (rsync not available on runner)..."
ssh "${SSH_OPTS[@]}" "$REMOTE" "mkdir -p ${REMOTE_ROOT} && rm -rf ${REMOTE_ROOT:?}/*"
tar -C dist -cf - . | ssh "${SSH_OPTS[@]}" "$REMOTE" "tar -C ${REMOTE_ROOT} -xf -"
fi
echo "Deployed dist/ → ${REMOTE}:${REMOTE_ROOT}/"

5
src/assets.ts Normal file
View File

@@ -0,0 +1,5 @@
const assetVersion = '20260518-1'
export function assetPath(path: string) {
return `${path}?v=${assetVersion}`
}

View File

@@ -1,4 +1,5 @@
---
import { assetPath } from '../assets'
import type { Translations } from '../i18n/translations'
export interface Props {
@@ -7,10 +8,12 @@ export interface Props {
const { t } = Astro.props
const slides = [
"/assets/preview-phone.png",
"/assets/preview-phone.png",
"/assets/preview-phone.png",
assetPath("/assets/preview-phone.png"),
assetPath("/assets/preview-phone.png"),
assetPath("/assets/preview-phone.png"),
]
const arrowLeft = assetPath("/assets/preview-arrow-left.svg")
const arrowRight = assetPath("/assets/preview-arrow-right.svg")
---
<section class="app-preview">
@@ -31,7 +34,7 @@ const slides = [
<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" />
<img alt={t.previous} class="app-preview__button-icon" src={arrowLeft} />
</button>
</div>
</div>
@@ -43,7 +46,7 @@ const slides = [
<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" />
<img alt={t.next} class="app-preview__button-icon app-preview__button-icon--next" src={arrowRight} />
</button>
</div>
</div>

View File

@@ -1,4 +1,5 @@
---
import { assetPath } from '../assets'
import type { Translations } from '../i18n/translations'
export interface Props {
@@ -6,14 +7,14 @@ export interface Props {
}
const { t } = Astro.props
const halftone = "/assets/core-halftone-bg.png";
const halftone = assetPath("/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",
assetPath("/assets/core-icon-private.png"),
assetPath("/assets/core-icon-groups.png"),
assetPath("/assets/core-icon-channels.png"),
assetPath("/assets/core-icon-voice.png"),
assetPath("/assets/core-icon-video.png"),
assetPath("/assets/core-icon-media.png"),
]
---

View File

@@ -1,16 +1,20 @@
---
import { assetPath } from '../assets'
import type { Translations } from '../i18n/translations'
export interface Props {
t: Translations['download']
siteLinks: Translations['siteLinks']
}
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";
const appleIcon = "/assets/cta-apple-icon.svg";
const phoneArt = "/assets/cta-phone-art.png";
const { t, siteLinks } = Astro.props
const bgPattern = assetPath("/assets/cta-bg-pattern.svg");
const talkproLogo = assetPath("/assets/cta-talkpro-logo.svg");
const androidIcon = assetPath("/assets/cta-android-icon.svg");
const appleIcon = assetPath("/assets/cta-apple-icon.svg");
const phoneArt = assetPath("/assets/cta-phone-art.png");
const defaultApkHref = "https://talkspro.xyz/download";
const siteLinksJson = JSON.stringify(siteLinks);
---
<section id="download" class="download-cta">
@@ -35,14 +39,25 @@ const phoneArt = "/assets/cta-phone-art.png";
</div>
<div class="store-badges">
<div class="store-badge store-badge--android">
<img alt={t.androidAlt} class="store-badge__icon" src={androidIcon} />
<a
class="store-badge store-badge--android store-badge--browser"
href={defaultApkHref}
rel="noopener noreferrer"
target="_blank"
>
<div class="store-badge__icon-frame">
<img alt={t.androidAlt} class="store-badge__android-icon" src={androidIcon} />
</div>
<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="store-badge store-badge--ios">
</a>
<a
class="store-badge store-badge--ios store-badge--apple"
href="#"
data-app-soon="1"
>
<div class="store-badge__icon-frame">
<img alt={t.appleAlt} class="store-badge__apple-icon" src={appleIcon} />
</div>
@@ -50,8 +65,9 @@ const phoneArt = "/assets/cta-phone-art.png";
<p class="store-badge__platform">{t.ios}</p>
<p class="store-badge__label">{t.iosCta}</p>
</div>
</div>
</a>
</div>
</div>
<div class="download-cta__phone">
@@ -61,3 +77,5 @@ const phoneArt = "/assets/cta-phone-art.png";
</div>
</div>
</section>
<script type="application/json" id="site-links-i18n" set:html={siteLinksJson} />

View File

@@ -1,4 +1,5 @@
---
import { assetPath } from '../assets'
import type { Translations } from '../i18n/translations'
export interface Props {
@@ -6,15 +7,25 @@ export interface Props {
}
const { t } = Astro.props
const images = ["/assets/exp-card-1.png", "/assets/exp-card-2.png", "/assets/exp-card-3.png"]
const images = [
assetPath("/assets/exp-card-1.png"),
assetPath("/assets/exp-card-2.png"),
assetPath("/assets/exp-card-3.png"),
]
const imageClasses = ['experience-card__image--one', 'experience-card__image--two', 'experience-card__image--three']
---
<section id="experience" class="experience">
<div class="experience__inner">
<p class="experience__title">
{t.title}
</p>
<div class="experience__heading">
<p class="experience__title">
{t.title}
</p>
<p class="experience__caption">
{t.caption}
</p>
</div>
<div class="experience__body">
<div class="experience__grid">
@@ -36,10 +47,6 @@ const imageClasses = ['experience-card__image--one', 'experience-card__image--tw
</div>
))}
</div>
<p class="experience__caption">
{t.caption}
</p>
</div>
</div>
</section>

View File

@@ -1,4 +1,5 @@
---
import { assetPath } from '../assets'
import type { Translations } from '../i18n/translations'
export interface Props {
@@ -6,9 +7,7 @@ export interface Props {
}
const { t } = Astro.props
const logoFull = "/assets/footer-logo.png";
const androidIcon = "/assets/footer-android-icon.svg";
const appleIcon = "/assets/footer-apple-icon.svg";
const logoFull = assetPath("/assets/footer-logo.png");
---
<footer class="site-footer">
@@ -21,37 +20,6 @@ const appleIcon = "/assets/footer-apple-icon.svg";
<p class="site-footer__description">
{t.description}
</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="store-badge store-badge--ios">
<div class="store-badge__icon-frame">
<img alt="Apple" class="store-badge__apple-icon" src={appleIcon} />
</div>
<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>
<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="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>

View File

@@ -1,4 +1,5 @@
---
import { assetPath } from '../assets'
import { getLocalePath, languageLabels, languageNames, languages, type Lang, type Translations } from '../i18n/translations'
export interface Props {
@@ -7,9 +8,9 @@ export interface Props {
}
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 logoIcon = assetPath("/assets/header-logo-icon.png");
const logoWordmark = assetPath("/assets/header-logo-wordmark.svg");
const globeIcon = assetPath("/assets/header-globe.svg");
const navItems = [
{ href: '#hero', label: t.nav.home },
{ href: '#features', label: t.nav.features },

View File

@@ -1,13 +1,18 @@
---
import { assetPath } from '../assets'
import type { Translations } from '../i18n/translations'
export interface Props {
t: Translations['hero']
download: Translations['download']
}
const { t } = Astro.props
const heroBg = "/assets/hero-bg.png";
const phoneMockup = "/assets/hero-phone.png";
const { t, download } = Astro.props
const heroBg = assetPath("/assets/hero-bg.png");
const phoneMockup = assetPath("/assets/hero-phone.png");
const androidIcon = assetPath("/assets/cta-android-icon.svg");
const appleIcon = assetPath("/assets/cta-apple-icon.svg");
const defaultApkHref = "https://talkspro.xyz/download";
---
<section id="hero" class="hero">
@@ -36,11 +41,32 @@ const phoneMockup = "/assets/hero-phone.png";
{t.description}
</p>
<div class="hero__actions">
<a href="#download" class="hero__button hero__button--primary">
<span class="hero__button-label">{t.download}</span>
<a
href={defaultApkHref}
class="store-badge store-badge--android store-badge--browser hero__store-badge"
rel="noopener noreferrer"
target="_blank"
>
<div class="store-badge__icon-frame">
<img alt={download.androidAlt} class="store-badge__android-icon" src={androidIcon} />
</div>
<div class="store-badge__copy">
<p class="store-badge__platform">{download.android}</p>
<p class="store-badge__label">{download.androidCta}</p>
</div>
</a>
<a href="#features" class="hero__button hero__button--secondary">
<span class="hero__button-label">{t.explore}</span>
<a
href="#"
class="store-badge store-badge--ios store-badge--apple hero__store-badge"
data-app-soon="1"
>
<div class="store-badge__icon-frame">
<img alt={download.appleAlt} class="store-badge__apple-icon" src={appleIcon} />
</div>
<div class="store-badge__copy">
<p class="store-badge__platform">{download.ios}</p>
<p class="store-badge__label">{download.iosCta}</p>
</div>
</a>
</div>
</div>

View File

@@ -1,4 +1,5 @@
---
import { assetPath } from '../assets'
import type { Translations } from '../i18n/translations'
export interface Props {
@@ -6,6 +7,9 @@ export interface Props {
}
const { t } = Astro.props
const trustIconSprite = assetPath("/assets/trust-icon-sprite.png")
const trustIconImprovement = assetPath("/assets/trust-icon-improvement.png")
const trustDivider = assetPath("/assets/trust-divider.svg")
const iconClasses = [
'trust-card__icon--one',
'trust-card__icon--two',
@@ -35,7 +39,7 @@ const iconClasses = [
<img
alt=""
class={`trust-card__icon ${iconClasses[index]}`}
src={index === 3 ? "/assets/trust-icon-improvement.png" : "/assets/trust-icon-sprite.png"}
src={index === 3 ? trustIconImprovement : trustIconSprite}
/>
</div>
</div>
@@ -47,7 +51,7 @@ const iconClasses = [
{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" />
<img alt="" class="trust__divider-image" src={trustDivider} />
</div>
</div>
)}

View File

@@ -1,4 +1,5 @@
---
import { assetPath } from '../assets'
import type { Translations } from '../i18n/translations'
export interface Props {
@@ -6,14 +7,15 @@ export interface Props {
}
const { t } = Astro.props
const underline = "/assets/why-underline.svg";
const underline = assetPath("/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",
assetPath("/assets/why-icon-simple.svg"),
assetPath("/assets/why-icon-familiar.svg"),
assetPath("/assets/why-icon-connected.svg"),
assetPath("/assets/why-icon-modern.svg"),
]
const iconClasses = ['why-card__icon--square', 'why-card__icon--familiar', 'why-card__icon--square', 'why-card__icon--modern']
const illustrationVideo = assetPath("/assets/why-illustration.mp4")
const iconClasses = ['why-card__icon--simple', 'why-card__icon--familiar', 'why-card__icon--connected', 'why-card__icon--modern']
---
<section class="why">
@@ -40,7 +42,17 @@ const iconClasses = ['why-card__icon--square', 'why-card__icon--familiar', 'why-
</div>
<div class="why__illustration">
<img alt={t.illustrationAlt} class="why__illustration-image" src="/assets/why-illustration.png" />
<video
aria-label={t.illustrationAlt}
class="why__illustration-image"
autoplay
loop
muted
playsinline
preload="metadata"
>
<source src={illustrationVideo} type="video/mp4" />
</video>
</div>
</div>

File diff suppressed because it is too large Load Diff

View File

@@ -27,10 +27,49 @@ const {
</head>
<body class="bg-surface font-sans overflow-x-hidden">
<slot />
<script src="/site-links-client.js" defer></script>
<script>
(() => {
const header = document.getElementById('site-header');
const getOffset = () => header ? header.offsetHeight : 0;
let activeScrollAnimation = 0;
const easeInOutCubic = (t: number) => (
t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2
);
const animateScrollTo = (targetTop: number) => {
const startTop = window.scrollY;
const distance = targetTop - startTop;
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
window.scrollTo(0, targetTop);
return;
}
if (activeScrollAnimation) {
cancelAnimationFrame(activeScrollAnimation);
}
const duration = Math.min(1300, Math.max(650, Math.abs(distance) * 0.7));
const startTime = performance.now();
const step = (now: number) => {
const elapsed = now - startTime;
const progress = Math.min(elapsed / duration, 1);
const easedProgress = easeInOutCubic(progress);
window.scrollTo(0, startTop + distance * easedProgress);
if (progress < 1) {
activeScrollAnimation = requestAnimationFrame(step);
} else {
activeScrollAnimation = 0;
}
};
activeScrollAnimation = requestAnimationFrame(step);
};
document.querySelectorAll('a[href^="#"]').forEach(link => {
link.addEventListener('click', e => {
@@ -40,7 +79,8 @@ const {
if (!target) return;
e.preventDefault();
const top = target.getBoundingClientRect().top + window.scrollY - getOffset();
window.scrollTo({ top, behavior: 'smooth' });
animateScrollTo(top);
history.pushState(null, '', href);
});
});

View File

@@ -7,7 +7,6 @@ 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'
@@ -25,13 +24,13 @@ 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} />
<Hero t={t.hero} download={t.download} />
<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} />
<!-- AppPreview section disabled per lead request. -->
<DownloadCTA t={t.download} siteLinks={t.siteLinks} />
<Footer t={t.footer} />
</Base>

View File

@@ -7,7 +7,6 @@ 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 } from '../i18n/translations'
@@ -18,13 +17,13 @@ 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} />
<Hero t={t.hero} download={t.download} />
<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} />
<!-- AppPreview section disabled per lead request. -->
<DownloadCTA t={t.download} siteLinks={t.siteLinks} />
<Footer t={t.footer} />
</Base>

View File

@@ -1,241 +1,344 @@
.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;
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%);
position: absolute;
top: 50%;
left: 50%;
width: 1920px;
max-width: none;
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;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
max-width: 1280px;
gap: 0px;
margin: 0 auto;
padding: 60px 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;
display: flex;
order: 2;
flex: 1;
flex-direction: column;
align-items: center;
justify-content: center;
min-width: 0;
gap: 36px;
overflow: clip;
text-align: center;
}
.download-cta__copy {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
gap: 16px;
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
gap: 16px;
}
.download-cta__heading {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
flex-shrink: 0;
gap: 20px;
--download-heading-title-size: 32px;
display: flex;
flex-wrap: nowrap;
align-items: center;
flex-shrink: 0;
gap: 16px;
max-width: 100%;
}
.download-cta__title {
margin: 0;
font-size: 32px;
font-weight: 700;
line-height: 1.2;
color: #1a1a1a;
white-space: nowrap;
position: relative;
top: -4px;
margin: 0;
flex-shrink: 0;
font-size: var(--download-heading-title-size);
font-weight: 700;
line-height: 1.2;
letter-spacing: var(--ls-32);
color: #1a1a1a;
white-space: nowrap;
}
.download-cta__logo-frame {
position: relative;
flex-shrink: 0;
width: 188px;
height: 72px;
position: relative;
flex-shrink: 0;
width: calc(var(--download-heading-title-size) * 3.9167);
height: calc(var(--download-heading-title-size) * 1.5);
}
.download-cta__logo {
position: absolute;
inset: 0;
display: block;
width: 100%;
max-width: none;
height: 100%;
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;
max-width: 542px;
margin: 0;
font-size: 16px;
font-weight: 400;
line-height: 1.5;
letter-spacing: var(--ls-16);
color: #7a726d;
text-align: center;
}
.store-badges {
display: flex;
flex-wrap: wrap;
align-items: center;
flex-shrink: 0;
width: 100%;
gap: 16px;
overflow: clip;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
align-items: center;
justify-content: 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;
display: flex;
align-items: center;
flex-shrink: 0;
width: 260px;
max-width: 100%;
height: 70px;
gap: 8px;
padding: 12px 16px;
overflow: clip;
border-radius: 20px;
}
a.store-badge {
box-sizing: border-box;
color: inherit;
text-decoration: none;
cursor: pointer;
}
.download-cta__links-meta {
font-size: 13px;
color: #7a726d;
margin: 14px auto 0;
max-width: min(1180px, calc(100% - 40px));
text-align: center;
}
.store-badge--android {
background: #f28a4b;
border: 1px solid #c5834e;
background: #f28a4b;
border: 1px solid #c5834e;
}
.store-badge--ios {
background: #383838;
border: 1px solid #141414;
background: #383838;
border: 1px solid #141414;
}
.store-badge__icon {
display: block;
flex-shrink: 0;
width: 44px;
height: 44px;
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;
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;
display: block;
width: 22px;
height: 27px;
}
.store-badge--android .store-badge__icon-frame {
background: #d55f31;
}
.store-badge__android-icon {
display: block;
width: 28px;
height: 28px;
}
.store-badge__copy {
display: flex;
flex-direction: column;
align-items: flex-start;
flex-shrink: 0;
gap: 3px;
overflow: clip;
white-space: nowrap;
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;
margin: 0;
font-size: 13px;
font-weight: 600;
line-height: normal;
letter-spacing: var(--ls-13);
}
.store-badge--android .store-badge__platform {
color: #ffd6bc;
color: #ffd6bc;
}
.store-badge--ios .store-badge__platform {
color: #ccc;
color: #ccc;
}
.store-badge__label {
margin: 0;
font-size: 15px;
font-weight: 600;
line-height: normal;
color: #fff;
margin: 0;
font-size: 15px;
font-weight: 600;
line-height: normal;
letter-spacing: var(--ls-15);
color: #fff;
}
.download-cta__phone {
position: relative;
display: none;
flex-shrink: 0;
width: 418px;
height: 510px;
position: relative;
display: block;
order: 1;
flex-shrink: 0;
width: 240px;
height: 292px;
}
@media (min-width: 578px) {
.download-cta__phone {
width: min(418px, calc(100vw - 32px));
height: auto;
aspect-ratio: 418 / 510;
}
}
.download-cta__phone-crop {
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
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%;
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 (max-width: 397px) {
.download-cta__heading {
--download-heading-title-size: clamp(24px, 8vw, 32px);
gap: clamp(8px, 2.5vw, 12px);
}
.download-cta__title {
line-height: 1;
}
}
@media (min-width: 768px) {
.download-cta__title {
font-size: 40px;
}
@media (max-width: 569px) {
.store-badge {
width: min(100%, calc(100vw - 32px));
}
}
@media (min-width: 570px) {
.download-cta__heading {
--download-heading-title-size: 40px;
}
.download-cta__title {
letter-spacing: var(--ls-40);
}
.download-cta__description {
font-size: 18px;
letter-spacing: var(--ls-18);
}
.store-badges {
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
}
}
@media (min-width: 1024px) {
.download-cta {
height: 600px;
}
.download-cta {
height: 600px;
}
.download-cta__inner {
flex-direction: row;
gap: 0;
padding: 0;
}
.download-cta__inner {
flex-direction: row;
gap: 16px;
padding: 0 24px;
}
.download-cta__title {
font-size: 48px;
}
.download-cta__content {
order: 1;
align-items: flex-start;
text-align: left;
}
.download-cta__phone {
display: block;
}
.download-cta__copy {
align-items: flex-start;
}
.download-cta__description {
text-align: left;
}
.store-badges {
justify-content: flex-start;
}
.download-cta__heading {
--download-heading-title-size: 48px;
}
.download-cta__title {
letter-spacing: var(--ls-48);
}
.download-cta__phone {
order: 2;
width: 418px;
}
}
@media (min-width: 1280px) {
.download-cta__inner {
padding: 0;
}
}

View File

@@ -5,7 +5,7 @@
align-items: center;
width: 100%;
gap: 60px;
padding: 64px 0;
padding: 60px 0;
overflow: hidden;
}
@@ -38,9 +38,10 @@
.features__title {
width: 100%;
margin: 0;
font-size: 32px;
font-size: 28px;
font-weight: 700;
line-height: 1.2;
letter-spacing: var(--ls-28);
color: #1a1a1a;
text-align: center;
}
@@ -48,9 +49,10 @@
.features__description {
width: 100%;
margin: 0;
font-size: 18px;
font-size: 15px;
font-weight: 400;
line-height: 1.5;
letter-spacing: var(--ls-15);
color: #7a726d;
text-align: center;
}
@@ -70,8 +72,8 @@
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
padding: 32px;
gap: 24px;
padding: 36px;
background: rgba(255, 255, 255, 0.78);
border-radius: 30px;
}
@@ -105,9 +107,10 @@
.feature-card__title {
width: 100%;
margin: 0;
font-size: 24px;
font-size: 20px;
font-weight: 700;
line-height: normal;
letter-spacing: var(--ls-20);
color: #2e2a28;
}
@@ -117,34 +120,90 @@
font-size: 15px;
font-weight: 400;
line-height: 1.5;
letter-spacing: var(--ls-15);
color: #7a726d;
}
@media (min-width: 768px) {
@media (min-width: 440px) {
.features__header,
.features__grid {
padding-left: 20px;
padding-right: 20px;
}
.features__title {
font-size: 40px;
font-size: 32px;
letter-spacing: var(--ls-32);
}
}
@media (min-width: 576px) {
.features__header,
.features__grid {
padding-left: 24px;
padding-right: 24px;
}
.features__title {
font-size: 36px;
letter-spacing: var(--ls-36);
}
}
@media (min-width: 768px) {
.features__header,
.features__grid {
padding-left: 36px;
padding-right: 36px;
}
.features__title {
font-size: 42px;
letter-spacing: var(--ls-42);
}
.features__grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.feature-card__title {
font-size: 24px;
letter-spacing: var(--ls-24);
}
}
@media (min-width: 1024px) {
.features {
padding: 120px 0;
}
.features__header {
padding: 0 180px;
}
.features__title {
font-size: 48px;
padding: 0 clamp(36px, 14vw, 180px);
}
.features__grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
padding: 0 36px;
}
}
@media (min-width: 1200px) {
.features__title {
font-size: 48px;
letter-spacing: var(--ls-48);
}
.features__description {
font-size: 18px;
letter-spacing: var(--ls-18);
}
}
@media (min-width: 1280px) {
.features__grid {
padding: 0;
}
}
@media (min-width: 1376px) {
.features {
padding-top: 120px;
padding-bottom: 120px;
}
}

View File

@@ -4,7 +4,7 @@
align-items: center;
justify-content: center;
width: 100%;
padding: 64px 0;
padding: 60px 0;
background: #fef0eb;
}
@@ -30,7 +30,8 @@
display: flex;
flex-direction: column;
align-items: flex-start;
flex-shrink: 0;
flex: 1;
min-width: 0;
gap: 24px;
overflow: clip;
}
@@ -57,49 +58,10 @@
font-size: 14px;
font-weight: 400;
line-height: 1.5;
letter-spacing: var(--ls-14);
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;
@@ -119,6 +81,7 @@
font-size: 14px;
font-weight: 400;
line-height: normal;
letter-spacing: var(--ls-14);
color: #7a726d;
}
@@ -133,10 +96,6 @@
gap: 20px;
}
.site-footer__legal {
white-space: nowrap;
}
.site-footer__spacer {
display: block;
flex: 1;
@@ -146,11 +105,11 @@
@media (min-width: 1024px) {
.site-footer {
padding: 120px 0;
padding: 60px 0;
}
.site-footer__inner {
padding: 0;
padding: 0 24px;
}
.site-footer__top {
@@ -160,3 +119,13 @@
gap: 0;
}
}
@media (min-width: 1280px) {
.site-footer__inner {
padding: 0;
}
.site-footer__legal {
white-space: nowrap;
}
}

View File

@@ -8,3 +8,72 @@
@import './features.css';
@import './trust.css';
@import './preview.css';
body {
font-family: "Inter", sans-serif;
--ls-12: 0.01px;
--ls-13: -0.04px;
--ls-14: -0.09px;
--ls-15: -0.13px;
--ls-16: -0.18px;
--ls-17: -0.22px;
--ls-18: -0.26px;
--ls-19: -0.30px;
--ls-20: -0.33px;
--ls-21: -0.37px;
--ls-22: -0.40px;
--ls-23: -0.44px;
--ls-24: -0.47px;
--ls-25: -0.50px;
--ls-26: -0.53px;
--ls-27: -0.56px;
--ls-28: -0.59px;
--ls-29: -0.61px;
--ls-30: -0.64px;
--ls-31: -0.67px;
--ls-32: -0.69px;
--ls-33: -0.72px;
--ls-34: -0.74px;
--ls-35: -0.77px;
--ls-36: -0.79px;
--ls-37: -0.81px;
--ls-38: -0.84px;
--ls-39: -0.86px;
--ls-40: -0.89px;
--ls-41: -0.91px;
--ls-42: -0.93px;
--ls-43: -0.95px;
--ls-44: -0.98px;
--ls-45: -1.00px;
--ls-46: -1.02px;
--ls-47: -1.05px;
--ls-48: -1.07px;
--ls-49: -1.09px;
--ls-50: -1.11px;
--ls-51: -1.14px;
--ls-52: -1.16px;
--ls-53: -1.18px;
--ls-54: -1.20px;
--ls-55: -1.23px;
--ls-56: -1.25px;
--ls-57: -1.27px;
--ls-58: -1.29px;
--ls-59: -1.32px;
--ls-60: -1.34px;
--ls-61: -1.36px;
--ls-62: -1.38px;
--ls-63: -1.40px;
--ls-64: -1.43px;
--ls-65: -1.45px;
--ls-66: -1.47px;
--ls-67: -1.49px;
--ls-68: -1.52px;
--ls-69: -1.54px;
--ls-70: -1.56px;
--ls-71: -1.58px;
--ls-72: -1.61px;
}
:target {
scroll-margin-top: 72px;
}

View File

@@ -1,315 +1,354 @@
.site-header {
position: sticky;
top: 0;
z-index: 50;
width: 100%;
background: #fff;
border-bottom: 1px solid #e3d9d1;
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;
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;
display: flex;
flex: 1;
min-width: 0;
}
.site-header__brand {
align-items: center;
align-items: center;
}
.site-header__actions {
align-items: center;
justify-content: flex-end;
gap: 12px;
align-items: center;
justify-content: flex-end;
gap: 12px;
}
.site-logo {
position: relative;
display: block;
flex-shrink: 0;
width: 143px;
height: 42px;
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;
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%;
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%;
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%;
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;
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;
font-size: 14px;
font-weight: 600;
line-height: normal;
letter-spacing: var(--ls-14);
color: #7a726d;
text-decoration: none;
white-space: nowrap;
transition: color 160ms ease;
}
.site-nav__link:hover,
.site-nav__link.is-active {
color: #f28a4b;
color: #f28a4b;
}
.language-switcher {
position: relative;
display: none;
flex-shrink: 0;
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;
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__button[aria-expanded="true"] {
border-color: #f28a4b;
}
.language-switcher__icon {
display: block;
width: 26px;
height: 26px;
object-fit: contain;
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;
font-size: 14px;
font-weight: 600;
line-height: 14px;
letter-spacing: var(--ls-14);
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);
position: absolute;
top: 52px;
right: 0;
z-index: 60;
width: 240px;
max-height: min(520px, calc(100vh - 96px));
overflow-y: auto;
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;
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;
display: block;
padding: 14px 24px;
font-size: 14px;
font-weight: 600;
line-height: normal;
letter-spacing: var(--ls-14);
color: #7a726d;
text-decoration: none;
transition:
background-color 160ms ease,
color 160ms ease;
}
.language-switcher__option:hover {
color: #f28a4b;
background: #fef0eb;
color: #f28a4b;
background: #fef0eb;
}
.language-switcher__option.is-active {
color: #2e2a28;
background: #f8f3ee;
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;
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;
background: #e07a3b;
}
.site-header__download-label {
font-size: 14px;
font-weight: 700;
line-height: normal;
color: #fff;
white-space: nowrap;
font-size: 14px;
font-weight: 700;
line-height: normal;
letter-spacing: var(--ls-14);
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;
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;
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;
max-height: calc(100vh - 72px);
overflow-y: auto;
background: #fff;
border-top: 1px solid #e3d9d1;
}
.mobile-nav.is-hidden {
display: none;
display: none;
}
.mobile-nav__list {
display: flex;
flex-direction: column;
padding: 16px 24px;
margin: 0;
list-style: none;
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;
display: block;
padding: 16px 0;
font-size: 16px;
font-weight: 600;
letter-spacing: var(--ls-16);
color: #2e2a28;
text-decoration: none;
border-bottom: 1px solid #e3d9d1;
transition: color 160ms ease;
}
.mobile-nav__link.is-active {
color: #f28a4b;
}
.mobile-nav__link--last {
border-bottom: 0;
border-bottom: 0;
}
.mobile-nav__languages {
display: flex;
align-items: center;
gap: 16px;
padding: 16px 0;
border-top: 1px solid #e3d9d1;
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
align-items: center;
gap: 12px 16px;
padding: 16px 0;
border-top: 1px solid #e3d9d1;
}
.mobile-nav__language-link {
font-size: 15px;
font-weight: 600;
color: #2e2a28;
text-decoration: none;
min-width: 0;
font-size: 14px;
font-weight: 600;
line-height: 1.25;
letter-spacing: var(--ls-14);
color: #2e2a28;
text-align: center;
text-decoration: none;
}
.mobile-nav__language-link.is-active {
color: #f28a4b;
color: #f28a4b;
}
@media (max-width: 500px) {
.mobile-nav__languages {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
@media (min-width: 501px) and (max-width: 1024px) {
.mobile-nav__languages {
grid-template-columns: repeat(5, minmax(0, 1fr));
}
}
.mobile-nav__download-item {
margin: 16px 0 8px;
display: flex;
justify-content: center;
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;
display: block;
width: 250px;
max-width: 100%;
padding: 14px 24px;
font-size: 15px;
font-weight: 700;
letter-spacing: var(--ls-15);
color: #fff;
text-align: center;
text-decoration: none;
background: #f28a4b;
border-radius: 17px;
transition: background-color 160ms ease;
}
.mobile-nav__download:hover {
background: #e07a3b;
background: #e07a3b;
}
@media (min-width: 1024px) {
.site-header__bar {
padding: 0 24px;
}
.site-header__bar {
padding: 0 24px;
}
.site-nav,
.language-switcher,
.site-header__download {
display: flex;
}
.site-nav,
.language-switcher,
.site-header__download {
display: flex;
}
.menu-toggle {
display: none;
}
.menu-toggle {
display: none;
}
.mobile-nav {
display: none !important;
}
.mobile-nav {
display: none !important;
}
}

View File

@@ -1,237 +1,382 @@
.hero {
position: relative;
display: flex;
align-items: flex-start;
justify-content: center;
width: 100%;
min-height: 600px;
overflow: hidden;
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;
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;
position: relative;
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
max-width: 1280px;
height: 100%;
gap: 40px;
margin: 0 auto;
padding: 0 16px;
}
.hero__phone-column {
display: none;
position: relative;
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding-top: 24px;
pointer-events: none;
}
.hero__phone-frame {
position: relative;
width: 100%;
aspect-ratio: 673 / 1108;
position: relative;
z-index: 2;
width: min(320px, 100%);
height: 527px;
}
.hero__phone-crop {
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
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%;
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;
position: relative;
z-index: 1;
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;
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;
margin: 0;
font-size: 14px;
font-weight: 700;
line-height: normal;
letter-spacing: var(--ls-14);
color: #0d0d0d;
}
.hero__copy {
display: flex;
flex-direction: column;
align-items: flex-start;
flex-shrink: 0;
width: 100%;
gap: 24px;
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;
width: 100%;
font-size: 36px;
font-weight: 700;
line-height: 1.1;
letter-spacing: var(--ls-36);
color: #2e2a28;
}
.hero__title-line {
margin: 0;
line-height: 1.1;
margin: 0;
line-height: 1.1;
}
.hero__description {
width: 100%;
margin: 0;
font-size: 18px;
font-weight: 400;
line-height: 1.5;
color: #7a726d;
width: 100%;
margin: 0;
font-size: 15px;
font-weight: 400;
line-height: 1.5;
letter-spacing: var(--ls-15);
color: #7a726d;
}
.hero__actions {
display: flex;
flex-wrap: wrap;
align-items: center;
flex-shrink: 0;
gap: 14px;
overflow: clip;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-start;
flex-shrink: 0;
width: 100%;
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__store-badge {
text-decoration: none;
transition:
transform 160ms ease,
filter 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__store-badge:hover {
filter: brightness(0.96);
transform: translateY(-1px);
}
.hero__tags {
display: flex;
flex-wrap: wrap;
align-items: center;
flex-shrink: 0;
gap: 10px;
overflow: clip;
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;
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;
font-size: 14px;
font-weight: 700;
line-height: normal;
letter-spacing: var(--ls-14);
color: #7a726d;
white-space: nowrap;
}
@media (max-width: 433px) {
.hero__store-badge {
min-width: 0;
}
}
@media (max-width: 1024px) {
.hero__actions {
flex-wrap: nowrap;
}
.hero__store-badge {
flex: 1 1 calc((100% - 14px) / 2);
width: calc((100% - 14px) / 2);
min-width: 0;
padding-right: 10px;
padding-left: 10px;
}
.hero__store-badge .store-badge__copy,
.hero__store-badge .store-badge__label {
overflow: hidden;
text-overflow: ellipsis;
}
}
@media (max-width: 540px) {
.hero__actions {
flex-direction: column;
}
.hero__store-badge {
flex-basis: auto;
width: min(100%, calc(100vw - 32px));
}
.hero__tags {
justify-content: center;
width: 100%;
}
}
@media (min-width: 440px) {
.hero__title {
font-size: 42px;
letter-spacing: var(--ls-42);
}
}
@media (min-width: 576px) {
.hero__title {
font-size: 48px;
letter-spacing: var(--ls-48);
}
}
@media (min-width: 768px) {
.hero__title {
font-size: 56px;
}
.hero__title {
font-size: 56px;
letter-spacing: var(--ls-56);
}
.hero__phone-column {
padding-top: 60px;
}
.hero__phone-frame {
width: min(580px, 100%);
height: auto;
aspect-ratio: 116 / 191;
}
.hero__phone-crop {
position: relative;
inset: auto;
overflow: visible;
}
.hero__phone {
position: static;
width: 100%;
height: auto;
}
}
@media (min-width: 1024px) {
.hero {
height: 891px;
}
.hero {
height: 891px;
}
.hero__inner {
flex-direction: row;
padding: 0;
}
.hero__inner {
flex-direction: row;
padding: 0 24px;
}
.hero__phone-column {
display: flex;
align-items: center;
flex: 1;
min-width: 0;
height: 100%;
padding-top: 60px;
}
.hero__phone-column {
position: relative;
flex: 1;
min-width: 0;
height: 100%;
overflow: hidden;
}
.hero__content {
width: 660px;
padding: 80px 0;
}
.hero__phone-frame {
position: absolute;
top: 60px;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
}
.hero__title {
font-size: 72px;
}
.hero__phone-crop {
position: relative;
inset: auto;
height: 100%;
overflow: visible;
}
.hero__phone {
position: static;
width: auto;
height: 100%;
}
.hero__actions {
flex-wrap: nowrap;
}
.hero__store-badge {
flex: 0 1 auto;
min-width: 0;
}
.hero__content {
width: clamp(560px, 44vw, 600px);
padding: 0;
}
}
@media (min-width: 1200px) {
.hero__title {
font-size: 64px;
letter-spacing: var(--ls-64);
}
.hero__description {
font-size: 18px;
letter-spacing: var(--ls-18);
}
}
@media (min-width: 1280px) {
.hero__inner {
padding: 0;
}
.hero__phone-column {
align-items: flex-start;
padding-top: 60px;
}
.hero__phone-frame {
position: static;
top: auto;
right: auto;
bottom: auto;
overflow: visible;
flex: 1 0 0;
width: auto;
max-width: calc(955px * 116 / 191);
height: 955px;
aspect-ratio: 116 / 191;
}
.hero__phone-crop {
height: auto;
}
.hero__phone {
width: 100%;
height: 100%;
}
.hero__content {
width: clamp(560px, 52vw, 660px);
}
}
@media (min-width: 1376px) {
.hero__title {
font-size: 72px;
letter-spacing: var(--ls-72);
}
}

View File

@@ -1,158 +1,243 @@
.app-preview {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
gap: 60px;
padding: 64px 16px 0;
overflow: hidden;
background: #fef0eb;
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;
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;
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;
width: 100%;
margin: 0;
font-size: 15px;
font-weight: 400;
line-height: 1.5;
letter-spacing: var(--ls-15);
color: #7a726d;
text-align: center;
}
.app-preview__carousel {
display: flex;
align-items: flex-end;
justify-content: center;
flex-shrink: 0;
width: 100%;
gap: 20px;
box-sizing: border-box;
display: flex;
align-items: flex-end;
justify-content: center;
flex-shrink: 0;
width: 100%;
gap: 24px;
padding: 0 16px;
overflow: hidden;
}
.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;
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;
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;
display: flex;
align-items: flex-end;
align-self: stretch;
flex-shrink: 0;
}
.app-preview__control-inner {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
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;
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;
background: #e07a3b;
}
.app-preview__button:active {
transform: scale(0.95);
transform: scale(0.95);
}
.app-preview__button-icon {
display: block;
width: 24px;
height: 24px;
display: block;
width: 24px;
height: 24px;
}
.app-preview__button-icon--next {
transform: rotate(180deg);
transform: rotate(180deg);
}
.app-preview__center-phone {
position: relative;
flex-shrink: 0;
width: 100%;
aspect-ratio: 459 / 542;
overflow: hidden;
pointer-events: none;
position: relative;
flex-shrink: 0;
width: min(420px, calc(100vw - 168px));
aspect-ratio: 459 / 542;
overflow: hidden;
pointer-events: none;
}
@media (max-width: 594px) {
.app-preview__carousel {
gap: 12px;
}
.app-preview__button {
width: 40px;
height: 40px;
}
.app-preview__button-icon {
width: 20px;
height: 20px;
}
.app-preview__center-phone {
width: min(420px, calc(100vw - 120px));
}
}
@media (max-width: 554px) {
.app-preview__carousel {
gap: 8px;
padding: 0 12px;
}
.app-preview__button {
width: 36px;
height: 36px;
}
.app-preview__button-icon {
width: 18px;
height: 18px;
}
.app-preview__center-phone {
width: min(420px, calc(100vw - 104px));
}
}
@media (max-width: 540px) {
.app-preview__center-phone {
width: min(390px, calc(100vw - 120px));
}
}
@media (min-width: 768px) {
.app-preview__title {
font-size: 40px;
}
.app-preview__title {
font-size: 40px;
}
.app-preview__carousel {
gap: clamp(10px, 1.4vw, 16px);
padding: 0 clamp(16px, 3vw, 32px);
}
.app-preview__side-phone,
.app-preview__control-wrap {
display: flex;
}
.app-preview__side-phone {
display: block;
width: clamp(128px, 17vw, 190px);
height: auto;
aspect-ratio: 336 / 396;
}
.app-preview__center-phone {
width: clamp(220px, 31vw, 320px);
}
}
@media (min-width: 1024px) {
.app-preview {
padding: 120px 130px 0;
}
.app-preview {
padding: 120px clamp(32px, 6vw, 130px) 0;
}
.app-preview__title {
font-size: 48px;
}
.app-preview__title {
font-size: 48px;
}
.app-preview__side-phone,
.app-preview__control-wrap {
display: flex;
}
.app-preview__description {
font-size: 18px;
letter-spacing: var(--ls-18);
}
.app-preview__side-phone {
display: block;
}
.app-preview__side-phone,
.app-preview__control-wrap {
display: flex;
}
.app-preview__center-phone {
width: 459px;
height: 542px;
aspect-ratio: auto;
}
.app-preview__carousel {
gap: clamp(16px, 1.4vw, 20px);
padding: 0;
}
.app-preview__side-phone {
display: block;
width: clamp(190px, 20vw, 336px);
}
.app-preview__center-phone {
width: clamp(300px, 27vw, 459px);
height: auto;
aspect-ratio: 459 / 542;
}
}

View File

@@ -1,331 +1,488 @@
.experience {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 64px 16px;
background: #fff;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 60px 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;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
max-width: 1008px;
gap: 40px;
margin: 0 auto;
}
.experience__heading {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
gap: 24px;
}
.experience__title {
width: 100%;
margin: 0;
font-size: 32px;
font-weight: 700;
line-height: 1.2;
color: #1a1a1a;
text-align: center;
width: 100%;
margin: 0;
font-size: 28px;
font-weight: 700;
line-height: 1.2;
letter-spacing: var(--ls-28);
color: #1a1a1a;
text-align: center;
}
.experience__body {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
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;
display: grid;
grid-template-columns: minmax(0, 1fr);
justify-content: center;
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;
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
gap: 36px;
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;
position: relative;
flex-shrink: 0;
width: 100%;
aspect-ratio: 320 / 232;
overflow: hidden;
}
.experience-card__media--tinted {
display: flex;
flex-direction: column;
align-items: flex-start;
background: #ffeddf;
display: flex;
flex-direction: column;
align-items: flex-start;
background: #ffeddf;
}
.experience-card__media-crop {
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
}
.experience-card__image {
position: absolute;
max-width: none;
position: absolute;
max-width: none;
}
.experience-card__image--one {
top: -58.58%;
left: 0;
width: 100%;
height: 298.5%;
top: -86.5%;
left: 0;
width: 100%;
height: 298.5%;
}
.experience-card__image--two {
top: -335.6%;
left: -5.95%;
width: 137.79%;
height: 411.28%;
top: -137.86%;
left: -3.13%;
width: 130.62%;
height: 389.91%;
}
.experience-card__image--three {
top: -99.23%;
left: 0;
width: 100%;
height: 298.5%;
top: -115.66%;
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;
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;
width: 100%;
margin: 0;
font-size: 24px;
font-weight: 600;
line-height: 1.4;
letter-spacing: var(--ls-24);
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;
width: 100%;
margin: 0;
font-size: 16px;
font-weight: 500;
line-height: 1.5;
letter-spacing: var(--ls-16);
color: #7a726d;
}
.experience__caption {
width: 100%;
margin: 0;
font-size: 18px;
font-weight: 400;
line-height: 1.5;
color: #7a726d;
text-align: center;
width: 100%;
margin: 0;
font-size: 15px;
font-weight: 400;
line-height: 1.5;
letter-spacing: var(--ls-15);
color: #7a726d;
text-align: center;
}
.use-cases {
display: flex;
align-items: flex-start;
justify-content: center;
width: 100%;
padding: 64px 16px;
background: #fef0eb;
display: flex;
align-items: flex-start;
justify-content: center;
width: 100%;
padding: 60px 16px;
background: #fef0eb;
}
.use-cases__inner {
display: grid;
grid-template-columns: minmax(0, 1fr);
width: 100%;
max-width: 1280px;
gap: 32px;
margin: 0 auto;
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;
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
gap: 24px;
overflow: clip;
}
@media (max-width: 1294px) {
.use-cases__inner {
grid-template-columns: minmax(0, 1128px);
justify-content: center;
}
.use-cases__copy {
justify-self: start;
width: min(580px, 100%);
max-width: 580px;
margin: 0;
}
.use-cases__title,
.use-cases__description {
max-width: 100%;
}
}
.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;
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;
font-size: 14px;
font-weight: 700;
line-height: normal;
letter-spacing: var(--ls-14);
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;
width: 100%;
margin: 0;
font-size: 28px;
font-weight: 700;
line-height: 1.2;
letter-spacing: var(--ls-28);
color: #1a1a1a;
text-align: left;
}
.use-cases__description {
width: 100%;
margin: 0;
font-size: 18px;
font-weight: 400;
line-height: 1.5;
color: #7a726d;
width: 100%;
margin: 0;
font-size: 15px;
font-weight: 400;
line-height: 1.5;
letter-spacing: var(--ls-15);
color: #7a726d;
text-align: left;
}
@media (max-width: 768px) {
.use-cases__copy {
align-items: flex-start;
justify-self: stretch;
width: 100%;
max-width: none;
text-align: left;
}
.use-cases__title,
.use-cases__description {
text-align: left;
}
}
.use-cases__rows {
display: flex;
flex-direction: column;
align-items: stretch;
min-width: 0;
overflow: hidden;
border-radius: 30px;
gap: 1px;
display: flex;
flex-direction: column;
align-items: stretch;
width: 100%;
max-width: 1128px;
min-width: 0;
margin: 0 auto;
overflow: hidden;
border-radius: 30px;
gap: 1px;
}
.use-case-row {
display: grid;
grid-template-columns: minmax(0, 1fr);
width: 100%;
overflow: hidden;
background: #faede8;
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;
display: flex;
align-items: center;
min-width: 0;
padding: 16px 24px;
}
.use-case-row__title-cell {
background: #f08458;
background: #f08458;
}
.use-case-row__description-cell {
background: #fff;
background: #fff;
}
.use-case-row__title {
min-width: 0;
margin: 0;
font-size: 18px;
font-weight: 600;
line-height: normal;
color: #fff;
min-width: 0;
margin: 0;
font-size: 18px;
font-weight: 600;
line-height: normal;
letter-spacing: var(--ls-18);
color: #fff;
}
.use-case-row__description {
min-width: 0;
margin: 0;
font-size: 15px;
font-weight: 500;
line-height: 1.5;
color: #7a726d;
min-width: 0;
margin: 0;
font-size: 15px;
font-weight: 500;
line-height: 1.5;
letter-spacing: var(--ls-15);
color: #7a726d;
}
@media (min-width: 640px) {
.use-case-row {
grid-template-columns: minmax(220px, 300px) minmax(280px, 1fr);
min-height: 120px;
}
@media (max-width: 578px) {
.use-cases__rows {
gap: 24px;
overflow: visible;
border-radius: 0;
}
.use-case-row__title-cell,
.use-case-row__description-cell {
padding: 24px 36px;
}
.use-case-row {
overflow: hidden;
background: #fff;
border-radius: 16px;
}
.use-case-row__title {
font-size: 20px;
}
.use-case-row__title-cell,
.use-case-row__description-cell {
padding: 24px;
}
.use-case-row__title {
font-size: 20px;
letter-spacing: var(--ls-20);
}
}
@media (min-width: 440px) {
.experience,
.use-cases {
padding-left: 20px;
padding-right: 20px;
}
.experience__title,
.use-cases__title {
font-size: 32px;
letter-spacing: var(--ls-32);
}
}
@media (min-width: 576px) {
.experience,
.use-cases {
padding-left: 24px;
padding-right: 24px;
}
.experience__title,
.use-cases__title {
font-size: 36px;
letter-spacing: var(--ls-36);
}
}
@media (min-width: 578px) {
.experience__grid {
grid-template-columns: repeat(2, minmax(0, 320px));
}
.experience-card {
max-width: 320px;
justify-self: center;
}
.experience-card:nth-child(3):last-child {
grid-column: 1 / -1;
justify-self: center;
}
}
@media (min-width: 578px) {
.use-case-row {
grid-template-columns: minmax(220px, 300px) minmax(280px, 1fr);
height: 120px;
}
.use-case-row__title-cell,
.use-case-row__description-cell {
padding: 24px 36px;
}
.use-case-row__title {
font-size: 20px;
letter-spacing: var(--ls-20);
}
}
@media (min-width: 768px) {
.experience__title,
.use-cases__title {
font-size: 40px;
}
}
.experience,
.use-cases {
padding-left: 36px;
padding-right: 36px;
}
@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;
}
.experience__title,
.use-cases__title {
font-size: 42px;
letter-spacing: var(--ls-42);
}
}
@media (min-width: 1200px) {
.use-cases {
padding: 120px 64px;
}
.experience__grid {
grid-template-columns: repeat(3, minmax(0, 320px));
}
.use-cases__inner {
grid-template-columns: minmax(420px, 540px) minmax(560px, 1fr);
align-items: center;
gap: 40px;
}
.experience-card:nth-child(3):last-child {
grid-column: auto;
}
}
@media (min-width: 576px) {
.experience-card__title {
white-space: nowrap;
}
}
@media (min-width: 1024px) {
.experience {
padding-top: 60px;
padding-bottom: 60px;
padding-left: 36px;
padding-right: 36px;
}
}
@media (min-width: 1200px) {
.experience__title,
.use-cases__title {
font-size: 48px;
letter-spacing: var(--ls-48);
}
.experience__caption,
.use-cases__description {
font-size: 18px;
letter-spacing: var(--ls-18);
}
}
@media (min-width: 1201px) {
.use-cases {
padding: 60px 64px;
}
.use-cases__inner {
grid-template-columns: minmax(420px, 540px) minmax(560px, 1fr);
align-items: center;
gap: 40px;
}
}
@media (min-width: 1376px) {
.experience {
padding-top: 120px;
padding-bottom: 120px;
padding-left: 0;
padding-right: 0;
}
.use-cases {
padding-top: 120px;
padding-bottom: 120px;
}
}
@media (min-width: 1440px) {
.use-cases {
padding-right: 130px;
padding-left: 130px;
}
.use-cases {
padding-right: 130px;
padding-left: 130px;
}
}

View File

@@ -1,192 +1,328 @@
.trust {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
padding: 64px 16px;
background: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
padding: 60px 16px;
background: #fff;
}
.trust__inner {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
max-width: 1280px;
gap: 40px;
margin: 0 auto;
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;
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;
width: 100%;
margin: 0;
font-size: 28px;
font-weight: 700;
line-height: 1.2;
letter-spacing: var(--ls-28);
color: #1a1a1a;
}
.trust__description {
width: 100%;
margin: 0;
font-size: 18px;
font-weight: 400;
line-height: 1.5;
color: #7a726d;
width: 100%;
margin: 0;
font-size: 15px;
font-weight: 400;
line-height: 1.5;
letter-spacing: var(--ls-15);
color: #7a726d;
}
.trust__grid {
display: grid;
grid-template-columns: minmax(0, 1fr);
align-items: center;
justify-content: center;
width: 100%;
gap: 32px;
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;
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;
position: relative;
flex-shrink: 0;
width: 128px;
height: 128px;
}
.trust-card__icon-crop {
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
}
.trust-card__icon {
position: absolute;
max-width: none;
position: absolute;
max-width: none;
}
.trust-card__icon--one {
top: 7.04%;
left: -31.48%;
width: 312.73%;
height: 174.55%;
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%;
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%;
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%;
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;
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;
width: 100%;
margin: 0;
font-size: 16px;
font-weight: 600;
line-height: 22px;
letter-spacing: var(--ls-16);
color: #0d0d0d;
}
.trust-card__description {
width: 100%;
margin: 0;
font-size: 15px;
font-weight: 500;
line-height: 1.5;
color: #7a726d;
width: 100%;
margin: 0;
font-size: 15px;
font-weight: 500;
line-height: 1.5;
letter-spacing: var(--ls-15);
color: #7a726d;
}
.trust__divider {
position: relative;
display: none;
flex-shrink: 0;
width: 0;
height: 118px;
position: relative;
display: none; /* shown only in desktop flex row via 1023px breakpoint */
flex-shrink: 0;
width: 0;
height: 118px;
}
.trust__divider-frame {
position: absolute;
inset: 0 -0.5px;
position: absolute;
inset: 0 -0.5px;
}
.trust__divider-image {
display: block;
width: 100%;
max-width: none;
height: 100%;
display: block;
width: 100%;
max-width: none;
height: 100%;
}
@media (max-width: 1023px) {
.trust-card__copy {
align-items: center;
text-align: center;
}
.trust-card__title,
.trust-card__description {
text-align: center;
}
}
@media (min-width: 440px) {
.trust {
padding-left: 20px;
padding-right: 20px;
}
.trust__title {
font-size: 32px;
letter-spacing: var(--ls-32);
}
}
@media (min-width: 576px) {
.trust {
padding-left: 24px;
padding-right: 24px;
}
.trust__title {
font-size: 36px;
letter-spacing: var(--ls-36);
}
}
@media (min-width: 768px) {
.trust__title {
font-size: 40px;
}
.trust {
padding-left: 36px;
padding-right: 36px;
}
.trust__grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.trust__title {
font-size: 42px;
letter-spacing: var(--ls-42);
}
.trust__grid {
position: relative;
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (min-width: 768px) and (max-width: 1023px) {
.trust__grid > .trust-card:nth-child(1),
.trust__grid > .trust-card:nth-child(5) {
position: relative;
}
.trust__grid > .trust-card:nth-child(1)::after,
.trust__grid > .trust-card:nth-child(5)::after {
content: "";
position: absolute;
top: 50%;
right: -16px;
transform: translateY(-50%);
width: 0;
height: 118px;
border-left: 1px solid rgba(240, 132, 88, 0.5);
}
}
@media (min-width: 1024px) {
.trust {
padding: 120px;
}
.trust {
padding-top: 60px;
padding-bottom: 60px;
padding-left: 28px;
padding-right: 28px;
}
.trust__title {
font-size: 48px;
}
.trust__grid {
display: flex;
gap: 14px;
}
.trust__grid {
display: flex;
gap: 24px;
}
.trust-card {
flex: 1;
padding: 16px 8px;
}
.trust-card {
flex: 1;
}
.trust-card__icon-frame {
width: 112px;
height: 112px;
}
.trust__divider {
display: block;
}
.trust-card__copy {
align-items: center;
text-align: center;
}
.trust-card__title {
font-size: 15px;
line-height: 20px;
letter-spacing: var(--ls-15);
text-align: center;
}
.trust-card__description {
font-size: 14px;
line-height: 1.45;
letter-spacing: var(--ls-14);
text-align: center;
}
.trust__divider {
display: block;
}
}
@media (min-width: 1200px) {
.trust__title {
font-size: 48px;
letter-spacing: var(--ls-48);
}
.trust__description {
font-size: 18px;
letter-spacing: var(--ls-18);
}
.trust__grid {
gap: 24px;
}
.trust-card {
padding: 24px;
}
.trust-card__icon-frame {
width: 128px;
height: 128px;
}
.trust-card__title {
font-size: 16px;
line-height: 22px;
letter-spacing: var(--ls-16);
}
.trust-card__description {
font-size: 15px;
line-height: 1.5;
letter-spacing: var(--ls-15);
}
}
@media (min-width: 1376px) {
.trust {
padding-top: 120px;
padding-bottom: 120px;
padding-left: 120px;
padding-right: 120px;
}
}

View File

@@ -1,211 +1,317 @@
.why {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
padding: 64px 16px;
background: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
padding: 60px 16px;
background: #fff;
}
.why__inner {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
max-width: 1280px;
gap: 40px;
margin: 0 auto;
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;
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;
display: flex;
order: 2;
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;
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;
width: 100%;
font-size: 28px;
font-weight: 700;
letter-spacing: var(--ls-28);
color: #1a1a1a;
}
.why__title-line {
margin: 0;
line-height: 1.2;
margin: 0;
line-height: 1.2;
}
.why__underline {
position: relative;
flex-shrink: 0;
width: 295.5px;
height: 0;
position: relative;
flex-shrink: 0;
width: 295.5px;
height: 0;
}
.why__underline-frame {
position: absolute;
inset: -0.5px 0;
position: absolute;
inset: -0.5px 0;
}
.why__underline-image {
display: block;
width: 100%;
max-width: none;
height: 100%;
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;
font-size: 15px;
font-weight: 400;
line-height: 1.5;
letter-spacing: var(--ls-15);
color: #7a726d;
}
@media (min-width: 1200px) {
.why__description {
font-size: 18px;
letter-spacing: var(--ls-18);
}
}
.why__illustration {
position: relative;
display: none;
flex-shrink: 0;
width: 480px;
height: 480px;
display: block;
order: 1;
align-self: center;
flex-shrink: 0;
width: 480px;
max-width: calc(100vw - 32px);
height: 480px;
max-height: calc(100vw - 32px);
}
.why__illustration-image {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: contain;
position: absolute;
inset: 0;
display: block;
width: 100%;
height: 100%;
object-fit: contain;
}
.why__grid {
display: grid;
grid-template-columns: minmax(0, 1fr);
width: 100%;
gap: 24px;
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;
display: flex;
align-items: center;
min-width: 0;
gap: 20px;
padding: 20px 16px;
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;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
width: 60px;
height: 60px;
overflow: clip;
background: #f08458;
border-radius: 9999px;
}
.why-card__icon {
display: block;
display: block;
}
.why-card__icon--square {
width: 44px;
height: 44px;
.why-card__icon--simple {
width: 33.001px;
height: 32.973px;
}
.why-card__icon--familiar {
width: 38px;
height: 40px;
width: 28.5px;
height: 30px;
}
.why-card__icon--connected {
width: 33px;
height: 32.936px;
}
.why-card__icon--modern {
width: 24px;
height: 44px;
width: 18.125px;
height: 33px;
}
.why-card__copy {
display: flex;
flex: 1;
flex-direction: column;
align-items: flex-start;
min-width: 0;
gap: 12px;
overflow: clip;
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;
width: 100%;
margin: 0;
font-size: 20px;
font-weight: 600;
line-height: 23px;
letter-spacing: var(--ls-20);
color: #0d0d0d;
}
.why-card__description {
width: 100%;
margin: 0;
font-size: 16px;
font-weight: 500;
line-height: 1.5;
color: #7a726d;
width: 100%;
margin: 0;
font-size: 16px;
font-weight: 500;
line-height: 1.5;
letter-spacing: var(--ls-16);
color: #7a726d;
}
@media (min-width: 440px) {
.why {
padding-left: 20px;
padding-right: 20px;
}
.why-card {
gap: 24px;
}
.why-card__icon-frame {
width: 80px;
height: 80px;
}
.why-card__icon--simple {
width: 44.001px;
height: 43.964px;
}
.why-card__icon--familiar {
width: 38px;
height: 40px;
}
.why-card__icon--connected {
width: 44px;
height: 43.914px;
}
.why-card__icon--modern {
width: 24.168px;
height: 44px;
}
.why__title {
font-size: 32px;
letter-spacing: var(--ls-32);
}
}
@media (min-width: 576px) {
.why {
padding-left: 24px;
padding-right: 24px;
}
.why__title {
font-size: 36px;
letter-spacing: var(--ls-36);
}
}
@media (min-width: 768px) {
.why__title {
font-size: 40px;
}
.why {
padding-left: 36px;
padding-right: 36px;
}
.why__grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.why__title {
font-size: 42px;
letter-spacing: var(--ls-42);
}
.why-card {
min-height: 152px;
}
.why-card {
padding: 36px;
min-height: 152px;
}
.why-card__title {
font-size: 24px;
letter-spacing: var(--ls-24);
}
}
@media (min-width: 1024px) {
.why {
padding: 120px 0;
}
.why {
padding-top: 60px;
padding-bottom: 60px;
padding-left: 36px;
padding-right: 36px;
}
.why__intro {
flex-direction: row;
}
.why__grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.why__title {
font-size: 48px;
}
.why__intro {
flex-direction: row;
}
.why__illustration {
display: block;
}
.why__copy {
order: 1;
}
.why__illustration {
order: 2;
}
}
@media (min-width: 1200px) {
.why__title {
font-size: 48px;
letter-spacing: var(--ls-48);
}
}
@media (min-width: 1376px) {
.why {
padding-top: 120px;
padding-bottom: 120px;
padding-left: 0;
padding-right: 0;
}
}