Compare commits
2 Commits
50c5868da6
...
4b1ca280b6
| Author | SHA1 | Date | |
|---|---|---|---|
| 4b1ca280b6 | |||
| 2d7e7f2fe1 |
Binary file not shown.
|
After Width: | Height: | Size: 89 KiB |
@@ -5,6 +5,7 @@ import "../globals.css";
|
|||||||
import SiteHeader from "@/components/site-header";
|
import SiteHeader from "@/components/site-header";
|
||||||
import SiteFooter from "@/components/site-footer";
|
import SiteFooter from "@/components/site-footer";
|
||||||
import Analytics, { AnalyticsNoScript } from "@/components/analytics";
|
import Analytics, { AnalyticsNoScript } from "@/components/analytics";
|
||||||
|
import { themeScript } from "@/components/theme-toggle";
|
||||||
import { dirOf, locales, localize, ogLocale } from "@/i18n/config";
|
import { dirOf, locales, localize, ogLocale } from "@/i18n/config";
|
||||||
import { mainNav } from "@/i18n/nav";
|
import { mainNav } from "@/i18n/nav";
|
||||||
import { getUI } from "@/i18n/server";
|
import { getUI } from "@/i18n/server";
|
||||||
@@ -51,7 +52,7 @@ export async function generateMetadata(): Promise<Metadata> {
|
|||||||
|
|
||||||
export const viewport: Viewport = {
|
export const viewport: Viewport = {
|
||||||
themeColor: "#000000",
|
themeColor: "#000000",
|
||||||
colorScheme: "dark",
|
colorScheme: "dark light",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function RootLayout({ children }: LayoutProps<"/[lang]">) {
|
export default async function RootLayout({ children }: LayoutProps<"/[lang]">) {
|
||||||
@@ -63,6 +64,8 @@ export default async function RootLayout({ children }: LayoutProps<"/[lang]">) {
|
|||||||
closeMenu: t.nav.closeMenu,
|
closeMenu: t.nav.closeMenu,
|
||||||
language: t.nav.language,
|
language: t.nav.language,
|
||||||
logoHome: t.logoHome,
|
logoHome: t.logoHome,
|
||||||
|
lightTheme: t.nav.lightTheme,
|
||||||
|
darkTheme: t.nav.darkTheme,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -71,7 +74,12 @@ export default async function RootLayout({ children }: LayoutProps<"/[lang]">) {
|
|||||||
dir={dirOf(locale)}
|
dir={dirOf(locale)}
|
||||||
className={`${inter.variable} ${arabic.variable}`}
|
className={`${inter.variable} ${arabic.variable}`}
|
||||||
data-scroll-behavior="smooth"
|
data-scroll-behavior="smooth"
|
||||||
|
// The theme script sets data-theme before React hydrates.
|
||||||
|
suppressHydrationWarning
|
||||||
>
|
>
|
||||||
|
<head>
|
||||||
|
<script dangerouslySetInnerHTML={{ __html: themeScript }} />
|
||||||
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<AnalyticsNoScript />
|
<AnalyticsNoScript />
|
||||||
<a href="#main" className="skip-link">
|
<a href="#main" className="skip-link">
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import ProductVisual from "@/components/product-visuals";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { home } from "@/content/home";
|
import { home } from "@/content/home";
|
||||||
import { localize } from "@/i18n/config";
|
import { localize } from "@/i18n/config";
|
||||||
import { getLocale } from "@/i18n/server";
|
import { getUI } from "@/i18n/server";
|
||||||
|
import CtaBand from "@/components/cta-band";
|
||||||
|
|
||||||
type Vars = CSSProperties & Record<`--${string}`, string | number>;
|
type Vars = CSSProperties & Record<`--${string}`, string | number>;
|
||||||
const delay = (ms: number) => ({ "--d": `${ms}ms` }) as Vars;
|
const delay = (ms: number) => ({ "--d": `${ms}ms` }) as Vars;
|
||||||
@@ -25,7 +26,7 @@ function Eyebrow({ index, children }: { index?: string; children: ReactNode }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default async function Home() {
|
export default async function Home() {
|
||||||
const locale = await getLocale();
|
const { locale, t } = await getUI();
|
||||||
const c = home[locale];
|
const c = home[locale];
|
||||||
const to = (path: string) => localize(path, locale);
|
const to = (path: string) => localize(path, locale);
|
||||||
const { hero, numbers, capabilities, technology, discovery, journey, difference, cta } = c;
|
const { hero, numbers, capabilities, technology, discovery, journey, difference, cta } = c;
|
||||||
@@ -134,6 +135,8 @@ export default async function Home() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<CtaBand t={t} locale={locale} />
|
||||||
|
|
||||||
{/* ───────────────────────── Proprietary technology ───────────────────────── */}
|
{/* ───────────────────────── Proprietary technology ───────────────────────── */}
|
||||||
<section className="section" id="technology" aria-labelledby="tech-title">
|
<section className="section" id="technology" aria-labelledby="tech-title">
|
||||||
<div className="wrap">
|
<div className="wrap">
|
||||||
@@ -241,6 +244,8 @@ export default async function Home() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<CtaBand t={t} locale={locale} />
|
||||||
|
|
||||||
{/* ───────────────────────── Attention to action ───────────────────────── */}
|
{/* ───────────────────────── Attention to action ───────────────────────── */}
|
||||||
<section className="section" id="approach" aria-labelledby="journey-title">
|
<section className="section" id="approach" aria-labelledby="journey-title">
|
||||||
<div className="wrap">
|
<div className="wrap">
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
+185
-33
@@ -13,6 +13,13 @@
|
|||||||
--fumo: #8f8f8f;
|
--fumo: #8f8f8f;
|
||||||
--piombo: #666666;
|
--piombo: #666666;
|
||||||
--argento: #d2d2d2;
|
--argento: #d2d2d2;
|
||||||
|
/* The names keep their roles in both themes: bianco is ink, nero is paper. */
|
||||||
|
--ink-rgb: 255, 255, 255;
|
||||||
|
--paper-rgb: 0, 0, 0;
|
||||||
|
--cap-line: #262626;
|
||||||
|
--panel: #070707;
|
||||||
|
--panel-line: #1c1c1c;
|
||||||
|
color-scheme: dark;
|
||||||
|
|
||||||
--font-sans: var(--font-inter), "Helvetica Neue", Arial, sans-serif;
|
--font-sans: var(--font-inter), "Helvetica Neue", Arial, sans-serif;
|
||||||
|
|
||||||
@@ -28,6 +35,23 @@
|
|||||||
--dir: -1;
|
--dir: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Light theme, chosen with the header toggle. */
|
||||||
|
:root[data-theme="light"] {
|
||||||
|
--bianco: #0a0a0a;
|
||||||
|
--nero: #ffffff;
|
||||||
|
--notte: #f4f4f2;
|
||||||
|
--grafite: #d9d9d6;
|
||||||
|
--fumo: #5c5c5c;
|
||||||
|
--piombo: #808080;
|
||||||
|
--argento: #333333;
|
||||||
|
--ink-rgb: 10, 10, 10;
|
||||||
|
--paper-rgb: 255, 255, 255;
|
||||||
|
--cap-line: #e2e2e2;
|
||||||
|
--panel: #f7f7f5;
|
||||||
|
--panel-line: #e4e4e1;
|
||||||
|
color-scheme: light;
|
||||||
|
}
|
||||||
|
|
||||||
*,
|
*,
|
||||||
*::before,
|
*::before,
|
||||||
*::after {
|
*::after {
|
||||||
@@ -55,7 +79,7 @@ body {
|
|||||||
|
|
||||||
::selection {
|
::selection {
|
||||||
background: var(--rosso);
|
background: var(--rosso);
|
||||||
color: var(--bianco);
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
@@ -220,7 +244,7 @@ a {
|
|||||||
.btn-ghost {
|
.btn-ghost {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--bianco);
|
color: var(--bianco);
|
||||||
border-color: rgba(255, 255, 255, 0.35);
|
border-color: rgba(var(--ink-rgb), 0.35);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-ghost:hover {
|
.btn-ghost:hover {
|
||||||
@@ -261,7 +285,7 @@ a {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
padding: 0 14px;
|
padding: 0 14px;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.28);
|
border: 1px solid rgba(var(--ink-rgb), 0.28);
|
||||||
border-radius: 9999px;
|
border-radius: 9999px;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -303,7 +327,7 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.site-header.is-scrolled {
|
.site-header.is-scrolled {
|
||||||
background: rgba(0, 0, 0, 0.82);
|
background: rgba(var(--paper-rgb), 0.82);
|
||||||
backdrop-filter: blur(14px);
|
backdrop-filter: blur(14px);
|
||||||
-webkit-backdrop-filter: blur(14px);
|
-webkit-backdrop-filter: blur(14px);
|
||||||
border-color: var(--grafite);
|
border-color: var(--grafite);
|
||||||
@@ -350,6 +374,7 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.logo-type b {
|
.logo-type b {
|
||||||
|
white-space: nowrap;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
letter-spacing: 0.2em;
|
letter-spacing: 0.2em;
|
||||||
@@ -376,7 +401,7 @@ a {
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
letter-spacing: 0.2em;
|
letter-spacing: 0.2em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: rgba(255, 255, 255, 0.78);
|
color: rgba(var(--ink-rgb), 0.78);
|
||||||
transition: color 0.3s var(--ease);
|
transition: color 0.3s var(--ease);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,9 +537,9 @@ a {
|
|||||||
inset: 0;
|
inset: 0;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
background:
|
background:
|
||||||
linear-gradient(180deg, rgba(0, 0, 0, 0.55) 0%, transparent 22%),
|
linear-gradient(180deg, rgba(var(--paper-rgb), 0.55) 0%, transparent 22%),
|
||||||
linear-gradient(0deg, #000 4%, rgba(0, 0, 0, 0.6) 34%, transparent 62%),
|
linear-gradient(0deg, var(--nero) 4%, rgba(var(--paper-rgb), 0.6) 34%, transparent 62%),
|
||||||
linear-gradient(90deg, rgba(0, 0, 0, 0.7) 0%, transparent 55%);
|
linear-gradient(90deg, rgba(var(--paper-rgb), 0.7) 0%, transparent 55%);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -858,13 +883,13 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.cap-map line {
|
.cap-map line {
|
||||||
stroke: #262626;
|
stroke: var(--cap-line);
|
||||||
stroke-width: 1;
|
stroke-width: 1;
|
||||||
transition: stroke 0.5s var(--ease);
|
transition: stroke 0.5s var(--ease);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cap-map line.on {
|
.cap-map line.on {
|
||||||
stroke: rgba(255, 255, 255, 0.6);
|
stroke: rgba(var(--ink-rgb), 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cap-map .node {
|
.cap-map .node {
|
||||||
@@ -882,7 +907,7 @@ a {
|
|||||||
|
|
||||||
.cap-map .core {
|
.cap-map .core {
|
||||||
fill: var(--nero);
|
fill: var(--nero);
|
||||||
stroke: rgba(255, 255, 255, 0.4);
|
stroke: rgba(var(--ink-rgb), 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cap-map text {
|
.cap-map text {
|
||||||
@@ -1002,8 +1027,8 @@ a {
|
|||||||
grid-column: 1 / span 6;
|
grid-column: 1 / span 6;
|
||||||
position: relative;
|
position: relative;
|
||||||
aspect-ratio: 600 / 412;
|
aspect-ratio: 600 / 412;
|
||||||
background: #070707;
|
background: var(--panel);
|
||||||
outline: 1px solid #1c1c1c;
|
outline: 1px solid var(--panel-line);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1071,7 +1096,7 @@ a {
|
|||||||
/* journey viz */
|
/* journey viz */
|
||||||
.viz-journey .path {
|
.viz-journey .path {
|
||||||
fill: none;
|
fill: none;
|
||||||
stroke: rgba(255, 255, 255, 0.16);
|
stroke: rgba(var(--ink-rgb), 0.16);
|
||||||
stroke-width: 1;
|
stroke-width: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1099,7 +1124,7 @@ a {
|
|||||||
|
|
||||||
.viz-journey .node {
|
.viz-journey .node {
|
||||||
fill: var(--nero);
|
fill: var(--nero);
|
||||||
stroke: rgba(255, 255, 255, 0.6);
|
stroke: rgba(var(--ink-rgb), 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.viz-journey .goal {
|
.viz-journey .goal {
|
||||||
@@ -1117,11 +1142,11 @@ a {
|
|||||||
/* radar viz */
|
/* radar viz */
|
||||||
.viz-radar .ring {
|
.viz-radar .ring {
|
||||||
fill: none;
|
fill: none;
|
||||||
stroke: rgba(255, 255, 255, 0.12);
|
stroke: rgba(var(--ink-rgb), 0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
.viz-radar .axis {
|
.viz-radar .axis {
|
||||||
stroke: rgba(255, 255, 255, 0.07);
|
stroke: rgba(var(--ink-rgb), 0.07);
|
||||||
}
|
}
|
||||||
|
|
||||||
.viz-radar .sweep {
|
.viz-radar .sweep {
|
||||||
@@ -1160,12 +1185,12 @@ a {
|
|||||||
|
|
||||||
/* grid viz */
|
/* grid viz */
|
||||||
.viz-grid .cell {
|
.viz-grid .cell {
|
||||||
fill: rgba(255, 255, 255, 0.035);
|
fill: rgba(var(--ink-rgb), 0.035);
|
||||||
stroke: rgba(255, 255, 255, 0.08);
|
stroke: rgba(var(--ink-rgb), 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
.viz-grid .cell.on {
|
.viz-grid .cell.on {
|
||||||
fill: rgba(255, 255, 255, 0.85);
|
fill: rgba(var(--ink-rgb), 0.85);
|
||||||
stroke: none;
|
stroke: none;
|
||||||
animation: cell 4.8s var(--ease) infinite;
|
animation: cell 4.8s var(--ease) infinite;
|
||||||
animation-delay: var(--t);
|
animation-delay: var(--t);
|
||||||
@@ -1201,7 +1226,7 @@ a {
|
|||||||
|
|
||||||
.viz-grid .frame {
|
.viz-grid .frame {
|
||||||
fill: none;
|
fill: none;
|
||||||
stroke: rgba(255, 255, 255, 0.5);
|
stroke: rgba(var(--ink-rgb), 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1023px) {
|
@media (max-width: 1023px) {
|
||||||
@@ -1290,7 +1315,7 @@ a {
|
|||||||
place-items: center;
|
place-items: center;
|
||||||
width: 96px;
|
width: 96px;
|
||||||
height: 96px;
|
height: 96px;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.35);
|
border: 1px solid rgba(var(--ink-rgb), 0.35);
|
||||||
border-radius: 9999px;
|
border-radius: 9999px;
|
||||||
font-size: 9px;
|
font-size: 9px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@@ -1360,7 +1385,7 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.journey ol::after {
|
.journey ol::after {
|
||||||
background: linear-gradient(90deg, rgba(255, 255, 255, 0.7), var(--rosso));
|
background: linear-gradient(90deg, rgba(var(--ink-rgb), 0.7), var(--rosso));
|
||||||
transform: scaleX(0);
|
transform: scaleX(0);
|
||||||
transform-origin: left;
|
transform-origin: left;
|
||||||
transition: transform 2.6s var(--ease) 0.2s;
|
transition: transform 2.6s var(--ease) 0.2s;
|
||||||
@@ -1434,7 +1459,7 @@ a {
|
|||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
.journey ol::after {
|
.journey ol::after {
|
||||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.7), var(--rosso));
|
background: linear-gradient(180deg, rgba(var(--ink-rgb), 0.7), var(--rosso));
|
||||||
transform: scaleY(0);
|
transform: scaleY(0);
|
||||||
transform-origin: top;
|
transform-origin: top;
|
||||||
}
|
}
|
||||||
@@ -1542,7 +1567,7 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.gaps .break line {
|
.gaps .break line {
|
||||||
stroke: rgba(255, 255, 255, 0.45);
|
stroke: rgba(var(--ink-rgb), 0.45);
|
||||||
}
|
}
|
||||||
|
|
||||||
.gaps .break .cut {
|
.gaps .break .cut {
|
||||||
@@ -1635,7 +1660,7 @@ a {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0.9) 55%, #000 80%);
|
background: radial-gradient(ellipse at center, rgba(var(--paper-rgb), 0.6) 0%, rgba(var(--paper-rgb), 0.9) 55%, var(--nero) 80%);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1758,7 +1783,7 @@ a {
|
|||||||
line-height: 0.9;
|
line-height: 0.9;
|
||||||
letter-spacing: -0.05em;
|
letter-spacing: -0.05em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: rgba(255, 255, 255, 0.07);
|
color: rgba(var(--ink-rgb), 0.07);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
@@ -1873,7 +1898,7 @@ a {
|
|||||||
|
|
||||||
.nav-panel-inner {
|
.nav-panel-inner {
|
||||||
padding: 22px 28px 26px;
|
padding: 22px 28px 26px;
|
||||||
background: rgba(0, 0, 0, 0.94);
|
background: rgba(var(--paper-rgb), 0.94);
|
||||||
backdrop-filter: blur(14px);
|
backdrop-filter: blur(14px);
|
||||||
-webkit-backdrop-filter: blur(14px);
|
-webkit-backdrop-filter: blur(14px);
|
||||||
border: 1px solid var(--grafite);
|
border: 1px solid var(--grafite);
|
||||||
@@ -2115,7 +2140,7 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.link-card:hover {
|
.link-card:hover {
|
||||||
background: rgba(255, 255, 255, 0.03);
|
background: rgba(var(--ink-rgb), 0.03);
|
||||||
}
|
}
|
||||||
|
|
||||||
.link-card:hover .arrow-link {
|
.link-card:hover .arrow-link {
|
||||||
@@ -2516,11 +2541,28 @@ a {
|
|||||||
resize: vertical;
|
resize: vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The message gets a full outline so it reads as a box to type in. */
|
||||||
|
.field textarea {
|
||||||
|
min-height: 132px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
border: 1px solid var(--grafite);
|
||||||
|
}
|
||||||
|
|
||||||
.field input:focus,
|
.field input:focus,
|
||||||
.field textarea:focus {
|
.field textarea:focus {
|
||||||
border-color: var(--rosso);
|
border-color: var(--rosso);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Browser autofill paints its own pale background; keep the field on-theme and readable. */
|
||||||
|
.field input:-webkit-autofill,
|
||||||
|
.field input:-webkit-autofill:hover,
|
||||||
|
.field input:-webkit-autofill:focus {
|
||||||
|
-webkit-text-fill-color: var(--bianco);
|
||||||
|
caret-color: var(--bianco);
|
||||||
|
-webkit-box-shadow: 0 0 0 1000px var(--nero) inset;
|
||||||
|
transition: background-color 9999s;
|
||||||
|
}
|
||||||
|
|
||||||
.field input::placeholder {
|
.field input::placeholder {
|
||||||
color: var(--piombo);
|
color: var(--piombo);
|
||||||
}
|
}
|
||||||
@@ -2680,6 +2722,64 @@ a {
|
|||||||
color: var(--bianco);
|
color: var(--bianco);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.theme-toggle {
|
||||||
|
display: inline-grid;
|
||||||
|
place-items: center;
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
flex: none;
|
||||||
|
padding: 0;
|
||||||
|
border: 1px solid var(--grafite);
|
||||||
|
border-radius: 50%;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--bianco);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color 0.3s var(--ease);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-toggle:hover {
|
||||||
|
border-color: var(--bianco);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-toggle svg {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
fill: none;
|
||||||
|
stroke: currentColor;
|
||||||
|
stroke-width: 1.5;
|
||||||
|
stroke-linecap: round;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shows the theme you'd switch to: a sun on dark pages, a moon on light ones. */
|
||||||
|
.theme-toggle .moon,
|
||||||
|
:root[data-theme="light"] .theme-toggle .sun {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="light"] .theme-toggle .moon {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Phones: the languages move into the menu (it carries its own switch) so the logo has room. */
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.site-header .lang-switch {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.site-header .theme-toggle {
|
||||||
|
margin-inline-start: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The stacked logo's wordmark is white; the light theme swaps in the dark-lettered file. */
|
||||||
|
.logo-stacked .on-light,
|
||||||
|
:root[data-theme="light"] .logo-stacked .on-dark {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-theme="light"] .logo-stacked .on-light {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.lang-switch [aria-current] {
|
.lang-switch [aria-current] {
|
||||||
color: var(--bianco);
|
color: var(--bianco);
|
||||||
box-shadow: inset 0 -1px 0 var(--rosso);
|
box-shadow: inset 0 -1px 0 var(--rosso);
|
||||||
@@ -2706,7 +2806,7 @@ a {
|
|||||||
gap: 16px;
|
gap: 16px;
|
||||||
max-width: 340px;
|
max-width: 340px;
|
||||||
padding: 14px 18px;
|
padding: 14px 18px;
|
||||||
border: 1px solid var(--grafite);
|
border: 1px solid var(--piombo);
|
||||||
transition: border-color 0.3s var(--ease);
|
transition: border-color 0.3s var(--ease);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2739,7 +2839,7 @@ a {
|
|||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
flex: none;
|
flex: none;
|
||||||
border: 1px solid var(--fumo);
|
border: 1.5px solid var(--argento);
|
||||||
transition:
|
transition:
|
||||||
border-color 0.3s var(--ease),
|
border-color 0.3s var(--ease),
|
||||||
background-color 0.3s var(--ease);
|
background-color 0.3s var(--ease);
|
||||||
@@ -2754,7 +2854,7 @@ a {
|
|||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
fill: none;
|
fill: none;
|
||||||
stroke: var(--bianco);
|
stroke: #fff;
|
||||||
stroke-width: 1.8;
|
stroke-width: 1.8;
|
||||||
stroke-dasharray: 16;
|
stroke-dasharray: 16;
|
||||||
stroke-dashoffset: 16;
|
stroke-dashoffset: 16;
|
||||||
@@ -2810,7 +2910,7 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[dir="rtl"] .journey ol::after {
|
[dir="rtl"] .journey ol::after {
|
||||||
background: linear-gradient(270deg, rgba(255, 255, 255, 0.7), var(--rosso));
|
background: linear-gradient(270deg, rgba(var(--ink-rgb), 0.7), var(--rosso));
|
||||||
transform-origin: right;
|
transform-origin: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2839,3 +2939,55 @@ html[lang="ar"] .btn,
|
|||||||
html[lang="ar"] .nav a {
|
html[lang="ar"] .nav a {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* booking band between sections */
|
||||||
|
.cta-band {
|
||||||
|
position: relative;
|
||||||
|
padding-block: clamp(36px, 5vw, 56px);
|
||||||
|
border-block: 1px solid var(--grafite);
|
||||||
|
background:
|
||||||
|
radial-gradient(ellipse at 85% 50%, rgba(var(--ink-rgb), 0.05), transparent 60%),
|
||||||
|
var(--nero);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-band-inner {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-band-copy {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-band-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: clamp(20px, 2.2vw, 30px);
|
||||||
|
font-weight: 300;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
line-height: 1.2;
|
||||||
|
color: var(--bianco);
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-band-body {
|
||||||
|
margin: 0;
|
||||||
|
max-width: 60ch;
|
||||||
|
font-size: 15px;
|
||||||
|
color: var(--argento);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-band .btn {
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 760px) {
|
||||||
|
.cta-band-inner {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -98,9 +98,13 @@ export default function ContactForm({
|
|||||||
<span>{t.website}</span>
|
<span>{t.website}</span>
|
||||||
<input
|
<input
|
||||||
name="website"
|
name="website"
|
||||||
type="url"
|
// Plain text, not type="url": people write "company.com" and shouldn't be made to add https://.
|
||||||
|
type="text"
|
||||||
inputMode="url"
|
inputMode="url"
|
||||||
placeholder="https://"
|
autoComplete="url"
|
||||||
|
autoCapitalize="none"
|
||||||
|
spellCheck={false}
|
||||||
|
placeholder="company.com"
|
||||||
maxLength={300}
|
maxLength={300}
|
||||||
defaultValue={values?.website}
|
defaultValue={values?.website}
|
||||||
dir="ltr"
|
dir="ltr"
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import type { CSSProperties, ReactNode } from "react";
|
import { Fragment, type CSSProperties, type ReactNode } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import GlobeCanvas from "@/components/globe-canvas";
|
import GlobeCanvas from "@/components/globe-canvas";
|
||||||
import StatCounter from "@/components/stat-counter";
|
import StatCounter from "@/components/stat-counter";
|
||||||
import RevealObserver from "@/components/reveal-observer";
|
import RevealObserver from "@/components/reveal-observer";
|
||||||
import ContactForm from "./contact-form";
|
import ContactForm from "./contact-form";
|
||||||
|
import CtaBand from "@/components/cta-band";
|
||||||
import { localize } from "@/i18n/config";
|
import { localize } from "@/i18n/config";
|
||||||
import { getUI } from "@/i18n/server";
|
import { getUI } from "@/i18n/server";
|
||||||
import type { UI } from "@/i18n/ui";
|
import type { UI } from "@/i18n/ui";
|
||||||
@@ -537,9 +538,12 @@ export default async function ContentPage({ page, trail }: { page: Page; trail:
|
|||||||
<PageHero page={page} crumbs={crumbs} t={t} />
|
<PageHero page={page} crumbs={crumbs} t={t} />
|
||||||
{body.map((section, i) => {
|
{body.map((section, i) => {
|
||||||
const Variant = variants[section.kind] ?? TextSection;
|
const Variant = variants[section.kind] ?? TextSection;
|
||||||
|
// A booking band after the 2nd section and every 3rd after that, unless the section
|
||||||
|
// already ends in its own call to action or holds the form.
|
||||||
|
const band = i % 3 === 1 && i < body.length - 1 && !section.form && section.ctas.length === 0;
|
||||||
return (
|
return (
|
||||||
|
<Fragment key={i}>
|
||||||
<section
|
<section
|
||||||
key={i}
|
|
||||||
id={section.form ? "contact-form" : undefined}
|
id={section.form ? "contact-form" : undefined}
|
||||||
className={`section${i % 2 === 0 ? " section-night" : ""} kind-${section.kind}`}
|
className={`section${i % 2 === 0 ? " section-night" : ""} kind-${section.kind}`}
|
||||||
>
|
>
|
||||||
@@ -552,6 +556,8 @@ export default async function ContentPage({ page, trail }: { page: Page; trail:
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
{band && <CtaBand t={t} locale={locale} />}
|
||||||
|
</Fragment>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{closing && <ClosingCta section={closing} />}
|
{closing && <ClosingCta section={closing} />}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
import { localize, type Locale } from "@/i18n/config";
|
||||||
|
import type { UI } from "@/i18n/ui";
|
||||||
|
|
||||||
|
/** Compact call to action placed between sections, so a booking link is always close while scrolling. */
|
||||||
|
export default function CtaBand({ t, locale }: { t: UI; locale: Locale }) {
|
||||||
|
return (
|
||||||
|
<aside className="cta-band" aria-label={t.bookCall}>
|
||||||
|
<div className="wrap cta-band-inner" data-reveal>
|
||||||
|
<div className="cta-band-copy">
|
||||||
|
<p className="cta-band-title">{t.ctaBand.title}</p>
|
||||||
|
<p className="cta-band-body">{t.ctaBand.body}</p>
|
||||||
|
</div>
|
||||||
|
<Link href={localize("/contact", locale)} className="btn btn-solid">
|
||||||
|
{t.bookCall} <span className="arrow">→</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -59,6 +59,10 @@ export default function GlobeCanvas({ layout = "hero", className = "hero-canvas"
|
|||||||
|
|
||||||
const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||||
|
|
||||||
|
// Dots and lines use the theme's ink colour, re-read whenever the theme changes.
|
||||||
|
const readInk = () => getComputedStyle(document.documentElement).getPropertyValue("--ink-rgb").trim() || "255, 255, 255";
|
||||||
|
let ink = readInk();
|
||||||
|
|
||||||
// Fibonacci sphere
|
// Fibonacci sphere
|
||||||
const COUNT = 1500;
|
const COUNT = 1500;
|
||||||
const points: Vec[] = [];
|
const points: Vec[] = [];
|
||||||
@@ -159,15 +163,15 @@ export default function GlobeCanvas({ layout = "hero", className = "hero-canvas"
|
|||||||
|
|
||||||
// soft halo
|
// soft halo
|
||||||
const halo = ctx.createRadialGradient(cx, cy, R * 0.7, cx, cy, R * 1.45);
|
const halo = ctx.createRadialGradient(cx, cy, R * 0.7, cx, cy, R * 1.45);
|
||||||
halo.addColorStop(0, "rgba(255,255,255,0.045)");
|
halo.addColorStop(0, `rgba(${ink},0.045)`);
|
||||||
halo.addColorStop(1, "rgba(255,255,255,0)");
|
halo.addColorStop(1, `rgba(${ink},0)`);
|
||||||
ctx.fillStyle = halo;
|
ctx.fillStyle = halo;
|
||||||
ctx.fillRect(0, 0, w, h);
|
ctx.fillRect(0, 0, w, h);
|
||||||
|
|
||||||
// outline
|
// outline
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(cx, cy, R * 1.0, 0, Math.PI * 2);
|
ctx.arc(cx, cy, R * 1.0, 0, Math.PI * 2);
|
||||||
ctx.strokeStyle = "rgba(255,255,255,0.08)";
|
ctx.strokeStyle = `rgba(${ink},0.08)`;
|
||||||
ctx.lineWidth = 1;
|
ctx.lineWidth = 1;
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
@@ -177,7 +181,7 @@ export default function GlobeCanvas({ layout = "hero", className = "hero-canvas"
|
|||||||
const front = p.z > 0;
|
const front = p.z > 0;
|
||||||
const a = front ? 0.18 + p.z * 0.62 : 0.05 + (1 + p.z) * 0.05;
|
const a = front ? 0.18 + p.z * 0.62 : 0.05 + (1 + p.z) * 0.05;
|
||||||
const size = (front ? 1.15 : 0.8) * p.s;
|
const size = (front ? 1.15 : 0.8) * p.s;
|
||||||
ctx.fillStyle = `rgba(255,255,255,${a.toFixed(3)})`;
|
ctx.fillStyle = `rgba(${ink},${a.toFixed(3)})`;
|
||||||
ctx.fillRect(p.x - size / 2, p.y - size / 2, size, size);
|
ctx.fillRect(p.x - size / 2, p.y - size / 2, size, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,7 +194,7 @@ export default function GlobeCanvas({ layout = "hero", className = "hero-canvas"
|
|||||||
const b = proj[s];
|
const b = proj[s];
|
||||||
const vis = (a.z + b.z) / 2;
|
const vis = (a.z + b.z) / 2;
|
||||||
if (vis < -0.15) continue;
|
if (vis < -0.15) continue;
|
||||||
ctx.strokeStyle = `rgba(255,255,255,${(0.08 + Math.max(0, vis) * 0.22).toFixed(3)})`;
|
ctx.strokeStyle = `rgba(${ink},${(0.08 + Math.max(0, vis) * 0.22).toFixed(3)})`;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.moveTo(a.x, a.y);
|
ctx.moveTo(a.x, a.y);
|
||||||
ctx.lineTo(b.x, b.y);
|
ctx.lineTo(b.x, b.y);
|
||||||
@@ -224,7 +228,7 @@ export default function GlobeCanvas({ layout = "hero", className = "hero-canvas"
|
|||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(p.x, p.y, 3 + pulse * 14, 0, Math.PI * 2);
|
ctx.arc(p.x, p.y, 3 + pulse * 14, 0, Math.PI * 2);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
ctx.fillStyle = `rgba(255,255,255,${(0.4 + p.z * 0.6).toFixed(3)})`;
|
ctx.fillStyle = `rgba(${ink},${(0.4 + p.z * 0.6).toFixed(3)})`;
|
||||||
ctx.fillRect(p.x - 2.5, p.y - 2.5, 5, 5);
|
ctx.fillRect(p.x - 2.5, p.y - 2.5, 5, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,6 +247,12 @@ export default function GlobeCanvas({ layout = "hero", className = "hero-canvas"
|
|||||||
});
|
});
|
||||||
ro.observe(canvas);
|
ro.observe(canvas);
|
||||||
|
|
||||||
|
const themeObserver = new MutationObserver(() => {
|
||||||
|
ink = readInk();
|
||||||
|
if (reduced) draw(performance.now());
|
||||||
|
});
|
||||||
|
themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ["data-theme"] });
|
||||||
|
|
||||||
const io = new IntersectionObserver(([entry]) => {
|
const io = new IntersectionObserver(([entry]) => {
|
||||||
const visible = entry.isIntersecting;
|
const visible = entry.isIntersecting;
|
||||||
if (visible && !running) {
|
if (visible && !running) {
|
||||||
@@ -263,6 +273,7 @@ export default function GlobeCanvas({ layout = "hero", className = "hero-canvas"
|
|||||||
running = false;
|
running = false;
|
||||||
cancelAnimationFrame(raf);
|
cancelAnimationFrame(raf);
|
||||||
ro.disconnect();
|
ro.disconnect();
|
||||||
|
themeObserver.disconnect();
|
||||||
io.disconnect();
|
io.disconnect();
|
||||||
window.removeEventListener("pointermove", onMove);
|
window.removeEventListener("pointermove", onMove);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ export default function Logo({ href, label }: { href: string; label: string }) {
|
|||||||
export function LogoStacked({ href, label }: { href: string; label: string }) {
|
export function LogoStacked({ href, label }: { href: string; label: string }) {
|
||||||
return (
|
return (
|
||||||
<Link href={href} className="logo-stacked" aria-label={label}>
|
<Link href={href} className="logo-stacked" aria-label={label}>
|
||||||
<Image src="/logo-stacked.png" alt="AI Growth Technologies" width={480} height={547} />
|
<Image className="on-dark" src="/logo-stacked.png" alt="AI Growth Technologies" width={480} height={547} />
|
||||||
|
<Image className="on-light" src="/logo-stacked-dark.png" alt="AI Growth Technologies" width={480} height={547} />
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ function JourneyViz({ labels }: { labels: VisualLabels }) {
|
|||||||
return (
|
return (
|
||||||
<svg className="viz viz-journey" viewBox={`0 0 ${W} ${H}`} aria-hidden="true">
|
<svg className="viz viz-journey" viewBox={`0 0 ${W} ${H}`} aria-hidden="true">
|
||||||
{[180, 280, 380].map((x) => (
|
{[180, 280, 380].map((x) => (
|
||||||
<line key={x} x1={x} y1={28} x2={x} y2={H - 28} stroke="rgba(255,255,255,0.05)" />
|
<line key={x} x1={x} y1={28} x2={x} y2={H - 28} style={{ stroke: "rgba(var(--ink-rgb), 0.05)" }} />
|
||||||
))}
|
))}
|
||||||
{sources.map((s, i) => {
|
{sources.map((s, i) => {
|
||||||
const y = top + i * gap;
|
const y = top + i * gap;
|
||||||
@@ -98,7 +98,7 @@ function RadarViz({ labels }: { labels: VisualLabels }) {
|
|||||||
))}
|
))}
|
||||||
<g className="sweep">
|
<g className="sweep">
|
||||||
<path d={`M${cx} ${cy} L${cx + sweepR} ${cy} A${sweepR} ${sweepR} 0 0 0 ${ex} ${ey} Z`} fill="url(#sweepGrad)" />
|
<path d={`M${cx} ${cy} L${cx + sweepR} ${cy} A${sweepR} ${sweepR} 0 0 0 ${ex} ${ey} Z`} fill="url(#sweepGrad)" />
|
||||||
<line x1={cx} y1={cy} x2={cx + sweepR} y2={cy} stroke="rgba(255,255,255,0.6)" />
|
<line x1={cx} y1={cy} x2={cx + sweepR} y2={cy} style={{ stroke: "rgba(var(--ink-rgb), 0.6)" }} />
|
||||||
</g>
|
</g>
|
||||||
{dots.map((d, i) => {
|
{dots.map((d, i) => {
|
||||||
const x = cx + Math.cos(rad(d.a)) * d.r;
|
const x = cx + Math.cos(rad(d.a)) * d.r;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import Link from "next/link";
|
|||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import Logo from "./logo";
|
import Logo from "./logo";
|
||||||
|
import ThemeToggle from "./theme-toggle";
|
||||||
import { localeNames, localeShort, locales, localize, splitLocale, type Locale } from "@/i18n/config";
|
import { localeNames, localeShort, locales, localize, splitLocale, type Locale } from "@/i18n/config";
|
||||||
import type { NavItem } from "@/i18n/nav";
|
import type { NavItem } from "@/i18n/nav";
|
||||||
|
|
||||||
@@ -14,6 +15,8 @@ export type HeaderLabels = {
|
|||||||
closeMenu: string;
|
closeMenu: string;
|
||||||
language: string;
|
language: string;
|
||||||
logoHome: string;
|
logoHome: string;
|
||||||
|
lightTheme: string;
|
||||||
|
darkTheme: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function LanguageSwitch({ locale, path, label }: { locale: Locale; path: string; label: string }) {
|
function LanguageSwitch({ locale, path, label }: { locale: Locale; path: string; label: string }) {
|
||||||
@@ -120,6 +123,7 @@ export default function SiteHeader({ locale, nav, t }: { locale: Locale; nav: Na
|
|||||||
)}
|
)}
|
||||||
</nav>
|
</nav>
|
||||||
<LanguageSwitch locale={locale} path={path} label={t.language} />
|
<LanguageSwitch locale={locale} path={path} label={t.language} />
|
||||||
|
<ThemeToggle t={t} />
|
||||||
<Link href={contactHref} className="btn btn-solid header-cta">
|
<Link href={contactHref} className="btn btn-solid header-cta">
|
||||||
{t.bookCall} <span className="arrow">→</span>
|
{t.bookCall} <span className="arrow">→</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useSyncExternalStore } from "react";
|
||||||
|
|
||||||
|
export type Theme = "dark" | "light";
|
||||||
|
|
||||||
|
// The site is dark by default; a visitor's choice is remembered in localStorage under this key.
|
||||||
|
const KEY = "theme";
|
||||||
|
|
||||||
|
/** Runs in <head> before the page paints, so a saved light theme never flashes dark first. */
|
||||||
|
export const themeScript = `try{if(localStorage.getItem("${KEY}")==="light")document.documentElement.dataset.theme="light"}catch(e){}`;
|
||||||
|
|
||||||
|
const read = (): Theme => (document.documentElement.dataset.theme === "light" ? "light" : "dark");
|
||||||
|
|
||||||
|
function subscribe(onChange: () => void) {
|
||||||
|
const observer = new MutationObserver(onChange);
|
||||||
|
observer.observe(document.documentElement, { attributes: true, attributeFilter: ["data-theme"] });
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The current theme, kept in sync with <html data-theme>. */
|
||||||
|
export function useTheme(): Theme {
|
||||||
|
return useSyncExternalStore(subscribe, read, () => "dark");
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ThemeToggle({ t }: { t: { lightTheme: string; darkTheme: string } }) {
|
||||||
|
const theme = useTheme();
|
||||||
|
const label = theme === "dark" ? t.lightTheme : t.darkTheme;
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
const next: Theme = theme === "dark" ? "light" : "dark";
|
||||||
|
if (next === "light") document.documentElement.dataset.theme = "light";
|
||||||
|
else delete document.documentElement.dataset.theme;
|
||||||
|
try {
|
||||||
|
localStorage.setItem(KEY, next);
|
||||||
|
} catch {
|
||||||
|
// Storage can be blocked (private mode); the theme still switches for this visit.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button type="button" className="theme-toggle" onClick={toggle} aria-label={label} title={label}>
|
||||||
|
<svg className="sun" viewBox="0 0 24 24" aria-hidden="true">
|
||||||
|
<circle cx="12" cy="12" r="4.2" />
|
||||||
|
<path d="M12 2.5v2.2M12 19.3v2.2M2.5 12h2.2M19.3 12h2.2M5.3 5.3l1.6 1.6M17.1 17.1l1.6 1.6M5.3 18.7l1.6-1.6M17.1 6.9l1.6-1.6" />
|
||||||
|
</svg>
|
||||||
|
<svg className="moon" viewBox="0 0 24 24" aria-hidden="true">
|
||||||
|
<path d="M20 14.6A8.5 8.5 0 0 1 9.4 4a8.5 8.5 0 1 0 10.6 10.6z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
"subtitle": "المقر العالمي",
|
"subtitle": "المقر العالمي",
|
||||||
"body": [
|
"body": [
|
||||||
"مقرنا العالمي ومركز الابتكار لدينا في منطقة الشرق الأوسط وشمال أفريقيا.",
|
"مقرنا العالمي ومركز الابتكار لدينا في منطقة الشرق الأوسط وشمال أفريقيا.",
|
||||||
"Downtown Dubai, UAE\nPhone: +971 55 647 0342\nEmail: info@aigrowthtechnologies.com"
|
"Blue Bay Tower, Office 312, 3rd Floor\nMarasi Drive Street, Business Bay\nDubai, UAE\nPhone: +971 55 647 0342\nEmail: info@aigrowthtechnologies.com"
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null
|
"cta": null
|
||||||
@@ -128,7 +128,7 @@
|
|||||||
"subtitle": "مكتب شريك",
|
"subtitle": "مكتب شريك",
|
||||||
"body": [
|
"body": [
|
||||||
"نقطة تواصل في الولايات المتحدة للشركات في تكساس وخارجها.",
|
"نقطة تواصل في الولايات المتحدة للشركات في تكساس وخارجها.",
|
||||||
"Downtown Houston, TX, USA\nPhone: +1 832-350-0465"
|
"Downtown Houston, TX, USA\nPhone: +1 832-350-0465\nEmail: info@aigrowthtechnologies.com"
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null
|
"cta": null
|
||||||
@@ -139,7 +139,7 @@
|
|||||||
"subtitle": "مكتب شريك",
|
"subtitle": "مكتب شريك",
|
||||||
"body": [
|
"body": [
|
||||||
"نقطة تواصل في الولايات المتحدة مقرها جنوب فلوريدا.",
|
"نقطة تواصل في الولايات المتحدة مقرها جنوب فلوريدا.",
|
||||||
"Brickell Avenue, FL, USA\nPhone: +1 954-235-4974"
|
"Brickell Avenue, FL, USA\nPhone: +1 954-235-4974\nEmail: info@aigrowthtechnologies.com"
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null
|
"cta": null
|
||||||
@@ -150,7 +150,7 @@
|
|||||||
"subtitle": "مكتب شريك",
|
"subtitle": "مكتب شريك",
|
||||||
"body": [
|
"body": [
|
||||||
"نقطة تواصل في الولايات المتحدة في أحد أبرز أسواق الأعمال في العالم.",
|
"نقطة تواصل في الولايات المتحدة في أحد أبرز أسواق الأعمال في العالم.",
|
||||||
"Manhattan Financial District, NY, USA\nPhone: +1 713-289-4577"
|
"Manhattan Financial District, NY, USA\nPhone: +1 713-289-4577\nEmail: info@aigrowthtechnologies.com"
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null
|
"cta": null
|
||||||
|
|||||||
@@ -117,7 +117,7 @@
|
|||||||
"subtitle": "Global HQ",
|
"subtitle": "Global HQ",
|
||||||
"body": [
|
"body": [
|
||||||
"Our global headquarters and innovation hub in the MENA region.",
|
"Our global headquarters and innovation hub in the MENA region.",
|
||||||
"Downtown Dubai, UAE\nPhone: +971 55 647 0342\nEmail: info@aigrowthtechnologies.com"
|
"Blue Bay Tower, Office 312, 3rd Floor\nMarasi Drive Street, Business Bay\nDubai, UAE\nPhone: +971 55 647 0342\nEmail: info@aigrowthtechnologies.com"
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null
|
"cta": null
|
||||||
@@ -128,7 +128,7 @@
|
|||||||
"subtitle": "Partner Office",
|
"subtitle": "Partner Office",
|
||||||
"body": [
|
"body": [
|
||||||
"A US point of contact for businesses across Texas and beyond.",
|
"A US point of contact for businesses across Texas and beyond.",
|
||||||
"Downtown Houston, TX, USA\nPhone: +1 832-350-0465"
|
"Downtown Houston, TX, USA\nPhone: +1 832-350-0465\nEmail: info@aigrowthtechnologies.com"
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null
|
"cta": null
|
||||||
@@ -139,7 +139,7 @@
|
|||||||
"subtitle": "Partner Office",
|
"subtitle": "Partner Office",
|
||||||
"body": [
|
"body": [
|
||||||
"A US point of contact based in South Florida.",
|
"A US point of contact based in South Florida.",
|
||||||
"Brickell Avenue, FL, USA\nPhone: +1 954-235-4974"
|
"Brickell Avenue, FL, USA\nPhone: +1 954-235-4974\nEmail: info@aigrowthtechnologies.com"
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null
|
"cta": null
|
||||||
@@ -150,7 +150,7 @@
|
|||||||
"subtitle": "Partner Office",
|
"subtitle": "Partner Office",
|
||||||
"body": [
|
"body": [
|
||||||
"A US point of contact in one of the world’s leading business markets.",
|
"A US point of contact in one of the world’s leading business markets.",
|
||||||
"Manhattan Financial District, NY, USA\nPhone: +1 713-289-4577"
|
"Manhattan Financial District, NY, USA\nPhone: +1 713-289-4577\nEmail: info@aigrowthtechnologies.com"
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null
|
"cta": null
|
||||||
|
|||||||
@@ -28,9 +28,9 @@
|
|||||||
"eyebrow": "WHEN EVERY CHANNEL HAS ITS OWN PLAN",
|
"eyebrow": "WHEN EVERY CHANNEL HAS ITS OWN PLAN",
|
||||||
"title": "Good Marketing Can Still Add Up to a Bad Growth System.",
|
"title": "Good Marketing Can Still Add Up to a Bad Growth System.",
|
||||||
"intro": [
|
"intro": [
|
||||||
"Your SEO team is chasing rankings. Paid media is optimising campaigns. Social is building engagement. The website team is working through its own list. Everyone is busy.",
|
"Your SEO team is chasing rankings. Paid media is optimizing campaigns. Social is building engagement. The website team is working through its own list. Everyone is busy.",
|
||||||
"But is the business learning anything across those channels?",
|
"But is the business learning anything across those channels?",
|
||||||
"A high-converting paid search term could shape organic content. Search behaviour could reveal questions worth targeting in AI answers. Website data could expose where promising traffic disappears. Brand insights could improve the ads people see before they ever search for you.",
|
"A high-converting paid search term could shape organic content. Search behavior could reveal questions worth targeting in AI answers. Website data could expose where promising traffic disappears. Brand insights could improve the ads people see before they ever search for you.",
|
||||||
"When those signals stay inside separate teams and dashboards, the business misses part of their value.",
|
"When those signals stay inside separate teams and dashboards, the business misses part of their value.",
|
||||||
"We bring them together so what works in one place can make the next decision smarter."
|
"We bring them together so what works in one place can make the next decision smarter."
|
||||||
],
|
],
|
||||||
@@ -108,7 +108,7 @@
|
|||||||
"title": "Brand Creation & Optimization",
|
"title": "Brand Creation & Optimization",
|
||||||
"subtitle": null,
|
"subtitle": null,
|
||||||
"body": [
|
"body": [
|
||||||
"Clarify how your business looks, sounds, and positions itself so people recognise the same company wherever they encounter it.",
|
"Clarify how your business looks, sounds, and positions itself so people recognize the same company wherever they encounter it.",
|
||||||
"Strong positioning gives search, media, social, and web a clearer message to carry."
|
"Strong positioning gives search, media, social, and web a clearer message to carry."
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
@@ -147,7 +147,7 @@
|
|||||||
"eyebrow": "THE VALUE IS IN WHAT CONNECTS",
|
"eyebrow": "THE VALUE IS IN WHAT CONNECTS",
|
||||||
"title": "One Useful Signal Should Never Stop at One Channel.",
|
"title": "One Useful Signal Should Never Stop at One Channel.",
|
||||||
"intro": [
|
"intro": [
|
||||||
"A paid campaign tells us which message gets attention. Search data tells us what people are actively looking for. AI visibility shows where the brand is entering new forms of discovery. Website behaviour tells us what happens when people arrive.",
|
"A paid campaign tells us which message gets attention. Search data tells us what people are actively looking for. AI visibility shows where the brand is entering new forms of discovery. Website behavior tells us what happens when people arrive.",
|
||||||
"None of those signals needs to live alone.",
|
"None of those signals needs to live alone.",
|
||||||
"We use what the business is already learning to improve what happens next.",
|
"We use what the business is already learning to improve what happens next.",
|
||||||
"That is where an integrated growth system becomes more valuable over time. Not because there are more channels, but because each one gives the others better information."
|
"That is where an integrated growth system becomes more valuable over time. Not because there are more channels, but because each one gives the others better information."
|
||||||
@@ -163,9 +163,9 @@
|
|||||||
"eyebrow": "SAME SYSTEM. DIFFERENT REALITY.",
|
"eyebrow": "SAME SYSTEM. DIFFERENT REALITY.",
|
||||||
"title": "Different Industries Change the Playbook.",
|
"title": "Different Industries Change the Playbook.",
|
||||||
"intro": [
|
"intro": [
|
||||||
"The fundamentals of growth may travel. Customer behaviour does not.",
|
"The fundamentals of growth may travel. Customer behavior does not.",
|
||||||
"A hospitality company doesn't acquire customers the same way a B2B organisation does. Medical and dental businesses operate within different constraints than e-commerce brands.",
|
"A hospitality company doesn't acquire customers the same way a B2B organization does. Medical and dental businesses operate within different constraints than e-commerce brands.",
|
||||||
"Home services, automotive companies, and creators each have their own buying cycles, competition, search behaviour, and conversion points.",
|
"Home services, automotive companies, and creators each have their own buying cycles, competition, search behavior, and conversion points.",
|
||||||
"We keep the capabilities connected while adapting the strategy to the market they have to perform in."
|
"We keep the capabilities connected while adapting the strategy to the market they have to perform in."
|
||||||
],
|
],
|
||||||
"items": [],
|
"items": [],
|
||||||
|
|||||||
@@ -123,7 +123,7 @@
|
|||||||
"title": "Atrilyx Connects the Signals Behind the Spend.",
|
"title": "Atrilyx Connects the Signals Behind the Spend.",
|
||||||
"intro": [
|
"intro": [
|
||||||
"Paid media creates information everywhere.",
|
"Paid media creates information everywhere.",
|
||||||
"Campaign platforms hold media data. Your website captures behaviour. Your CRM may know which leads became customers. Revenue data tells another part of the story.",
|
"Campaign platforms hold media data. Your website captures behavior. Your CRM may know which leads became customers. Revenue data tells another part of the story.",
|
||||||
"Atrilyx brings those signals into a more connected view."
|
"Atrilyx brings those signals into a more connected view."
|
||||||
],
|
],
|
||||||
"items": [
|
"items": [
|
||||||
@@ -212,7 +212,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"eyebrow": "A CLEARER WAY TO RUN PAID MEDIA",
|
"eyebrow": "A CLEARER WAY TO RUN PAID MEDIA",
|
||||||
"title": "From Audit to Ongoing Optimisation.",
|
"title": "From Audit to Ongoing Optimization.",
|
||||||
"intro": [],
|
"intro": [],
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
@@ -256,7 +256,7 @@
|
|||||||
"title": "Learn",
|
"title": "Learn",
|
||||||
"subtitle": null,
|
"subtitle": null,
|
||||||
"body": [
|
"body": [
|
||||||
"We evaluate acquisition cost, conversion behaviour, lead or customer quality, creative performance, and the wider signals available through Atrilyx."
|
"We evaluate acquisition cost, conversion behavior, lead or customer quality, creative performance, and the wider signals available through Atrilyx."
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null,
|
"cta": null,
|
||||||
@@ -264,11 +264,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"kicker": null,
|
"kicker": null,
|
||||||
"title": "Optimise",
|
"title": "Optimize",
|
||||||
"subtitle": null,
|
"subtitle": null,
|
||||||
"body": [
|
"body": [
|
||||||
"Budgets shift. Creative evolves. Weak assumptions get replaced. Strong campaigns earn room to scale.",
|
"Budgets shift. Creative evolves. Weak assumptions get replaced. Strong campaigns earn room to scale.",
|
||||||
"Optimisation continues because the market keeps giving us new information."
|
"Optimization continues because the market keeps giving us new information."
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null,
|
"cta": null,
|
||||||
@@ -285,7 +285,7 @@
|
|||||||
"eyebrow": "ONE MEDIA PLAN DOESN’T FIT EVERY MARKET",
|
"eyebrow": "ONE MEDIA PLAN DOESN’T FIT EVERY MARKET",
|
||||||
"title": "Global Reach Needs Local Judgment.",
|
"title": "Global Reach Needs Local Judgment.",
|
||||||
"intro": [
|
"intro": [
|
||||||
"Customer behaviour changes by market. So do competition, search patterns, platform usage, media costs, and creative expectations.",
|
"Customer behavior changes by market. So do competition, search patterns, platform usage, media costs, and creative expectations.",
|
||||||
"AI Growth Technologies supports multi-market campaigns with a connected view of performance, while letting targeting, creative, channel mix, and budget decisions respond to local conditions.",
|
"AI Growth Technologies supports multi-market campaigns with a connected view of performance, while letting targeting, creative, channel mix, and budget decisions respond to local conditions.",
|
||||||
"The strategy stays coordinated without pretending every market behaves the same way."
|
"The strategy stays coordinated without pretending every market behaves the same way."
|
||||||
],
|
],
|
||||||
@@ -302,7 +302,7 @@
|
|||||||
"eyebrow": "PAID MEDIA DOESN’T WORK ALONE",
|
"eyebrow": "PAID MEDIA DOESN’T WORK ALONE",
|
||||||
"title": "Explore the Services Around Your Media Strategy.",
|
"title": "Explore the Services Around Your Media Strategy.",
|
||||||
"intro": [
|
"intro": [
|
||||||
"Paid campaigns often reveal opportunities beyond the ad account. Search demand, landing-page behaviour, creative response, and conversion data can point to what to address next."
|
"Paid campaigns often reveal opportunities beyond the ad account. Search demand, landing-page behavior, creative response, and conversion data can point to what to address next."
|
||||||
],
|
],
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
@@ -394,7 +394,7 @@
|
|||||||
"title": "How do you measure paid media performance?",
|
"title": "How do you measure paid media performance?",
|
||||||
"subtitle": null,
|
"subtitle": null,
|
||||||
"body": [
|
"body": [
|
||||||
"That depends on what the business is trying to achieve. Measurement can include qualified leads, customer acquisition cost, revenue, ROAS, conversion behaviour, and other business outcomes alongside platform metrics."
|
"That depends on what the business is trying to achieve. Measurement can include qualified leads, customer acquisition cost, revenue, ROAS, conversion behavior, and other business outcomes alongside platform metrics."
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null
|
"cta": null
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"path": "/services/seo",
|
"path": "/services/seo",
|
||||||
"meta": {
|
"meta": {
|
||||||
"title": "SEO Services | AI Growth Technologies",
|
"title": "SEO Services | AI Growth Technologies",
|
||||||
"description": "Build organic visibility with technical SEO, content, authority, local search, and meSEO insights that connect rankings with visitor behaviour."
|
"description": "Build organic visibility with technical SEO, content, authority, local search, and meSEO insights that connect rankings with visitor behavior."
|
||||||
},
|
},
|
||||||
"hero": {
|
"hero": {
|
||||||
"eyebrow": "RANKINGS ARE ONLY THE BEGINNING.",
|
"eyebrow": "RANKINGS ARE ONLY THE BEGINNING.",
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
"intro": [
|
"intro": [
|
||||||
"A page can rank first and still bring the wrong traffic. Organic visits can climb while leads stay flat. A keyword report can look impressive without telling you what happened after someone landed.",
|
"A page can rank first and still bring the wrong traffic. Organic visits can climb while leads stay flat. A keyword report can look impressive without telling you what happened after someone landed.",
|
||||||
"That is why we look at more than position.",
|
"That is why we look at more than position.",
|
||||||
"AI Growth Technologies combines technical SEO, on-page optimisation, content, authority, and behavioural insight to build organic visibility around searches that matter to the business.",
|
"AI Growth Technologies combines technical SEO, on-page optimization, content, authority, and behavioral insight to build organic visibility around searches that matter to the business.",
|
||||||
"Then meSEO helps us see what visitors actually do with that visibility."
|
"Then meSEO helps us see what visitors actually do with that visibility."
|
||||||
],
|
],
|
||||||
"items": [],
|
"items": [],
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
"Useful information. Not the whole story.",
|
"Useful information. Not the whole story.",
|
||||||
"What did those visitors do next?",
|
"What did those visitors do next?",
|
||||||
"Did they find what they came for? Which pages kept them moving? Where did they leave? Which search topics produced meaningful engagement or conversion?",
|
"Did they find what they came for? Which pages kept them moving? Where did they leave? Which search topics produced meaningful engagement or conversion?",
|
||||||
"We connect search performance with post-click behaviour, so SEO decisions are shaped by more than what happened on the results page."
|
"We connect search performance with post-click behavior, so SEO decisions are shaped by more than what happened on the results page."
|
||||||
],
|
],
|
||||||
"items": [],
|
"items": [],
|
||||||
"outro": [],
|
"outro": [],
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
"subtitle": null,
|
"subtitle": null,
|
||||||
"body": [
|
"body": [
|
||||||
"See what organic visitors do once the ranking has done its job.",
|
"See what organic visitors do once the ranking has done its job.",
|
||||||
"meSEO connects search visibility with on-site behaviour so we can identify where organic traffic engages, moves forward, converts, or disappears."
|
"meSEO connects search visibility with on-site behavior so we can identify where organic traffic engages, moves forward, converts, or disappears."
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null
|
"cta": null
|
||||||
@@ -164,7 +164,7 @@
|
|||||||
"title": "Site Intelligence",
|
"title": "Site Intelligence",
|
||||||
"subtitle": null,
|
"subtitle": null,
|
||||||
"body": [
|
"body": [
|
||||||
"Identify technical health issues and optimisation opportunities that could affect organic performance."
|
"Identify technical health issues and optimization opportunities that could affect organic performance."
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null
|
"cta": null
|
||||||
@@ -198,12 +198,12 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"eyebrow": "THE BEST SEO INSIGHT DOESN’T HAVE TO STAY IN SEO",
|
"eyebrow": "THE BEST SEO INSIGHT DOESN’T HAVE TO STAY IN SEO",
|
||||||
"title": "Search Behaviour Can Improve More Than Rankings.",
|
"title": "Search Behavior Can Improve More Than Rankings.",
|
||||||
"intro": [
|
"intro": [
|
||||||
"Search is one of the clearest expressions of customer intent available to a business.",
|
"Search is one of the clearest expressions of customer intent available to a business.",
|
||||||
"People tell Google what they want to know, what they are comparing, what is confusing them, and sometimes exactly what they are ready to buy.",
|
"People tell Google what they want to know, what they are comparing, what is confusing them, and sometimes exactly what they are ready to buy.",
|
||||||
"That information can go further.",
|
"That information can go further.",
|
||||||
"High-value queries can inform paid media. Recurring questions can reveal opportunities for LLMO and AI visibility. Organic behaviour can expose problems in web development. Search language can even sharpen brand messaging.",
|
"High-value queries can inform paid media. Recurring questions can reveal opportunities for LLMO and AI visibility. Organic behavior can expose problems in web development. Search language can even sharpen brand messaging.",
|
||||||
"SEO becomes more useful when the rest of the growth system can learn from it."
|
"SEO becomes more useful when the rest of the growth system can learn from it."
|
||||||
],
|
],
|
||||||
"items": [],
|
"items": [],
|
||||||
@@ -272,7 +272,7 @@
|
|||||||
"title": "Keep Compounding",
|
"title": "Keep Compounding",
|
||||||
"subtitle": null,
|
"subtitle": null,
|
||||||
"body": [
|
"body": [
|
||||||
"Search behaviour changes. Competitors publish. Sites grow. Algorithms evolve. New opportunities appear.",
|
"Search behavior changes. Competitors publish. Sites grow. Algorithms evolve. New opportunities appear.",
|
||||||
"We keep refining the technical foundation, content, authority, and user experience around what the data continues to reveal."
|
"We keep refining the technical foundation, content, authority, and user experience around what the data continues to reveal."
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
@@ -380,7 +380,7 @@
|
|||||||
"title": "What is included in your SEO services?",
|
"title": "What is included in your SEO services?",
|
||||||
"subtitle": null,
|
"subtitle": null,
|
||||||
"body": [
|
"body": [
|
||||||
"SEO engagements can include technical SEO, on-page optimisation, content strategy, local SEO, internal linking, authority building, competitor analysis, measurement, and behavioural analysis through meSEO. The mix depends on what the site and business actually need."
|
"SEO engagements can include technical SEO, on-page optimization, content strategy, local SEO, internal linking, authority building, competitor analysis, measurement, and behavioral analysis through meSEO. The mix depends on what the site and business actually need."
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null
|
"cta": null
|
||||||
@@ -410,7 +410,7 @@
|
|||||||
"title": "What is meSEO, and how does it support SEO?",
|
"title": "What is meSEO, and how does it support SEO?",
|
||||||
"subtitle": null,
|
"subtitle": null,
|
||||||
"body": [
|
"body": [
|
||||||
"meSEO is AI Growth Technologies’ proprietary search and behavioural analytics platform. It helps connect ranking and search data with what organic visitors do after reaching the site, giving us another layer of evidence for content, technical, and conversion decisions."
|
"meSEO is AI Growth Technologies’ proprietary search and behavioral analytics platform. It helps connect ranking and search data with what organic visitors do after reaching the site, giving us another layer of evidence for content, technical, and conversion decisions."
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null
|
"cta": null
|
||||||
@@ -436,7 +436,7 @@
|
|||||||
"title": "See Where Your Search Opportunities Really Are.",
|
"title": "See Where Your Search Opportunities Really Are.",
|
||||||
"intro": [
|
"intro": [
|
||||||
"If SEO is already producing traffic, we can assess what that visibility is contributing and where valuable opportunities may still be missed.",
|
"If SEO is already producing traffic, we can assess what that visibility is contributing and where valuable opportunities may still be missed.",
|
||||||
"If organic growth has stalled, we can examine the technical foundation, content, authority, competitors, and visitor behaviour to understand what deserves attention first."
|
"If organic growth has stalled, we can examine the technical foundation, content, authority, competitors, and visitor behavior to understand what deserves attention first."
|
||||||
],
|
],
|
||||||
"items": [],
|
"items": [],
|
||||||
"outro": [],
|
"outro": [],
|
||||||
|
|||||||
@@ -117,7 +117,7 @@
|
|||||||
"subtitle": "Sede global",
|
"subtitle": "Sede global",
|
||||||
"body": [
|
"body": [
|
||||||
"Nuestra sede global y centro de innovación en la región MENA.",
|
"Nuestra sede global y centro de innovación en la región MENA.",
|
||||||
"Downtown Dubai, UAE\nPhone: +971 55 647 0342\nEmail: info@aigrowthtechnologies.com"
|
"Blue Bay Tower, Office 312, 3rd Floor\nMarasi Drive Street, Business Bay\nDubai, UAE\nPhone: +971 55 647 0342\nEmail: info@aigrowthtechnologies.com"
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null
|
"cta": null
|
||||||
@@ -128,7 +128,7 @@
|
|||||||
"subtitle": "Oficina asociada",
|
"subtitle": "Oficina asociada",
|
||||||
"body": [
|
"body": [
|
||||||
"Un punto de contacto en EE. UU. para empresas de Texas y más allá.",
|
"Un punto de contacto en EE. UU. para empresas de Texas y más allá.",
|
||||||
"Downtown Houston, TX, USA\nPhone: +1 832-350-0465"
|
"Downtown Houston, TX, USA\nPhone: +1 832-350-0465\nEmail: info@aigrowthtechnologies.com"
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null
|
"cta": null
|
||||||
@@ -139,7 +139,7 @@
|
|||||||
"subtitle": "Oficina asociada",
|
"subtitle": "Oficina asociada",
|
||||||
"body": [
|
"body": [
|
||||||
"Un punto de contacto en EE. UU. ubicado en el sur de Florida.",
|
"Un punto de contacto en EE. UU. ubicado en el sur de Florida.",
|
||||||
"Brickell Avenue, FL, USA\nPhone: +1 954-235-4974"
|
"Brickell Avenue, FL, USA\nPhone: +1 954-235-4974\nEmail: info@aigrowthtechnologies.com"
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null
|
"cta": null
|
||||||
@@ -150,7 +150,7 @@
|
|||||||
"subtitle": "Oficina asociada",
|
"subtitle": "Oficina asociada",
|
||||||
"body": [
|
"body": [
|
||||||
"Un punto de contacto en EE. UU. en uno de los mercados de negocios más importantes del mundo.",
|
"Un punto de contacto en EE. UU. en uno de los mercados de negocios más importantes del mundo.",
|
||||||
"Manhattan Financial District, NY, USA\nPhone: +1 713-289-4577"
|
"Manhattan Financial District, NY, USA\nPhone: +1 713-289-4577\nEmail: info@aigrowthtechnologies.com"
|
||||||
],
|
],
|
||||||
"list": [],
|
"list": [],
|
||||||
"cta": null
|
"cta": null
|
||||||
|
|||||||
@@ -19,8 +19,14 @@ export const ar: UI = {
|
|||||||
openMenu: "فتح القائمة",
|
openMenu: "فتح القائمة",
|
||||||
closeMenu: "إغلاق القائمة",
|
closeMenu: "إغلاق القائمة",
|
||||||
language: "اللغة",
|
language: "اللغة",
|
||||||
|
lightTheme: "التبديل إلى الوضع الفاتح",
|
||||||
|
darkTheme: "التبديل إلى الوضع الداكن",
|
||||||
},
|
},
|
||||||
bookCall: "احجز مكالمة استراتيجية",
|
bookCall: "احجز مكالمة استراتيجية",
|
||||||
|
ctaBand: {
|
||||||
|
title: "هل أنت مستعد لمعرفة أين يتعثر نمو أعمالك؟",
|
||||||
|
body: "تحدث مع أحد خبراء الاستراتيجية حول قنواتك وبياناتك وما يجب إصلاحه أولاً.",
|
||||||
|
},
|
||||||
services: {
|
services: {
|
||||||
"paid-media": "الإعلانات المدفوعة",
|
"paid-media": "الإعلانات المدفوعة",
|
||||||
seo: "تحسين محركات البحث (SEO)",
|
seo: "تحسين محركات البحث (SEO)",
|
||||||
|
|||||||
@@ -19,8 +19,14 @@ export const en = {
|
|||||||
openMenu: "Open menu",
|
openMenu: "Open menu",
|
||||||
closeMenu: "Close menu",
|
closeMenu: "Close menu",
|
||||||
language: "Language",
|
language: "Language",
|
||||||
|
lightTheme: "Switch to light theme",
|
||||||
|
darkTheme: "Switch to dark theme",
|
||||||
},
|
},
|
||||||
bookCall: "Book a Strategy Call",
|
bookCall: "Book a Strategy Call",
|
||||||
|
ctaBand: {
|
||||||
|
title: "Ready to see where growth is getting stuck?",
|
||||||
|
body: "Talk to a strategist about your channels, your data, and what to fix first.",
|
||||||
|
},
|
||||||
services: {
|
services: {
|
||||||
"paid-media": "Paid Media",
|
"paid-media": "Paid Media",
|
||||||
seo: "SEO",
|
seo: "SEO",
|
||||||
|
|||||||
@@ -19,8 +19,14 @@ export const es: UI = {
|
|||||||
openMenu: "Abrir menú",
|
openMenu: "Abrir menú",
|
||||||
closeMenu: "Cerrar menú",
|
closeMenu: "Cerrar menú",
|
||||||
language: "Idioma",
|
language: "Idioma",
|
||||||
|
lightTheme: "Cambiar a tema claro",
|
||||||
|
darkTheme: "Cambiar a tema oscuro",
|
||||||
},
|
},
|
||||||
bookCall: "Agenda una llamada estratégica",
|
bookCall: "Agenda una llamada estratégica",
|
||||||
|
ctaBand: {
|
||||||
|
title: "¿Listo para ver dónde se está frenando tu crecimiento?",
|
||||||
|
body: "Habla con un estratega sobre tus canales, tus datos y qué conviene resolver primero.",
|
||||||
|
},
|
||||||
services: {
|
services: {
|
||||||
"paid-media": "Medios pagados",
|
"paid-media": "Medios pagados",
|
||||||
seo: "SEO",
|
seo: "SEO",
|
||||||
|
|||||||
Reference in New Issue
Block a user